LCOV - code coverage report
Current view: top level - libavfilter - af_afir.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 0 288 0.0 %
Date: 2017-12-16 01:21:47 Functions: 0 11 0.0 %

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 2017 Paul B Mahol
       3             :  *
       4             :  * This file is part of FFmpeg.
       5             :  *
       6             :  * FFmpeg is free software; you can redistribute it and/or
       7             :  * modify it under the terms of the GNU Lesser General Public
       8             :  * License as published by the Free Software Foundation; either
       9             :  * version 2.1 of the License, 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             : /**
      22             :  * @file
      23             :  * An arbitrary audio FIR filter
      24             :  */
      25             : 
      26             : #include "libavutil/audio_fifo.h"
      27             : #include "libavutil/common.h"
      28             : #include "libavutil/float_dsp.h"
      29             : #include "libavutil/opt.h"
      30             : #include "libavcodec/avfft.h"
      31             : 
      32             : #include "audio.h"
      33             : #include "avfilter.h"
      34             : #include "formats.h"
      35             : #include "internal.h"
      36             : #include "af_afir.h"
      37             : 
      38           0 : static void fcmul_add_c(float *sum, const float *t, const float *c, ptrdiff_t len)
      39             : {
      40             :     int n;
      41             : 
      42           0 :     for (n = 0; n < len; n++) {
      43           0 :         const float cre = c[2 * n    ];
      44           0 :         const float cim = c[2 * n + 1];
      45           0 :         const float tre = t[2 * n    ];
      46           0 :         const float tim = t[2 * n + 1];
      47             : 
      48           0 :         sum[2 * n    ] += tre * cre - tim * cim;
      49           0 :         sum[2 * n + 1] += tre * cim + tim * cre;
      50             :     }
      51             : 
      52           0 :     sum[2 * n] += t[2 * n] * c[2 * n];
      53           0 : }
      54             : 
      55           0 : static int fir_channel(AVFilterContext *ctx, void *arg, int ch, int nb_jobs)
      56             : {
      57           0 :     AudioFIRContext *s = ctx->priv;
      58           0 :     const float *src = (const float *)s->in[0]->extended_data[ch];
      59           0 :     int index1 = (s->index + 1) % 3;
      60           0 :     int index2 = (s->index + 2) % 3;
      61           0 :     float *sum = s->sum[ch];
      62           0 :     AVFrame *out = arg;
      63             :     float *block;
      64             :     float *dst;
      65             :     int n, i, j;
      66             : 
      67           0 :     memset(sum, 0, sizeof(*sum) * s->fft_length);
      68           0 :     block = s->block[ch] + s->part_index * s->block_size;
      69           0 :     memset(block, 0, sizeof(*block) * s->fft_length);
      70             : 
      71           0 :     s->fdsp->vector_fmul_scalar(block + s->part_size, src, s->dry_gain, FFALIGN(s->nb_samples, 4));
      72           0 :     emms_c();
      73             : 
      74           0 :     av_rdft_calc(s->rdft[ch], block);
      75           0 :     block[2 * s->part_size] = block[1];
      76           0 :     block[1] = 0;
      77             : 
      78           0 :     j = s->part_index;
      79             : 
      80           0 :     for (i = 0; i < s->nb_partitions; i++) {
      81           0 :         const int coffset = i * s->coeff_size;
      82           0 :         const FFTComplex *coeff = s->coeff[ch * !s->one2many] + coffset;
      83             : 
      84           0 :         block = s->block[ch] + j * s->block_size;
      85           0 :         s->fcmul_add(sum, block, (const float *)coeff, s->part_size);
      86             : 
      87           0 :         if (j == 0)
      88           0 :             j = s->nb_partitions;
      89           0 :         j--;
      90             :     }
      91             : 
      92           0 :     sum[1] = sum[2 * s->part_size];
      93           0 :     av_rdft_calc(s->irdft[ch], sum);
      94             : 
      95           0 :     dst = (float *)s->buffer->extended_data[ch] + index1 * s->part_size;
      96           0 :     for (n = 0; n < s->part_size; n++) {
      97           0 :         dst[n] += sum[n];
      98             :     }
      99             : 
     100           0 :     dst = (float *)s->buffer->extended_data[ch] + index2 * s->part_size;
     101             : 
     102           0 :     memcpy(dst, sum + s->part_size, s->part_size * sizeof(*dst));
     103             : 
     104           0 :     dst = (float *)s->buffer->extended_data[ch] + s->index * s->part_size;
     105             : 
     106           0 :     if (out) {
     107           0 :         float *ptr = (float *)out->extended_data[ch];
     108           0 :         s->fdsp->vector_fmul_scalar(ptr, dst, s->gain * s->wet_gain, FFALIGN(out->nb_samples, 4));
     109           0 :         emms_c();
     110             :     }
     111             : 
     112           0 :     return 0;
     113             : }
     114             : 
     115           0 : static int fir_frame(AudioFIRContext *s, AVFilterLink *outlink)
     116             : {
     117           0 :     AVFilterContext *ctx = outlink->src;
     118           0 :     AVFrame *out = NULL;
     119             :     int ret;
     120             : 
     121           0 :     s->nb_samples = FFMIN(s->part_size, av_audio_fifo_size(s->fifo[0]));
     122             : 
     123           0 :     if (!s->want_skip) {
     124           0 :         out = ff_get_audio_buffer(outlink, s->nb_samples);
     125           0 :         if (!out)
     126           0 :             return AVERROR(ENOMEM);
     127             :     }
     128             : 
     129           0 :     s->in[0] = ff_get_audio_buffer(ctx->inputs[0], s->nb_samples);
     130           0 :     if (!s->in[0]) {
     131           0 :         av_frame_free(&out);
     132           0 :         return AVERROR(ENOMEM);
     133             :     }
     134             : 
     135           0 :     av_audio_fifo_peek(s->fifo[0], (void **)s->in[0]->extended_data, s->nb_samples);
     136             : 
     137           0 :     ctx->internal->execute(ctx, fir_channel, out, NULL, outlink->channels);
     138             : 
     139           0 :     s->part_index = (s->part_index + 1) % s->nb_partitions;
     140             : 
     141           0 :     av_audio_fifo_drain(s->fifo[0], s->nb_samples);
     142             : 
     143           0 :     if (!s->want_skip) {
     144           0 :         out->pts = s->pts;
     145           0 :         if (s->pts != AV_NOPTS_VALUE)
     146           0 :             s->pts += av_rescale_q(out->nb_samples, (AVRational){1, outlink->sample_rate}, outlink->time_base);
     147             :     }
     148             : 
     149           0 :     s->index++;
     150           0 :     if (s->index == 3)
     151           0 :         s->index = 0;
     152             : 
     153           0 :     av_frame_free(&s->in[0]);
     154             : 
     155           0 :     if (s->want_skip == 1) {
     156           0 :         s->want_skip = 0;
     157           0 :         ret = 0;
     158             :     } else {
     159           0 :         ret = ff_filter_frame(outlink, out);
     160             :     }
     161             : 
     162           0 :     return ret;
     163             : }
     164             : 
     165           0 : static int convert_coeffs(AVFilterContext *ctx)
     166             : {
     167           0 :     AudioFIRContext *s = ctx->priv;
     168             :     int i, ch, n, N;
     169           0 :     float power = 0;
     170             : 
     171           0 :     s->nb_taps = av_audio_fifo_size(s->fifo[1]);
     172           0 :     if (s->nb_taps <= 0)
     173           0 :         return AVERROR(EINVAL);
     174             : 
     175           0 :     for (n = 4; (1 << n) < s->nb_taps; n++);
     176           0 :     N = FFMIN(n, 16);
     177           0 :     s->ir_length = 1 << n;
     178           0 :     s->fft_length = (1 << (N + 1)) + 1;
     179           0 :     s->part_size = 1 << (N - 1);
     180           0 :     s->block_size = FFALIGN(s->fft_length, 32);
     181           0 :     s->coeff_size = FFALIGN(s->part_size + 1, 32);
     182           0 :     s->nb_partitions = (s->nb_taps + s->part_size - 1) / s->part_size;
     183           0 :     s->nb_coeffs = s->ir_length + s->nb_partitions;
     184             : 
     185           0 :     for (ch = 0; ch < ctx->inputs[0]->channels; ch++) {
     186           0 :         s->sum[ch] = av_calloc(s->fft_length, sizeof(**s->sum));
     187           0 :         if (!s->sum[ch])
     188           0 :             return AVERROR(ENOMEM);
     189             :     }
     190             : 
     191           0 :     for (ch = 0; ch < ctx->inputs[1]->channels; ch++) {
     192           0 :         s->coeff[ch] = av_calloc(s->nb_partitions * s->coeff_size, sizeof(**s->coeff));
     193           0 :         if (!s->coeff[ch])
     194           0 :             return AVERROR(ENOMEM);
     195             :     }
     196             : 
     197           0 :     for (ch = 0; ch < ctx->inputs[0]->channels; ch++) {
     198           0 :         s->block[ch] = av_calloc(s->nb_partitions * s->block_size, sizeof(**s->block));
     199           0 :         if (!s->block[ch])
     200           0 :             return AVERROR(ENOMEM);
     201             :     }
     202             : 
     203           0 :     for (ch = 0; ch < ctx->inputs[0]->channels; ch++) {
     204           0 :         s->rdft[ch]  = av_rdft_init(N, DFT_R2C);
     205           0 :         s->irdft[ch] = av_rdft_init(N, IDFT_C2R);
     206           0 :         if (!s->rdft[ch] || !s->irdft[ch])
     207           0 :             return AVERROR(ENOMEM);
     208             :     }
     209             : 
     210           0 :     s->in[1] = ff_get_audio_buffer(ctx->inputs[1], s->nb_taps);
     211           0 :     if (!s->in[1])
     212           0 :         return AVERROR(ENOMEM);
     213             : 
     214           0 :     s->buffer = ff_get_audio_buffer(ctx->inputs[0], s->part_size * 3);
     215           0 :     if (!s->buffer)
     216           0 :         return AVERROR(ENOMEM);
     217             : 
     218           0 :     av_audio_fifo_read(s->fifo[1], (void **)s->in[1]->extended_data, s->nb_taps);
     219             : 
     220           0 :     for (ch = 0; ch < ctx->inputs[1]->channels; ch++) {
     221           0 :         float *time = (float *)s->in[1]->extended_data[!s->one2many * ch];
     222           0 :         float *block = s->block[ch];
     223           0 :         FFTComplex *coeff = s->coeff[ch];
     224             : 
     225           0 :         power += s->fdsp->scalarproduct_float(time, time, s->nb_taps);
     226             : 
     227           0 :         for (i = FFMAX(1, s->length * s->nb_taps); i < s->nb_taps; i++)
     228           0 :             time[i] = 0;
     229             : 
     230           0 :         for (i = 0; i < s->nb_partitions; i++) {
     231           0 :             const float scale = 1.f / s->part_size;
     232           0 :             const int toffset = i * s->part_size;
     233           0 :             const int coffset = i * s->coeff_size;
     234           0 :             const int boffset = s->part_size;
     235           0 :             const int remaining = s->nb_taps - (i * s->part_size);
     236           0 :             const int size = remaining >= s->part_size ? s->part_size : remaining;
     237             : 
     238           0 :             memset(block, 0, sizeof(*block) * s->fft_length);
     239           0 :             memcpy(block + boffset, time + toffset, size * sizeof(*block));
     240             : 
     241           0 :             av_rdft_calc(s->rdft[0], block);
     242             : 
     243           0 :             coeff[coffset].re = block[0] * scale;
     244           0 :             coeff[coffset].im = 0;
     245           0 :             for (n = 1; n < s->part_size; n++) {
     246           0 :                 coeff[coffset + n].re = block[2 * n] * scale;
     247           0 :                 coeff[coffset + n].im = block[2 * n + 1] * scale;
     248             :             }
     249           0 :             coeff[coffset + s->part_size].re = block[1] * scale;
     250           0 :             coeff[coffset + s->part_size].im = 0;
     251             :         }
     252             :     }
     253             : 
     254           0 :     av_frame_free(&s->in[1]);
     255           0 :     s->gain = s->again ? 1.f / sqrtf(power / ctx->inputs[1]->channels) : 1.f;
     256           0 :     av_log(ctx, AV_LOG_DEBUG, "nb_taps: %d\n", s->nb_taps);
     257           0 :     av_log(ctx, AV_LOG_DEBUG, "nb_partitions: %d\n", s->nb_partitions);
     258           0 :     av_log(ctx, AV_LOG_DEBUG, "partition size: %d\n", s->part_size);
     259           0 :     av_log(ctx, AV_LOG_DEBUG, "ir_length: %d\n", s->ir_length);
     260             : 
     261           0 :     s->have_coeffs = 1;
     262             : 
     263           0 :     return 0;
     264             : }
     265             : 
     266           0 : static int read_ir(AVFilterLink *link, AVFrame *frame)
     267             : {
     268           0 :     AVFilterContext *ctx = link->dst;
     269           0 :     AudioFIRContext *s = ctx->priv;
     270             :     int nb_taps, max_nb_taps, ret;
     271             : 
     272           0 :     ret = av_audio_fifo_write(s->fifo[1], (void **)frame->extended_data,
     273           0 :                              frame->nb_samples);
     274           0 :     av_frame_free(&frame);
     275           0 :     if (ret < 0)
     276           0 :         return ret;
     277             : 
     278           0 :     nb_taps = av_audio_fifo_size(s->fifo[1]);
     279           0 :     max_nb_taps = MAX_IR_DURATION * ctx->outputs[0]->sample_rate;
     280           0 :     if (nb_taps > max_nb_taps) {
     281           0 :         av_log(ctx, AV_LOG_ERROR, "Too big number of coefficients: %d > %d.\n", nb_taps, max_nb_taps);
     282           0 :         return AVERROR(EINVAL);
     283             :     }
     284             : 
     285           0 :     return 0;
     286             : }
     287             : 
     288           0 : static int filter_frame(AVFilterLink *link, AVFrame *frame)
     289             : {
     290           0 :     AVFilterContext *ctx = link->dst;
     291           0 :     AudioFIRContext *s = ctx->priv;
     292           0 :     AVFilterLink *outlink = ctx->outputs[0];
     293             :     int ret;
     294             : 
     295           0 :     ret = av_audio_fifo_write(s->fifo[0], (void **)frame->extended_data,
     296           0 :                               frame->nb_samples);
     297           0 :     if (ret > 0 && s->pts == AV_NOPTS_VALUE)
     298           0 :         s->pts = frame->pts;
     299             : 
     300           0 :     av_frame_free(&frame);
     301             : 
     302           0 :     if (ret < 0)
     303           0 :         return ret;
     304             : 
     305           0 :     if (!s->have_coeffs && s->eof_coeffs) {
     306           0 :         ret = convert_coeffs(ctx);
     307           0 :         if (ret < 0)
     308           0 :             return ret;
     309             :     }
     310             : 
     311           0 :     if (s->have_coeffs) {
     312           0 :         while (av_audio_fifo_size(s->fifo[0]) >= s->part_size) {
     313           0 :             ret = fir_frame(s, outlink);
     314           0 :             if (ret < 0)
     315           0 :                 return ret;
     316             :         }
     317             :     }
     318           0 :     return 0;
     319             : }
     320             : 
     321           0 : static int request_frame(AVFilterLink *outlink)
     322             : {
     323           0 :     AVFilterContext *ctx = outlink->src;
     324           0 :     AudioFIRContext *s = ctx->priv;
     325             :     int ret;
     326             : 
     327           0 :     if (!s->eof_coeffs) {
     328           0 :         ret = ff_request_frame(ctx->inputs[1]);
     329           0 :         if (ret == AVERROR_EOF) {
     330           0 :             s->eof_coeffs = 1;
     331           0 :             ret = 0;
     332             :         }
     333           0 :         return ret;
     334             :     }
     335           0 :     ret = ff_request_frame(ctx->inputs[0]);
     336           0 :     if (ret == AVERROR_EOF && s->have_coeffs) {
     337           0 :         if (s->need_padding) {
     338           0 :             AVFrame *silence = ff_get_audio_buffer(outlink, s->part_size);
     339             : 
     340           0 :             if (!silence)
     341           0 :                 return AVERROR(ENOMEM);
     342           0 :             ret = av_audio_fifo_write(s->fifo[0], (void **)silence->extended_data,
     343           0 :                                       silence->nb_samples);
     344           0 :             av_frame_free(&silence);
     345           0 :             if (ret < 0)
     346           0 :                 return ret;
     347           0 :             s->need_padding = 0;
     348             :         }
     349             : 
     350           0 :         while (av_audio_fifo_size(s->fifo[0]) > 0) {
     351           0 :             ret = fir_frame(s, outlink);
     352           0 :             if (ret < 0)
     353           0 :                 return ret;
     354             :         }
     355           0 :         ret = AVERROR_EOF;
     356             :     }
     357           0 :     return ret;
     358             : }
     359             : 
     360           0 : static int query_formats(AVFilterContext *ctx)
     361             : {
     362             :     AVFilterFormats *formats;
     363             :     AVFilterChannelLayouts *layouts;
     364             :     static const enum AVSampleFormat sample_fmts[] = {
     365             :         AV_SAMPLE_FMT_FLTP,
     366             :         AV_SAMPLE_FMT_NONE
     367             :     };
     368             :     int ret, i;
     369             : 
     370           0 :     layouts = ff_all_channel_counts();
     371           0 :     if ((ret = ff_channel_layouts_ref(layouts, &ctx->outputs[0]->in_channel_layouts)) < 0)
     372           0 :         return ret;
     373             : 
     374           0 :     for (i = 0; i < 2; i++) {
     375           0 :         layouts = ff_all_channel_counts();
     376           0 :         if ((ret = ff_channel_layouts_ref(layouts, &ctx->inputs[i]->out_channel_layouts)) < 0)
     377           0 :             return ret;
     378             :     }
     379             : 
     380           0 :     formats = ff_make_format_list(sample_fmts);
     381           0 :     if ((ret = ff_set_common_formats(ctx, formats)) < 0)
     382           0 :         return ret;
     383             : 
     384           0 :     formats = ff_all_samplerates();
     385           0 :     return ff_set_common_samplerates(ctx, formats);
     386             : }
     387             : 
     388           0 : static int config_output(AVFilterLink *outlink)
     389             : {
     390           0 :     AVFilterContext *ctx = outlink->src;
     391           0 :     AudioFIRContext *s = ctx->priv;
     392             : 
     393           0 :     if (ctx->inputs[0]->channels != ctx->inputs[1]->channels &&
     394           0 :         ctx->inputs[1]->channels != 1) {
     395           0 :         av_log(ctx, AV_LOG_ERROR,
     396             :                "Second input must have same number of channels as first input or "
     397             :                "exactly 1 channel.\n");
     398           0 :         return AVERROR(EINVAL);
     399             :     }
     400             : 
     401           0 :     s->one2many = ctx->inputs[1]->channels == 1;
     402           0 :     outlink->sample_rate = ctx->inputs[0]->sample_rate;
     403           0 :     outlink->time_base   = ctx->inputs[0]->time_base;
     404           0 :     outlink->channel_layout = ctx->inputs[0]->channel_layout;
     405           0 :     outlink->channels = ctx->inputs[0]->channels;
     406             : 
     407           0 :     s->fifo[0] = av_audio_fifo_alloc(ctx->inputs[0]->format, ctx->inputs[0]->channels, 1024);
     408           0 :     s->fifo[1] = av_audio_fifo_alloc(ctx->inputs[1]->format, ctx->inputs[1]->channels, 1024);
     409           0 :     if (!s->fifo[0] || !s->fifo[1])
     410           0 :         return AVERROR(ENOMEM);
     411             : 
     412           0 :     s->sum = av_calloc(outlink->channels, sizeof(*s->sum));
     413           0 :     s->coeff = av_calloc(ctx->inputs[1]->channels, sizeof(*s->coeff));
     414           0 :     s->block = av_calloc(ctx->inputs[0]->channels, sizeof(*s->block));
     415           0 :     s->rdft = av_calloc(outlink->channels, sizeof(*s->rdft));
     416           0 :     s->irdft = av_calloc(outlink->channels, sizeof(*s->irdft));
     417           0 :     if (!s->sum || !s->coeff || !s->block || !s->rdft || !s->irdft)
     418           0 :         return AVERROR(ENOMEM);
     419             : 
     420           0 :     s->nb_channels = outlink->channels;
     421           0 :     s->nb_coef_channels = ctx->inputs[1]->channels;
     422           0 :     s->want_skip = 1;
     423           0 :     s->need_padding = 1;
     424           0 :     s->pts = AV_NOPTS_VALUE;
     425             : 
     426           0 :     return 0;
     427             : }
     428             : 
     429           0 : static av_cold void uninit(AVFilterContext *ctx)
     430             : {
     431           0 :     AudioFIRContext *s = ctx->priv;
     432             :     int ch;
     433             : 
     434           0 :     if (s->sum) {
     435           0 :         for (ch = 0; ch < s->nb_channels; ch++) {
     436           0 :             av_freep(&s->sum[ch]);
     437             :         }
     438             :     }
     439           0 :     av_freep(&s->sum);
     440             : 
     441           0 :     if (s->coeff) {
     442           0 :         for (ch = 0; ch < s->nb_coef_channels; ch++) {
     443           0 :             av_freep(&s->coeff[ch]);
     444             :         }
     445             :     }
     446           0 :     av_freep(&s->coeff);
     447             : 
     448           0 :     if (s->block) {
     449           0 :         for (ch = 0; ch < s->nb_channels; ch++) {
     450           0 :             av_freep(&s->block[ch]);
     451             :         }
     452             :     }
     453           0 :     av_freep(&s->block);
     454             : 
     455           0 :     if (s->rdft) {
     456           0 :         for (ch = 0; ch < s->nb_channels; ch++) {
     457           0 :             av_rdft_end(s->rdft[ch]);
     458             :         }
     459             :     }
     460           0 :     av_freep(&s->rdft);
     461             : 
     462           0 :     if (s->irdft) {
     463           0 :         for (ch = 0; ch < s->nb_channels; ch++) {
     464           0 :             av_rdft_end(s->irdft[ch]);
     465             :         }
     466             :     }
     467           0 :     av_freep(&s->irdft);
     468             : 
     469           0 :     av_frame_free(&s->in[0]);
     470           0 :     av_frame_free(&s->in[1]);
     471           0 :     av_frame_free(&s->buffer);
     472             : 
     473           0 :     av_audio_fifo_free(s->fifo[0]);
     474           0 :     av_audio_fifo_free(s->fifo[1]);
     475             : 
     476           0 :     av_freep(&s->fdsp);
     477           0 : }
     478             : 
     479           0 : static av_cold int init(AVFilterContext *ctx)
     480             : {
     481           0 :     AudioFIRContext *s = ctx->priv;
     482             : 
     483           0 :     s->fcmul_add = fcmul_add_c;
     484             : 
     485           0 :     s->fdsp = avpriv_float_dsp_alloc(0);
     486           0 :     if (!s->fdsp)
     487           0 :         return AVERROR(ENOMEM);
     488             : 
     489             :     if (ARCH_X86)
     490           0 :         ff_afir_init_x86(s);
     491             : 
     492           0 :     return 0;
     493             : }
     494             : 
     495             : static const AVFilterPad afir_inputs[] = {
     496             :     {
     497             :         .name           = "main",
     498             :         .type           = AVMEDIA_TYPE_AUDIO,
     499             :         .filter_frame   = filter_frame,
     500             :     },{
     501             :         .name           = "ir",
     502             :         .type           = AVMEDIA_TYPE_AUDIO,
     503             :         .filter_frame   = read_ir,
     504             :     },
     505             :     { NULL }
     506             : };
     507             : 
     508             : static const AVFilterPad afir_outputs[] = {
     509             :     {
     510             :         .name          = "default",
     511             :         .type          = AVMEDIA_TYPE_AUDIO,
     512             :         .config_props  = config_output,
     513             :         .request_frame = request_frame,
     514             :     },
     515             :     { NULL }
     516             : };
     517             : 
     518             : #define AF AV_OPT_FLAG_AUDIO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
     519             : #define OFFSET(x) offsetof(AudioFIRContext, x)
     520             : 
     521             : static const AVOption afir_options[] = {
     522             :     { "dry",    "set dry gain",     OFFSET(dry_gain), AV_OPT_TYPE_FLOAT, {.dbl=1}, 0, 1, AF },
     523             :     { "wet",    "set wet gain",     OFFSET(wet_gain), AV_OPT_TYPE_FLOAT, {.dbl=1}, 0, 1, AF },
     524             :     { "length", "set IR length",    OFFSET(length),   AV_OPT_TYPE_FLOAT, {.dbl=1}, 0, 1, AF },
     525             :     { "again",  "enable auto gain", OFFSET(again),    AV_OPT_TYPE_BOOL,  {.i64=1}, 0, 1, AF },
     526             :     { NULL }
     527             : };
     528             : 
     529             : AVFILTER_DEFINE_CLASS(afir);
     530             : 
     531             : AVFilter ff_af_afir = {
     532             :     .name          = "afir",
     533             :     .description   = NULL_IF_CONFIG_SMALL("Apply Finite Impulse Response filter with supplied coefficients in 2nd stream."),
     534             :     .priv_size     = sizeof(AudioFIRContext),
     535             :     .priv_class    = &afir_class,
     536             :     .query_formats = query_formats,
     537             :     .init          = init,
     538             :     .uninit        = uninit,
     539             :     .inputs        = afir_inputs,
     540             :     .outputs       = afir_outputs,
     541             :     .flags         = AVFILTER_FLAG_SLICE_THREADS,
     542             : };

Generated by: LCOV version 1.13