|
|
|
@ -24,7 +24,7 @@ |
|
|
|
|
* @todo support float pixel format |
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
#include "libavcodec/avfft.h" |
|
|
|
|
#include "libavutil/tx.h" |
|
|
|
|
#include "libavutil/avassert.h" |
|
|
|
|
#include "libavutil/channel_layout.h" |
|
|
|
|
#include "libavutil/ffmath.h" |
|
|
|
@ -53,9 +53,10 @@ typedef struct SpectrumSynthContext { |
|
|
|
|
int orientation; |
|
|
|
|
|
|
|
|
|
AVFrame *magnitude, *phase; |
|
|
|
|
FFTContext *fft; ///< 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
|
|
|
|
|
AVTXContext *fft; ///< Fast Fourier Transform context
|
|
|
|
|
av_tx_fn tx_fn; |
|
|
|
|
AVComplexFloat **fft_in; ///< bins holder for each (displayed) channels
|
|
|
|
|
AVComplexFloat **fft_out; ///< bins holder for each (displayed) channels
|
|
|
|
|
int win_size; |
|
|
|
|
int size; |
|
|
|
|
int nb_freq; |
|
|
|
@ -150,8 +151,8 @@ static int config_output(AVFilterLink *outlink) |
|
|
|
|
int height = ctx->inputs[0]->h; |
|
|
|
|
AVRational time_base = ctx->inputs[0]->time_base; |
|
|
|
|
AVRational frame_rate = ctx->inputs[0]->frame_rate; |
|
|
|
|
int i, ch, fft_bits; |
|
|
|
|
float factor, overlap; |
|
|
|
|
float factor, overlap, scale; |
|
|
|
|
int i, ch, ret; |
|
|
|
|
|
|
|
|
|
outlink->sample_rate = s->sample_rate; |
|
|
|
|
outlink->time_base = (AVRational){1, s->sample_rate}; |
|
|
|
@ -182,23 +183,30 @@ static int config_output(AVFilterLink *outlink) |
|
|
|
|
s->size = s->orientation == VERTICAL ? height / s->channels : width / s->channels; |
|
|
|
|
s->xend = s->orientation == VERTICAL ? width : height; |
|
|
|
|
|
|
|
|
|
for (fft_bits = 1; 1 << fft_bits < 2 * s->size; fft_bits++); |
|
|
|
|
s->win_size = s->size * 2; |
|
|
|
|
s->nb_freq = s->size; |
|
|
|
|
|
|
|
|
|
s->win_size = 1 << fft_bits; |
|
|
|
|
s->nb_freq = 1 << (fft_bits - 1); |
|
|
|
|
|
|
|
|
|
s->fft = av_fft_init(fft_bits, 1); |
|
|
|
|
if (!s->fft) { |
|
|
|
|
ret = av_tx_init(&s->fft, &s->tx_fn, AV_TX_FLOAT_FFT, 1, s->win_size, &scale, 0); |
|
|
|
|
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; |
|
|
|
|
} |
|
|
|
|
s->fft_data = av_calloc(s->channels, sizeof(*s->fft_data)); |
|
|
|
|
if (!s->fft_data) |
|
|
|
|
|
|
|
|
|
s->fft_in = av_calloc(s->channels, sizeof(*s->fft_in)); |
|
|
|
|
if (!s->fft_in) |
|
|
|
|
return AVERROR(ENOMEM); |
|
|
|
|
s->fft_out = av_calloc(s->channels, sizeof(*s->fft_out)); |
|
|
|
|
if (!s->fft_out) |
|
|
|
|
return AVERROR(ENOMEM); |
|
|
|
|
|
|
|
|
|
for (ch = 0; ch < s->channels; ch++) { |
|
|
|
|
s->fft_data[ch] = av_calloc(s->win_size, sizeof(**s->fft_data)); |
|
|
|
|
if (!s->fft_data[ch]) |
|
|
|
|
s->fft_in[ch] = av_calloc(FFALIGN(s->win_size, av_cpu_max_align()), sizeof(**s->fft_in)); |
|
|
|
|
if (!s->fft_in[ch]) |
|
|
|
|
return AVERROR(ENOMEM); |
|
|
|
|
|
|
|
|
|
s->fft_out[ch] = av_calloc(FFALIGN(s->win_size, av_cpu_max_align()), sizeof(**s->fft_out)); |
|
|
|
|
if (!s->fft_out[ch]) |
|
|
|
|
return AVERROR(ENOMEM); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -244,8 +252,8 @@ static void read16_fft_bin(SpectrumSynthContext *s, |
|
|
|
|
} |
|
|
|
|
phase = ((p[x] / (double)UINT16_MAX) * 2. - 1.) * M_PI; |
|
|
|
|
|
|
|
|
|
s->fft_data[ch][f].re = magnitude * cos(phase); |
|
|
|
|
s->fft_data[ch][f].im = magnitude * sin(phase); |
|
|
|
|
s->fft_in[ch][f].re = magnitude * cos(phase); |
|
|
|
|
s->fft_in[ch][f].im = magnitude * sin(phase); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static void read8_fft_bin(SpectrumSynthContext *s, |
|
|
|
@ -269,8 +277,8 @@ static void read8_fft_bin(SpectrumSynthContext *s, |
|
|
|
|
} |
|
|
|
|
phase = ((p[x] / (double)UINT8_MAX) * 2. - 1.) * M_PI; |
|
|
|
|
|
|
|
|
|
s->fft_data[ch][f].re = magnitude * cos(phase); |
|
|
|
|
s->fft_data[ch][f].im = magnitude * sin(phase); |
|
|
|
|
s->fft_in[ch][f].re = magnitude * cos(phase); |
|
|
|
|
s->fft_in[ch][f].im = magnitude * sin(phase); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static void read_fft_data(AVFilterContext *ctx, int x, int h, int ch) |
|
|
|
@ -330,17 +338,16 @@ static void synth_window(AVFilterContext *ctx, int x) |
|
|
|
|
read_fft_data(ctx, x, h, ch); |
|
|
|
|
|
|
|
|
|
for (y = h; y <= s->nb_freq; y++) { |
|
|
|
|
s->fft_data[ch][y].re = 0; |
|
|
|
|
s->fft_data[ch][y].im = 0; |
|
|
|
|
s->fft_in[ch][y].re = 0; |
|
|
|
|
s->fft_in[ch][y].im = 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
for (y = s->nb_freq + 1, f = s->nb_freq - 1; y < nb; y++, f--) { |
|
|
|
|
s->fft_data[ch][y].re = s->fft_data[ch][f].re; |
|
|
|
|
s->fft_data[ch][y].im = -s->fft_data[ch][f].im; |
|
|
|
|
s->fft_in[ch][y].re = s->fft_in[ch][f].re; |
|
|
|
|
s->fft_in[ch][y].im = -s->fft_in[ch][f].im; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
av_fft_permute(s->fft, s->fft_data[ch]); |
|
|
|
|
av_fft_calc(s->fft, s->fft_data[ch]); |
|
|
|
|
s->tx_fn(s->fft, s->fft_out[ch], s->fft_in[ch], sizeof(float)); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -363,11 +370,11 @@ static int try_push_frame(AVFilterContext *ctx, int x) |
|
|
|
|
end = s->end; |
|
|
|
|
k = end; |
|
|
|
|
for (i = 0, j = start; j < k && i < s->win_size; i++, j++) { |
|
|
|
|
buf[j] += s->fft_data[ch][i].re; |
|
|
|
|
buf[j] += s->fft_out[ch][i].re; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
for (; i < s->win_size; i++, j++) { |
|
|
|
|
buf[j] = s->fft_data[ch][i].re; |
|
|
|
|
buf[j] = s->fft_out[ch][i].re; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
start += s->hop_size; |
|
|
|
@ -499,12 +506,19 @@ static av_cold void uninit(AVFilterContext *ctx) |
|
|
|
|
av_frame_free(&s->magnitude); |
|
|
|
|
av_frame_free(&s->phase); |
|
|
|
|
av_frame_free(&s->buffer); |
|
|
|
|
av_fft_end(s->fft); |
|
|
|
|
if (s->fft_data) { |
|
|
|
|
|
|
|
|
|
av_tx_uninit(&s->fft); |
|
|
|
|
|
|
|
|
|
if (s->fft_in) { |
|
|
|
|
for (i = 0; i < s->channels; i++) |
|
|
|
|
av_freep(&s->fft_in[i]); |
|
|
|
|
} |
|
|
|
|
if (s->fft_out) { |
|
|
|
|
for (i = 0; i < s->channels; i++) |
|
|
|
|
av_freep(&s->fft_data[i]); |
|
|
|
|
av_freep(&s->fft_out[i]); |
|
|
|
|
} |
|
|
|
|
av_freep(&s->fft_data); |
|
|
|
|
av_freep(&s->fft_in); |
|
|
|
|
av_freep(&s->fft_out); |
|
|
|
|
av_freep(&s->window_func_lut); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|