blob: 46211a710ada8eb3993f73042e9612ac63b2344b
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 | double level_in; |
45 | double level_out; |
46 | int auto_release; |
47 | int auto_level; |
48 | double asc; |
49 | int asc_c; |
50 | int asc_pos; |
51 | double asc_coeff; |
52 | |
53 | double *buffer; |
54 | int buffer_size; |
55 | int pos; |
56 | int *nextpos; |
57 | double *nextdelta; |
58 | |
59 | double delta; |
60 | int nextiter; |
61 | int nextlen; |
62 | int asc_changed; |
63 | } AudioLimiterContext; |
64 | |
65 | #define OFFSET(x) offsetof(AudioLimiterContext, x) |
66 | #define A AV_OPT_FLAG_AUDIO_PARAM |
67 | #define F AV_OPT_FLAG_FILTERING_PARAM |
68 | |
69 | static const AVOption alimiter_options[] = { |
70 | { "level_in", "set input level", OFFSET(level_in), AV_OPT_TYPE_DOUBLE, {.dbl=1},.015625, 64, A|F }, |
71 | { "level_out", "set output level", OFFSET(level_out), AV_OPT_TYPE_DOUBLE, {.dbl=1},.015625, 64, A|F }, |
72 | { "limit", "set limit", OFFSET(limit), AV_OPT_TYPE_DOUBLE, {.dbl=1}, 0.0625, 1, A|F }, |
73 | { "attack", "set attack", OFFSET(attack), AV_OPT_TYPE_DOUBLE, {.dbl=5}, 0.1, 80, A|F }, |
74 | { "release", "set release", OFFSET(release), AV_OPT_TYPE_DOUBLE, {.dbl=50}, 1, 8000, A|F }, |
75 | { "asc", "enable asc", OFFSET(auto_release), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1, A|F }, |
76 | { "asc_level", "set asc level", OFFSET(asc_coeff), AV_OPT_TYPE_DOUBLE, {.dbl=0.5}, 0, 1, A|F }, |
77 | { "level", "auto level", OFFSET(auto_level), AV_OPT_TYPE_BOOL, {.i64=1}, 0, 1, A|F }, |
78 | { NULL } |
79 | }; |
80 | |
81 | AVFILTER_DEFINE_CLASS(alimiter); |
82 | |
83 | static av_cold int init(AVFilterContext *ctx) |
84 | { |
85 | AudioLimiterContext *s = ctx->priv; |
86 | |
87 | s->attack /= 1000.; |
88 | s->release /= 1000.; |
89 | s->att = 1.; |
90 | s->asc_pos = -1; |
91 | s->asc_coeff = pow(0.5, s->asc_coeff - 0.5) * 2 * -1; |
92 | |
93 | return 0; |
94 | } |
95 | |
96 | static double get_rdelta(AudioLimiterContext *s, double release, int sample_rate, |
97 | double peak, double limit, double patt, int asc) |
98 | { |
99 | double rdelta = (1.0 - patt) / (sample_rate * release); |
100 | |
101 | if (asc && s->auto_release && s->asc_c > 0) { |
102 | double a_att = limit / (s->asc_coeff * s->asc) * (double)s->asc_c; |
103 | |
104 | if (a_att > patt) { |
105 | double delta = FFMAX((a_att - patt) / (sample_rate * release), rdelta / 10); |
106 | |
107 | if (delta < rdelta) |
108 | rdelta = delta; |
109 | } |
110 | } |
111 | |
112 | return rdelta; |
113 | } |
114 | |
115 | static int filter_frame(AVFilterLink *inlink, AVFrame *in) |
116 | { |
117 | AVFilterContext *ctx = inlink->dst; |
118 | AudioLimiterContext *s = ctx->priv; |
119 | AVFilterLink *outlink = ctx->outputs[0]; |
120 | const double *src = (const double *)in->data[0]; |
121 | const int channels = inlink->channels; |
122 | const int buffer_size = s->buffer_size; |
123 | double *dst, *buffer = s->buffer; |
124 | const double release = s->release; |
125 | const double limit = s->limit; |
126 | double *nextdelta = s->nextdelta; |
127 | double level = s->auto_level ? 1 / limit : 1; |
128 | const double level_out = s->level_out; |
129 | const double level_in = s->level_in; |
130 | int *nextpos = s->nextpos; |
131 | AVFrame *out; |
132 | double *buf; |
133 | int n, c, i; |
134 | |
135 | if (av_frame_is_writable(in)) { |
136 | out = in; |
137 | } else { |
138 | out = ff_get_audio_buffer(inlink, in->nb_samples); |
139 | if (!out) { |
140 | av_frame_free(&in); |
141 | return AVERROR(ENOMEM); |
142 | } |
143 | av_frame_copy_props(out, in); |
144 | } |
145 | dst = (double *)out->data[0]; |
146 | |
147 | for (n = 0; n < in->nb_samples; n++) { |
148 | double peak = 0; |
149 | |
150 | for (c = 0; c < channels; c++) { |
151 | double sample = src[c] * level_in; |
152 | |
153 | buffer[s->pos + c] = sample; |
154 | peak = FFMAX(peak, fabs(sample)); |
155 | } |
156 | |
157 | if (s->auto_release && peak > limit) { |
158 | s->asc += peak; |
159 | s->asc_c++; |
160 | } |
161 | |
162 | if (peak > limit) { |
163 | double patt = FFMIN(limit / peak, 1.); |
164 | double rdelta = get_rdelta(s, release, inlink->sample_rate, |
165 | peak, limit, patt, 0); |
166 | double delta = (limit / peak - s->att) / buffer_size * channels; |
167 | int found = 0; |
168 | |
169 | if (delta < s->delta) { |
170 | s->delta = delta; |
171 | nextpos[0] = s->pos; |
172 | nextpos[1] = -1; |
173 | nextdelta[0] = rdelta; |
174 | s->nextlen = 1; |
175 | s->nextiter= 0; |
176 | } else { |
177 | for (i = s->nextiter; i < s->nextiter + s->nextlen; i++) { |
178 | int j = i % buffer_size; |
179 | double ppeak, pdelta; |
180 | |
181 | ppeak = fabs(buffer[nextpos[j]]) > fabs(buffer[nextpos[j] + 1]) ? |
182 | fabs(buffer[nextpos[j]]) : fabs(buffer[nextpos[j] + 1]); |
183 | pdelta = (limit / peak - limit / ppeak) / (((buffer_size - nextpos[j] + s->pos) % buffer_size) / channels); |
184 | if (pdelta < nextdelta[j]) { |
185 | nextdelta[j] = pdelta; |
186 | found = 1; |
187 | break; |
188 | } |
189 | } |
190 | if (found) { |
191 | s->nextlen = i - s->nextiter + 1; |
192 | nextpos[(s->nextiter + s->nextlen) % buffer_size] = s->pos; |
193 | nextdelta[(s->nextiter + s->nextlen) % buffer_size] = rdelta; |
194 | nextpos[(s->nextiter + s->nextlen + 1) % buffer_size] = -1; |
195 | s->nextlen++; |
196 | } |
197 | } |
198 | } |
199 | |
200 | buf = &s->buffer[(s->pos + channels) % buffer_size]; |
201 | peak = 0; |
202 | for (c = 0; c < channels; c++) { |
203 | double sample = buf[c]; |
204 | |
205 | peak = FFMAX(peak, fabs(sample)); |
206 | } |
207 | |
208 | if (s->pos == s->asc_pos && !s->asc_changed) |
209 | s->asc_pos = -1; |
210 | |
211 | if (s->auto_release && s->asc_pos == -1 && peak > limit) { |
212 | s->asc -= peak; |
213 | s->asc_c--; |
214 | } |
215 | |
216 | s->att += s->delta; |
217 | |
218 | for (c = 0; c < channels; c++) |
219 | dst[c] = buf[c] * s->att; |
220 | |
221 | if ((s->pos + channels) % buffer_size == nextpos[s->nextiter]) { |
222 | if (s->auto_release) { |
223 | s->delta = get_rdelta(s, release, inlink->sample_rate, |
224 | peak, limit, s->att, 1); |
225 | if (s->nextlen > 1) { |
226 | int pnextpos = nextpos[(s->nextiter + 1) % buffer_size]; |
227 | double ppeak = fabs(buffer[pnextpos]) > fabs(buffer[pnextpos + 1]) ? |
228 | fabs(buffer[pnextpos]) : |
229 | fabs(buffer[pnextpos + 1]); |
230 | double pdelta = (limit / ppeak - s->att) / |
231 | (((buffer_size + pnextpos - |
232 | ((s->pos + channels) % buffer_size)) % |
233 | buffer_size) / channels); |
234 | if (pdelta < s->delta) |
235 | s->delta = pdelta; |
236 | } |
237 | } else { |
238 | s->delta = nextdelta[s->nextiter]; |
239 | s->att = limit / peak; |
240 | } |
241 | |
242 | s->nextlen -= 1; |
243 | nextpos[s->nextiter] = -1; |
244 | s->nextiter = (s->nextiter + 1) % buffer_size; |
245 | } |
246 | |
247 | if (s->att > 1.) { |
248 | s->att = 1.; |
249 | s->delta = 0.; |
250 | s->nextiter = 0; |
251 | s->nextlen = 0; |
252 | nextpos[0] = -1; |
253 | } |
254 | |
255 | if (s->att <= 0.) { |
256 | s->att = 0.0000000000001; |
257 | s->delta = (1.0 - s->att) / (inlink->sample_rate * release); |
258 | } |
259 | |
260 | if (s->att != 1. && (1. - s->att) < 0.0000000000001) |
261 | s->att = 1.; |
262 | |
263 | if (s->delta != 0. && fabs(s->delta) < 0.00000000000001) |
264 | s->delta = 0.; |
265 | |
266 | for (c = 0; c < channels; c++) |
267 | dst[c] = av_clipd(dst[c], -limit, limit) * level * level_out; |
268 | |
269 | s->pos = (s->pos + channels) % buffer_size; |
270 | src += channels; |
271 | dst += channels; |
272 | } |
273 | |
274 | if (in != out) |
275 | av_frame_free(&in); |
276 | |
277 | return ff_filter_frame(outlink, out); |
278 | } |
279 | |
280 | static int query_formats(AVFilterContext *ctx) |
281 | { |
282 | AVFilterFormats *formats; |
283 | AVFilterChannelLayouts *layouts; |
284 | static const enum AVSampleFormat sample_fmts[] = { |
285 | AV_SAMPLE_FMT_DBL, |
286 | AV_SAMPLE_FMT_NONE |
287 | }; |
288 | int ret; |
289 | |
290 | layouts = ff_all_channel_counts(); |
291 | if (!layouts) |
292 | return AVERROR(ENOMEM); |
293 | ret = ff_set_common_channel_layouts(ctx, layouts); |
294 | if (ret < 0) |
295 | return ret; |
296 | |
297 | formats = ff_make_format_list(sample_fmts); |
298 | if (!formats) |
299 | return AVERROR(ENOMEM); |
300 | ret = ff_set_common_formats(ctx, formats); |
301 | if (ret < 0) |
302 | return ret; |
303 | |
304 | formats = ff_all_samplerates(); |
305 | if (!formats) |
306 | return AVERROR(ENOMEM); |
307 | return ff_set_common_samplerates(ctx, formats); |
308 | } |
309 | |
310 | static int config_input(AVFilterLink *inlink) |
311 | { |
312 | AVFilterContext *ctx = inlink->dst; |
313 | AudioLimiterContext *s = ctx->priv; |
314 | int obuffer_size; |
315 | |
316 | obuffer_size = inlink->sample_rate * inlink->channels * 100 / 1000. + inlink->channels; |
317 | if (obuffer_size < inlink->channels) |
318 | return AVERROR(EINVAL); |
319 | |
320 | s->buffer = av_calloc(obuffer_size, sizeof(*s->buffer)); |
321 | s->nextdelta = av_calloc(obuffer_size, sizeof(*s->nextdelta)); |
322 | s->nextpos = av_malloc_array(obuffer_size, sizeof(*s->nextpos)); |
323 | if (!s->buffer || !s->nextdelta || !s->nextpos) |
324 | return AVERROR(ENOMEM); |
325 | |
326 | memset(s->nextpos, -1, obuffer_size * sizeof(*s->nextpos)); |
327 | s->buffer_size = inlink->sample_rate * s->attack * inlink->channels; |
328 | s->buffer_size -= s->buffer_size % inlink->channels; |
329 | |
330 | return 0; |
331 | } |
332 | |
333 | static av_cold void uninit(AVFilterContext *ctx) |
334 | { |
335 | AudioLimiterContext *s = ctx->priv; |
336 | |
337 | av_freep(&s->buffer); |
338 | av_freep(&s->nextdelta); |
339 | av_freep(&s->nextpos); |
340 | } |
341 | |
342 | static const AVFilterPad alimiter_inputs[] = { |
343 | { |
344 | .name = "main", |
345 | .type = AVMEDIA_TYPE_AUDIO, |
346 | .filter_frame = filter_frame, |
347 | .config_props = config_input, |
348 | }, |
349 | { NULL } |
350 | }; |
351 | |
352 | static const AVFilterPad alimiter_outputs[] = { |
353 | { |
354 | .name = "default", |
355 | .type = AVMEDIA_TYPE_AUDIO, |
356 | }, |
357 | { NULL } |
358 | }; |
359 | |
360 | AVFilter ff_af_alimiter = { |
361 | .name = "alimiter", |
362 | .description = NULL_IF_CONFIG_SMALL("Audio lookahead limiter."), |
363 | .priv_size = sizeof(AudioLimiterContext), |
364 | .priv_class = &alimiter_class, |
365 | .init = init, |
366 | .uninit = uninit, |
367 | .query_formats = query_formats, |
368 | .inputs = alimiter_inputs, |
369 | .outputs = alimiter_outputs, |
370 | }; |
371 |