Line | Branch | Exec | Source |
---|---|---|---|
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/channel_layout.h" | ||
28 | #include "libavutil/common.h" | ||
29 | #include "libavutil/fifo.h" | ||
30 | #include "libavutil/mem.h" | ||
31 | #include "libavutil/opt.h" | ||
32 | |||
33 | #include "audio.h" | ||
34 | #include "avfilter.h" | ||
35 | #include "filters.h" | ||
36 | |||
37 | typedef struct MetaItem { | ||
38 | int64_t pts; | ||
39 | int nb_samples; | ||
40 | } MetaItem; | ||
41 | |||
42 | typedef struct AudioLimiterContext { | ||
43 | const AVClass *class; | ||
44 | |||
45 | double limit; | ||
46 | double attack; | ||
47 | double release; | ||
48 | double att; | ||
49 | double level_in; | ||
50 | double level_out; | ||
51 | int auto_release; | ||
52 | int auto_level; | ||
53 | double asc; | ||
54 | int asc_c; | ||
55 | int asc_pos; | ||
56 | double asc_coeff; | ||
57 | |||
58 | double *buffer; | ||
59 | int buffer_size; | ||
60 | int pos; | ||
61 | int *nextpos; | ||
62 | double *nextdelta; | ||
63 | |||
64 | int in_trim; | ||
65 | int out_pad; | ||
66 | int64_t next_in_pts; | ||
67 | int64_t next_out_pts; | ||
68 | int latency; | ||
69 | |||
70 | AVFifo *fifo; | ||
71 | |||
72 | double delta; | ||
73 | int nextiter; | ||
74 | int nextlen; | ||
75 | int asc_changed; | ||
76 | } AudioLimiterContext; | ||
77 | |||
78 | #define OFFSET(x) offsetof(AudioLimiterContext, x) | ||
79 | #define AF AV_OPT_FLAG_AUDIO_PARAM | AV_OPT_FLAG_FILTERING_PARAM | AV_OPT_FLAG_RUNTIME_PARAM | ||
80 | |||
81 | static const AVOption alimiter_options[] = { | ||
82 | { "level_in", "set input level", OFFSET(level_in), AV_OPT_TYPE_DOUBLE, {.dbl=1},.015625, 64, AF }, | ||
83 | { "level_out", "set output level", OFFSET(level_out), AV_OPT_TYPE_DOUBLE, {.dbl=1},.015625, 64, AF }, | ||
84 | { "limit", "set limit", OFFSET(limit), AV_OPT_TYPE_DOUBLE, {.dbl=1}, 0.0625, 1, AF }, | ||
85 | { "attack", "set attack", OFFSET(attack), AV_OPT_TYPE_DOUBLE, {.dbl=5}, 0.1, 80, AF }, | ||
86 | { "release", "set release", OFFSET(release), AV_OPT_TYPE_DOUBLE, {.dbl=50}, 1, 8000, AF }, | ||
87 | { "asc", "enable asc", OFFSET(auto_release), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1, AF }, | ||
88 | { "asc_level", "set asc level", OFFSET(asc_coeff), AV_OPT_TYPE_DOUBLE, {.dbl=0.5}, 0, 1, AF }, | ||
89 | { "level", "auto level", OFFSET(auto_level), AV_OPT_TYPE_BOOL, {.i64=1}, 0, 1, AF }, | ||
90 | { "latency", "compensate delay", OFFSET(latency), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1, AF }, | ||
91 | { NULL } | ||
92 | }; | ||
93 | |||
94 | AVFILTER_DEFINE_CLASS(alimiter); | ||
95 | |||
96 | 2 | static av_cold int init(AVFilterContext *ctx) | |
97 | { | ||
98 | 2 | AudioLimiterContext *s = ctx->priv; | |
99 | |||
100 | 2 | s->attack /= 1000.; | |
101 | 2 | s->release /= 1000.; | |
102 | 2 | s->att = 1.; | |
103 | 2 | s->asc_pos = -1; | |
104 | 2 | s->asc_coeff = pow(0.5, s->asc_coeff - 0.5) * 2 * -1; | |
105 | |||
106 | 2 | return 0; | |
107 | } | ||
108 | |||
109 | 138816 | static double get_rdelta(AudioLimiterContext *s, double release, int sample_rate, | |
110 | double peak, double limit, double patt, int asc) | ||
111 | { | ||
112 | 138816 | double rdelta = (1.0 - patt) / (sample_rate * release); | |
113 | |||
114 |
1/6✗ Branch 0 not taken.
✓ Branch 1 taken 138816 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
|
138816 | if (asc && s->auto_release && s->asc_c > 0) { |
115 | ✗ | double a_att = limit / (s->asc_coeff * s->asc) * (double)s->asc_c; | |
116 | |||
117 | ✗ | if (a_att > patt) { | |
118 | ✗ | double delta = FFMAX((a_att - patt) / (sample_rate * release), rdelta / 10); | |
119 | |||
120 | ✗ | if (delta < rdelta) | |
121 | ✗ | rdelta = delta; | |
122 | } | ||
123 | } | ||
124 | |||
125 | 138816 | return rdelta; | |
126 | } | ||
127 | |||
128 | 65 | static int filter_frame(AVFilterLink *inlink, AVFrame *in) | |
129 | { | ||
130 | 65 | AVFilterContext *ctx = inlink->dst; | |
131 | 65 | AudioLimiterContext *s = ctx->priv; | |
132 | 65 | AVFilterLink *outlink = ctx->outputs[0]; | |
133 | 65 | const double *src = (const double *)in->data[0]; | |
134 | 65 | const int channels = inlink->ch_layout.nb_channels; | |
135 | 65 | const int buffer_size = s->buffer_size; | |
136 | 65 | double *dst, *buffer = s->buffer; | |
137 | 65 | const double release = s->release; | |
138 | 65 | const double limit = s->limit; | |
139 | 65 | double *nextdelta = s->nextdelta; | |
140 |
1/2✓ Branch 0 taken 65 times.
✗ Branch 1 not taken.
|
65 | double level = s->auto_level ? 1 / limit : 1; |
141 | 65 | const double level_out = s->level_out; | |
142 | 65 | const double level_in = s->level_in; | |
143 | 65 | int *nextpos = s->nextpos; | |
144 | AVFrame *out; | ||
145 | double *buf; | ||
146 | int n, c, i; | ||
147 | int new_out_samples; | ||
148 | int64_t out_duration; | ||
149 | int64_t in_duration; | ||
150 | int64_t in_pts; | ||
151 | MetaItem meta; | ||
152 | |||
153 |
1/2✓ Branch 1 taken 65 times.
✗ Branch 2 not taken.
|
65 | if (av_frame_is_writable(in)) { |
154 | 65 | out = in; | |
155 | } else { | ||
156 | ✗ | out = ff_get_audio_buffer(outlink, in->nb_samples); | |
157 | ✗ | if (!out) { | |
158 | ✗ | av_frame_free(&in); | |
159 | ✗ | return AVERROR(ENOMEM); | |
160 | } | ||
161 | ✗ | av_frame_copy_props(out, in); | |
162 | } | ||
163 | 65 | dst = (double *)out->data[0]; | |
164 | |||
165 |
2/2✓ Branch 0 taken 264600 times.
✓ Branch 1 taken 65 times.
|
264665 | for (n = 0; n < in->nb_samples; n++) { |
166 | 264600 | double peak = 0; | |
167 | |||
168 |
2/2✓ Branch 0 taken 529200 times.
✓ Branch 1 taken 264600 times.
|
793800 | for (c = 0; c < channels; c++) { |
169 | 529200 | double sample = src[c] * level_in; | |
170 | |||
171 | 529200 | buffer[s->pos + c] = sample; | |
172 |
2/2✓ Branch 0 taken 67140 times.
✓ Branch 1 taken 462060 times.
|
529200 | peak = FFMAX(peak, fabs(sample)); |
173 | } | ||
174 | |||
175 |
1/4✗ Branch 0 not taken.
✓ Branch 1 taken 264600 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
264600 | if (s->auto_release && peak > limit) { |
176 | ✗ | s->asc += peak; | |
177 | ✗ | s->asc_c++; | |
178 | } | ||
179 | |||
180 |
2/2✓ Branch 0 taken 138816 times.
✓ Branch 1 taken 125784 times.
|
264600 | if (peak > limit) { |
181 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 138816 times.
|
138816 | double patt = FFMIN(limit / peak, 1.); |
182 | 138816 | double rdelta = get_rdelta(s, release, inlink->sample_rate, | |
183 | peak, limit, patt, 0); | ||
184 | 138816 | double delta = (limit / peak - s->att) / buffer_size * channels; | |
185 | 138816 | int found = 0; | |
186 | |||
187 |
2/2✓ Branch 0 taken 1669 times.
✓ Branch 1 taken 137147 times.
|
138816 | if (delta < s->delta) { |
188 | 1669 | s->delta = delta; | |
189 | 1669 | nextpos[0] = s->pos; | |
190 | 1669 | nextpos[1] = -1; | |
191 | 1669 | nextdelta[0] = rdelta; | |
192 | 1669 | s->nextlen = 1; | |
193 | 1669 | s->nextiter= 0; | |
194 | } else { | ||
195 |
2/2✓ Branch 0 taken 439864 times.
✓ Branch 1 taken 124511 times.
|
564375 | for (i = s->nextiter; i < s->nextiter + s->nextlen; i++) { |
196 | 439864 | int j = i % buffer_size; | |
197 | 439864 | double ppeak = 0, pdelta; | |
198 | |||
199 |
1/2✓ Branch 0 taken 439864 times.
✗ Branch 1 not taken.
|
439864 | if (nextpos[j] >= 0) |
200 |
2/2✓ Branch 0 taken 879728 times.
✓ Branch 1 taken 439864 times.
|
1319592 | for (c = 0; c < channels; c++) { |
201 |
2/2✓ Branch 0 taken 121013 times.
✓ Branch 1 taken 758715 times.
|
879728 | ppeak = FFMAX(ppeak, fabs(buffer[nextpos[j] + c])); |
202 | } | ||
203 | 439864 | pdelta = (limit / peak - limit / ppeak) / (((buffer_size - nextpos[j] + s->pos) % buffer_size) / channels); | |
204 |
2/2✓ Branch 0 taken 12636 times.
✓ Branch 1 taken 427228 times.
|
439864 | if (pdelta < nextdelta[j]) { |
205 | 12636 | nextdelta[j] = pdelta; | |
206 | 12636 | found = 1; | |
207 | 12636 | break; | |
208 | } | ||
209 | } | ||
210 |
2/2✓ Branch 0 taken 12636 times.
✓ Branch 1 taken 124511 times.
|
137147 | if (found) { |
211 | 12636 | s->nextlen = i - s->nextiter + 1; | |
212 | 12636 | nextpos[(s->nextiter + s->nextlen) % buffer_size] = s->pos; | |
213 | 12636 | nextdelta[(s->nextiter + s->nextlen) % buffer_size] = rdelta; | |
214 | 12636 | nextpos[(s->nextiter + s->nextlen + 1) % buffer_size] = -1; | |
215 | 12636 | s->nextlen++; | |
216 | } | ||
217 | } | ||
218 | } | ||
219 | |||
220 | 264600 | buf = &s->buffer[(s->pos + channels) % buffer_size]; | |
221 | 264600 | peak = 0; | |
222 |
2/2✓ Branch 0 taken 529200 times.
✓ Branch 1 taken 264600 times.
|
793800 | for (c = 0; c < channels; c++) { |
223 | 529200 | double sample = buf[c]; | |
224 | |||
225 |
2/2✓ Branch 0 taken 67137 times.
✓ Branch 1 taken 462063 times.
|
529200 | peak = FFMAX(peak, fabs(sample)); |
226 | } | ||
227 | |||
228 |
1/4✗ Branch 0 not taken.
✓ Branch 1 taken 264600 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
264600 | if (s->pos == s->asc_pos && !s->asc_changed) |
229 | ✗ | s->asc_pos = -1; | |
230 | |||
231 |
1/6✗ Branch 0 not taken.
✓ Branch 1 taken 264600 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
|
264600 | if (s->auto_release && s->asc_pos == -1 && peak > limit) { |
232 | ✗ | s->asc -= peak; | |
233 | ✗ | s->asc_c--; | |
234 | } | ||
235 | |||
236 | 264600 | s->att += s->delta; | |
237 | |||
238 |
2/2✓ Branch 0 taken 529200 times.
✓ Branch 1 taken 264600 times.
|
793800 | for (c = 0; c < channels; c++) |
239 | 529200 | dst[c] = buf[c] * s->att; | |
240 | |||
241 |
2/2✓ Branch 0 taken 2019 times.
✓ Branch 1 taken 262581 times.
|
264600 | if ((s->pos + channels) % buffer_size == nextpos[s->nextiter]) { |
242 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2019 times.
|
2019 | if (s->auto_release) { |
243 | ✗ | s->delta = get_rdelta(s, release, inlink->sample_rate, | |
244 | peak, limit, s->att, 1); | ||
245 | ✗ | if (s->nextlen > 1) { | |
246 | ✗ | double ppeak = 0, pdelta; | |
247 | ✗ | int pnextpos = nextpos[(s->nextiter + 1) % buffer_size]; | |
248 | |||
249 | ✗ | for (c = 0; c < channels; c++) { | |
250 | ✗ | ppeak = FFMAX(ppeak, fabs(buffer[pnextpos + c])); | |
251 | } | ||
252 | ✗ | pdelta = (limit / ppeak - s->att) / | |
253 | ✗ | (((buffer_size + pnextpos - | |
254 | ✗ | ((s->pos + channels) % buffer_size)) % | |
255 | ✗ | buffer_size) / channels); | |
256 | ✗ | if (pdelta < s->delta) | |
257 | ✗ | s->delta = pdelta; | |
258 | } | ||
259 | } else { | ||
260 | 2019 | s->delta = nextdelta[s->nextiter]; | |
261 | 2019 | s->att = limit / peak; | |
262 | } | ||
263 | |||
264 | 2019 | s->nextlen -= 1; | |
265 | 2019 | nextpos[s->nextiter] = -1; | |
266 | 2019 | s->nextiter = (s->nextiter + 1) % buffer_size; | |
267 | } | ||
268 | |||
269 |
2/2✓ Branch 0 taken 11 times.
✓ Branch 1 taken 264589 times.
|
264600 | if (s->att > 1.) { |
270 | 11 | s->att = 1.; | |
271 | 11 | s->delta = 0.; | |
272 | 11 | s->nextiter = 0; | |
273 | 11 | s->nextlen = 0; | |
274 | 11 | nextpos[0] = -1; | |
275 | } | ||
276 | |||
277 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 264600 times.
|
264600 | if (s->att <= 0.) { |
278 | ✗ | s->att = 0.0000000000001; | |
279 | ✗ | s->delta = (1.0 - s->att) / (inlink->sample_rate * release); | |
280 | } | ||
281 | |||
282 |
4/4✓ Branch 0 taken 258924 times.
✓ Branch 1 taken 5676 times.
✓ Branch 2 taken 5 times.
✓ Branch 3 taken 258919 times.
|
264600 | if (s->att != 1. && (1. - s->att) < 0.0000000000001) |
283 | 5 | s->att = 1.; | |
284 | |||
285 |
3/4✓ Branch 0 taken 203760 times.
✓ Branch 1 taken 60840 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 203760 times.
|
264600 | if (s->delta != 0. && fabs(s->delta) < 0.00000000000001) |
286 | ✗ | s->delta = 0.; | |
287 | |||
288 |
2/2✓ Branch 0 taken 529200 times.
✓ Branch 1 taken 264600 times.
|
793800 | for (c = 0; c < channels; c++) |
289 | 529200 | dst[c] = av_clipd(dst[c], -limit, limit) * level * level_out; | |
290 | |||
291 | 264600 | s->pos = (s->pos + channels) % buffer_size; | |
292 | 264600 | src += channels; | |
293 | 264600 | dst += channels; | |
294 | } | ||
295 | |||
296 | 65 | in_duration = av_rescale_q(in->nb_samples, inlink->time_base, av_make_q(1, in->sample_rate)); | |
297 | 65 | in_pts = in->pts; | |
298 | 65 | meta = (MetaItem){ in->pts, in->nb_samples }; | |
299 | 65 | av_fifo_write(s->fifo, &meta, 1); | |
300 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 65 times.
|
65 | if (in != out) |
301 | ✗ | av_frame_free(&in); | |
302 | |||
303 | 65 | new_out_samples = out->nb_samples; | |
304 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 65 times.
|
65 | if (s->in_trim > 0) { |
305 | ✗ | int trim = FFMIN(new_out_samples, s->in_trim); | |
306 | ✗ | new_out_samples -= trim; | |
307 | ✗ | s->in_trim -= trim; | |
308 | } | ||
309 | |||
310 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 65 times.
|
65 | if (new_out_samples <= 0) { |
311 | ✗ | av_frame_free(&out); | |
312 | ✗ | return 0; | |
313 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 65 times.
|
65 | } else if (new_out_samples < out->nb_samples) { |
314 | ✗ | int offset = out->nb_samples - new_out_samples; | |
315 | ✗ | memmove(out->extended_data[0], out->extended_data[0] + sizeof(double) * offset * out->ch_layout.nb_channels, | |
316 | ✗ | sizeof(double) * new_out_samples * out->ch_layout.nb_channels); | |
317 | ✗ | out->nb_samples = new_out_samples; | |
318 | ✗ | s->in_trim = 0; | |
319 | } | ||
320 | |||
321 | 65 | av_fifo_read(s->fifo, &meta, 1); | |
322 | |||
323 | 65 | out_duration = av_rescale_q(out->nb_samples, inlink->time_base, av_make_q(1, out->sample_rate)); | |
324 | 65 | in_duration = av_rescale_q(meta.nb_samples, inlink->time_base, av_make_q(1, out->sample_rate)); | |
325 | 65 | in_pts = meta.pts; | |
326 | |||
327 |
3/4✓ Branch 0 taken 64 times.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 64 times.
|
65 | if (s->next_out_pts != AV_NOPTS_VALUE && out->pts != s->next_out_pts && |
328 | ✗ | s->next_in_pts != AV_NOPTS_VALUE && in_pts == s->next_in_pts) { | |
329 | ✗ | out->pts = s->next_out_pts; | |
330 | } else { | ||
331 | 65 | out->pts = in_pts; | |
332 | } | ||
333 | 65 | s->next_in_pts = in_pts + in_duration; | |
334 | 65 | s->next_out_pts = out->pts + out_duration; | |
335 | |||
336 | 65 | return ff_filter_frame(outlink, out); | |
337 | } | ||
338 | |||
339 | 66 | static int request_frame(AVFilterLink* outlink) | |
340 | { | ||
341 | 66 | AVFilterContext *ctx = outlink->src; | |
342 | 66 | AudioLimiterContext *s = (AudioLimiterContext*)ctx->priv; | |
343 | int ret; | ||
344 | |||
345 | 66 | ret = ff_request_frame(ctx->inputs[0]); | |
346 | |||
347 |
3/4✓ Branch 0 taken 1 times.
✓ Branch 1 taken 65 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
|
66 | if (ret == AVERROR_EOF && s->out_pad > 0) { |
348 | ✗ | AVFrame *frame = ff_get_audio_buffer(outlink, FFMIN(1024, s->out_pad)); | |
349 | ✗ | if (!frame) | |
350 | ✗ | return AVERROR(ENOMEM); | |
351 | |||
352 | ✗ | s->out_pad -= frame->nb_samples; | |
353 | ✗ | frame->pts = s->next_in_pts; | |
354 | ✗ | return filter_frame(ctx->inputs[0], frame); | |
355 | } | ||
356 | 66 | return ret; | |
357 | } | ||
358 | |||
359 | 1 | static int config_input(AVFilterLink *inlink) | |
360 | { | ||
361 | 1 | AVFilterContext *ctx = inlink->dst; | |
362 | 1 | AudioLimiterContext *s = ctx->priv; | |
363 | int obuffer_size; | ||
364 | |||
365 | 1 | obuffer_size = inlink->sample_rate * inlink->ch_layout.nb_channels * 100 / 1000. + inlink->ch_layout.nb_channels; | |
366 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (obuffer_size < inlink->ch_layout.nb_channels) |
367 | ✗ | return AVERROR(EINVAL); | |
368 | |||
369 | 1 | s->buffer = av_calloc(obuffer_size, sizeof(*s->buffer)); | |
370 | 1 | s->nextdelta = av_calloc(obuffer_size, sizeof(*s->nextdelta)); | |
371 | 1 | s->nextpos = av_malloc_array(obuffer_size, sizeof(*s->nextpos)); | |
372 |
3/6✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 1 times.
|
1 | if (!s->buffer || !s->nextdelta || !s->nextpos) |
373 | ✗ | return AVERROR(ENOMEM); | |
374 | |||
375 | 1 | memset(s->nextpos, -1, obuffer_size * sizeof(*s->nextpos)); | |
376 | 1 | s->buffer_size = inlink->sample_rate * s->attack * inlink->ch_layout.nb_channels; | |
377 | 1 | s->buffer_size -= s->buffer_size % inlink->ch_layout.nb_channels; | |
378 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (s->latency) |
379 | ✗ | s->in_trim = s->out_pad = s->buffer_size / inlink->ch_layout.nb_channels - 1; | |
380 | 1 | s->next_out_pts = AV_NOPTS_VALUE; | |
381 | 1 | s->next_in_pts = AV_NOPTS_VALUE; | |
382 | |||
383 | 1 | s->fifo = av_fifo_alloc2(8, sizeof(MetaItem), AV_FIFO_FLAG_AUTO_GROW); | |
384 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (!s->fifo) { |
385 | ✗ | return AVERROR(ENOMEM); | |
386 | } | ||
387 | |||
388 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (s->buffer_size <= 0) { |
389 | ✗ | av_log(ctx, AV_LOG_ERROR, "Attack is too small.\n"); | |
390 | ✗ | return AVERROR(EINVAL); | |
391 | } | ||
392 | |||
393 | 1 | return 0; | |
394 | } | ||
395 | |||
396 | 2 | static av_cold void uninit(AVFilterContext *ctx) | |
397 | { | ||
398 | 2 | AudioLimiterContext *s = ctx->priv; | |
399 | |||
400 | 2 | av_freep(&s->buffer); | |
401 | 2 | av_freep(&s->nextdelta); | |
402 | 2 | av_freep(&s->nextpos); | |
403 | |||
404 | 2 | av_fifo_freep2(&s->fifo); | |
405 | 2 | } | |
406 | |||
407 | static const AVFilterPad alimiter_inputs[] = { | ||
408 | { | ||
409 | .name = "main", | ||
410 | .type = AVMEDIA_TYPE_AUDIO, | ||
411 | .filter_frame = filter_frame, | ||
412 | .config_props = config_input, | ||
413 | }, | ||
414 | }; | ||
415 | |||
416 | static const AVFilterPad alimiter_outputs[] = { | ||
417 | { | ||
418 | .name = "default", | ||
419 | .type = AVMEDIA_TYPE_AUDIO, | ||
420 | .request_frame = request_frame, | ||
421 | }, | ||
422 | }; | ||
423 | |||
424 | const AVFilter ff_af_alimiter = { | ||
425 | .name = "alimiter", | ||
426 | .description = NULL_IF_CONFIG_SMALL("Audio lookahead limiter."), | ||
427 | .priv_size = sizeof(AudioLimiterContext), | ||
428 | .priv_class = &alimiter_class, | ||
429 | .init = init, | ||
430 | .uninit = uninit, | ||
431 | FILTER_INPUTS(alimiter_inputs), | ||
432 | FILTER_OUTPUTS(alimiter_outputs), | ||
433 | FILTER_SINGLE_SAMPLEFMT(AV_SAMPLE_FMT_DBL), | ||
434 | .process_command = ff_filter_process_command, | ||
435 | .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC, | ||
436 | }; | ||
437 |