1 /*
2 *
3 * This file is part of Libav.
4 *
5 * Libav is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
9 *
10 * Libav is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with Libav; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18 */
19
20 /**
21 * @file
22 * Audio join filter
23 *
24 * Join multiple audio inputs as different channels in
25 * a single output
26 */
27
32
37
39 int input;
///< input stream index
40 int in_channel_idx;
///< index of in_channel in the input stream data
41 uint64_t
in_channel;
///< layout describing the input channel
42 uint64_t
out_channel;
///< layout describing the output channel
44
47
52
55
56 /**
57 * Temporary storage for input frames, until we get one on each input.
58 */
60
61 /**
62 * Temporary storage for buffer references, for assembling the output frame.
63 */
66
67 #define OFFSET(x) offsetof(JoinContext, x)
68 #define A AV_OPT_FLAG_AUDIO_PARAM
69 #define F AV_OPT_FLAG_FILTERING_PARAM
72 { "channel_layout", "Channel layout of the "
74 { "map", "A comma-separated list of channels maps in the format "
75 "'input_stream.input_channel-output_channel.",
77 { NULL },
78 };
79
81
83 {
86 int i;
87
89 if (link == ctx->
inputs[i])
90 break;
94
95 return 0;
96 }
97
99 {
101 char separator = '|';
103
104 #if FF_API_OLD_FILTER_OPTS
105 if (cur && strchr(cur, ',')) {
107 "separate the mappings.\n");
108 separator = ',';
109 }
110 #endif
111
112 while (cur && *cur) {
113 char *sep, *next, *p;
114 uint64_t in_channel = 0, out_channel = 0;
115 int input_idx, out_ch_idx, in_ch_idx;
116
117 next = strchr(cur, separator);
118 if (next)
119 *next++ = 0;
120
121 /* split the map into input and output parts */
122 if (!(sep = strchr(cur, '-'))) {
124 "map '%s'\n", cur);
126 }
127 *sep++ = 0;
128
129 #define PARSE_CHANNEL(str, var, inout) \
130 if (!(var = av_get_channel_layout(str))) { \
131 av_log(ctx, AV_LOG_ERROR, "Invalid " inout " channel: %s.\n", str);\
132 return AVERROR(EINVAL); \
133 } \
134 if (av_get_channel_layout_nb_channels(var) != 1) { \
135 av_log(ctx, AV_LOG_ERROR, "Channel map describes more than one " \
136 inout " channel.\n"); \
137 return AVERROR(EINVAL); \
138 }
139
140 /* parse output channel */
144 "requested channel layout.\n", sep);
146 }
147
149 out_channel);
152 "'%s'.\n", sep);
154 }
155
156 /* parse input channel */
157 input_idx = strtol(cur, &cur, 0);
158 if (input_idx < 0 || input_idx >= s->
inputs) {
160 input_idx);
162 }
163
164 if (*cur)
165 cur++;
166
167 in_ch_idx = strtol(cur, &p, 0);
168 if (p == cur) {
169 /* channel specifier is not a number,
170 * try to parse as channel name */
172 }
173
175 if (in_channel)
177 else
179
180 cur = next;
181 }
182 return 0;
183 }
184
186 {
189
194 goto fail;
195 }
196
203 goto fail;
204 }
205
209 }
210
212 goto fail;
213
214 for (i = 0; i < s->
inputs; i++) {
217
218 snprintf(name,
sizeof(name),
"input%d", i);
222
224
226 }
227
228 fail:
231 }
232
234 {
236 int i;
237
241 }
242
246 }
247
249 {
252 int i;
253
256
260
263
264 return 0;
265 }
266
269 {
270 int i;
271
274
280 return;
281 }
282 }
283 }
284
287 {
288 int i;
289
292
295
299 return;
300 }
301 }
302 }
303
305 {
308 uint64_t *
inputs;
// nth element tracks which channels are used from nth input
310
311 /* initialize inputs to user-specified mappings */
317
319 continue;
320
322
326
332 goto fail;
333 }
334
336 }
337
338 /* guess channel maps when not explicitly defined */
339 /* first try unused matching channels */
342
345 }
346
347 /* if the above failed, try to find _any_ unused input channel */
350
353
356 "output channel '%s'.\n",
358 goto fail;
359 }
360
363 }
364
365 /* print mappings */
372 }
374
376 if (!inputs[i])
378 "stream %d.\n", i);
379 }
380
381 fail:
384 }
385
387 {
391 int linesize = INT_MAX;
392 int nb_samples = 0;
393 int nb_buffers = 0;
395
396 /* get a frame on each input */
399
403
404 /* request the same number of samples on all inputs */
405 if (i == 0) {
407
408 for (j = 1; !i && j < ctx->
nb_inputs; j++)
410 }
411 }
412
413 /* setup the output frame */
415 if (!frame)
422 goto fail;
423 }
424 }
425
426 /* copy the data pointers */
431
434
435 /* add the buffer where this plan is stored to the list if it's
436 * not already there */
438 if (!buf) {
440 goto fail;
441 }
442 for (j = 0; j < nb_buffers; j++)
444 break;
445 if (j == i)
447 }
448
449 /* create references to the buffers we copied to output */
457 goto fail;
458 }
459 }
462 if (!frame->
buf[i]) {
464 goto fail;
465 }
466 }
472 goto fail;
473 }
474 }
475
486 }
487
489
492
494
495 fail:
498 }
499
501 {
506 },
507 { NULL }
508 };
509
513 "multi-channel output."),
515 .priv_class = &join_class,
516
520
522 .
outputs = avfilter_af_join_outputs,
523
525 };