| 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 FFFilter ff_af_alimiter = { | ||
| 425 | .p.name = "alimiter", | ||
| 426 | .p.description = NULL_IF_CONFIG_SMALL("Audio lookahead limiter."), | ||
| 427 | .p.priv_class = &alimiter_class, | ||
| 428 | .p.flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC, | ||
| 429 | .priv_size = sizeof(AudioLimiterContext), | ||
| 430 | .init = init, | ||
| 431 | .uninit = uninit, | ||
| 432 | FILTER_INPUTS(alimiter_inputs), | ||
| 433 | FILTER_OUTPUTS(alimiter_outputs), | ||
| 434 | FILTER_SINGLE_SAMPLEFMT(AV_SAMPLE_FMT_DBL), | ||
| 435 | .process_command = ff_filter_process_command, | ||
| 436 | }; | ||
| 437 |