LCOV - code coverage report
Current view: top level - src/libavfilter - af_compand.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 174 298 58.4 %
Date: 2017-05-26 21:11:57 Functions: 10 12 83.3 %

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 1999 Chris Bagwell
       3             :  * Copyright (c) 1999 Nick Bailey
       4             :  * Copyright (c) 2007 Rob Sykes <robs@users.sourceforge.net>
       5             :  * Copyright (c) 2013 Paul B Mahol
       6             :  * Copyright (c) 2014 Andrew Kelley
       7             :  *
       8             :  * This file is part of FFmpeg.
       9             :  *
      10             :  * FFmpeg is free software; you can redistribute it and/or
      11             :  * modify it under the terms of the GNU Lesser General Public
      12             :  * License as published by the Free Software Foundation; either
      13             :  * version 2.1 of the License, or (at your option) any later version.
      14             :  *
      15             :  * FFmpeg is distributed in the hope that it will be useful,
      16             :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      17             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      18             :  * Lesser General Public License for more details.
      19             :  *
      20             :  * You should have received a copy of the GNU Lesser General Public
      21             :  * License along with FFmpeg; if not, write to the Free Software
      22             :  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
      23             :  */
      24             : 
      25             : /**
      26             :  * @file
      27             :  * audio compand filter
      28             :  */
      29             : 
      30             : #include "libavutil/avassert.h"
      31             : #include "libavutil/avstring.h"
      32             : #include "libavutil/ffmath.h"
      33             : #include "libavutil/opt.h"
      34             : #include "libavutil/samplefmt.h"
      35             : #include "audio.h"
      36             : #include "avfilter.h"
      37             : #include "internal.h"
      38             : 
      39             : typedef struct ChanParam {
      40             :     double attack;
      41             :     double decay;
      42             :     double volume;
      43             : } ChanParam;
      44             : 
      45             : typedef struct CompandSegment {
      46             :     double x, y;
      47             :     double a, b;
      48             : } CompandSegment;
      49             : 
      50             : typedef struct CompandContext {
      51             :     const AVClass *class;
      52             :     int nb_segments;
      53             :     char *attacks, *decays, *points;
      54             :     CompandSegment *segments;
      55             :     ChanParam *channels;
      56             :     double in_min_lin;
      57             :     double out_min_lin;
      58             :     double curve_dB;
      59             :     double gain_dB;
      60             :     double initial_volume;
      61             :     double delay;
      62             :     AVFrame *delay_frame;
      63             :     int delay_samples;
      64             :     int delay_count;
      65             :     int delay_index;
      66             :     int64_t pts;
      67             : 
      68             :     int (*compand)(AVFilterContext *ctx, AVFrame *frame);
      69             : } CompandContext;
      70             : 
      71             : #define OFFSET(x) offsetof(CompandContext, x)
      72             : #define A AV_OPT_FLAG_AUDIO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
      73             : 
      74             : static const AVOption compand_options[] = {
      75             :     { "attacks", "set time over which increase of volume is determined", OFFSET(attacks), AV_OPT_TYPE_STRING, { .str = "0" }, 0, 0, A },
      76             :     { "decays", "set time over which decrease of volume is determined", OFFSET(decays), AV_OPT_TYPE_STRING, { .str = "0.8" }, 0, 0, A },
      77             :     { "points", "set points of transfer function", OFFSET(points), AV_OPT_TYPE_STRING, { .str = "-70/-70|-60/-20|1/0" }, 0, 0, A },
      78             :     { "soft-knee", "set soft-knee", OFFSET(curve_dB), AV_OPT_TYPE_DOUBLE, { .dbl = 0.01 }, 0.01, 900, A },
      79             :     { "gain", "set output gain", OFFSET(gain_dB), AV_OPT_TYPE_DOUBLE, { .dbl = 0 }, -900, 900, A },
      80             :     { "volume", "set initial volume", OFFSET(initial_volume), AV_OPT_TYPE_DOUBLE, { .dbl = 0 }, -900, 0, A },
      81             :     { "delay", "set delay for samples before sending them to volume adjuster", OFFSET(delay), AV_OPT_TYPE_DOUBLE, { .dbl = 0 }, 0, 20, A },
      82             :     { NULL }
      83             : };
      84             : 
      85             : AVFILTER_DEFINE_CLASS(compand);
      86             : 
      87           2 : static av_cold int init(AVFilterContext *ctx)
      88             : {
      89           2 :     CompandContext *s = ctx->priv;
      90           2 :     s->pts            = AV_NOPTS_VALUE;
      91           2 :     return 0;
      92             : }
      93             : 
      94           3 : static av_cold void uninit(AVFilterContext *ctx)
      95             : {
      96           3 :     CompandContext *s = ctx->priv;
      97             : 
      98           3 :     av_freep(&s->channels);
      99           3 :     av_freep(&s->segments);
     100           3 :     av_frame_free(&s->delay_frame);
     101           3 : }
     102             : 
     103           1 : static int query_formats(AVFilterContext *ctx)
     104             : {
     105             :     AVFilterChannelLayouts *layouts;
     106             :     AVFilterFormats *formats;
     107             :     static const enum AVSampleFormat sample_fmts[] = {
     108             :         AV_SAMPLE_FMT_DBLP,
     109             :         AV_SAMPLE_FMT_NONE
     110             :     };
     111             :     int ret;
     112             : 
     113           1 :     layouts = ff_all_channel_counts();
     114           1 :     if (!layouts)
     115           0 :         return AVERROR(ENOMEM);
     116           1 :     ret = ff_set_common_channel_layouts(ctx, layouts);
     117           1 :     if (ret < 0)
     118           0 :         return ret;
     119             : 
     120           1 :     formats = ff_make_format_list(sample_fmts);
     121           1 :     if (!formats)
     122           0 :         return AVERROR(ENOMEM);
     123           1 :     ret = ff_set_common_formats(ctx, formats);
     124           1 :     if (ret < 0)
     125           0 :         return ret;
     126             : 
     127           1 :     formats = ff_all_samplerates();
     128           1 :     if (!formats)
     129           0 :         return AVERROR(ENOMEM);
     130           1 :     return ff_set_common_samplerates(ctx, formats);
     131             : }
     132             : 
     133           3 : static void count_items(char *item_str, int *nb_items)
     134             : {
     135             :     char *p;
     136             : 
     137           3 :     *nb_items = 1;
     138          34 :     for (p = item_str; *p; p++) {
     139          31 :         if (*p == ' ' || *p == '|')
     140           3 :             (*nb_items)++;
     141             :     }
     142           3 : }
     143             : 
     144       40960 : static void update_volume(ChanParam *cp, double in)
     145             : {
     146       40960 :     double delta = in - cp->volume;
     147             : 
     148       40960 :     if (delta > 0.0)
     149           0 :         cp->volume += delta * cp->attack;
     150             :     else
     151       40960 :         cp->volume += delta * cp->decay;
     152       40960 : }
     153             : 
     154       40960 : static double get_volume(CompandContext *s, double in_lin)
     155             : {
     156             :     CompandSegment *cs;
     157             :     double in_log, out_log;
     158             :     int i;
     159             : 
     160       40960 :     if (in_lin < s->in_min_lin)
     161           0 :         return s->out_min_lin;
     162             : 
     163       40960 :     in_log = log(in_lin);
     164             : 
     165      122966 :     for (i = 1; i < s->nb_segments; i++)
     166      122966 :         if (in_log <= s->segments[i].x)
     167       40960 :             break;
     168       40960 :     cs = &s->segments[i - 1];
     169       40960 :     in_log -= cs->x;
     170       40960 :     out_log = cs->y + in_log * (cs->a * in_log + cs->b);
     171             : 
     172       40960 :     return exp(out_log);
     173             : }
     174             : 
     175          20 : static int compand_nodelay(AVFilterContext *ctx, AVFrame *frame)
     176             : {
     177          20 :     CompandContext *s    = ctx->priv;
     178          20 :     AVFilterLink *inlink = ctx->inputs[0];
     179          20 :     const int channels   = inlink->channels;
     180          20 :     const int nb_samples = frame->nb_samples;
     181             :     AVFrame *out_frame;
     182             :     int chan, i;
     183             :     int err;
     184             : 
     185          20 :     if (av_frame_is_writable(frame)) {
     186          20 :         out_frame = frame;
     187             :     } else {
     188           0 :         out_frame = ff_get_audio_buffer(inlink, nb_samples);
     189           0 :         if (!out_frame) {
     190           0 :             av_frame_free(&frame);
     191           0 :             return AVERROR(ENOMEM);
     192             :         }
     193           0 :         err = av_frame_copy_props(out_frame, frame);
     194           0 :         if (err < 0) {
     195           0 :             av_frame_free(&out_frame);
     196           0 :             av_frame_free(&frame);
     197           0 :             return err;
     198             :         }
     199             :     }
     200             : 
     201          60 :     for (chan = 0; chan < channels; chan++) {
     202          40 :         const double *src = (double *)frame->extended_data[chan];
     203          40 :         double *dst = (double *)out_frame->extended_data[chan];
     204          40 :         ChanParam *cp = &s->channels[chan];
     205             : 
     206       41000 :         for (i = 0; i < nb_samples; i++) {
     207       40960 :             update_volume(cp, fabs(src[i]));
     208             : 
     209       40960 :             dst[i] = src[i] * get_volume(s, cp->volume);
     210             :         }
     211             :     }
     212             : 
     213          20 :     if (frame != out_frame)
     214           0 :         av_frame_free(&frame);
     215             : 
     216          20 :     return ff_filter_frame(ctx->outputs[0], out_frame);
     217             : }
     218             : 
     219             : #define MOD(a, b) (((a) >= (b)) ? (a) - (b) : (a))
     220             : 
     221           0 : static int compand_delay(AVFilterContext *ctx, AVFrame *frame)
     222             : {
     223           0 :     CompandContext *s    = ctx->priv;
     224           0 :     AVFilterLink *inlink = ctx->inputs[0];
     225           0 :     const int channels = inlink->channels;
     226           0 :     const int nb_samples = frame->nb_samples;
     227           0 :     int chan, i, av_uninit(dindex), oindex, av_uninit(count);
     228           0 :     AVFrame *out_frame   = NULL;
     229             :     int err;
     230             : 
     231           0 :     if (s->pts == AV_NOPTS_VALUE) {
     232           0 :         s->pts = (frame->pts == AV_NOPTS_VALUE) ? 0 : frame->pts;
     233             :     }
     234             : 
     235             :     av_assert1(channels > 0); /* would corrupt delay_count and delay_index */
     236             : 
     237           0 :     for (chan = 0; chan < channels; chan++) {
     238           0 :         AVFrame *delay_frame = s->delay_frame;
     239           0 :         const double *src    = (double *)frame->extended_data[chan];
     240           0 :         double *dbuf         = (double *)delay_frame->extended_data[chan];
     241           0 :         ChanParam *cp        = &s->channels[chan];
     242             :         double *dst;
     243             : 
     244           0 :         count  = s->delay_count;
     245           0 :         dindex = s->delay_index;
     246           0 :         for (i = 0, oindex = 0; i < nb_samples; i++) {
     247           0 :             const double in = src[i];
     248           0 :             update_volume(cp, fabs(in));
     249             : 
     250           0 :             if (count >= s->delay_samples) {
     251           0 :                 if (!out_frame) {
     252           0 :                     out_frame = ff_get_audio_buffer(inlink, nb_samples - i);
     253           0 :                     if (!out_frame) {
     254           0 :                         av_frame_free(&frame);
     255           0 :                         return AVERROR(ENOMEM);
     256             :                     }
     257           0 :                     err = av_frame_copy_props(out_frame, frame);
     258           0 :                     if (err < 0) {
     259           0 :                         av_frame_free(&out_frame);
     260           0 :                         av_frame_free(&frame);
     261           0 :                         return err;
     262             :                     }
     263           0 :                     out_frame->pts = s->pts;
     264           0 :                     s->pts += av_rescale_q(nb_samples - i,
     265           0 :                         (AVRational){ 1, inlink->sample_rate },
     266             :                         inlink->time_base);
     267             :                 }
     268             : 
     269           0 :                 dst = (double *)out_frame->extended_data[chan];
     270           0 :                 dst[oindex++] = dbuf[dindex] * get_volume(s, cp->volume);
     271             :             } else {
     272           0 :                 count++;
     273             :             }
     274             : 
     275           0 :             dbuf[dindex] = in;
     276           0 :             dindex = MOD(dindex + 1, s->delay_samples);
     277             :         }
     278             :     }
     279             : 
     280           0 :     s->delay_count = count;
     281           0 :     s->delay_index = dindex;
     282             : 
     283           0 :     av_frame_free(&frame);
     284             : 
     285           0 :     if (out_frame) {
     286           0 :         err = ff_filter_frame(ctx->outputs[0], out_frame);
     287           0 :         return err;
     288             :     }
     289             : 
     290           0 :     return 0;
     291             : }
     292             : 
     293           0 : static int compand_drain(AVFilterLink *outlink)
     294             : {
     295           0 :     AVFilterContext *ctx = outlink->src;
     296           0 :     CompandContext *s    = ctx->priv;
     297           0 :     const int channels   = outlink->channels;
     298           0 :     AVFrame *frame       = NULL;
     299             :     int chan, i, dindex;
     300             : 
     301             :     /* 2048 is to limit output frame size during drain */
     302           0 :     frame = ff_get_audio_buffer(outlink, FFMIN(2048, s->delay_count));
     303           0 :     if (!frame)
     304           0 :         return AVERROR(ENOMEM);
     305           0 :     frame->pts = s->pts;
     306           0 :     s->pts += av_rescale_q(frame->nb_samples,
     307           0 :             (AVRational){ 1, outlink->sample_rate }, outlink->time_base);
     308             : 
     309           0 :     av_assert0(channels > 0);
     310           0 :     for (chan = 0; chan < channels; chan++) {
     311           0 :         AVFrame *delay_frame = s->delay_frame;
     312           0 :         double *dbuf = (double *)delay_frame->extended_data[chan];
     313           0 :         double *dst = (double *)frame->extended_data[chan];
     314           0 :         ChanParam *cp = &s->channels[chan];
     315             : 
     316           0 :         dindex = s->delay_index;
     317           0 :         for (i = 0; i < frame->nb_samples; i++) {
     318           0 :             dst[i] = dbuf[dindex] * get_volume(s, cp->volume);
     319           0 :             dindex = MOD(dindex + 1, s->delay_samples);
     320             :         }
     321             :     }
     322           0 :     s->delay_count -= frame->nb_samples;
     323           0 :     s->delay_index = dindex;
     324             : 
     325           0 :     return ff_filter_frame(outlink, frame);
     326             : }
     327             : 
     328           1 : static int config_output(AVFilterLink *outlink)
     329             : {
     330           1 :     AVFilterContext *ctx  = outlink->src;
     331           1 :     CompandContext *s     = ctx->priv;
     332           1 :     const int sample_rate = outlink->sample_rate;
     333           1 :     double radius         = s->curve_dB * M_LN10 / 20.0;
     334           1 :     char *p, *saveptr     = NULL;
     335           1 :     const int channels    = outlink->channels;
     336             :     int nb_attacks, nb_decays, nb_points;
     337             :     int new_nb_items, num;
     338             :     int i;
     339             :     int err;
     340             : 
     341             : 
     342           1 :     count_items(s->attacks, &nb_attacks);
     343           1 :     count_items(s->decays, &nb_decays);
     344           1 :     count_items(s->points, &nb_points);
     345             : 
     346           1 :     if (channels <= 0) {
     347           0 :         av_log(ctx, AV_LOG_ERROR, "Invalid number of channels: %d\n", channels);
     348           0 :         return AVERROR(EINVAL);
     349             :     }
     350             : 
     351           1 :     if (nb_attacks > channels || nb_decays > channels) {
     352           0 :         av_log(ctx, AV_LOG_ERROR,
     353             :                 "Number of attacks/decays bigger than number of channels.\n");
     354           0 :         return AVERROR(EINVAL);
     355             :     }
     356             : 
     357           1 :     uninit(ctx);
     358             : 
     359           1 :     s->channels = av_mallocz_array(channels, sizeof(*s->channels));
     360           1 :     s->nb_segments = (nb_points + 4) * 2;
     361           1 :     s->segments = av_mallocz_array(s->nb_segments, sizeof(*s->segments));
     362             : 
     363           1 :     if (!s->channels || !s->segments) {
     364           0 :         uninit(ctx);
     365           0 :         return AVERROR(ENOMEM);
     366             :     }
     367             : 
     368           1 :     p = s->attacks;
     369           2 :     for (i = 0, new_nb_items = 0; i < nb_attacks; i++) {
     370           1 :         char *tstr = av_strtok(p, " |", &saveptr);
     371           1 :         if (!tstr) {
     372           0 :             uninit(ctx);
     373           0 :             return AVERROR(EINVAL);
     374             :         }
     375           1 :         p = NULL;
     376           1 :         new_nb_items += sscanf(tstr, "%lf", &s->channels[i].attack) == 1;
     377           1 :         if (s->channels[i].attack < 0) {
     378           0 :             uninit(ctx);
     379           0 :             return AVERROR(EINVAL);
     380             :         }
     381             :     }
     382           1 :     nb_attacks = new_nb_items;
     383             : 
     384           1 :     p = s->decays;
     385           2 :     for (i = 0, new_nb_items = 0; i < nb_decays; i++) {
     386           1 :         char *tstr = av_strtok(p, " |", &saveptr);
     387           1 :         if (!tstr) {
     388           0 :             uninit(ctx);
     389           0 :             return AVERROR(EINVAL);
     390             :         }
     391           1 :         p = NULL;
     392           1 :         new_nb_items += sscanf(tstr, "%lf", &s->channels[i].decay) == 1;
     393           1 :         if (s->channels[i].decay < 0) {
     394           0 :             uninit(ctx);
     395           0 :             return AVERROR(EINVAL);
     396             :         }
     397             :     }
     398           1 :     nb_decays = new_nb_items;
     399             : 
     400           1 :     if (nb_attacks != nb_decays) {
     401           0 :         av_log(ctx, AV_LOG_ERROR,
     402             :                 "Number of attacks %d differs from number of decays %d.\n",
     403             :                 nb_attacks, nb_decays);
     404           0 :         uninit(ctx);
     405           0 :         return AVERROR(EINVAL);
     406             :     }
     407             : 
     408           2 :     for (i = nb_decays; i < channels; i++) {
     409           1 :         s->channels[i].attack = s->channels[nb_decays - 1].attack;
     410           1 :         s->channels[i].decay = s->channels[nb_decays - 1].decay;
     411             :     }
     412             : 
     413             : #define S(x) s->segments[2 * ((x) + 1)]
     414           1 :     p = s->points;
     415           5 :     for (i = 0, new_nb_items = 0; i < nb_points; i++) {
     416           4 :         char *tstr = av_strtok(p, " |", &saveptr);
     417           4 :         p = NULL;
     418           4 :         if (!tstr || sscanf(tstr, "%lf/%lf", &S(i).x, &S(i).y) != 2) {
     419           0 :             av_log(ctx, AV_LOG_ERROR,
     420             :                     "Invalid and/or missing input/output value.\n");
     421           0 :             uninit(ctx);
     422           0 :             return AVERROR(EINVAL);
     423             :         }
     424           4 :         if (i && S(i - 1).x > S(i).x) {
     425           0 :             av_log(ctx, AV_LOG_ERROR,
     426             :                     "Transfer function input values must be increasing.\n");
     427           0 :             uninit(ctx);
     428           0 :             return AVERROR(EINVAL);
     429             :         }
     430           4 :         S(i).y -= S(i).x;
     431           4 :         av_log(ctx, AV_LOG_DEBUG, "%d: x=%f y=%f\n", i, S(i).x, S(i).y);
     432           4 :         new_nb_items++;
     433             :     }
     434           1 :     num = new_nb_items;
     435             : 
     436             :     /* Add 0,0 if necessary */
     437           1 :     if (num == 0 || S(num - 1).x)
     438           1 :         num++;
     439             : 
     440             : #undef S
     441             : #define S(x) s->segments[2 * (x)]
     442             :     /* Add a tail off segment at the start */
     443           1 :     S(0).x = S(1).x - 2 * s->curve_dB;
     444           1 :     S(0).y = S(1).y;
     445           1 :     num++;
     446             : 
     447             :     /* Join adjacent colinear segments */
     448           5 :     for (i = 2; i < num; i++) {
     449           4 :         double g1 = (S(i - 1).y - S(i - 2).y) * (S(i - 0).x - S(i - 1).x);
     450           4 :         double g2 = (S(i - 0).y - S(i - 1).y) * (S(i - 1).x - S(i - 2).x);
     451             :         int j;
     452             : 
     453           4 :         if (fabs(g1 - g2))
     454           3 :             continue;
     455           1 :         num--;
     456           5 :         for (j = --i; j < num; j++)
     457           4 :             S(j) = S(j + 1);
     458             :     }
     459             : 
     460           9 :     for (i = 0; i < s->nb_segments; i += 2) {
     461           8 :         s->segments[i].y += s->gain_dB;
     462           8 :         s->segments[i].x *= M_LN10 / 20;
     463           8 :         s->segments[i].y *= M_LN10 / 20;
     464             :     }
     465             : 
     466             : #define L(x) s->segments[i - (x)]
     467           7 :     for (i = 4; i < s->nb_segments; i += 2) {
     468             :         double x, y, cx, cy, in1, in2, out1, out2, theta, len, r;
     469             : 
     470           6 :         L(4).a = 0;
     471           6 :         L(4).b = (L(2).y - L(4).y) / (L(2).x - L(4).x);
     472             : 
     473           6 :         L(2).a = 0;
     474           6 :         L(2).b = (L(0).y - L(2).y) / (L(0).x - L(2).x);
     475             : 
     476           6 :         theta = atan2(L(2).y - L(4).y, L(2).x - L(4).x);
     477           6 :         len = hypot(L(2).x - L(4).x, L(2).y - L(4).y);
     478           6 :         r = FFMIN(radius, len);
     479           6 :         L(3).x = L(2).x - r * cos(theta);
     480           6 :         L(3).y = L(2).y - r * sin(theta);
     481             : 
     482           6 :         theta = atan2(L(0).y - L(2).y, L(0).x - L(2).x);
     483           6 :         len = hypot(L(0).x - L(2).x, L(0).y - L(2).y);
     484           6 :         r = FFMIN(radius, len / 2);
     485           6 :         x = L(2).x + r * cos(theta);
     486           6 :         y = L(2).y + r * sin(theta);
     487             : 
     488           6 :         cx = (L(3).x + L(2).x + x) / 3;
     489           6 :         cy = (L(3).y + L(2).y + y) / 3;
     490             : 
     491           6 :         L(2).x = x;
     492           6 :         L(2).y = y;
     493             : 
     494           6 :         in1  = cx - L(3).x;
     495           6 :         out1 = cy - L(3).y;
     496           6 :         in2  = L(2).x - L(3).x;
     497           6 :         out2 = L(2).y - L(3).y;
     498           6 :         L(3).a = (out2 / in2 - out1 / in1) / (in2 - in1);
     499           6 :         L(3).b = out1 / in1 - L(3).a * in1;
     500             :     }
     501           1 :     L(3).x = 0;
     502           1 :     L(3).y = L(2).y;
     503             : 
     504           1 :     s->in_min_lin  = exp(s->segments[1].x);
     505           1 :     s->out_min_lin = exp(s->segments[1].y);
     506             : 
     507           3 :     for (i = 0; i < channels; i++) {
     508           2 :         ChanParam *cp = &s->channels[i];
     509             : 
     510           2 :         if (cp->attack > 1.0 / sample_rate)
     511           0 :             cp->attack = 1.0 - exp(-1.0 / (sample_rate * cp->attack));
     512             :         else
     513           2 :             cp->attack = 1.0;
     514           2 :         if (cp->decay > 1.0 / sample_rate)
     515           2 :             cp->decay = 1.0 - exp(-1.0 / (sample_rate * cp->decay));
     516             :         else
     517           0 :             cp->decay = 1.0;
     518           2 :         cp->volume = ff_exp10(s->initial_volume / 20);
     519             :     }
     520             : 
     521           1 :     s->delay_samples = s->delay * sample_rate;
     522           1 :     if (s->delay_samples <= 0) {
     523           1 :         s->compand = compand_nodelay;
     524           1 :         return 0;
     525             :     }
     526             : 
     527           0 :     s->delay_frame = av_frame_alloc();
     528           0 :     if (!s->delay_frame) {
     529           0 :         uninit(ctx);
     530           0 :         return AVERROR(ENOMEM);
     531             :     }
     532             : 
     533           0 :     s->delay_frame->format         = outlink->format;
     534           0 :     s->delay_frame->nb_samples     = s->delay_samples;
     535           0 :     s->delay_frame->channel_layout = outlink->channel_layout;
     536             : 
     537           0 :     err = av_frame_get_buffer(s->delay_frame, 32);
     538           0 :     if (err)
     539           0 :         return err;
     540             : 
     541           0 :     s->compand = compand_delay;
     542           0 :     return 0;
     543             : }
     544             : 
     545          20 : static int filter_frame(AVFilterLink *inlink, AVFrame *frame)
     546             : {
     547          20 :     AVFilterContext *ctx = inlink->dst;
     548          20 :     CompandContext *s    = ctx->priv;
     549             : 
     550          20 :     return s->compand(ctx, frame);
     551             : }
     552             : 
     553          20 : static int request_frame(AVFilterLink *outlink)
     554             : {
     555          20 :     AVFilterContext *ctx = outlink->src;
     556          20 :     CompandContext *s    = ctx->priv;
     557          20 :     int ret = 0;
     558             : 
     559          20 :     ret = ff_request_frame(ctx->inputs[0]);
     560             : 
     561          20 :     if (ret == AVERROR_EOF && !ctx->is_disabled && s->delay_count)
     562           0 :         ret = compand_drain(outlink);
     563             : 
     564          20 :     return ret;
     565             : }
     566             : 
     567             : static const AVFilterPad compand_inputs[] = {
     568             :     {
     569             :         .name         = "default",
     570             :         .type         = AVMEDIA_TYPE_AUDIO,
     571             :         .filter_frame = filter_frame,
     572             :     },
     573             :     { NULL }
     574             : };
     575             : 
     576             : static const AVFilterPad compand_outputs[] = {
     577             :     {
     578             :         .name          = "default",
     579             :         .request_frame = request_frame,
     580             :         .config_props  = config_output,
     581             :         .type          = AVMEDIA_TYPE_AUDIO,
     582             :     },
     583             :     { NULL }
     584             : };
     585             : 
     586             : 
     587             : AVFilter ff_af_compand = {
     588             :     .name           = "compand",
     589             :     .description    = NULL_IF_CONFIG_SMALL(
     590             :             "Compress or expand audio dynamic range."),
     591             :     .query_formats  = query_formats,
     592             :     .priv_size      = sizeof(CompandContext),
     593             :     .priv_class     = &compand_class,
     594             :     .init           = init,
     595             :     .uninit         = uninit,
     596             :     .inputs         = compand_inputs,
     597             :     .outputs        = compand_outputs,
     598             : };

Generated by: LCOV version 1.13