FFmpeg coverage


Directory: ../../../ffmpeg/
File: src/libavfilter/af_amix.c
Date: 2024-09-07 18:49:03
Exec Total Coverage
Lines: 241 288 83.7%
Functions: 14 15 93.3%
Branches: 135 188 71.8%

Line Branch Exec Source
1 /*
2 * Audio Mix Filter
3 * Copyright (c) 2012 Justin Ruggles <justin.ruggles@gmail.com>
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 * Audio Mix Filter
25 *
26 * Mixes audio from multiple sources into a single output. The channel layout,
27 * sample rate, and sample format will be the same for all inputs and the
28 * output.
29 */
30
31 #include "libavutil/attributes.h"
32 #include "libavutil/audio_fifo.h"
33 #include "libavutil/avassert.h"
34 #include "libavutil/avstring.h"
35 #include "libavutil/channel_layout.h"
36 #include "libavutil/common.h"
37 #include "libavutil/eval.h"
38 #include "libavutil/float_dsp.h"
39 #include "libavutil/mathematics.h"
40 #include "libavutil/mem.h"
41 #include "libavutil/opt.h"
42 #include "libavutil/samplefmt.h"
43
44 #include "audio.h"
45 #include "avfilter.h"
46 #include "filters.h"
47
48 #define INPUT_ON 1 /**< input is active */
49 #define INPUT_EOF 2 /**< input has reached EOF (may still be active) */
50
51 #define DURATION_LONGEST 0
52 #define DURATION_SHORTEST 1
53 #define DURATION_FIRST 2
54
55
56 typedef struct FrameInfo {
57 int nb_samples;
58 int64_t pts;
59 struct FrameInfo *next;
60 } FrameInfo;
61
62 /**
63 * Linked list used to store timestamps and frame sizes of all frames in the
64 * FIFO for the first input.
65 *
66 * This is needed to keep timestamps synchronized for the case where multiple
67 * input frames are pushed to the filter for processing before a frame is
68 * requested by the output link.
69 */
70 typedef struct FrameList {
71 int nb_frames;
72 int nb_samples;
73 FrameInfo *list;
74 FrameInfo *end;
75 } FrameList;
76
77 901 static void frame_list_clear(FrameList *frame_list)
78 {
79
2/2
✓ Branch 0 taken 895 times.
✓ Branch 1 taken 6 times.
901 if (frame_list) {
80
2/2
✓ Branch 0 taken 663 times.
✓ Branch 1 taken 895 times.
1558 while (frame_list->list) {
81 663 FrameInfo *info = frame_list->list;
82 663 frame_list->list = info->next;
83 663 av_free(info);
84 }
85 895 frame_list->nb_frames = 0;
86 895 frame_list->nb_samples = 0;
87 895 frame_list->end = NULL;
88 }
89 901 }
90
91 2303 static int frame_list_next_frame_size(FrameList *frame_list)
92 {
93
2/2
✓ Branch 0 taken 226 times.
✓ Branch 1 taken 2077 times.
2303 if (!frame_list->list)
94 226 return 0;
95 2077 return frame_list->list->nb_samples;
96 }
97
98 1162 static int64_t frame_list_next_pts(FrameList *frame_list)
99 {
100
2/2
✓ Branch 0 taken 226 times.
✓ Branch 1 taken 936 times.
1162 if (!frame_list->list)
101 226 return AV_NOPTS_VALUE;
102 936 return frame_list->list->pts;
103 }
104
105 1162 static void frame_list_remove_samples(FrameList *frame_list, int nb_samples)
106 {
107
2/2
✓ Branch 0 taken 889 times.
✓ Branch 1 taken 273 times.
1162 if (nb_samples >= frame_list->nb_samples) {
108 889 frame_list_clear(frame_list);
109 } else {
110 273 int samples = nb_samples;
111
2/2
✓ Branch 0 taken 273 times.
✓ Branch 1 taken 273 times.
546 while (samples > 0) {
112 273 FrameInfo *info = frame_list->list;
113
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 273 times.
273 av_assert0(info);
114
2/2
✓ Branch 0 taken 267 times.
✓ Branch 1 taken 6 times.
273 if (info->nb_samples <= samples) {
115 267 samples -= info->nb_samples;
116 267 frame_list->list = info->next;
117
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 267 times.
267 if (!frame_list->list)
118 frame_list->end = NULL;
119 267 frame_list->nb_frames--;
120 267 frame_list->nb_samples -= info->nb_samples;
121 267 av_free(info);
122 } else {
123 6 info->nb_samples -= samples;
124 6 info->pts += samples;
125 6 frame_list->nb_samples -= samples;
126 6 samples = 0;
127 }
128 }
129 }
130 1162 }
131
132 930 static int frame_list_add_frame(FrameList *frame_list, int nb_samples, int64_t pts)
133 {
134 930 FrameInfo *info = av_malloc(sizeof(*info));
135
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 930 times.
930 if (!info)
136 return AVERROR(ENOMEM);
137 930 info->nb_samples = nb_samples;
138 930 info->pts = pts;
139 930 info->next = NULL;
140
141
2/2
✓ Branch 0 taken 663 times.
✓ Branch 1 taken 267 times.
930 if (!frame_list->list) {
142 663 frame_list->list = info;
143 663 frame_list->end = info;
144 } else {
145
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 267 times.
267 av_assert0(frame_list->end);
146 267 frame_list->end->next = info;
147 267 frame_list->end = info;
148 }
149 930 frame_list->nb_frames++;
150 930 frame_list->nb_samples += nb_samples;
151
152 930 return 0;
153 }
154
155 /* FIXME: use directly links fifo */
156
157 typedef struct MixContext {
158 const AVClass *class; /**< class for AVOptions */
159 AVFloatDSPContext *fdsp;
160
161 int nb_inputs; /**< number of inputs */
162 int active_inputs; /**< number of input currently active */
163 int duration_mode; /**< mode for determining duration */
164 float dropout_transition; /**< transition time when an input drops out */
165 char *weights_str; /**< string for custom weights for every input */
166 int normalize; /**< if inputs are scaled */
167
168 int nb_channels; /**< number of channels */
169 int sample_rate; /**< sample rate */
170 int planar;
171 AVAudioFifo **fifos; /**< audio fifo for each input */
172 uint8_t *input_state; /**< current state of each input */
173 float *input_scale; /**< mixing scale factor for each input */
174 float *weights; /**< custom weights for every input */
175 float weight_sum; /**< sum of custom weights for every input */
176 float *scale_norm; /**< normalization factor for every input */
177 int64_t next_pts; /**< calculated pts for next output frame */
178 FrameList *frame_list; /**< list of frame info for the first input */
179 } MixContext;
180
181 #define OFFSET(x) offsetof(MixContext, x)
182 #define A AV_OPT_FLAG_AUDIO_PARAM
183 #define F AV_OPT_FLAG_FILTERING_PARAM
184 #define T AV_OPT_FLAG_RUNTIME_PARAM
185 static const AVOption amix_options[] = {
186 { "inputs", "Number of inputs.",
187 OFFSET(nb_inputs), AV_OPT_TYPE_INT, { .i64 = 2 }, 1, INT16_MAX, A|F },
188 { "duration", "How to determine the end-of-stream.",
189 OFFSET(duration_mode), AV_OPT_TYPE_INT, { .i64 = DURATION_LONGEST }, 0, 2, A|F, .unit = "duration" },
190 { "longest", "Duration of longest input.", 0, AV_OPT_TYPE_CONST, { .i64 = DURATION_LONGEST }, 0, 0, A|F, .unit = "duration" },
191 { "shortest", "Duration of shortest input.", 0, AV_OPT_TYPE_CONST, { .i64 = DURATION_SHORTEST }, 0, 0, A|F, .unit = "duration" },
192 { "first", "Duration of first input.", 0, AV_OPT_TYPE_CONST, { .i64 = DURATION_FIRST }, 0, 0, A|F, .unit = "duration" },
193 { "dropout_transition", "Transition time, in seconds, for volume "
194 "renormalization when an input stream ends.",
195 OFFSET(dropout_transition), AV_OPT_TYPE_FLOAT, { .dbl = 2.0 }, 0, INT_MAX, A|F },
196 { "weights", "Set weight for each input.",
197 OFFSET(weights_str), AV_OPT_TYPE_STRING, {.str="1 1"}, 0, 0, A|F|T },
198 { "normalize", "Scale inputs",
199 OFFSET(normalize), AV_OPT_TYPE_BOOL, {.i64=1}, 0, 1, A|F|T },
200 { NULL }
201 };
202
203 AVFILTER_DEFINE_CLASS(amix);
204
205 /**
206 * Update the scaling factors to apply to each input during mixing.
207 *
208 * This balances the full volume range between active inputs and handles
209 * volume transitions when EOF is encountered on an input but mixing continues
210 * with the remaining inputs.
211 */
212 1168 static void calculate_scales(MixContext *s, int nb_samples)
213 {
214 1168 float weight_sum = 0.f;
215 int i;
216
217
2/2
✓ Branch 0 taken 2685 times.
✓ Branch 1 taken 1168 times.
3853 for (i = 0; i < s->nb_inputs; i++)
218
2/2
✓ Branch 0 taken 2062 times.
✓ Branch 1 taken 623 times.
2685 if (s->input_state[i] & INPUT_ON)
219 2062 weight_sum += FFABS(s->weights[i]);
220
221
2/2
✓ Branch 0 taken 2685 times.
✓ Branch 1 taken 1168 times.
3853 for (i = 0; i < s->nb_inputs; i++) {
222
2/2
✓ Branch 0 taken 2062 times.
✓ Branch 1 taken 623 times.
2685 if (s->input_state[i] & INPUT_ON) {
223
2/2
✓ Branch 0 taken 349 times.
✓ Branch 1 taken 1713 times.
2062 if (s->scale_norm[i] > weight_sum / FFABS(s->weights[i])) {
224 349 s->scale_norm[i] -= ((s->weight_sum / FFABS(s->weights[i])) / s->nb_inputs) *
225 349 nb_samples / (s->dropout_transition * s->sample_rate);
226
2/2
✓ Branch 0 taken 345 times.
✓ Branch 1 taken 4 times.
349 s->scale_norm[i] = FFMAX(s->scale_norm[i], weight_sum / FFABS(s->weights[i]));
227 }
228 }
229 }
230
231
2/2
✓ Branch 0 taken 2685 times.
✓ Branch 1 taken 1168 times.
3853 for (i = 0; i < s->nb_inputs; i++) {
232
2/2
✓ Branch 0 taken 2062 times.
✓ Branch 1 taken 623 times.
2685 if (s->input_state[i] & INPUT_ON) {
233
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2062 times.
2062 if (!s->normalize)
234 s->input_scale[i] = FFABS(s->weights[i]);
235 else
236
1/2
✓ Branch 0 taken 2062 times.
✗ Branch 1 not taken.
2062 s->input_scale[i] = 1.0f / s->scale_norm[i] * FFSIGN(s->weights[i]);
237 } else {
238 623 s->input_scale[i] = 0.0f;
239 }
240 }
241 1168 }
242
243 6 static int config_output(AVFilterLink *outlink)
244 {
245 6 AVFilterContext *ctx = outlink->src;
246 6 MixContext *s = ctx->priv;
247 int i;
248 char buf[64];
249
250 6 s->planar = av_sample_fmt_is_planar(outlink->format);
251 6 s->sample_rate = outlink->sample_rate;
252 6 outlink->time_base = (AVRational){ 1, outlink->sample_rate };
253 6 s->next_pts = AV_NOPTS_VALUE;
254
255 6 s->frame_list = av_mallocz(sizeof(*s->frame_list));
256
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if (!s->frame_list)
257 return AVERROR(ENOMEM);
258
259 6 s->fifos = av_calloc(s->nb_inputs, sizeof(*s->fifos));
260
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if (!s->fifos)
261 return AVERROR(ENOMEM);
262
263 6 s->nb_channels = outlink->ch_layout.nb_channels;
264
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 6 times.
19 for (i = 0; i < s->nb_inputs; i++) {
265 13 s->fifos[i] = av_audio_fifo_alloc(outlink->format, s->nb_channels, 1024);
266
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 13 times.
13 if (!s->fifos[i])
267 return AVERROR(ENOMEM);
268 }
269
270 6 s->input_state = av_malloc(s->nb_inputs);
271
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if (!s->input_state)
272 return AVERROR(ENOMEM);
273 6 memset(s->input_state, INPUT_ON, s->nb_inputs);
274 6 s->active_inputs = s->nb_inputs;
275
276 6 s->input_scale = av_calloc(s->nb_inputs, sizeof(*s->input_scale));
277 6 s->scale_norm = av_calloc(s->nb_inputs, sizeof(*s->scale_norm));
278
2/4
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 6 times.
6 if (!s->input_scale || !s->scale_norm)
279 return AVERROR(ENOMEM);
280
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 6 times.
19 for (i = 0; i < s->nb_inputs; i++)
281 13 s->scale_norm[i] = s->weight_sum / FFABS(s->weights[i]);
282 6 calculate_scales(s, 0);
283
284 6 av_channel_layout_describe(&outlink->ch_layout, buf, sizeof(buf));
285
286 6 av_log(ctx, AV_LOG_VERBOSE,
287 "inputs:%d fmt:%s srate:%d cl:%s\n", s->nb_inputs,
288 6 av_get_sample_fmt_name(outlink->format), outlink->sample_rate, buf);
289
290 6 return 0;
291 }
292
293 /**
294 * Read samples from the input FIFOs, mix, and write to the output link.
295 */
296 1596 static int output_frame(AVFilterLink *outlink)
297 {
298 1596 AVFilterContext *ctx = outlink->src;
299 1596 MixContext *s = ctx->priv;
300 AVFrame *out_buf, *in_buf;
301 int nb_samples, ns, i;
302
303
1/2
✓ Branch 0 taken 1596 times.
✗ Branch 1 not taken.
1596 if (s->input_state[0] & INPUT_ON) {
304 /* first input live: use the corresponding frame size */
305 1596 nb_samples = frame_list_next_frame_size(s->frame_list);
306
2/2
✓ Branch 0 taken 2023 times.
✓ Branch 1 taken 1162 times.
3185 for (i = 1; i < s->nb_inputs; i++) {
307
2/2
✓ Branch 0 taken 1400 times.
✓ Branch 1 taken 623 times.
2023 if (s->input_state[i] & INPUT_ON) {
308 1400 ns = av_audio_fifo_size(s->fifos[i]);
309
2/2
✓ Branch 0 taken 440 times.
✓ Branch 1 taken 960 times.
1400 if (ns < nb_samples) {
310
2/2
✓ Branch 0 taken 434 times.
✓ Branch 1 taken 6 times.
440 if (!(s->input_state[i] & INPUT_EOF))
311 /* unclosed input with not enough samples */
312 434 return 0;
313 /* closed input to drain */
314 6 nb_samples = ns;
315 }
316 }
317 }
318
319 1162 s->next_pts = frame_list_next_pts(s->frame_list);
320 } else {
321 /* first input closed: use the available samples */
322 nb_samples = INT_MAX;
323 for (i = 1; i < s->nb_inputs; i++) {
324 if (s->input_state[i] & INPUT_ON) {
325 ns = av_audio_fifo_size(s->fifos[i]);
326 nb_samples = FFMIN(nb_samples, ns);
327 }
328 }
329 if (nb_samples == INT_MAX) {
330 ff_outlink_set_status(outlink, AVERROR_EOF, s->next_pts);
331 return 0;
332 }
333 }
334
335 1162 frame_list_remove_samples(s->frame_list, nb_samples);
336
337 1162 calculate_scales(s, nb_samples);
338
339
2/2
✓ Branch 0 taken 226 times.
✓ Branch 1 taken 936 times.
1162 if (nb_samples == 0)
340 226 return 0;
341
342 936 out_buf = ff_get_audio_buffer(outlink, nb_samples);
343
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 936 times.
936 if (!out_buf)
344 return AVERROR(ENOMEM);
345
346 936 in_buf = ff_get_audio_buffer(outlink, nb_samples);
347
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 936 times.
936 if (!in_buf) {
348 av_frame_free(&out_buf);
349 return AVERROR(ENOMEM);
350 }
351
352
2/2
✓ Branch 0 taken 2133 times.
✓ Branch 1 taken 936 times.
3069 for (i = 0; i < s->nb_inputs; i++) {
353
2/2
✓ Branch 0 taken 1546 times.
✓ Branch 1 taken 587 times.
2133 if (s->input_state[i] & INPUT_ON) {
354 int planes, plane_size, p;
355
356 1546 av_audio_fifo_read(s->fifos[i], (void **)in_buf->extended_data,
357 nb_samples);
358
359
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1546 times.
1546 planes = s->planar ? s->nb_channels : 1;
360
1/2
✓ Branch 0 taken 1546 times.
✗ Branch 1 not taken.
1546 plane_size = nb_samples * (s->planar ? 1 : s->nb_channels);
361 1546 plane_size = FFALIGN(plane_size, 16);
362
363
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1546 times.
1546 if (out_buf->format == AV_SAMPLE_FMT_FLT ||
364 out_buf->format == AV_SAMPLE_FMT_FLTP) {
365
2/2
✓ Branch 0 taken 1546 times.
✓ Branch 1 taken 1546 times.
3092 for (p = 0; p < planes; p++) {
366 1546 s->fdsp->vector_fmac_scalar((float *)out_buf->extended_data[p],
367 1546 (float *) in_buf->extended_data[p],
368 1546 s->input_scale[i], plane_size);
369 }
370 } else {
371 for (p = 0; p < planes; p++) {
372 s->fdsp->vector_dmac_scalar((double *)out_buf->extended_data[p],
373 (double *) in_buf->extended_data[p],
374 s->input_scale[i], plane_size);
375 }
376 }
377 }
378 }
379 936 av_frame_free(&in_buf);
380
381 936 out_buf->pts = s->next_pts;
382 936 out_buf->duration = av_rescale_q(out_buf->nb_samples, av_make_q(1, outlink->sample_rate),
383 outlink->time_base);
384
385
1/2
✓ Branch 0 taken 936 times.
✗ Branch 1 not taken.
936 if (s->next_pts != AV_NOPTS_VALUE)
386 936 s->next_pts += nb_samples;
387
388 936 return ff_filter_frame(outlink, out_buf);
389 }
390
391 /**
392 * Requests a frame, if needed, from each input link other than the first.
393 */
394 707 static int request_samples(AVFilterContext *ctx, int min_samples)
395 {
396 707 MixContext *s = ctx->priv;
397 int i;
398
399
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 707 times.
707 av_assert0(s->nb_inputs > 1);
400
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 707 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
707 if (min_samples == 1 && s->duration_mode == DURATION_FIRST)
401 min_samples = av_audio_fifo_size(s->fifos[0]);
402
403
2/2
✓ Branch 0 taken 813 times.
✓ Branch 1 taken 57 times.
870 for (i = 1; i < s->nb_inputs; i++) {
404
2/2
✓ Branch 0 taken 749 times.
✓ Branch 1 taken 64 times.
813 if (!(s->input_state[i] & INPUT_ON) ||
405
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 744 times.
749 (s->input_state[i] & INPUT_EOF))
406 69 continue;
407
2/2
✓ Branch 1 taken 94 times.
✓ Branch 2 taken 650 times.
744 if (av_audio_fifo_size(s->fifos[i]) >= min_samples)
408 94 continue;
409 650 ff_inlink_request_frame(ctx->inputs[i]);
410 650 return 0;
411 }
412 57 return output_frame(ctx->outputs[0]);
413 }
414
415 /**
416 * Calculates the number of active inputs and determines EOF based on the
417 * duration option.
418 *
419 * @return 0 if mixing should continue, or AVERROR_EOF if mixing should stop.
420 */
421 2484 static int calc_active_inputs(MixContext *s)
422 {
423 int i;
424 2484 int active_inputs = 0;
425
2/2
✓ Branch 0 taken 5751 times.
✓ Branch 1 taken 2484 times.
8235 for (i = 0; i < s->nb_inputs; i++)
426 5751 active_inputs += !!(s->input_state[i] & INPUT_ON);
427 2484 s->active_inputs = active_inputs;
428
429
2/2
✓ Branch 0 taken 2480 times.
✓ Branch 1 taken 4 times.
2484 if (!active_inputs ||
430
4/4
✓ Branch 0 taken 261 times.
✓ Branch 1 taken 2219 times.
✓ Branch 2 taken 260 times.
✓ Branch 3 taken 1 times.
2480 (s->duration_mode == DURATION_FIRST && !(s->input_state[0] & INPUT_ON)) ||
431
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 2479 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
2479 (s->duration_mode == DURATION_SHORTEST && active_inputs != s->nb_inputs))
432 5 return AVERROR_EOF;
433 2479 return 0;
434 }
435
436 2487 static int activate(AVFilterContext *ctx)
437 {
438 2487 AVFilterLink *outlink = ctx->outputs[0];
439 2487 MixContext *s = ctx->priv;
440 2487 AVFrame *buf = NULL;
441 int i, ret;
442
443
4/4
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 2484 times.
✓ Branch 4 taken 7 times.
✓ Branch 5 taken 3 times.
2494 FF_FILTER_FORWARD_STATUS_BACK_ALL(outlink, ctx);
444
445
2/2
✓ Branch 0 taken 5751 times.
✓ Branch 1 taken 2484 times.
8235 for (i = 0; i < s->nb_inputs; i++) {
446 5751 AVFilterLink *inlink = ctx->inputs[i];
447
448
2/2
✓ Branch 1 taken 1539 times.
✓ Branch 2 taken 4212 times.
5751 if ((ret = ff_inlink_consume_frame(ctx->inputs[i], &buf)) > 0) {
449
2/2
✓ Branch 0 taken 930 times.
✓ Branch 1 taken 609 times.
1539 if (i == 0) {
450 930 int64_t pts = av_rescale_q(buf->pts, inlink->time_base,
451 outlink->time_base);
452 930 ret = frame_list_add_frame(s->frame_list, buf->nb_samples, pts);
453
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 930 times.
930 if (ret < 0) {
454 av_frame_free(&buf);
455 return ret;
456 }
457 }
458
459 1539 ret = av_audio_fifo_write(s->fifos[i], (void **)buf->extended_data,
460 1539 buf->nb_samples);
461
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1539 times.
1539 if (ret < 0) {
462 av_frame_free(&buf);
463 return ret;
464 }
465
466 1539 av_frame_free(&buf);
467
468 1539 ret = output_frame(outlink);
469
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1539 times.
1539 if (ret < 0)
470 return ret;
471 }
472 }
473
474
2/2
✓ Branch 0 taken 5751 times.
✓ Branch 1 taken 2484 times.
8235 for (i = 0; i < s->nb_inputs; i++) {
475 int64_t pts;
476 int status;
477
478
2/2
✓ Branch 1 taken 1271 times.
✓ Branch 2 taken 4480 times.
5751 if (ff_inlink_acknowledge_status(ctx->inputs[i], &status, &pts)) {
479
1/2
✓ Branch 0 taken 1271 times.
✗ Branch 1 not taken.
1271 if (status == AVERROR_EOF) {
480 1271 s->input_state[i] |= INPUT_EOF;
481
2/2
✓ Branch 1 taken 1218 times.
✓ Branch 2 taken 53 times.
1271 if (av_audio_fifo_size(s->fifos[i]) == 0) {
482 1218 s->input_state[i] &= ~INPUT_ON;
483
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1218 times.
1218 if (s->nb_inputs == 1) {
484 ff_outlink_set_status(outlink, status, pts);
485 return 0;
486 }
487 }
488 }
489 }
490 }
491
492
2/2
✓ Branch 1 taken 5 times.
✓ Branch 2 taken 2479 times.
2484 if (calc_active_inputs(s)) {
493 5 ff_outlink_set_status(outlink, AVERROR_EOF, s->next_pts);
494 5 return 0;
495 }
496
497
2/2
✓ Branch 1 taken 1594 times.
✓ Branch 2 taken 885 times.
2479 if (ff_outlink_frame_wanted(outlink)) {
498 int wanted_samples;
499
500
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1594 times.
1594 if (!(s->input_state[0] & INPUT_ON))
501 return request_samples(ctx, 1);
502
503
2/2
✓ Branch 0 taken 887 times.
✓ Branch 1 taken 707 times.
1594 if (s->frame_list->nb_frames == 0) {
504 887 ff_inlink_request_frame(ctx->inputs[0]);
505 887 return 0;
506 }
507
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 707 times.
707 av_assert0(s->frame_list->nb_frames > 0);
508
509 707 wanted_samples = frame_list_next_frame_size(s->frame_list);
510
511 707 return request_samples(ctx, wanted_samples);
512 }
513
514 885 return 0;
515 }
516
517 12 static void parse_weights(AVFilterContext *ctx)
518 {
519 12 MixContext *s = ctx->priv;
520 12 float last_weight = 1.f;
521 char *p;
522 int i;
523
524 12 s->weight_sum = 0.f;
525 12 p = s->weights_str;
526
1/2
✓ Branch 0 taken 24 times.
✗ Branch 1 not taken.
24 for (i = 0; i < s->nb_inputs; i++) {
527 24 last_weight = av_strtod(p, &p);
528 24 s->weights[i] = last_weight;
529 24 s->weight_sum += FFABS(last_weight);
530
3/4
✓ Branch 0 taken 24 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 12 times.
✓ Branch 3 taken 12 times.
24 if (p && *p) {
531 12 p++;
532 } else {
533 12 i++;
534 12 break;
535 }
536 }
537
538
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 12 times.
14 for (; i < s->nb_inputs; i++) {
539 2 s->weights[i] = last_weight;
540 2 s->weight_sum += FFABS(last_weight);
541 }
542 12 }
543
544 12 static av_cold int init(AVFilterContext *ctx)
545 {
546 12 MixContext *s = ctx->priv;
547 int i, ret;
548
549
2/2
✓ Branch 0 taken 26 times.
✓ Branch 1 taken 12 times.
38 for (i = 0; i < s->nb_inputs; i++) {
550 26 AVFilterPad pad = { 0 };
551
552 26 pad.type = AVMEDIA_TYPE_AUDIO;
553 26 pad.name = av_asprintf("input%d", i);
554
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 26 times.
26 if (!pad.name)
555 return AVERROR(ENOMEM);
556
557
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 26 times.
26 if ((ret = ff_append_inpad_free_name(ctx, &pad)) < 0)
558 return ret;
559 }
560
561 12 s->fdsp = avpriv_float_dsp_alloc(0);
562
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
12 if (!s->fdsp)
563 return AVERROR(ENOMEM);
564
565 12 s->weights = av_calloc(s->nb_inputs, sizeof(*s->weights));
566
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
12 if (!s->weights)
567 return AVERROR(ENOMEM);
568
569 12 parse_weights(ctx);
570
571 12 return 0;
572 }
573
574 12 static av_cold void uninit(AVFilterContext *ctx)
575 {
576 int i;
577 12 MixContext *s = ctx->priv;
578
579
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 6 times.
12 if (s->fifos) {
580
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 6 times.
19 for (i = 0; i < s->nb_inputs; i++)
581 13 av_audio_fifo_free(s->fifos[i]);
582 6 av_freep(&s->fifos);
583 }
584 12 frame_list_clear(s->frame_list);
585 12 av_freep(&s->frame_list);
586 12 av_freep(&s->input_state);
587 12 av_freep(&s->input_scale);
588 12 av_freep(&s->scale_norm);
589 12 av_freep(&s->weights);
590 12 av_freep(&s->fdsp);
591 12 }
592
593 static int process_command(AVFilterContext *ctx, const char *cmd, const char *args,
594 char *res, int res_len, int flags)
595 {
596 MixContext *s = ctx->priv;
597 int ret;
598
599 ret = ff_filter_process_command(ctx, cmd, args, res, res_len, flags);
600 if (ret < 0)
601 return ret;
602
603 parse_weights(ctx);
604 for (int i = 0; i < s->nb_inputs; i++)
605 s->scale_norm[i] = s->weight_sum / FFABS(s->weights[i]);
606 calculate_scales(s, 0);
607
608 return 0;
609 }
610
611 static const AVFilterPad avfilter_af_amix_outputs[] = {
612 {
613 .name = "default",
614 .type = AVMEDIA_TYPE_AUDIO,
615 .config_props = config_output,
616 },
617 };
618
619 const AVFilter ff_af_amix = {
620 .name = "amix",
621 .description = NULL_IF_CONFIG_SMALL("Audio mixing."),
622 .priv_size = sizeof(MixContext),
623 .priv_class = &amix_class,
624 .init = init,
625 .uninit = uninit,
626 .activate = activate,
627 .inputs = NULL,
628 FILTER_OUTPUTS(avfilter_af_amix_outputs),
629 FILTER_SAMPLEFMTS(AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_FLTP,
630 AV_SAMPLE_FMT_DBL, AV_SAMPLE_FMT_DBLP),
631 .process_command = process_command,
632 .flags = AVFILTER_FLAG_DYNAMIC_INPUTS,
633 };
634