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
31
36
38 int input;
///< input stream index
39 int in_channel_idx;
///< index of in_channel in the input stream data
40 uint64_t
in_channel;
///< layout describing the input channel
41 uint64_t
out_channel;
///< layout describing the output channel
43
46
51
54
55 /**
56 * Temporary storage for input frames, until we get one on each input.
57 */
59
60 /**
61 * Temporary storage for buffer references, for assembling the output frame.
62 */
65
66 #define OFFSET(x) offsetof(JoinContext, x)
67 #define A AV_OPT_FLAG_AUDIO_PARAM
68 #define F AV_OPT_FLAG_FILTERING_PARAM
71 { "channel_layout", "Channel layout of the "
73 { "map", "A comma-separated list of channels maps in the format "
74 "'input_stream.input_channel-output_channel.",
76 { NULL }
77 };
78
80
82 {
85 int i;
86
88 if (link == ctx->
inputs[i])
89 break;
93
94 return 0;
95 }
96
98 {
100 char separator = '|';
102
103 #if FF_API_OLD_FILTER_OPTS
104 if (cur && strchr(cur, ',')) {
106 "separate the mappings.\n");
107 separator = ',';
108 }
109 #endif
110
111 while (cur && *cur) {
112 char *sep, *next, *p;
113 uint64_t in_channel = 0, out_channel = 0;
114 int input_idx, out_ch_idx, in_ch_idx;
115
116 next = strchr(cur, separator);
117 if (next)
118 *next++ = 0;
119
120 /* split the map into input and output parts */
121 if (!(sep = strchr(cur, '-'))) {
123 "map '%s'\n", cur);
125 }
126 *sep++ = 0;
127
128 #define PARSE_CHANNEL(str, var, inout) \
129 if (!(var = av_get_channel_layout(str))) { \
130 av_log(ctx, AV_LOG_ERROR, "Invalid " inout " channel: %s.\n", str);\
131 return AVERROR(EINVAL); \
132 } \
133 if (av_get_channel_layout_nb_channels(var) != 1) { \
134 av_log(ctx, AV_LOG_ERROR, "Channel map describes more than one " \
135 inout " channel.\n"); \
136 return AVERROR(EINVAL); \
137 }
138
139 /* parse output channel */
143 "requested channel layout.\n", sep);
145 }
146
148 out_channel);
151 "'%s'.\n", sep);
153 }
154
155 /* parse input channel */
156 input_idx = strtol(cur, &cur, 0);
157 if (input_idx < 0 || input_idx >= s->
inputs) {
159 input_idx);
161 }
162
163 if (*cur)
164 cur++;
165
166 in_ch_idx = strtol(cur, &p, 0);
167 if (p == cur) {
168 /* channel specifier is not a number,
169 * try to parse as channel name */
171 }
172
174 if (in_channel)
176 else
178
179 cur = next;
180 }
181 return 0;
182 }
183
185 {
188
193 }
194
201
205 }
206
209
210 for (i = 0; i < s->
inputs; i++) {
213
214 snprintf(name,
sizeof(name),
"input%d", i);
218
220
222 }
223
224 return 0;
225 }
226
228 {
230 int i;
231
235 }
236
240 }
241
243 {
246 int i;
247
250
254
257
258 return 0;
259 }
260
263 {
264 int i;
265
268
274 return;
275 }
276 }
277 }
278
281 {
282 int i;
283
286
289
293 return;
294 }
295 }
296 }
297
299 {
302 uint64_t *
inputs;
// nth element tracks which channels are used from nth input
304
305 /* initialize inputs to user-specified mappings */
311
313 continue;
314
316
320
326 goto fail;
327 }
328
330 }
331
332 /* guess channel maps when not explicitly defined */
333 /* first try unused matching channels */
336
339 }
340
341 /* if the above failed, try to find _any_ unused input channel */
344
347
350 "output channel '%s'.\n",
352 goto fail;
353 }
354
357 }
358
359 /* print mappings */
366 }
368
370 if (!inputs[i])
372 "stream %d.\n", i);
373 }
374
375 fail:
378 }
379
381 {
385 int linesize = INT_MAX;
386 int nb_samples = 0;
387 int nb_buffers = 0;
389
390 /* get a frame on each input */
393
397
398 /* request the same number of samples on all inputs */
399 if (i == 0) {
401
402 for (j = 1; !i && j < ctx->
nb_inputs; j++)
404 }
405 }
406
407 /* setup the output frame */
409 if (!frame)
416 goto fail;
417 }
418 }
419
420 /* copy the data pointers */
425
428
429 /* add the buffer where this plan is stored to the list if it's
430 * not already there */
432 if (!buf) {
434 goto fail;
435 }
436 for (j = 0; j < nb_buffers; j++)
438 break;
439 if (j == i)
441 }
442
443 /* create references to the buffers we copied to output */
451 goto fail;
452 }
453 }
456 if (!frame->
buf[i]) {
458 goto fail;
459 }
460 }
466 goto fail;
467 }
468 }
469
480 }
481
483
486
488
489 fail:
492 }
493
495 {
500 },
501 { NULL }
502 };
503
507 "multi-channel output."),
509 .priv_class = &join_class,
514 .
outputs = avfilter_af_join_outputs,
516 };