]> git.sesse.net Git - ffmpeg/blob - libavfilter/af_afftfilt.c
avfilter/af_afftfilt: extend filter functionality
[ffmpeg] / libavfilter / af_afftfilt.c
1 /*
2  * Copyright (c) 2016 Paul B Mahol
3  *
4  * This file is part of FFmpeg.
5  *
6  * FFmpeg is free software; you can redistribute it and/or modify it
7  * under the terms of the GNU Lesser General Public License as published
8  * by the Free Software Foundation; either version 2.1 of the License,
9  * or (at your option) any later version.
10  *
11  * FFmpeg is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with FFmpeg; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19  */
20
21 #include "libavutil/audio_fifo.h"
22 #include "libavutil/avstring.h"
23 #include "libavfilter/internal.h"
24 #include "libavutil/common.h"
25 #include "libavutil/opt.h"
26 #include "libavcodec/avfft.h"
27 #include "libavutil/eval.h"
28 #include "audio.h"
29 #include "window_func.h"
30
31 typedef struct AFFTFiltContext {
32     const AVClass *class;
33     char *real_str;
34     char *img_str;
35     int fft_bits;
36
37     FFTContext *fft, *ifft;
38     FFTComplex **fft_data;
39     FFTComplex **fft_temp;
40     int nb_exprs;
41     int window_size;
42     AVExpr **real;
43     AVExpr **imag;
44     AVAudioFifo *fifo;
45     int64_t pts;
46     int hop_size;
47     float overlap;
48     AVFrame *buffer;
49     int start, end;
50     int win_func;
51     float win_scale;
52     float *window_func_lut;
53 } AFFTFiltContext;
54
55 static const char *const var_names[] = {            "sr",     "b",       "nb",        "ch",        "chs",   "pts",     "re",     "im", NULL };
56 enum                                   { VAR_SAMPLE_RATE, VAR_BIN, VAR_NBBINS, VAR_CHANNEL, VAR_CHANNELS, VAR_PTS, VAR_REAL, VAR_IMAG, VAR_VARS_NB };
57
58 #define OFFSET(x) offsetof(AFFTFiltContext, x)
59 #define A AV_OPT_FLAG_AUDIO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
60
61 static const AVOption afftfilt_options[] = {
62     { "real", "set channels real expressions",       OFFSET(real_str), AV_OPT_TYPE_STRING, {.str = "re" }, 0, 0, A },
63     { "imag", "set channels imaginary expressions",  OFFSET(img_str),  AV_OPT_TYPE_STRING, {.str = "im" }, 0, 0, A },
64     { "win_size", "set window size", OFFSET(fft_bits), AV_OPT_TYPE_INT, {.i64=12}, 4, 17, A, "fft" },
65         { "w16",    0, 0, AV_OPT_TYPE_CONST, {.i64=4},  0, 0, A, "fft" },
66         { "w32",    0, 0, AV_OPT_TYPE_CONST, {.i64=5},  0, 0, A, "fft" },
67         { "w64",    0, 0, AV_OPT_TYPE_CONST, {.i64=6},  0, 0, A, "fft" },
68         { "w128",   0, 0, AV_OPT_TYPE_CONST, {.i64=7},  0, 0, A, "fft" },
69         { "w256",   0, 0, AV_OPT_TYPE_CONST, {.i64=8},  0, 0, A, "fft" },
70         { "w512",   0, 0, AV_OPT_TYPE_CONST, {.i64=9},  0, 0, A, "fft" },
71         { "w1024",  0, 0, AV_OPT_TYPE_CONST, {.i64=10}, 0, 0, A, "fft" },
72         { "w2048",  0, 0, AV_OPT_TYPE_CONST, {.i64=11}, 0, 0, A, "fft" },
73         { "w4096",  0, 0, AV_OPT_TYPE_CONST, {.i64=12}, 0, 0, A, "fft" },
74         { "w8192",  0, 0, AV_OPT_TYPE_CONST, {.i64=13}, 0, 0, A, "fft" },
75         { "w16384", 0, 0, AV_OPT_TYPE_CONST, {.i64=14}, 0, 0, A, "fft" },
76         { "w32768", 0, 0, AV_OPT_TYPE_CONST, {.i64=15}, 0, 0, A, "fft" },
77         { "w65536", 0, 0, AV_OPT_TYPE_CONST, {.i64=16}, 0, 0, A, "fft" },
78         { "w131072",0, 0, AV_OPT_TYPE_CONST, {.i64=17}, 0, 0, A, "fft" },
79     { "win_func", "set window function", OFFSET(win_func), AV_OPT_TYPE_INT, {.i64 = WFUNC_HANNING}, 0, NB_WFUNC-1, A, "win_func" },
80         { "rect",     "Rectangular",      0, AV_OPT_TYPE_CONST, {.i64=WFUNC_RECT},     0, 0, A, "win_func" },
81         { "bartlett", "Bartlett",         0, AV_OPT_TYPE_CONST, {.i64=WFUNC_BARTLETT}, 0, 0, A, "win_func" },
82         { "hann",     "Hann",             0, AV_OPT_TYPE_CONST, {.i64=WFUNC_HANNING},  0, 0, A, "win_func" },
83         { "hanning",  "Hanning",          0, AV_OPT_TYPE_CONST, {.i64=WFUNC_HANNING},  0, 0, A, "win_func" },
84         { "hamming",  "Hamming",          0, AV_OPT_TYPE_CONST, {.i64=WFUNC_HAMMING},  0, 0, A, "win_func" },
85         { "sine",     "Sine",             0, AV_OPT_TYPE_CONST, {.i64=WFUNC_SINE},     0, 0, A, "win_func" },
86     { "overlap", "set window overlap", OFFSET(overlap), AV_OPT_TYPE_FLOAT, {.dbl=0.75}, 0,  1, A },
87     { NULL },
88 };
89
90 AVFILTER_DEFINE_CLASS(afftfilt);
91
92 static inline double getreal(void *priv, double x, double ch)
93 {
94     AFFTFiltContext *s = priv;
95     int ich, ix;
96
97     ich = av_clip(ch, 0, s->nb_exprs - 1);
98     ix = av_clip(x, 0, s->window_size / 2);
99
100     return s->fft_data[ich][ix].re;
101 }
102
103 static inline double getimag(void *priv, double x, double ch)
104 {
105     AFFTFiltContext *s = priv;
106     int ich, ix;
107
108     ich = av_clip(ch, 0, s->nb_exprs - 1);
109     ix = av_clip(x, 0, s->window_size / 2);
110
111     return s->fft_data[ich][ix].im;
112 }
113
114 static double realf(void *priv, double x, double ch) { return getreal(priv, x, ch); }
115 static double imagf(void *priv, double x, double ch) { return getimag(priv, x, ch); }
116
117 static const char *const func2_names[]    = { "real", "imag", NULL };
118 double (*func2[])(void *, double, double) = {  realf,  imagf, NULL };
119
120 static int config_input(AVFilterLink *inlink)
121 {
122     AVFilterContext *ctx = inlink->dst;
123     AFFTFiltContext *s = ctx->priv;
124     char *saveptr = NULL;
125     int ret = 0, ch, i;
126     float overlap;
127     char *args;
128     const char *last_expr = "1";
129
130     s->fft  = av_fft_init(s->fft_bits, 0);
131     s->ifft = av_fft_init(s->fft_bits, 1);
132     if (!s->fft || !s->ifft)
133         return AVERROR(ENOMEM);
134
135     s->window_size = 1 << s->fft_bits;
136
137     s->fft_data = av_calloc(inlink->channels, sizeof(*s->fft_data));
138     if (!s->fft_data)
139         return AVERROR(ENOMEM);
140
141     s->fft_temp = av_calloc(inlink->channels, sizeof(*s->fft_temp));
142     if (!s->fft_temp)
143         return AVERROR(ENOMEM);
144
145     for (ch = 0; ch < inlink->channels; ch++) {
146         s->fft_data[ch] = av_calloc(s->window_size, sizeof(**s->fft_data));
147         if (!s->fft_data[ch])
148             return AVERROR(ENOMEM);
149     }
150
151     for (ch = 0; ch < inlink->channels; ch++) {
152         s->fft_temp[ch] = av_calloc(s->window_size, sizeof(**s->fft_temp));
153         if (!s->fft_temp[ch])
154             return AVERROR(ENOMEM);
155     }
156
157     s->real = av_calloc(inlink->channels, sizeof(*s->real));
158     if (!s->real)
159         return AVERROR(ENOMEM);
160
161     s->imag = av_calloc(inlink->channels, sizeof(*s->imag));
162     if (!s->imag)
163         return AVERROR(ENOMEM);
164
165     args = av_strdup(s->real_str);
166     if (!args)
167         return AVERROR(ENOMEM);
168
169     for (ch = 0; ch < inlink->channels; ch++) {
170         char *arg = av_strtok(ch == 0 ? args : NULL, "|", &saveptr);
171
172         ret = av_expr_parse(&s->real[ch], arg ? arg : last_expr, var_names,
173                             NULL, NULL, func2_names, func2, 0, ctx);
174         if (ret < 0)
175             break;
176         if (arg)
177             last_expr = arg;
178         s->nb_exprs++;
179     }
180
181     av_free(args);
182
183     args = av_strdup(s->img_str ? s->img_str : s->real_str);
184     if (!args)
185         return AVERROR(ENOMEM);
186
187     for (ch = 0; ch < inlink->channels; ch++) {
188         char *arg = av_strtok(ch == 0 ? args : NULL, "|", &saveptr);
189
190         ret = av_expr_parse(&s->imag[ch], arg ? arg : last_expr, var_names,
191                             NULL, NULL, func2_names, func2, 0, ctx);
192         if (ret < 0)
193             break;
194         if (arg)
195             last_expr = arg;
196     }
197
198     av_free(args);
199
200     s->fifo = av_audio_fifo_alloc(inlink->format, inlink->channels, s->window_size);
201     if (!s->fifo)
202         return AVERROR(ENOMEM);
203
204     s->window_func_lut = av_realloc_f(s->window_func_lut, s->window_size,
205                                       sizeof(*s->window_func_lut));
206     if (!s->window_func_lut)
207         return AVERROR(ENOMEM);
208     generate_window_func(s->window_func_lut, s->window_size, s->win_func, &overlap);
209     if (s->overlap == 1)
210         s->overlap = overlap;
211
212     for (s->win_scale = 0, i = 0; i < s->window_size; i++) {
213         s->win_scale += s->window_func_lut[i] * s->window_func_lut[i];
214     }
215
216     s->hop_size = s->window_size * (1 - s->overlap);
217     if (s->hop_size <= 0)
218         return AVERROR(EINVAL);
219
220     s->buffer = ff_get_audio_buffer(inlink, s->window_size * 2);
221     if (!s->buffer)
222         return AVERROR(ENOMEM);
223
224     return ret;
225 }
226
227 static int filter_frame(AVFilterLink *inlink, AVFrame *frame)
228 {
229     AVFilterContext *ctx = inlink->dst;
230     AVFilterLink *outlink = ctx->outputs[0];
231     AFFTFiltContext *s = ctx->priv;
232     const int window_size = s->window_size;
233     const float f = 1. / s->win_scale;
234     double values[VAR_VARS_NB];
235     AVFrame *out, *in = NULL;
236     int ch, n, ret, i, j, k;
237     int start = s->start, end = s->end;
238
239     ret = av_audio_fifo_write(s->fifo, (void **)frame->extended_data, frame->nb_samples);
240     av_frame_free(&frame);
241     if (ret < 0)
242         return ret;
243
244     while (av_audio_fifo_size(s->fifo) >= window_size) {
245         if (!in) {
246             in = ff_get_audio_buffer(outlink, window_size);
247             if (!in)
248                 return AVERROR(ENOMEM);
249         }
250
251         ret = av_audio_fifo_peek(s->fifo, (void **)in->extended_data, window_size);
252         if (ret < 0)
253             break;
254
255         for (ch = 0; ch < inlink->channels; ch++) {
256             const float *src = (float *)in->extended_data[ch];
257             FFTComplex *fft_data = s->fft_data[ch];
258
259             for (n = 0; n < in->nb_samples; n++) {
260                 fft_data[n].re = src[n] * s->window_func_lut[n];
261                 fft_data[n].im = 0;
262             }
263
264             for (; n < window_size; n++) {
265                 fft_data[n].re = 0;
266                 fft_data[n].im = 0;
267             }
268         }
269
270         values[VAR_PTS]         = s->pts;
271         values[VAR_SAMPLE_RATE] = inlink->sample_rate;
272         values[VAR_NBBINS]      = window_size / 2;
273         values[VAR_CHANNELS]    = inlink->channels;
274
275         for (ch = 0; ch < inlink->channels; ch++) {
276             FFTComplex *fft_data = s->fft_data[ch];
277             FFTComplex *fft_temp = s->fft_temp[ch];
278             float *buf = (float *)s->buffer->extended_data[ch];
279             int x;
280
281             values[VAR_CHANNEL] = ch;
282
283             av_fft_permute(s->fft, fft_data);
284             av_fft_calc(s->fft, fft_data);
285
286             for (n = 0; n <= window_size / 2; n++) {
287                 float fr, fi;
288
289                 values[VAR_BIN] = n;
290                 values[VAR_REAL] = fft_data[n].re;
291                 values[VAR_IMAG] = fft_data[n].im;
292
293                 fr = av_expr_eval(s->real[ch], values, s);
294                 fi = av_expr_eval(s->imag[ch], values, s);
295
296                 fft_temp[n].re = fr;
297                 fft_temp[n].im = fi;
298             }
299
300             for (n = window_size / 2 + 1, x = window_size / 2 - 1; n < window_size; n++, x--) {
301                 fft_temp[n].re =  fft_temp[x].re;
302                 fft_temp[n].im = -fft_temp[x].im;
303             }
304
305             av_fft_permute(s->ifft, fft_temp);
306             av_fft_calc(s->ifft, fft_temp);
307
308             start = s->start;
309             end = s->end;
310             k = end;
311             for (i = 0, j = start; j < k && i < window_size; i++, j++) {
312                 buf[j] += s->fft_temp[ch][i].re * f;
313             }
314
315             for (; i < window_size; i++, j++) {
316                 buf[j] = s->fft_temp[ch][i].re * f;
317             }
318
319             start += s->hop_size;
320             end = j;
321         }
322
323         s->start = start;
324         s->end = end;
325
326         if (start >= window_size) {
327             float *dst, *buf;
328
329             start -= window_size;
330             end   -= window_size;
331
332             s->start = start;
333             s->end = end;
334
335             out = ff_get_audio_buffer(outlink, window_size);
336             if (!out) {
337                 ret = AVERROR(ENOMEM);
338                 break;
339             }
340
341             out->pts = s->pts;
342             s->pts += window_size;
343
344             for (ch = 0; ch < inlink->channels; ch++) {
345                 dst = (float *)out->extended_data[ch];
346                 buf = (float *)s->buffer->extended_data[ch];
347
348                 for (n = 0; n < window_size; n++) {
349                     dst[n] = buf[n] * (1 - s->overlap);
350                 }
351                 memmove(buf, buf + window_size, window_size * 4);
352             }
353
354             ret = ff_filter_frame(outlink, out);
355             if (ret < 0)
356                 break;
357         }
358
359         av_audio_fifo_drain(s->fifo, s->hop_size);
360     }
361
362     av_frame_free(&in);
363     return ret < 0 ? ret : 0;
364 }
365
366 static int query_formats(AVFilterContext *ctx)
367 {
368     AVFilterFormats *formats;
369     AVFilterChannelLayouts *layouts;
370     static const enum AVSampleFormat sample_fmts[] = {
371         AV_SAMPLE_FMT_FLTP,
372         AV_SAMPLE_FMT_NONE
373     };
374     int ret;
375
376     layouts = ff_all_channel_counts();
377     if (!layouts)
378         return AVERROR(ENOMEM);
379     ret = ff_set_common_channel_layouts(ctx, layouts);
380     if (ret < 0)
381         return ret;
382
383     formats = ff_make_format_list(sample_fmts);
384     if (!formats)
385         return AVERROR(ENOMEM);
386     ret = ff_set_common_formats(ctx, formats);
387     if (ret < 0)
388         return ret;
389
390     formats = ff_all_samplerates();
391     if (!formats)
392         return AVERROR(ENOMEM);
393     return ff_set_common_samplerates(ctx, formats);
394 }
395
396 static av_cold void uninit(AVFilterContext *ctx)
397 {
398     AFFTFiltContext *s = ctx->priv;
399     int i;
400
401     av_fft_end(s->fft);
402     av_fft_end(s->ifft);
403
404     for (i = 0; i < s->nb_exprs; i++) {
405         if (s->fft_data)
406             av_freep(&s->fft_data[i]);
407         if (s->fft_temp)
408             av_freep(&s->fft_temp[i]);
409     }
410     av_freep(&s->fft_data);
411     av_freep(&s->fft_temp);
412
413     for (i = 0; i < s->nb_exprs; i++) {
414         av_expr_free(s->real[i]);
415         av_expr_free(s->imag[i]);
416     }
417
418     av_freep(&s->real);
419     av_freep(&s->imag);
420     av_frame_free(&s->buffer);
421     av_freep(&s->window_func_lut);
422
423     av_audio_fifo_free(s->fifo);
424 }
425
426 static const AVFilterPad inputs[] = {
427     {
428         .name         = "default",
429         .type         = AVMEDIA_TYPE_AUDIO,
430         .config_props = config_input,
431         .filter_frame = filter_frame,
432     },
433     { NULL }
434 };
435
436 static const AVFilterPad outputs[] = {
437     {
438         .name = "default",
439         .type = AVMEDIA_TYPE_AUDIO,
440     },
441     { NULL }
442 };
443
444 AVFilter ff_af_afftfilt = {
445     .name            = "afftfilt",
446     .description     = NULL_IF_CONFIG_SMALL("Apply arbitrary expressions to samples in frequency domain."),
447     .priv_size       = sizeof(AFFTFiltContext),
448     .priv_class      = &afftfilt_class,
449     .inputs          = inputs,
450     .outputs         = outputs,
451     .query_formats   = query_formats,
452     .uninit          = uninit,
453 };