X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=libavfilter%2Faf_afftfilt.c;h=8518f08dc5eb5238abe1e5d81a6e5d8794ea8f8d;hb=fda424b300c1a0b991296aa585691609d01196bd;hp=7f28e1f77bcdf3437a6d544722c9b7a07ccf71a5;hpb=ae7e66fb4b1a256fb79a016b9c585de84ac77339;p=ffmpeg diff --git a/libavfilter/af_afftfilt.c b/libavfilter/af_afftfilt.c index 7f28e1f77bc..8518f08dc5e 100644 --- a/libavfilter/af_afftfilt.c +++ b/libavfilter/af_afftfilt.c @@ -36,6 +36,7 @@ typedef struct AFFTFiltContext { FFTContext *fft, *ifft; FFTComplex **fft_data; + FFTComplex **fft_temp; int nb_exprs; int window_size; AVExpr **real; @@ -51,15 +52,15 @@ typedef struct AFFTFiltContext { float *window_func_lut; } AFFTFiltContext; -static const char *const var_names[] = { "sr", "b", "nb", "ch", "chs", "pts", NULL }; -enum { VAR_SAMPLE_RATE, VAR_BIN, VAR_NBBINS, VAR_CHANNEL, VAR_CHANNELS, VAR_PTS, VAR_VARS_NB }; +static const char *const var_names[] = { "sr", "b", "nb", "ch", "chs", "pts", "re", "im", NULL }; +enum { VAR_SAMPLE_RATE, VAR_BIN, VAR_NBBINS, VAR_CHANNEL, VAR_CHANNELS, VAR_PTS, VAR_REAL, VAR_IMAG, VAR_VARS_NB }; #define OFFSET(x) offsetof(AFFTFiltContext, x) #define A AV_OPT_FLAG_AUDIO_PARAM|AV_OPT_FLAG_FILTERING_PARAM static const AVOption afftfilt_options[] = { - { "real", "set channels real expressions", OFFSET(real_str), AV_OPT_TYPE_STRING, {.str = "1" }, 0, 0, A }, - { "imag", "set channels imaginary expressions", OFFSET(img_str), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, A }, + { "real", "set channels real expressions", OFFSET(real_str), AV_OPT_TYPE_STRING, {.str = "re" }, 0, 0, A }, + { "imag", "set channels imaginary expressions", OFFSET(img_str), AV_OPT_TYPE_STRING, {.str = "im" }, 0, 0, A }, { "win_size", "set window size", OFFSET(fft_bits), AV_OPT_TYPE_INT, {.i64=12}, 4, 17, A, "fft" }, { "w16", 0, 0, AV_OPT_TYPE_CONST, {.i64=4}, 0, 0, A, "fft" }, { "w32", 0, 0, AV_OPT_TYPE_CONST, {.i64=5}, 0, 0, A, "fft" }, @@ -81,13 +82,56 @@ static const AVOption afftfilt_options[] = { { "hann", "Hann", 0, AV_OPT_TYPE_CONST, {.i64=WFUNC_HANNING}, 0, 0, A, "win_func" }, { "hanning", "Hanning", 0, AV_OPT_TYPE_CONST, {.i64=WFUNC_HANNING}, 0, 0, A, "win_func" }, { "hamming", "Hamming", 0, AV_OPT_TYPE_CONST, {.i64=WFUNC_HAMMING}, 0, 0, A, "win_func" }, + { "blackman", "Blackman", 0, AV_OPT_TYPE_CONST, {.i64=WFUNC_BLACKMAN}, 0, 0, A, "win_func" }, + { "welch", "Welch", 0, AV_OPT_TYPE_CONST, {.i64=WFUNC_WELCH}, 0, 0, A, "win_func" }, + { "flattop", "Flat-top", 0, AV_OPT_TYPE_CONST, {.i64=WFUNC_FLATTOP}, 0, 0, A, "win_func" }, + { "bharris", "Blackman-Harris", 0, AV_OPT_TYPE_CONST, {.i64=WFUNC_BHARRIS}, 0, 0, A, "win_func" }, + { "bnuttall", "Blackman-Nuttall", 0, AV_OPT_TYPE_CONST, {.i64=WFUNC_BNUTTALL}, 0, 0, A, "win_func" }, + { "bhann", "Bartlett-Hann", 0, AV_OPT_TYPE_CONST, {.i64=WFUNC_BHANN}, 0, 0, A, "win_func" }, { "sine", "Sine", 0, AV_OPT_TYPE_CONST, {.i64=WFUNC_SINE}, 0, 0, A, "win_func" }, + { "nuttall", "Nuttall", 0, AV_OPT_TYPE_CONST, {.i64=WFUNC_NUTTALL}, 0, 0, A, "win_func" }, + { "lanczos", "Lanczos", 0, AV_OPT_TYPE_CONST, {.i64=WFUNC_LANCZOS}, 0, 0, A, "win_func" }, + { "gauss", "Gauss", 0, AV_OPT_TYPE_CONST, {.i64=WFUNC_GAUSS}, 0, 0, A, "win_func" }, + { "tukey", "Tukey", 0, AV_OPT_TYPE_CONST, {.i64=WFUNC_TUKEY}, 0, 0, A, "win_func" }, + { "dolph", "Dolph-Chebyshev", 0, AV_OPT_TYPE_CONST, {.i64=WFUNC_DOLPH}, 0, 0, A, "win_func" }, + { "cauchy", "Cauchy", 0, AV_OPT_TYPE_CONST, {.i64=WFUNC_CAUCHY}, 0, 0, A, "win_func" }, + { "parzen", "Parzen", 0, AV_OPT_TYPE_CONST, {.i64=WFUNC_PARZEN}, 0, 0, A, "win_func" }, + { "poisson", "Poisson", 0, AV_OPT_TYPE_CONST, {.i64=WFUNC_POISSON}, 0, 0, A, "win_func" }, + { "bohman", "Bohman", 0, AV_OPT_TYPE_CONST, {.i64=WFUNC_BOHMAN}, 0, 0, A, "win_func" }, { "overlap", "set window overlap", OFFSET(overlap), AV_OPT_TYPE_FLOAT, {.dbl=0.75}, 0, 1, A }, { NULL }, }; AVFILTER_DEFINE_CLASS(afftfilt); +static inline double getreal(void *priv, double x, double ch) +{ + AFFTFiltContext *s = priv; + int ich, ix; + + ich = av_clip(ch, 0, s->nb_exprs - 1); + ix = av_clip(x, 0, s->window_size / 2); + + return s->fft_data[ich][ix].re; +} + +static inline double getimag(void *priv, double x, double ch) +{ + AFFTFiltContext *s = priv; + int ich, ix; + + ich = av_clip(ch, 0, s->nb_exprs - 1); + ix = av_clip(x, 0, s->window_size / 2); + + return s->fft_data[ich][ix].im; +} + +static double realf(void *priv, double x, double ch) { return getreal(priv, x, ch); } +static double imagf(void *priv, double x, double ch) { return getimag(priv, x, ch); } + +static const char *const func2_names[] = { "real", "imag", NULL }; +double (*func2[])(void *, double, double) = { realf, imagf, NULL }; + static int config_input(AVFilterLink *inlink) { AVFilterContext *ctx = inlink->dst; @@ -98,6 +142,7 @@ static int config_input(AVFilterLink *inlink) char *args; const char *last_expr = "1"; + s->pts = AV_NOPTS_VALUE; s->fft = av_fft_init(s->fft_bits, 0); s->ifft = av_fft_init(s->fft_bits, 1); if (!s->fft || !s->ifft) @@ -109,12 +154,22 @@ static int config_input(AVFilterLink *inlink) if (!s->fft_data) return AVERROR(ENOMEM); + s->fft_temp = av_calloc(inlink->channels, sizeof(*s->fft_temp)); + if (!s->fft_temp) + return AVERROR(ENOMEM); + for (ch = 0; ch < inlink->channels; ch++) { s->fft_data[ch] = av_calloc(s->window_size, sizeof(**s->fft_data)); if (!s->fft_data[ch]) return AVERROR(ENOMEM); } + for (ch = 0; ch < inlink->channels; ch++) { + s->fft_temp[ch] = av_calloc(s->window_size, sizeof(**s->fft_temp)); + if (!s->fft_temp[ch]) + return AVERROR(ENOMEM); + } + s->real = av_calloc(inlink->channels, sizeof(*s->real)); if (!s->real) return AVERROR(ENOMEM); @@ -131,7 +186,7 @@ static int config_input(AVFilterLink *inlink) char *arg = av_strtok(ch == 0 ? args : NULL, "|", &saveptr); ret = av_expr_parse(&s->real[ch], arg ? arg : last_expr, var_names, - NULL, NULL, NULL, NULL, 0, ctx); + NULL, NULL, func2_names, func2, 0, ctx); if (ret < 0) break; if (arg) @@ -149,7 +204,7 @@ static int config_input(AVFilterLink *inlink) char *arg = av_strtok(ch == 0 ? args : NULL, "|", &saveptr); ret = av_expr_parse(&s->imag[ch], arg ? arg : last_expr, var_names, - NULL, NULL, NULL, NULL, 0, ctx); + NULL, NULL, func2_names, func2, 0, ctx); if (ret < 0) break; if (arg) @@ -197,6 +252,9 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *frame) int ch, n, ret, i, j, k; int start = s->start, end = s->end; + if (s->pts == AV_NOPTS_VALUE) + s->pts = frame->pts; + ret = av_audio_fifo_write(s->fifo, (void **)frame->extended_data, frame->nb_samples); av_frame_free(&frame); if (ret < 0) @@ -235,43 +293,49 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *frame) for (ch = 0; ch < inlink->channels; ch++) { FFTComplex *fft_data = s->fft_data[ch]; - float *buf = (float *)s->buffer->extended_data[ch]; - int x; - - values[VAR_CHANNEL] = ch; av_fft_permute(s->fft, fft_data); av_fft_calc(s->fft, fft_data); + } + + for (ch = 0; ch < inlink->channels; ch++) { + FFTComplex *fft_data = s->fft_data[ch]; + FFTComplex *fft_temp = s->fft_temp[ch]; + float *buf = (float *)s->buffer->extended_data[ch]; + int x; + values[VAR_CHANNEL] = ch; - for (n = 0; n < window_size / 2; n++) { + for (n = 0; n <= window_size / 2; n++) { float fr, fi; values[VAR_BIN] = n; + values[VAR_REAL] = fft_data[n].re; + values[VAR_IMAG] = fft_data[n].im; fr = av_expr_eval(s->real[ch], values, s); fi = av_expr_eval(s->imag[ch], values, s); - fft_data[n].re *= fr; - fft_data[n].im *= fi; + fft_temp[n].re = fr; + fft_temp[n].im = fi; } for (n = window_size / 2 + 1, x = window_size / 2 - 1; n < window_size; n++, x--) { - fft_data[n].re = fft_data[x].re; - fft_data[n].im = -fft_data[x].im; + fft_temp[n].re = fft_temp[x].re; + fft_temp[n].im = -fft_temp[x].im; } - av_fft_permute(s->ifft, fft_data); - av_fft_calc(s->ifft, fft_data); + av_fft_permute(s->ifft, fft_temp); + av_fft_calc(s->ifft, fft_temp); start = s->start; end = s->end; k = end; for (i = 0, j = start; j < k && i < window_size; i++, j++) { - buf[j] += s->fft_data[ch][i].re * f; + buf[j] += s->fft_temp[ch][i].re * f; } for (; i < window_size; i++, j++) { - buf[j] = s->fft_data[ch][i].re * f; + buf[j] = s->fft_temp[ch][i].re * f; } start += s->hop_size; @@ -362,8 +426,11 @@ static av_cold void uninit(AVFilterContext *ctx) for (i = 0; i < s->nb_exprs; i++) { if (s->fft_data) av_freep(&s->fft_data[i]); + if (s->fft_temp) + av_freep(&s->fft_temp[i]); } av_freep(&s->fft_data); + av_freep(&s->fft_temp); for (i = 0; i < s->nb_exprs; i++) { av_expr_free(s->real[i]);