Line | Branch | Exec | Source |
---|---|---|---|
1 | /* | ||
2 | * Copyright (c) 2013 Paul B Mahol | ||
3 | * | ||
4 | * This file is part of FFmpeg. | ||
5 | * | ||
6 | * FFmpeg is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of the GNU Lesser General Public | ||
8 | * License as published by the Free Software Foundation; either | ||
9 | * version 2.1 of the License, or (at your option) any later version. | ||
10 | * | ||
11 | * FFmpeg is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
14 | * Lesser General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU Lesser General Public | ||
17 | * License along with FFmpeg; if not, write to the Free Software | ||
18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||
19 | */ | ||
20 | |||
21 | #include "libavutil/avstring.h" | ||
22 | #include "libavutil/eval.h" | ||
23 | #include "libavutil/opt.h" | ||
24 | #include "libavutil/samplefmt.h" | ||
25 | #include "avfilter.h" | ||
26 | #include "audio.h" | ||
27 | #include "filters.h" | ||
28 | #include "internal.h" | ||
29 | |||
30 | typedef struct ChanDelay { | ||
31 | int64_t delay; | ||
32 | size_t delay_index; | ||
33 | size_t index; | ||
34 | unsigned int samples_size; | ||
35 | uint8_t *samples; | ||
36 | } ChanDelay; | ||
37 | |||
38 | typedef struct AudioDelayContext { | ||
39 | const AVClass *class; | ||
40 | int all; | ||
41 | char *delays; | ||
42 | ChanDelay *chandelay; | ||
43 | int nb_delays; | ||
44 | int block_align; | ||
45 | int64_t padding; | ||
46 | int64_t max_delay; | ||
47 | int64_t offset; | ||
48 | int64_t next_pts; | ||
49 | int eof; | ||
50 | |||
51 | AVFrame *input; | ||
52 | |||
53 | void (*delay_channel)(ChanDelay *d, int nb_samples, | ||
54 | const uint8_t *src, uint8_t *dst); | ||
55 | int (*resize_channel_samples)(ChanDelay *d, int64_t new_delay); | ||
56 | } AudioDelayContext; | ||
57 | |||
58 | #define OFFSET(x) offsetof(AudioDelayContext, x) | ||
59 | #define A AV_OPT_FLAG_AUDIO_PARAM|AV_OPT_FLAG_FILTERING_PARAM | ||
60 | |||
61 | static const AVOption adelay_options[] = { | ||
62 | { "delays", "set list of delays for each channel", OFFSET(delays), AV_OPT_TYPE_STRING, {.str=NULL}, 0, 0, A | AV_OPT_FLAG_RUNTIME_PARAM }, | ||
63 | { "all", "use last available delay for remained channels", OFFSET(all), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1, A }, | ||
64 | { NULL } | ||
65 | }; | ||
66 | |||
67 | AVFILTER_DEFINE_CLASS(adelay); | ||
68 | |||
69 | #define DELAY(name, type, fill) \ | ||
70 | static void delay_channel_## name ##p(ChanDelay *d, int nb_samples, \ | ||
71 | const uint8_t *ssrc, uint8_t *ddst) \ | ||
72 | { \ | ||
73 | const type *src = (type *)ssrc; \ | ||
74 | type *dst = (type *)ddst; \ | ||
75 | type *samples = (type *)d->samples; \ | ||
76 | \ | ||
77 | while (nb_samples) { \ | ||
78 | if (d->delay_index < d->delay) { \ | ||
79 | const int len = FFMIN(nb_samples, d->delay - d->delay_index); \ | ||
80 | \ | ||
81 | memcpy(&samples[d->delay_index], src, len * sizeof(type)); \ | ||
82 | memset(dst, fill, len * sizeof(type)); \ | ||
83 | d->delay_index += len; \ | ||
84 | src += len; \ | ||
85 | dst += len; \ | ||
86 | nb_samples -= len; \ | ||
87 | } else { \ | ||
88 | *dst = samples[d->index]; \ | ||
89 | samples[d->index] = *src; \ | ||
90 | nb_samples--; \ | ||
91 | d->index++; \ | ||
92 | src++, dst++; \ | ||
93 | d->index = d->index >= d->delay ? 0 : d->index; \ | ||
94 | } \ | ||
95 | } \ | ||
96 | } | ||
97 | |||
98 | ✗ | DELAY(u8, uint8_t, 0x80) | |
99 |
6/6✓ Branch 0 taken 1 times.
✓ Branch 1 taken 264600 times.
✓ Branch 2 taken 264458 times.
✓ Branch 3 taken 142 times.
✓ Branch 4 taken 264601 times.
✓ Branch 5 taken 66 times.
|
264667 | DELAY(s16, int16_t, 0) |
100 | ✗ | DELAY(s32, int32_t, 0) | |
101 | ✗ | DELAY(flt, float, 0) | |
102 | ✗ | DELAY(dbl, double, 0) | |
103 | |||
104 | #define CHANGE_DELAY(name, type, fill) \ | ||
105 | static int resize_samples_## name ##p(ChanDelay *d, int64_t new_delay) \ | ||
106 | { \ | ||
107 | type *samples; \ | ||
108 | \ | ||
109 | if (new_delay == d->delay) { \ | ||
110 | return 0; \ | ||
111 | } \ | ||
112 | \ | ||
113 | if (new_delay == 0) { \ | ||
114 | av_freep(&d->samples); \ | ||
115 | d->samples_size = 0; \ | ||
116 | d->delay = 0; \ | ||
117 | d->index = 0; \ | ||
118 | d->delay_index = 0; \ | ||
119 | return 0; \ | ||
120 | } \ | ||
121 | \ | ||
122 | samples = (type *) av_fast_realloc(d->samples, &d->samples_size, new_delay * sizeof(type)); \ | ||
123 | if (!samples) { \ | ||
124 | return AVERROR(ENOMEM); \ | ||
125 | } \ | ||
126 | \ | ||
127 | if (new_delay < d->delay) { \ | ||
128 | if (d->index > new_delay) { \ | ||
129 | d->index -= new_delay; \ | ||
130 | memmove(samples, &samples[new_delay], d->index * sizeof(type)); \ | ||
131 | d->delay_index = new_delay; \ | ||
132 | } else if (d->delay_index > d->index) { \ | ||
133 | memmove(&samples[d->index], &samples[d->index+(d->delay-new_delay)], \ | ||
134 | (new_delay - d->index) * sizeof(type)); \ | ||
135 | d->delay_index -= d->delay - new_delay; \ | ||
136 | } \ | ||
137 | } else { \ | ||
138 | size_t block_size; \ | ||
139 | if (d->delay_index >= d->delay) { \ | ||
140 | block_size = (d->delay - d->index) * sizeof(type); \ | ||
141 | memmove(&samples[d->index+(new_delay - d->delay)], &samples[d->index], block_size); \ | ||
142 | d->delay_index = new_delay; \ | ||
143 | } else { \ | ||
144 | d->delay_index += new_delay - d->delay; \ | ||
145 | } \ | ||
146 | block_size = (new_delay - d->delay) * sizeof(type); \ | ||
147 | memset(&samples[d->index], fill, block_size); \ | ||
148 | } \ | ||
149 | d->delay = new_delay; \ | ||
150 | d->samples = (void *) samples; \ | ||
151 | return 0; \ | ||
152 | } | ||
153 | |||
154 | ✗ | CHANGE_DELAY(u8, uint8_t, 0x80) | |
155 | ✗ | CHANGE_DELAY(s16, int16_t, 0) | |
156 | ✗ | CHANGE_DELAY(s32, int32_t, 0) | |
157 | ✗ | CHANGE_DELAY(flt, float, 0) | |
158 | ✗ | CHANGE_DELAY(dbl, double, 0) | |
159 | |||
160 | 2 | static int parse_delays(char *p, char **saveptr, int64_t *result, AVFilterContext *ctx, int sample_rate) { | |
161 | float delay, div; | ||
162 | int ret; | ||
163 | char *arg; | ||
164 | 2 | char type = 0; | |
165 | |||
166 |
2/2✓ Branch 1 taken 1 times.
✓ Branch 2 taken 1 times.
|
2 | if (!(arg = av_strtok(p, "|", saveptr))) |
167 | 1 | return 1; | |
168 | |||
169 | 1 | ret = av_sscanf(arg, "%"SCNd64"%c", result, &type); | |
170 |
1/4✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
1 | if (ret != 2 || type != 'S') { |
171 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | div = type == 's' ? 1.0 : 1000.0; |
172 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
|
1 | if (av_sscanf(arg, "%f", &delay) != 1) { |
173 | ✗ | av_log(ctx, AV_LOG_ERROR, "Invalid syntax for delay.\n"); | |
174 | ✗ | return AVERROR(EINVAL); | |
175 | } | ||
176 | 1 | *result = delay * sample_rate / div; | |
177 | } | ||
178 | |||
179 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (*result < 0) { |
180 | ✗ | av_log(ctx, AV_LOG_ERROR, "Delay must be non negative number.\n"); | |
181 | ✗ | return AVERROR(EINVAL); | |
182 | } | ||
183 | 1 | return 0; | |
184 | } | ||
185 | |||
186 | 1 | static int config_input(AVFilterLink *inlink) | |
187 | { | ||
188 | 1 | AVFilterContext *ctx = inlink->dst; | |
189 | 1 | AudioDelayContext *s = ctx->priv; | |
190 | 1 | char *p, *saveptr = NULL; | |
191 | int i; | ||
192 | |||
193 | 1 | s->next_pts = AV_NOPTS_VALUE; | |
194 | 1 | s->chandelay = av_calloc(inlink->ch_layout.nb_channels, sizeof(*s->chandelay)); | |
195 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (!s->chandelay) |
196 | ✗ | return AVERROR(ENOMEM); | |
197 | 1 | s->nb_delays = inlink->ch_layout.nb_channels; | |
198 | 1 | s->block_align = av_get_bytes_per_sample(inlink->format); | |
199 | |||
200 | 1 | p = s->delays; | |
201 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 | for (i = 0; i < s->nb_delays; i++) { |
202 | 2 | ChanDelay *d = &s->chandelay[i]; | |
203 | int ret; | ||
204 | |||
205 | 2 | ret = parse_delays(p, &saveptr, &d->delay, ctx, inlink->sample_rate); | |
206 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
|
2 | if (ret == 1) |
207 | 1 | break; | |
208 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | else if (ret < 0) |
209 | ✗ | return ret; | |
210 | 1 | p = NULL; | |
211 | } | ||
212 | |||
213 |
1/4✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
1 | if (s->all && i) { |
214 | ✗ | for (int j = i; j < s->nb_delays; j++) | |
215 | ✗ | s->chandelay[j].delay = s->chandelay[i-1].delay; | |
216 | } | ||
217 | |||
218 | 1 | s->padding = s->chandelay[0].delay; | |
219 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
|
2 | for (i = 1; i < s->nb_delays; i++) { |
220 | 1 | ChanDelay *d = &s->chandelay[i]; | |
221 | |||
222 | 1 | s->padding = FFMIN(s->padding, d->delay); | |
223 | } | ||
224 | |||
225 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (s->padding) { |
226 | ✗ | for (i = 0; i < s->nb_delays; i++) { | |
227 | ✗ | ChanDelay *d = &s->chandelay[i]; | |
228 | |||
229 | ✗ | d->delay -= s->padding; | |
230 | } | ||
231 | |||
232 | ✗ | s->offset = av_rescale_q(s->padding, | |
233 | av_make_q(1, inlink->sample_rate), | ||
234 | inlink->time_base); | ||
235 | } | ||
236 | |||
237 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
|
3 | for (i = 0; i < s->nb_delays; i++) { |
238 | 2 | ChanDelay *d = &s->chandelay[i]; | |
239 | |||
240 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
|
2 | if (!d->delay) |
241 | 1 | continue; | |
242 | |||
243 | if (d->delay > SIZE_MAX) { | ||
244 | av_log(ctx, AV_LOG_ERROR, "Requested delay is too big.\n"); | ||
245 | return AVERROR(EINVAL); | ||
246 | } | ||
247 | |||
248 | 1 | d->samples = av_malloc_array(d->delay, s->block_align); | |
249 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (!d->samples) |
250 | ✗ | return AVERROR(ENOMEM); | |
251 | 1 | d->samples_size = d->delay * s->block_align; | |
252 | |||
253 | 1 | s->max_delay = FFMAX(s->max_delay, d->delay); | |
254 | } | ||
255 | |||
256 |
1/6✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
|
1 | switch (inlink->format) { |
257 | ✗ | case AV_SAMPLE_FMT_U8P : s->delay_channel = delay_channel_u8p ; | |
258 | ✗ | s->resize_channel_samples = resize_samples_u8p; break; | |
259 | 1 | case AV_SAMPLE_FMT_S16P: s->delay_channel = delay_channel_s16p; | |
260 | 1 | s->resize_channel_samples = resize_samples_s16p; break; | |
261 | ✗ | case AV_SAMPLE_FMT_S32P: s->delay_channel = delay_channel_s32p; | |
262 | ✗ | s->resize_channel_samples = resize_samples_s32p; break; | |
263 | ✗ | case AV_SAMPLE_FMT_FLTP: s->delay_channel = delay_channel_fltp; | |
264 | ✗ | s->resize_channel_samples = resize_samples_fltp; break; | |
265 | ✗ | case AV_SAMPLE_FMT_DBLP: s->delay_channel = delay_channel_dblp; | |
266 | ✗ | s->resize_channel_samples = resize_samples_dblp; break; | |
267 | } | ||
268 | |||
269 | 1 | return 0; | |
270 | } | ||
271 | |||
272 | ✗ | static int process_command(AVFilterContext *ctx, const char *cmd, const char *args, | |
273 | char *res, int res_len, int flags) | ||
274 | { | ||
275 | ✗ | int ret = AVERROR(ENOSYS); | |
276 | ✗ | AVFilterLink *inlink = ctx->inputs[0]; | |
277 | ✗ | AudioDelayContext *s = ctx->priv; | |
278 | |||
279 | ✗ | if (!strcmp(cmd, "delays")) { | |
280 | int64_t delay; | ||
281 | ✗ | char *p, *saveptr = NULL; | |
282 | ✗ | int64_t all_delay = -1; | |
283 | ✗ | int64_t max_delay = 0; | |
284 | ✗ | char *args_cpy = av_strdup(args); | |
285 | ✗ | if (args_cpy == NULL) { | |
286 | ✗ | return AVERROR(ENOMEM); | |
287 | } | ||
288 | |||
289 | ✗ | ret = 0; | |
290 | ✗ | p = args_cpy; | |
291 | |||
292 | ✗ | if (!strncmp(args, "all:", 4)) { | |
293 | ✗ | p = &args_cpy[4]; | |
294 | ✗ | ret = parse_delays(p, &saveptr, &all_delay, ctx, inlink->sample_rate); | |
295 | ✗ | if (ret == 1) | |
296 | ✗ | ret = AVERROR(EINVAL); | |
297 | ✗ | else if (ret == 0) | |
298 | ✗ | delay = all_delay; | |
299 | } | ||
300 | |||
301 | ✗ | if (!ret) { | |
302 | ✗ | for (int i = 0; i < s->nb_delays; i++) { | |
303 | ✗ | ChanDelay *d = &s->chandelay[i]; | |
304 | |||
305 | ✗ | if (all_delay < 0) { | |
306 | ✗ | ret = parse_delays(p, &saveptr, &delay, ctx, inlink->sample_rate); | |
307 | ✗ | if (ret != 0) { | |
308 | ✗ | ret = 0; | |
309 | ✗ | break; | |
310 | } | ||
311 | ✗ | p = NULL; | |
312 | } | ||
313 | |||
314 | ✗ | ret = s->resize_channel_samples(d, delay); | |
315 | ✗ | if (ret) | |
316 | ✗ | break; | |
317 | ✗ | max_delay = FFMAX(max_delay, d->delay); | |
318 | } | ||
319 | ✗ | s->max_delay = FFMAX(s->max_delay, max_delay); | |
320 | } | ||
321 | ✗ | av_freep(&args_cpy); | |
322 | } | ||
323 | ✗ | return ret; | |
324 | } | ||
325 | |||
326 | 66 | static int filter_frame(AVFilterLink *inlink, AVFrame *frame) | |
327 | { | ||
328 | 66 | AVFilterContext *ctx = inlink->dst; | |
329 | 66 | AVFilterLink *outlink = ctx->outputs[0]; | |
330 | 66 | AudioDelayContext *s = ctx->priv; | |
331 | AVFrame *out_frame; | ||
332 | int i; | ||
333 | |||
334 |
2/4✓ Branch 0 taken 66 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 66 times.
|
66 | if (ctx->is_disabled || !s->delays) { |
335 | ✗ | s->input = NULL; | |
336 | ✗ | return ff_filter_frame(outlink, frame); | |
337 | } | ||
338 | |||
339 | 66 | s->next_pts = av_rescale_q(frame->pts, inlink->time_base, outlink->time_base); | |
340 | |||
341 | 66 | out_frame = ff_get_audio_buffer(outlink, frame->nb_samples); | |
342 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 66 times.
|
66 | if (!out_frame) { |
343 | ✗ | s->input = NULL; | |
344 | ✗ | av_frame_free(&frame); | |
345 | ✗ | return AVERROR(ENOMEM); | |
346 | } | ||
347 | 66 | av_frame_copy_props(out_frame, frame); | |
348 | |||
349 |
2/2✓ Branch 0 taken 132 times.
✓ Branch 1 taken 66 times.
|
198 | for (i = 0; i < s->nb_delays; i++) { |
350 | 132 | ChanDelay *d = &s->chandelay[i]; | |
351 | 132 | const uint8_t *src = frame->extended_data[i]; | |
352 | 132 | uint8_t *dst = out_frame->extended_data[i]; | |
353 | |||
354 |
2/2✓ Branch 0 taken 66 times.
✓ Branch 1 taken 66 times.
|
132 | if (!d->delay) |
355 | 66 | memcpy(dst, src, frame->nb_samples * s->block_align); | |
356 | else | ||
357 | 66 | s->delay_channel(d, frame->nb_samples, src, dst); | |
358 | } | ||
359 | |||
360 | 66 | out_frame->pts = s->next_pts + s->offset; | |
361 | 66 | out_frame->duration = av_rescale_q(out_frame->nb_samples, (AVRational){1, outlink->sample_rate}, outlink->time_base); | |
362 | 66 | s->next_pts += out_frame->duration; | |
363 | 66 | av_frame_free(&frame); | |
364 | 66 | s->input = NULL; | |
365 | 66 | return ff_filter_frame(outlink, out_frame); | |
366 | } | ||
367 | |||
368 | 132 | static int activate(AVFilterContext *ctx) | |
369 | { | ||
370 | 132 | AVFilterLink *inlink = ctx->inputs[0]; | |
371 | 132 | AVFilterLink *outlink = ctx->outputs[0]; | |
372 | 132 | AudioDelayContext *s = ctx->priv; | |
373 | 132 | AVFrame *frame = NULL; | |
374 | int ret, status; | ||
375 | int64_t pts; | ||
376 | |||
377 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 132 times.
|
132 | FF_FILTER_FORWARD_STATUS_BACK(outlink, inlink); |
378 | |||
379 |
1/2✓ Branch 0 taken 132 times.
✗ Branch 1 not taken.
|
132 | if (!s->input) { |
380 | 132 | ret = ff_inlink_consume_frame(inlink, &s->input); | |
381 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 132 times.
|
132 | if (ret < 0) |
382 | ✗ | return ret; | |
383 | } | ||
384 | |||
385 |
2/2✓ Branch 1 taken 2 times.
✓ Branch 2 taken 130 times.
|
132 | if (ff_inlink_acknowledge_status(inlink, &status, &pts)) { |
386 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 | if (status == AVERROR_EOF) |
387 | 2 | s->eof = 1; | |
388 | } | ||
389 | |||
390 |
3/4✓ Branch 0 taken 1 times.
✓ Branch 1 taken 131 times.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
|
132 | if (s->next_pts == AV_NOPTS_VALUE && pts != AV_NOPTS_VALUE) |
391 | 1 | s->next_pts = av_rescale_q(pts, inlink->time_base, outlink->time_base); | |
392 | |||
393 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 132 times.
|
132 | if (s->padding) { |
394 | ✗ | int nb_samples = FFMIN(s->padding, 2048); | |
395 | |||
396 | ✗ | frame = ff_get_audio_buffer(outlink, nb_samples); | |
397 | ✗ | if (!frame) | |
398 | ✗ | return AVERROR(ENOMEM); | |
399 | ✗ | s->padding -= nb_samples; | |
400 | |||
401 | ✗ | av_samples_set_silence(frame->extended_data, 0, | |
402 | frame->nb_samples, | ||
403 | outlink->ch_layout.nb_channels, | ||
404 | ✗ | frame->format); | |
405 | |||
406 | ✗ | frame->duration = av_rescale_q(frame->nb_samples, | |
407 | ✗ | (AVRational){1, outlink->sample_rate}, | |
408 | outlink->time_base); | ||
409 | ✗ | frame->pts = s->next_pts; | |
410 | ✗ | s->next_pts += frame->duration; | |
411 | |||
412 | ✗ | return ff_filter_frame(outlink, frame); | |
413 | } | ||
414 | |||
415 |
2/2✓ Branch 0 taken 65 times.
✓ Branch 1 taken 67 times.
|
132 | if (s->input) |
416 | 65 | return filter_frame(inlink, s->input); | |
417 | |||
418 |
4/4✓ Branch 0 taken 2 times.
✓ Branch 1 taken 65 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 1 times.
|
67 | if (s->eof && s->max_delay) { |
419 | 1 | int nb_samples = FFMIN(s->max_delay, 2048); | |
420 | |||
421 | 1 | frame = ff_get_audio_buffer(outlink, nb_samples); | |
422 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (!frame) |
423 | ✗ | return AVERROR(ENOMEM); | |
424 | 1 | s->max_delay -= nb_samples; | |
425 | |||
426 | 1 | av_samples_set_silence(frame->extended_data, 0, | |
427 | frame->nb_samples, | ||
428 | outlink->ch_layout.nb_channels, | ||
429 | 1 | frame->format); | |
430 | |||
431 | 1 | frame->duration = av_rescale_q(frame->nb_samples, | |
432 | 1 | (AVRational){1, outlink->sample_rate}, | |
433 | outlink->time_base); | ||
434 | 1 | frame->pts = s->next_pts; | |
435 | 1 | s->next_pts += frame->duration; | |
436 | 1 | return filter_frame(inlink, frame); | |
437 | } | ||
438 | |||
439 |
3/4✓ Branch 0 taken 1 times.
✓ Branch 1 taken 65 times.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
|
66 | if (s->eof && s->max_delay == 0) { |
440 | 1 | ff_outlink_set_status(outlink, AVERROR_EOF, s->next_pts); | |
441 | 1 | return 0; | |
442 | } | ||
443 | |||
444 |
1/2✓ Branch 0 taken 65 times.
✗ Branch 1 not taken.
|
65 | if (!s->eof) |
445 |
1/2✓ Branch 1 taken 65 times.
✗ Branch 2 not taken.
|
65 | FF_FILTER_FORWARD_WANTED(outlink, inlink); |
446 | |||
447 | ✗ | return FFERROR_NOT_READY; | |
448 | } | ||
449 | |||
450 | 2 | static av_cold void uninit(AVFilterContext *ctx) | |
451 | { | ||
452 | 2 | AudioDelayContext *s = ctx->priv; | |
453 | |||
454 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
|
2 | if (s->chandelay) { |
455 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
|
3 | for (int i = 0; i < s->nb_delays; i++) |
456 | 2 | av_freep(&s->chandelay[i].samples); | |
457 | } | ||
458 | 2 | av_freep(&s->chandelay); | |
459 | 2 | } | |
460 | |||
461 | static const AVFilterPad adelay_inputs[] = { | ||
462 | { | ||
463 | .name = "default", | ||
464 | .type = AVMEDIA_TYPE_AUDIO, | ||
465 | .config_props = config_input, | ||
466 | }, | ||
467 | }; | ||
468 | |||
469 | const AVFilter ff_af_adelay = { | ||
470 | .name = "adelay", | ||
471 | .description = NULL_IF_CONFIG_SMALL("Delay one or more audio channels."), | ||
472 | .priv_size = sizeof(AudioDelayContext), | ||
473 | .priv_class = &adelay_class, | ||
474 | .activate = activate, | ||
475 | .uninit = uninit, | ||
476 | FILTER_INPUTS(adelay_inputs), | ||
477 | FILTER_OUTPUTS(ff_audio_default_filterpad), | ||
478 | FILTER_SAMPLEFMTS(AV_SAMPLE_FMT_U8P, AV_SAMPLE_FMT_S16P, AV_SAMPLE_FMT_S32P, | ||
479 | AV_SAMPLE_FMT_FLTP, AV_SAMPLE_FMT_DBLP), | ||
480 | .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL, | ||
481 | .process_command = process_command, | ||
482 | }; | ||
483 |