1 /*
2 * This file is part of FFmpeg.
3 *
4 * FFmpeg is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
8 *
9 * FFmpeg is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with FFmpeg; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17 */
18
19 /**
20 * @file
21 * Audio join filter
22 *
23 * Join multiple audio inputs as different channels in
24 * a single output
25 */
26
33
38
40 int input;
///< input stream index
41 int in_channel_idx;
///< index of in_channel in the input stream data
45
48
52
55
57
58 /**
59 * Temporary storage for input frames, until we get one on each input.
60 */
62
63 /**
64 * Temporary storage for buffer references, for assembling the output frame.
65 */
68
69 #define OFFSET(x) offsetof(JoinContext, x)
70 #define A AV_OPT_FLAG_AUDIO_PARAM
71 #define F AV_OPT_FLAG_FILTERING_PARAM
74 { "channel_layout", "Channel layout of the "
76 { "map", "A comma-separated list of channels maps in the format "
77 "'input_stream.input_channel-output_channel.",
80 };
81
82 #define MAP_SEPARATOR '|'
83
85
87 {
90
91 while (cur && *cur) {
93 char *sep, *next, *p;
94 int input_idx, out_ch_idx;
95
97 if (next)
98 *next++ = 0;
99
100 /* split the map into input and output parts */
101 if (!(sep = strchr(cur, '-'))) {
103 "map '%s'\n", cur);
105 }
106 *sep++ = 0;
107
108 /* parse output channel */
110 if (out_ch_idx < 0) {
113 }
114
115 map = &
s->channels[out_ch_idx];
116
117 if (
map->input >= 0) {
119 "'%s'.\n", sep);
121 }
122
123 /* parse input channel */
124 input_idx = strtol(cur, &cur, 0);
125 if (input_idx < 0 || input_idx >=
s->inputs) {
127 input_idx);
129 }
130
131 if (*cur)
132 cur++;
133
134 map->input = input_idx;
136 map->in_channel_idx = strtol(cur, &p, 0);
137 if (p == cur) {
138 /* channel specifier is not a number, handle as channel name */
140 if (
map->in_channel < 0) {
143 }
144 }
else if (
map->in_channel_idx < 0) {
147 }
148
149 cur = next;
150 }
151 return 0;
152 }
153
155 {
158
159 s->channels =
av_calloc(
s->ch_layout.nb_channels,
sizeof(*
s->channels));
160 s->buffers =
av_calloc(
s->ch_layout.nb_channels,
sizeof(*
s->buffers));
161 s->input_frames =
av_calloc(
s->inputs,
sizeof(*
s->input_frames));
162 if (!
s->channels || !
s->buffers|| !
s->input_frames)
164
165 for (
i = 0;
i <
s->ch_layout.nb_channels;
i++) {
167 s->channels[
i].input = -1;
168 s->channels[
i].in_channel_idx = -1;
170 }
171
174
175 for (
i = 0;
i <
s->inputs;
i++) {
177
182
185 }
186
187 return 0;
188 }
189
191 {
194
195 for (
i = 0;
i <
s->inputs &&
s->input_frames;
i++) {
197 }
198
202 }
203
207 {
211
215
216 for (
i = 0;
i <
ctx->nb_inputs;
i++) {
220 }
221
224
225 return 0;
226 }
227
232
234 {
236 memmove(chl->
ch + idx, chl->
ch + idx + 1,
237 (chl->
nb_ch - idx - 1) *
sizeof(*chl->
ch));
240 }
241
242 /*
243 * If ch is present in chl, remove it from the list and return it.
244 * Otherwise return AV_CHAN_NONE.
245 */
247 {
248 for (
int i = 0;
i < chl->
nb_ch;
i++)
249 if (chl->
ch[
i] == ch)
252 }
253
256 {
258
259 for (
i = 0;
i <
ctx->nb_inputs;
i++) {
263 return;
264 }
265 }
266 }
267
270 {
272
273 for (
i = 0;
i <
ctx->nb_inputs;
i++) {
277 return;
278 }
279 }
280 }
281
283 {
286 // unused channels from each input
288 char inbuf[64], outbuf[64];
290
291 /* initialize unused channel list for each input */
292 inputs_unused =
av_calloc(
ctx->nb_inputs,
sizeof(*inputs_unused));
293 if (!inputs_unused)
295 for (
i = 0;
i <
ctx->nb_inputs;
i++) {
299
305 }
306
307 for (
int ch_idx = 0; ch_idx < iu->
nb_ch; ch_idx++) {
309 if (iu->
ch[ch_idx] < 0) {
310 /* no channel ordering information in this input,
311 * so don't auto-map from it */
313 break;
314 }
315 }
316 }
317
318 /* process user-specified maps */
319 for (
i = 0;
i <
s->ch_layout.nb_channels;
i++) {
324
326 continue;
327
329 ichl = &
inlink->ch_layout;
330 iu = &inputs_unused[ch->
input];
331
332 /* get the index for the channels defined by name */
338 "input stream #%d.\n", inbuf,
342 }
343 }
344
345 /* make sure channels specified by index actually exist */
351 }
352
354 }
355
356 /* guess channel maps when not explicitly defined */
357 /* first try unused matching channels */
358 for (
i = 0;
i <
s->ch_layout.nb_channels;
i++) {
360
363 }
364
365 /* if the above failed, try to find _any_ unused input channel */
366 for (
i = 0;
i <
s->ch_layout.nb_channels;
i++) {
368
371
375 "output channel '%s'.\n",
376 outbuf);
379 }
380
384 }
385
387 }
388
389 /* print mappings */
391 for (
i = 0;
i <
s->ch_layout.nb_channels;
i++) {
397
403 }
405
406 for (
i = 0;
i <
ctx->nb_inputs;
i++) {
407 if (inputs_unused[
i].nb_ch ==
ctx->inputs[
i]->ch_layout.nb_channels)
410 }
411
413 for (
i = 0;
i <
ctx->nb_inputs;
i++)
417 }
418
420 {
424 int linesize = INT_MAX;
425 int nb_samples = INT_MAX;
426 int nb_buffers = 0;
428
429 for (
i = 0;
i <
ctx->nb_inputs;
i++) {
430 if (!
s->input_frames[
i]) {
431 nb_samples = 0;
432 break;
433 } else {
434 nb_samples =
FFMIN(nb_samples,
s->input_frames[
i]->nb_samples);
435 }
436 }
437 if (!nb_samples)
438 goto eof;
439
440 /* setup the output frame */
446 sizeof(*
frame->extended_data));
447 if (!
frame->extended_data) {
450 }
451 }
452
453 /* copy the data pointers */
454 for (
i = 0;
i <
s->ch_layout.nb_channels;
i++) {
458
461
462 /* add the buffer where this plan is stored to the list if it's
463 * not already there */
465 if (!buf) {
468 }
469 for (j = 0; j < nb_buffers; j++)
470 if (
s->buffers[j]->buffer == buf->
buffer)
471 break;
473 s->buffers[nb_buffers++] = buf;
474 }
475
476 /* create references to the buffers we copied to output */
480 sizeof(*
frame->extended_buf));
481 if (!
frame->extended_buf) {
482 frame->nb_extended_buf = 0;
485 }
486 }
492 }
493 }
494 for (
i = 0;
i <
frame->nb_extended_buf;
i++) {
497 if (!
frame->extended_buf[
i]) {
500 }
501 }
502
503 frame->nb_samples = nb_samples;
507
512 frame->pts =
s->input_frames[0]->pts;
513 frame->linesize[0] = linesize;
517 }
518
523
524 for (
i = 0;
i <
ctx->nb_inputs;
i++)
526
528
532 eof:
533 for (
i = 0;
i <
ctx->nb_inputs;
i++) {
536 !
s->input_frames[
i]) {
538 break;
539 }
540 }
541
542 return 0;
543 }
544
546 {
549 int nb_samples = 0;
551
553
554 if (!
s->input_frames[0]) {
560 }
561
564 return 0;
565 }
566 }
567
568 if (
s->input_frames[0])
569 nb_samples =
s->input_frames[0]->nb_samples;
570
571 for (
i = 1;
i <
ctx->nb_inputs && nb_samples > 0;
i++) {
572 if (
s->input_frames[
i])
573 continue;
579 }
580
581 if (!
s->eof && !
s->input_frames[
i]) {
583 return 0;
584 }
585 }
586
588 }
589
591 {
595 },
596 };
597
601 "multi-channel output."),
603 .priv_class = &join_class,
611 };