]> git.sesse.net Git - ffmpeg/blob - libavfilter/af_alimiter.c
avfilter/af_alimiter: make description a bit longer
[ffmpeg] / libavfilter / af_alimiter.c
1 /*
2  * Copyright (C) 2001-2010 Krzysztof Foltman, Markus Schmidt, Thor Harald Johansen and others
3  * Copyright (c) 2015 Paul B Mahol
4  *
5  * This file is part of FFmpeg.
6  *
7  * FFmpeg is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * FFmpeg is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with FFmpeg; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20  */
21
22 /**
23  * @file
24  * Lookahead limiter filter
25  */
26
27 #include "libavutil/avassert.h"
28 #include "libavutil/channel_layout.h"
29 #include "libavutil/common.h"
30 #include "libavutil/opt.h"
31
32 #include "audio.h"
33 #include "avfilter.h"
34 #include "formats.h"
35 #include "internal.h"
36
37 typedef struct AudioLimiterContext {
38     const AVClass *class;
39
40     double limit;
41     double attack;
42     double release;
43     double att;
44     int auto_release;
45     double asc;
46     int asc_c;
47     int asc_pos;
48     double asc_coeff;
49
50     double *buffer;
51     int buffer_size;
52     int pos;
53     int *nextpos;
54     double *nextdelta;
55
56     double delta;
57     int nextiter;
58     int nextlen;
59     int asc_changed;
60 } AudioLimiterContext;
61
62 #define OFFSET(x) offsetof(AudioLimiterContext, x)
63 #define A AV_OPT_FLAG_AUDIO_PARAM
64 #define F AV_OPT_FLAG_FILTERING_PARAM
65
66 static const AVOption alimiter_options[] = {
67     { "limit",     "set limit",     OFFSET(limit),        AV_OPT_TYPE_DOUBLE, {.dbl=1}, 0.0625,    1, A|F },
68     { "attack",    "set attack",    OFFSET(attack),       AV_OPT_TYPE_DOUBLE, {.dbl=5},    0.1,   80, A|F },
69     { "release",   "set release",   OFFSET(release),      AV_OPT_TYPE_DOUBLE, {.dbl=50},     1, 8000, A|F },
70     { "asc",       "enable asc",    OFFSET(auto_release), AV_OPT_TYPE_BOOL,   {.i64=0},      0,    1, A|F },
71     { "asc_level", "set asc level", OFFSET(asc_coeff),    AV_OPT_TYPE_DOUBLE, {.dbl=0.5},    0,    1, A|F },
72     { NULL }
73 };
74
75 AVFILTER_DEFINE_CLASS(alimiter);
76
77 static av_cold int init(AVFilterContext *ctx)
78 {
79     AudioLimiterContext *s = ctx->priv;
80
81     s->attack   /= 1000.;
82     s->release  /= 1000.;
83     s->att       = 1.;
84     s->asc_pos   = -1;
85     s->asc_coeff = pow(0.5, s->asc_coeff - 0.5) * 2 * -1;
86
87     return 0;
88 }
89
90 static double get_rdelta(AudioLimiterContext *s, double release, int sample_rate,
91                          double peak, double limit, double patt, int asc)
92 {
93     double rdelta = (1.0 - patt) / (sample_rate * release);
94
95     if (asc && s->auto_release && s->asc_c > 0) {
96         double a_att = limit / (s->asc_coeff * s->asc) * (double)s->asc_c;
97
98         if (a_att > patt) {
99             double delta = FFMAX((a_att - patt) / (sample_rate * release), rdelta / 10);
100
101             if (delta < rdelta)
102                 rdelta = delta;
103         }
104     }
105
106     return rdelta;
107 }
108
109 static int filter_frame(AVFilterLink *inlink, AVFrame *in)
110 {
111     AVFilterContext *ctx = inlink->dst;
112     AudioLimiterContext *s = ctx->priv;
113     AVFilterLink *outlink = ctx->outputs[0];
114     const double *src = (const double *)in->data[0];
115     const int channels = inlink->channels;
116     const int buffer_size = s->buffer_size;
117     double *dst, *buffer = s->buffer;
118     const double release = s->release;
119     const double limit = s->limit;
120     double *nextdelta = s->nextdelta;
121     int *nextpos = s->nextpos;
122     AVFrame *out;
123     double *buf;
124     int n, c, i;
125
126     if (av_frame_is_writable(in)) {
127         out = in;
128     } else {
129         out = ff_get_audio_buffer(inlink, in->nb_samples);
130         if (!out) {
131             av_frame_free(&in);
132             return AVERROR(ENOMEM);
133         }
134         av_frame_copy_props(out, in);
135     }
136     dst = (double *)out->data[0];
137
138     for (n = 0; n < in->nb_samples; n++) {
139         double peak = 0;
140
141         for (c = 0; c < channels; c++) {
142             double sample = src[c];
143
144             buffer[s->pos + c] = sample;
145             peak = FFMAX(peak, fabs(sample));
146         }
147
148         if (s->auto_release && peak > limit) {
149             s->asc += peak;
150             s->asc_c++;
151         }
152
153         if (peak > limit) {
154             double patt = FFMIN(limit / peak, 1.);
155             double rdelta = get_rdelta(s, release, inlink->sample_rate,
156                                        peak, limit, patt, 0);
157             double delta = (limit / peak - s->att) / buffer_size * channels;
158             int found = 0;
159
160             if (delta < s->delta) {
161                 s->delta = delta;
162                 nextpos[0] = s->pos;
163                 nextpos[1] = -1;
164                 nextdelta[0] = rdelta;
165                 s->nextlen = 1;
166                 s->nextiter= 0;
167             } else {
168                 for (i = s->nextiter; i < s->nextiter + s->nextlen; i++) {
169                     int j = i % buffer_size;
170                     double ppeak, pdelta;
171
172                     ppeak = fabs(buffer[nextpos[j]]) > fabs(buffer[nextpos[j] + 1]) ?
173                             fabs(buffer[nextpos[j]]) : fabs(buffer[nextpos[j] + 1]);
174                     pdelta = (limit / peak - limit / ppeak) / (((buffer_size - nextpos[j] + s->pos) % buffer_size) / channels);
175                     if (pdelta < nextdelta[j]) {
176                         nextdelta[j] = pdelta;
177                         found = 1;
178                         break;
179                     }
180                 }
181                 if (found) {
182                     s->nextlen = i - s->nextiter + 1;
183                     nextpos[(s->nextiter + s->nextlen) % buffer_size] = s->pos;
184                     nextdelta[(s->nextiter + s->nextlen) % buffer_size] = rdelta;
185                     nextpos[(s->nextiter + s->nextlen + 1) % buffer_size] = -1;
186                     s->nextlen++;
187                 }
188             }
189         }
190
191         buf = &s->buffer[(s->pos + channels) % buffer_size];
192         peak = 0;
193         for (c = 0; c < channels; c++) {
194             double sample = buf[c];
195
196             peak = FFMAX(peak, fabs(sample));
197         }
198
199         if (s->pos == s->asc_pos && !s->asc_changed)
200             s->asc_pos = -1;
201
202         if (s->auto_release && s->asc_pos == -1 && peak > limit) {
203             s->asc -= peak;
204             s->asc_c--;
205         }
206
207         s->att += s->delta;
208
209         for (c = 0; c < channels; c++)
210             dst[c] = buf[c] * s->att;
211
212         if ((s->pos + channels) % buffer_size == nextpos[s->nextiter]) {
213             if (s->auto_release) {
214                 s->delta = get_rdelta(s, release, inlink->sample_rate,
215                                       peak, limit, s->att, 1);
216                 if (s->nextlen > 1) {
217                     int pnextpos = nextpos[(s->nextiter + 1) % buffer_size];
218                     double ppeak = fabs(buffer[pnextpos]) > fabs(buffer[pnextpos + 1]) ?
219                                                             fabs(buffer[pnextpos]) :
220                                                             fabs(buffer[pnextpos + 1]);
221                     double pdelta = (limit / ppeak - s->att) /
222                                     (((buffer_size + pnextpos -
223                                     ((s->pos + channels) % buffer_size)) %
224                                     buffer_size) / channels);
225                     if (pdelta < s->delta)
226                         s->delta = pdelta;
227                 }
228             } else {
229                 s->delta = nextdelta[s->nextiter];
230                 s->att = limit / peak;
231             }
232
233             s->nextlen -= 1;
234             nextpos[s->nextiter] = -1;
235             s->nextiter = (s->nextiter + 1) % buffer_size;
236         }
237
238         if (s->att > 1.) {
239             s->att = 1.;
240             s->delta = 0.;
241             s->nextiter = 0;
242             s->nextlen = 0;
243             nextpos[0] = -1;
244         }
245
246         if (s->att <= 0.) {
247             s->att = 0.0000000000001;
248             s->delta = (1.0 - s->att) / (inlink->sample_rate * release);
249         }
250
251         if (s->att != 1. && (1. - s->att) < 0.0000000000001)
252             s->att = 1.;
253
254         if (s->delta != 0. && fabs(s->delta) < 0.00000000000001)
255             s->delta = 0.;
256
257         for (c = 0; c < channels; c++)
258             dst[c] = av_clipd(dst[c], -limit, limit);
259
260         s->pos = (s->pos + channels) % buffer_size;
261         src += channels;
262         dst += channels;
263     }
264
265     if (in != out)
266         av_frame_free(&in);
267
268     return ff_filter_frame(outlink, out);
269 }
270
271 static int query_formats(AVFilterContext *ctx)
272 {
273     AVFilterFormats *formats;
274     AVFilterChannelLayouts *layouts;
275     static const enum AVSampleFormat sample_fmts[] = {
276         AV_SAMPLE_FMT_DBL,
277         AV_SAMPLE_FMT_NONE
278     };
279     int ret;
280
281     layouts = ff_all_channel_counts();
282     if (!layouts)
283         return AVERROR(ENOMEM);
284     ret = ff_set_common_channel_layouts(ctx, layouts);
285     if (ret < 0)
286         return ret;
287
288     formats = ff_make_format_list(sample_fmts);
289     if (!formats)
290         return AVERROR(ENOMEM);
291     ret = ff_set_common_formats(ctx, formats);
292     if (ret < 0)
293         return ret;
294
295     formats = ff_all_samplerates();
296     if (!formats)
297         return AVERROR(ENOMEM);
298     return ff_set_common_samplerates(ctx, formats);
299 }
300
301 static int config_input(AVFilterLink *inlink)
302 {
303     AVFilterContext *ctx = inlink->dst;
304     AudioLimiterContext *s = ctx->priv;
305     int obuffer_size;
306
307     obuffer_size = inlink->sample_rate * inlink->channels * 100 / 1000. + inlink->channels;
308     if (obuffer_size < inlink->channels)
309         return AVERROR(EINVAL);
310
311     s->buffer = av_calloc(obuffer_size, sizeof(*s->buffer));
312     s->nextdelta = av_calloc(obuffer_size, sizeof(*s->nextdelta));
313     s->nextpos = av_malloc_array(obuffer_size, sizeof(*s->nextpos));
314     if (!s->buffer || !s->nextdelta || !s->nextpos)
315         return AVERROR(ENOMEM);
316
317     memset(s->nextpos, -1, obuffer_size * sizeof(*s->nextpos));
318     s->buffer_size = inlink->sample_rate * s->attack * inlink->channels;
319     s->buffer_size -= s->buffer_size % inlink->channels;
320
321     return 0;
322 }
323
324 static av_cold void uninit(AVFilterContext *ctx)
325 {
326     AudioLimiterContext *s = ctx->priv;
327
328     av_freep(&s->buffer);
329     av_freep(&s->nextdelta);
330     av_freep(&s->nextpos);
331 }
332
333 static const AVFilterPad alimiter_inputs[] = {
334     {
335         .name         = "main",
336         .type         = AVMEDIA_TYPE_AUDIO,
337         .filter_frame = filter_frame,
338         .config_props = config_input,
339     },
340     { NULL }
341 };
342
343 static const AVFilterPad alimiter_outputs[] = {
344     {
345         .name = "default",
346         .type = AVMEDIA_TYPE_AUDIO,
347     },
348     { NULL }
349 };
350
351 AVFilter ff_af_alimiter = {
352     .name           = "alimiter",
353     .description    = NULL_IF_CONFIG_SMALL("Audio lookahead limiter."),
354     .priv_size      = sizeof(AudioLimiterContext),
355     .priv_class     = &alimiter_class,
356     .init           = init,
357     .uninit         = uninit,
358     .query_formats  = query_formats,
359     .inputs         = alimiter_inputs,
360     .outputs        = alimiter_outputs,
361 };