LCOV - code coverage report
Current view: top level - src/libavfilter - af_afftfilt.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 0 179 0.0 %
Date: 2017-04-23 07:57:23 Functions: 0 4 0.0 %

          Line data    Source code
       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             :     int nb_exprs;
      40             :     int window_size;
      41             :     AVExpr **real;
      42             :     AVExpr **imag;
      43             :     AVAudioFifo *fifo;
      44             :     int64_t pts;
      45             :     int hop_size;
      46             :     float overlap;
      47             :     AVFrame *buffer;
      48             :     int start, end;
      49             :     int win_func;
      50             :     float win_scale;
      51             :     float *window_func_lut;
      52             : } AFFTFiltContext;
      53             : 
      54             : static const char *const var_names[] = {            "sr",     "b",       "nb",        "ch",        "chs",   "pts",        NULL };
      55             : enum                                   { VAR_SAMPLE_RATE, VAR_BIN, VAR_NBBINS, VAR_CHANNEL, VAR_CHANNELS, VAR_PTS, VAR_VARS_NB };
      56             : 
      57             : #define OFFSET(x) offsetof(AFFTFiltContext, x)
      58             : #define A AV_OPT_FLAG_AUDIO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
      59             : 
      60             : static const AVOption afftfilt_options[] = {
      61             :     { "real", "set channels real expressions",       OFFSET(real_str), AV_OPT_TYPE_STRING, {.str = "1" }, 0, 0, A },
      62             :     { "imag",  "set channels imaginary expressions", OFFSET(img_str),  AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, A },
      63             :     { "win_size", "set window size", OFFSET(fft_bits), AV_OPT_TYPE_INT, {.i64=12}, 4, 17, A, "fft" },
      64             :         { "w16",    0, 0, AV_OPT_TYPE_CONST, {.i64=4},  0, 0, A, "fft" },
      65             :         { "w32",    0, 0, AV_OPT_TYPE_CONST, {.i64=5},  0, 0, A, "fft" },
      66             :         { "w64",    0, 0, AV_OPT_TYPE_CONST, {.i64=6},  0, 0, A, "fft" },
      67             :         { "w128",   0, 0, AV_OPT_TYPE_CONST, {.i64=7},  0, 0, A, "fft" },
      68             :         { "w256",   0, 0, AV_OPT_TYPE_CONST, {.i64=8},  0, 0, A, "fft" },
      69             :         { "w512",   0, 0, AV_OPT_TYPE_CONST, {.i64=9},  0, 0, A, "fft" },
      70             :         { "w1024",  0, 0, AV_OPT_TYPE_CONST, {.i64=10}, 0, 0, A, "fft" },
      71             :         { "w2048",  0, 0, AV_OPT_TYPE_CONST, {.i64=11}, 0, 0, A, "fft" },
      72             :         { "w4096",  0, 0, AV_OPT_TYPE_CONST, {.i64=12}, 0, 0, A, "fft" },
      73             :         { "w8192",  0, 0, AV_OPT_TYPE_CONST, {.i64=13}, 0, 0, A, "fft" },
      74             :         { "w16384", 0, 0, AV_OPT_TYPE_CONST, {.i64=14}, 0, 0, A, "fft" },
      75             :         { "w32768", 0, 0, AV_OPT_TYPE_CONST, {.i64=15}, 0, 0, A, "fft" },
      76             :         { "w65536", 0, 0, AV_OPT_TYPE_CONST, {.i64=16}, 0, 0, A, "fft" },
      77             :         { "w131072",0, 0, AV_OPT_TYPE_CONST, {.i64=17}, 0, 0, A, "fft" },
      78             :     { "win_func", "set window function", OFFSET(win_func), AV_OPT_TYPE_INT, {.i64 = WFUNC_HANNING}, 0, NB_WFUNC-1, A, "win_func" },
      79             :         { "rect",     "Rectangular",      0, AV_OPT_TYPE_CONST, {.i64=WFUNC_RECT},     0, 0, A, "win_func" },
      80             :         { "bartlett", "Bartlett",         0, AV_OPT_TYPE_CONST, {.i64=WFUNC_BARTLETT}, 0, 0, A, "win_func" },
      81             :         { "hann",     "Hann",             0, AV_OPT_TYPE_CONST, {.i64=WFUNC_HANNING},  0, 0, A, "win_func" },
      82             :         { "hanning",  "Hanning",          0, AV_OPT_TYPE_CONST, {.i64=WFUNC_HANNING},  0, 0, A, "win_func" },
      83             :         { "hamming",  "Hamming",          0, AV_OPT_TYPE_CONST, {.i64=WFUNC_HAMMING},  0, 0, A, "win_func" },
      84             :         { "sine",     "Sine",             0, AV_OPT_TYPE_CONST, {.i64=WFUNC_SINE},     0, 0, A, "win_func" },
      85             :     { "overlap", "set window overlap", OFFSET(overlap), AV_OPT_TYPE_FLOAT, {.dbl=0.75}, 0,  1, A },
      86             :     { NULL },
      87             : };
      88             : 
      89             : AVFILTER_DEFINE_CLASS(afftfilt);
      90             : 
      91           0 : static int config_input(AVFilterLink *inlink)
      92             : {
      93           0 :     AVFilterContext *ctx = inlink->dst;
      94           0 :     AFFTFiltContext *s = ctx->priv;
      95           0 :     char *saveptr = NULL;
      96           0 :     int ret = 0, ch, i;
      97             :     float overlap;
      98             :     char *args;
      99           0 :     const char *last_expr = "1";
     100             : 
     101           0 :     s->fft  = av_fft_init(s->fft_bits, 0);
     102           0 :     s->ifft = av_fft_init(s->fft_bits, 1);
     103           0 :     if (!s->fft || !s->ifft)
     104           0 :         return AVERROR(ENOMEM);
     105             : 
     106           0 :     s->window_size = 1 << s->fft_bits;
     107             : 
     108           0 :     s->fft_data = av_calloc(inlink->channels, sizeof(*s->fft_data));
     109           0 :     if (!s->fft_data)
     110           0 :         return AVERROR(ENOMEM);
     111             : 
     112           0 :     for (ch = 0; ch < inlink->channels; ch++) {
     113           0 :         s->fft_data[ch] = av_calloc(s->window_size, sizeof(**s->fft_data));
     114           0 :         if (!s->fft_data[ch])
     115           0 :             return AVERROR(ENOMEM);
     116             :     }
     117             : 
     118           0 :     s->real = av_calloc(inlink->channels, sizeof(*s->real));
     119           0 :     if (!s->real)
     120           0 :         return AVERROR(ENOMEM);
     121             : 
     122           0 :     s->imag = av_calloc(inlink->channels, sizeof(*s->imag));
     123           0 :     if (!s->imag)
     124           0 :         return AVERROR(ENOMEM);
     125             : 
     126           0 :     args = av_strdup(s->real_str);
     127           0 :     if (!args)
     128           0 :         return AVERROR(ENOMEM);
     129             : 
     130           0 :     for (ch = 0; ch < inlink->channels; ch++) {
     131           0 :         char *arg = av_strtok(ch == 0 ? args : NULL, "|", &saveptr);
     132             : 
     133           0 :         ret = av_expr_parse(&s->real[ch], arg ? arg : last_expr, var_names,
     134             :                             NULL, NULL, NULL, NULL, 0, ctx);
     135           0 :         if (ret < 0)
     136           0 :             break;
     137           0 :         if (arg)
     138           0 :             last_expr = arg;
     139           0 :         s->nb_exprs++;
     140             :     }
     141             : 
     142           0 :     av_free(args);
     143             : 
     144           0 :     args = av_strdup(s->img_str ? s->img_str : s->real_str);
     145           0 :     if (!args)
     146           0 :         return AVERROR(ENOMEM);
     147             : 
     148           0 :     for (ch = 0; ch < inlink->channels; ch++) {
     149           0 :         char *arg = av_strtok(ch == 0 ? args : NULL, "|", &saveptr);
     150             : 
     151           0 :         ret = av_expr_parse(&s->imag[ch], arg ? arg : last_expr, var_names,
     152             :                             NULL, NULL, NULL, NULL, 0, ctx);
     153           0 :         if (ret < 0)
     154           0 :             break;
     155           0 :         if (arg)
     156           0 :             last_expr = arg;
     157             :     }
     158             : 
     159           0 :     av_free(args);
     160             : 
     161           0 :     s->fifo = av_audio_fifo_alloc(inlink->format, inlink->channels, s->window_size);
     162           0 :     if (!s->fifo)
     163           0 :         return AVERROR(ENOMEM);
     164             : 
     165           0 :     s->window_func_lut = av_realloc_f(s->window_func_lut, s->window_size,
     166             :                                       sizeof(*s->window_func_lut));
     167           0 :     if (!s->window_func_lut)
     168           0 :         return AVERROR(ENOMEM);
     169           0 :     ff_generate_window_func(s->window_func_lut, s->window_size, s->win_func, &overlap);
     170           0 :     if (s->overlap == 1)
     171           0 :         s->overlap = overlap;
     172             : 
     173           0 :     for (s->win_scale = 0, i = 0; i < s->window_size; i++) {
     174           0 :         s->win_scale += s->window_func_lut[i] * s->window_func_lut[i];
     175             :     }
     176             : 
     177           0 :     s->hop_size = s->window_size * (1 - s->overlap);
     178           0 :     if (s->hop_size <= 0)
     179           0 :         return AVERROR(EINVAL);
     180             : 
     181           0 :     s->buffer = ff_get_audio_buffer(inlink, s->window_size * 2);
     182           0 :     if (!s->buffer)
     183           0 :         return AVERROR(ENOMEM);
     184             : 
     185           0 :     return ret;
     186             : }
     187             : 
     188           0 : static int filter_frame(AVFilterLink *inlink, AVFrame *frame)
     189             : {
     190           0 :     AVFilterContext *ctx = inlink->dst;
     191           0 :     AVFilterLink *outlink = ctx->outputs[0];
     192           0 :     AFFTFiltContext *s = ctx->priv;
     193           0 :     const int window_size = s->window_size;
     194           0 :     const float f = 1. / s->win_scale;
     195             :     double values[VAR_VARS_NB];
     196           0 :     AVFrame *out, *in = NULL;
     197             :     int ch, n, ret, i, j, k;
     198           0 :     int start = s->start, end = s->end;
     199             : 
     200           0 :     av_audio_fifo_write(s->fifo, (void **)frame->extended_data, frame->nb_samples);
     201           0 :     av_frame_free(&frame);
     202             : 
     203           0 :     while (av_audio_fifo_size(s->fifo) >= window_size) {
     204           0 :         if (!in) {
     205           0 :             in = ff_get_audio_buffer(outlink, window_size);
     206           0 :             if (!in)
     207           0 :                 return AVERROR(ENOMEM);
     208             :         }
     209             : 
     210           0 :         ret = av_audio_fifo_peek(s->fifo, (void **)in->extended_data, window_size);
     211           0 :         if (ret < 0)
     212           0 :             break;
     213             : 
     214           0 :         for (ch = 0; ch < inlink->channels; ch++) {
     215           0 :             const float *src = (float *)in->extended_data[ch];
     216           0 :             FFTComplex *fft_data = s->fft_data[ch];
     217             : 
     218           0 :             for (n = 0; n < in->nb_samples; n++) {
     219           0 :                 fft_data[n].re = src[n] * s->window_func_lut[n];
     220           0 :                 fft_data[n].im = 0;
     221             :             }
     222             : 
     223           0 :             for (; n < window_size; n++) {
     224           0 :                 fft_data[n].re = 0;
     225           0 :                 fft_data[n].im = 0;
     226             :             }
     227             :         }
     228             : 
     229           0 :         values[VAR_PTS]         = s->pts;
     230           0 :         values[VAR_SAMPLE_RATE] = inlink->sample_rate;
     231           0 :         values[VAR_NBBINS]      = window_size / 2;
     232           0 :         values[VAR_CHANNELS]    = inlink->channels;
     233             : 
     234           0 :         for (ch = 0; ch < inlink->channels; ch++) {
     235           0 :             FFTComplex *fft_data = s->fft_data[ch];
     236           0 :             float *buf = (float *)s->buffer->extended_data[ch];
     237             :             int x;
     238             : 
     239           0 :             values[VAR_CHANNEL] = ch;
     240             : 
     241           0 :             av_fft_permute(s->fft, fft_data);
     242           0 :             av_fft_calc(s->fft, fft_data);
     243             : 
     244           0 :             for (n = 0; n < window_size / 2; n++) {
     245             :                 float fr, fi;
     246             : 
     247           0 :                 values[VAR_BIN] = n;
     248             : 
     249           0 :                 fr = av_expr_eval(s->real[ch], values, s);
     250           0 :                 fi = av_expr_eval(s->imag[ch], values, s);
     251             : 
     252           0 :                 fft_data[n].re *= fr;
     253           0 :                 fft_data[n].im *= fi;
     254             :             }
     255             : 
     256           0 :             for (n = window_size / 2 + 1, x = window_size / 2 - 1; n < window_size; n++, x--) {
     257           0 :                 fft_data[n].re =  fft_data[x].re;
     258           0 :                 fft_data[n].im = -fft_data[x].im;
     259             :             }
     260             : 
     261           0 :             av_fft_permute(s->ifft, fft_data);
     262           0 :             av_fft_calc(s->ifft, fft_data);
     263             : 
     264           0 :             start = s->start;
     265           0 :             end = s->end;
     266           0 :             k = end;
     267           0 :             for (i = 0, j = start; j < k && i < window_size; i++, j++) {
     268           0 :                 buf[j] += s->fft_data[ch][i].re * f;
     269             :             }
     270             : 
     271           0 :             for (; i < window_size; i++, j++) {
     272           0 :                 buf[j] = s->fft_data[ch][i].re * f;
     273             :             }
     274             : 
     275           0 :             start += s->hop_size;
     276           0 :             end = j;
     277             :         }
     278             : 
     279           0 :         s->start = start;
     280           0 :         s->end = end;
     281             : 
     282           0 :         if (start >= window_size) {
     283             :             float *dst, *buf;
     284             : 
     285           0 :             start -= window_size;
     286           0 :             end   -= window_size;
     287             : 
     288           0 :             s->start = start;
     289           0 :             s->end = end;
     290             : 
     291           0 :             out = ff_get_audio_buffer(outlink, window_size);
     292           0 :             if (!out) {
     293           0 :                 ret = AVERROR(ENOMEM);
     294           0 :                 break;
     295             :             }
     296             : 
     297           0 :             out->pts = s->pts;
     298           0 :             s->pts += window_size;
     299             : 
     300           0 :             for (ch = 0; ch < inlink->channels; ch++) {
     301           0 :                 dst = (float *)out->extended_data[ch];
     302           0 :                 buf = (float *)s->buffer->extended_data[ch];
     303             : 
     304           0 :                 for (n = 0; n < window_size; n++) {
     305           0 :                     dst[n] = buf[n] * (1 - s->overlap);
     306             :                 }
     307           0 :                 memmove(buf, buf + window_size, window_size * 4);
     308             :             }
     309             : 
     310           0 :             ret = ff_filter_frame(outlink, out);
     311           0 :             if (ret < 0)
     312           0 :                 break;
     313             :         }
     314             : 
     315           0 :         av_audio_fifo_drain(s->fifo, s->hop_size);
     316             :     }
     317             : 
     318           0 :     av_frame_free(&in);
     319           0 :     return ret;
     320             : }
     321             : 
     322           0 : static int query_formats(AVFilterContext *ctx)
     323             : {
     324             :     AVFilterFormats *formats;
     325             :     AVFilterChannelLayouts *layouts;
     326             :     static const enum AVSampleFormat sample_fmts[] = {
     327             :         AV_SAMPLE_FMT_FLTP,
     328             :         AV_SAMPLE_FMT_NONE
     329             :     };
     330             :     int ret;
     331             : 
     332           0 :     layouts = ff_all_channel_counts();
     333           0 :     if (!layouts)
     334           0 :         return AVERROR(ENOMEM);
     335           0 :     ret = ff_set_common_channel_layouts(ctx, layouts);
     336           0 :     if (ret < 0)
     337           0 :         return ret;
     338             : 
     339           0 :     formats = ff_make_format_list(sample_fmts);
     340           0 :     if (!formats)
     341           0 :         return AVERROR(ENOMEM);
     342           0 :     ret = ff_set_common_formats(ctx, formats);
     343           0 :     if (ret < 0)
     344           0 :         return ret;
     345             : 
     346           0 :     formats = ff_all_samplerates();
     347           0 :     if (!formats)
     348           0 :         return AVERROR(ENOMEM);
     349           0 :     return ff_set_common_samplerates(ctx, formats);
     350             : }
     351             : 
     352           0 : static av_cold void uninit(AVFilterContext *ctx)
     353             : {
     354           0 :     AFFTFiltContext *s = ctx->priv;
     355             :     int i;
     356             : 
     357           0 :     av_fft_end(s->fft);
     358           0 :     av_fft_end(s->ifft);
     359             : 
     360           0 :     for (i = 0; i < s->nb_exprs; i++) {
     361           0 :         if (s->fft_data)
     362           0 :             av_freep(&s->fft_data[i]);
     363             :     }
     364           0 :     av_freep(&s->fft_data);
     365             : 
     366           0 :     for (i = 0; i < s->nb_exprs; i++) {
     367           0 :         av_expr_free(s->real[i]);
     368           0 :         av_expr_free(s->imag[i]);
     369             :     }
     370             : 
     371           0 :     av_freep(&s->real);
     372           0 :     av_freep(&s->imag);
     373           0 :     av_frame_free(&s->buffer);
     374           0 : }
     375             : 
     376             : static const AVFilterPad inputs[] = {
     377             :     {
     378             :         .name         = "default",
     379             :         .type         = AVMEDIA_TYPE_AUDIO,
     380             :         .config_props = config_input,
     381             :         .filter_frame = filter_frame,
     382             :     },
     383             :     { NULL }
     384             : };
     385             : 
     386             : static const AVFilterPad outputs[] = {
     387             :     {
     388             :         .name = "default",
     389             :         .type = AVMEDIA_TYPE_AUDIO,
     390             :     },
     391             :     { NULL }
     392             : };
     393             : 
     394             : AVFilter ff_af_afftfilt = {
     395             :     .name            = "afftfilt",
     396             :     .description     = NULL_IF_CONFIG_SMALL("Apply arbitrary expressions to samples in frequency domain."),
     397             :     .priv_size       = sizeof(AFFTFiltContext),
     398             :     .priv_class      = &afftfilt_class,
     399             :     .inputs          = inputs,
     400             :     .outputs         = outputs,
     401             :     .query_formats   = query_formats,
     402             :     .uninit          = uninit,
     403             : };

Generated by: LCOV version 1.13