]> git.sesse.net Git - ffmpeg/blob - libavfilter/af_join.c
lavfi: add join audio filter.
[ffmpeg] / libavfilter / af_join.c
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
28 #include "libavutil/audioconvert.h"
29 #include "libavutil/avassert.h"
30 #include "libavutil/opt.h"
31
32 #include "audio.h"
33 #include "avfilter.h"
34 #include "formats.h"
35 #include "internal.h"
36
37 typedef struct ChannelMap {
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
42 } ChannelMap;
43
44 typedef struct JoinContext {
45     const AVClass *class;
46
47     int inputs;
48     char *map;
49     char    *channel_layout_str;
50     uint64_t channel_layout;
51
52     int      nb_channels;
53     ChannelMap *channels;
54
55     /**
56      * Temporary storage for input frames, until we get one on each input.
57      */
58     AVFilterBufferRef **input_frames;
59
60     /**
61      *  Temporary storage for data pointers, for assembling the output buffer.
62      */
63     uint8_t **data;
64 } JoinContext;
65
66 /**
67  * To avoid copying the data from input buffers, this filter creates
68  * a custom output buffer that stores references to all inputs and
69  * unrefs them on free.
70  */
71 typedef struct JoinBufferPriv {
72     AVFilterBufferRef **in_buffers;
73     int              nb_in_buffers;
74 } JoinBufferPriv;
75
76 #define OFFSET(x) offsetof(JoinContext, x)
77 #define A AV_OPT_FLAG_AUDIO_PARAM
78 static const AVOption join_options[] = {
79     { "inputs",         "Number of input streams.", OFFSET(inputs),             AV_OPT_TYPE_INT,    { 2 }, 1, INT_MAX,       A },
80     { "channel_layout", "Channel layout of the "
81                         "output stream.",           OFFSET(channel_layout_str), AV_OPT_TYPE_STRING, {.str = "stereo"}, 0, 0, A },
82     { "map",            "A comma-separated list of channels maps in the format "
83                         "'input_stream.input_channel-output_channel.",
84                                                     OFFSET(map),                AV_OPT_TYPE_STRING,                 .flags = A },
85     { NULL },
86 };
87
88 static const AVClass join_class = {
89     .class_name = "join filter",
90     .item_name  = av_default_item_name,
91     .option     = join_options,
92     .version    = LIBAVUTIL_VERSION_INT,
93 };
94
95 static void filter_samples(AVFilterLink *link, AVFilterBufferRef *buf)
96 {
97     AVFilterContext *ctx = link->dst;
98     JoinContext       *s = ctx->priv;
99     int i;
100
101     for (i = 0; i < ctx->nb_inputs; i++)
102         if (link == ctx->inputs[i])
103             break;
104     av_assert0(i < ctx->nb_inputs);
105     av_assert0(!s->input_frames[i]);
106     s->input_frames[i] = buf;
107 }
108
109 static int parse_maps(AVFilterContext *ctx)
110 {
111     JoinContext *s = ctx->priv;
112     char *cur      = s->map;
113
114     while (cur && *cur) {
115         char *sep, *next, *p;
116         uint64_t in_channel = 0, out_channel = 0;
117         int input_idx, out_ch_idx, in_ch_idx;
118
119         next = strchr(cur, ',');
120         if (next)
121             *next++ = 0;
122
123         /* split the map into input and output parts */
124         if (!(sep = strchr(cur, '-'))) {
125             av_log(ctx, AV_LOG_ERROR, "Missing separator '-' in channel "
126                    "map '%s'\n", cur);
127             return AVERROR(EINVAL);
128         }
129         *sep++ = 0;
130
131 #define PARSE_CHANNEL(str, var, inout)                                         \
132         if (!(var = av_get_channel_layout(str))) {                             \
133             av_log(ctx, AV_LOG_ERROR, "Invalid " inout " channel: %s.\n", str);\
134             return AVERROR(EINVAL);                                            \
135         }                                                                      \
136         if (av_get_channel_layout_nb_channels(var) != 1) {                     \
137             av_log(ctx, AV_LOG_ERROR, "Channel map describes more than one "   \
138                    inout " channel.\n");                                       \
139             return AVERROR(EINVAL);                                            \
140         }
141
142         /* parse output channel */
143         PARSE_CHANNEL(sep, out_channel, "output");
144         if (!(out_channel & s->channel_layout)) {
145             av_log(ctx, AV_LOG_ERROR, "Output channel '%s' is not present in "
146                    "requested channel layout.\n", sep);
147             return AVERROR(EINVAL);
148         }
149
150         out_ch_idx = av_get_channel_layout_channel_index(s->channel_layout,
151                                                          out_channel);
152         if (s->channels[out_ch_idx].input >= 0) {
153             av_log(ctx, AV_LOG_ERROR, "Multiple maps for output channel "
154                    "'%s'.\n", sep);
155             return AVERROR(EINVAL);
156         }
157
158         /* parse input channel */
159         input_idx = strtol(cur, &cur, 0);
160         if (input_idx < 0 || input_idx >= s->inputs) {
161             av_log(ctx, AV_LOG_ERROR, "Invalid input stream index: %d.\n",
162                    input_idx);
163             return AVERROR(EINVAL);
164         }
165
166         if (*cur)
167             cur++;
168
169         in_ch_idx = strtol(cur, &p, 0);
170         if (p == cur) {
171             /* channel specifier is not a number,
172              * try to parse as channel name */
173             PARSE_CHANNEL(cur, in_channel, "input");
174         }
175
176         s->channels[out_ch_idx].input      = input_idx;
177         if (in_channel)
178             s->channels[out_ch_idx].in_channel = in_channel;
179         else
180             s->channels[out_ch_idx].in_channel_idx = in_ch_idx;
181
182         cur = next;
183     }
184     return 0;
185 }
186
187 static int join_init(AVFilterContext *ctx, const char *args, void *opaque)
188 {
189     JoinContext *s = ctx->priv;
190     int ret, i;
191
192     s->class = &join_class;
193     av_opt_set_defaults(s);
194     if ((ret = av_set_options_string(s, args, "=", ":")) < 0) {
195         av_log(ctx, AV_LOG_ERROR, "Error parsing options string '%s'.\n", args);
196         return ret;
197     }
198
199     if (!(s->channel_layout = av_get_channel_layout(s->channel_layout_str))) {
200         av_log(ctx, AV_LOG_ERROR, "Error parsing channel layout '%s'.\n",
201                s->channel_layout_str);
202         ret = AVERROR(EINVAL);
203         goto fail;
204     }
205
206     s->nb_channels  = av_get_channel_layout_nb_channels(s->channel_layout);
207     s->channels     = av_mallocz(sizeof(*s->channels) * s->nb_channels);
208     s->data         = av_mallocz(sizeof(*s->data)     * s->nb_channels);
209     s->input_frames = av_mallocz(sizeof(*s->input_frames) * s->inputs);
210     if (!s->channels || !s->data || !s->input_frames) {
211         ret = AVERROR(ENOMEM);
212         goto fail;
213     }
214
215     for (i = 0; i < s->nb_channels; i++) {
216         s->channels[i].out_channel = av_channel_layout_extract_channel(s->channel_layout, i);
217         s->channels[i].input       = -1;
218     }
219
220     if ((ret = parse_maps(ctx)) < 0)
221         goto fail;
222
223     for (i = 0; i < s->inputs; i++) {
224         char name[32];
225         AVFilterPad pad = { 0 };
226
227         snprintf(name, sizeof(name), "input%d", i);
228         pad.type           = AVMEDIA_TYPE_AUDIO;
229         pad.name           = av_strdup(name);
230         pad.filter_samples = filter_samples;
231
232         pad.needs_fifo = 1;
233
234         ff_insert_inpad(ctx, i, &pad);
235     }
236
237 fail:
238     av_opt_free(s);
239     return ret;
240 }
241
242 static void join_uninit(AVFilterContext *ctx)
243 {
244     JoinContext *s = ctx->priv;
245     int i;
246
247     for (i = 0; i < ctx->nb_inputs; i++) {
248         av_freep(&ctx->input_pads[i].name);
249         avfilter_unref_buffer(s->input_frames[i]);
250     }
251
252     av_freep(&s->channels);
253     av_freep(&s->data);
254     av_freep(&s->input_frames);
255 }
256
257 static int join_query_formats(AVFilterContext *ctx)
258 {
259     JoinContext *s = ctx->priv;
260     AVFilterChannelLayouts *layouts = NULL;
261     int i;
262
263     ff_add_channel_layout(&layouts, s->channel_layout);
264     ff_channel_layouts_ref(layouts, &ctx->outputs[0]->in_channel_layouts);
265
266     for (i = 0; i < ctx->nb_inputs; i++)
267         ff_channel_layouts_ref(ff_all_channel_layouts(),
268                                &ctx->inputs[i]->out_channel_layouts);
269
270     ff_set_common_formats    (ctx, ff_planar_sample_fmts());
271     ff_set_common_samplerates(ctx, ff_all_samplerates());
272
273     return 0;
274 }
275
276 static void guess_map_matching(AVFilterContext *ctx, ChannelMap *ch,
277                                uint64_t *inputs)
278 {
279     int i;
280
281     for (i = 0; i < ctx->nb_inputs; i++) {
282         AVFilterLink *link = ctx->inputs[i];
283
284         if (ch->out_channel & link->channel_layout &&
285             !(ch->out_channel & inputs[i])) {
286             ch->input      = i;
287             ch->in_channel = ch->out_channel;
288             inputs[i]     |= ch->out_channel;
289             return;
290         }
291     }
292 }
293
294 static void guess_map_any(AVFilterContext *ctx, ChannelMap *ch,
295                           uint64_t *inputs)
296 {
297     int i;
298
299     for (i = 0; i < ctx->nb_inputs; i++) {
300         AVFilterLink *link = ctx->inputs[i];
301
302         if ((inputs[i] & link->channel_layout) != link->channel_layout) {
303             uint64_t unused = link->channel_layout & ~inputs[i];
304
305             ch->input      = i;
306             ch->in_channel = av_channel_layout_extract_channel(unused, 0);
307             inputs[i]     |= ch->in_channel;
308             return;
309         }
310     }
311 }
312
313 static int join_config_output(AVFilterLink *outlink)
314 {
315     AVFilterContext *ctx = outlink->src;
316     JoinContext       *s = ctx->priv;
317     uint64_t *inputs;   // nth element tracks which channels are used from nth input
318     int i, ret = 0;
319
320     /* initialize inputs to user-specified mappings */
321     if (!(inputs = av_mallocz(sizeof(*inputs) * ctx->nb_inputs)))
322         return AVERROR(ENOMEM);
323     for (i = 0; i < s->nb_channels; i++) {
324         ChannelMap *ch = &s->channels[i];
325         AVFilterLink *inlink;
326
327         if (ch->input < 0)
328             continue;
329
330         inlink = ctx->inputs[ch->input];
331
332         if (!ch->in_channel)
333             ch->in_channel = av_channel_layout_extract_channel(inlink->channel_layout,
334                                                                ch->in_channel_idx);
335
336         if (!(ch->in_channel & inlink->channel_layout)) {
337             av_log(ctx, AV_LOG_ERROR, "Requested channel %s is not present in "
338                    "input stream #%d.\n", av_get_channel_name(ch->in_channel),
339                    ch->input);
340             ret = AVERROR(EINVAL);
341             goto fail;
342         }
343
344         inputs[ch->input] |= ch->in_channel;
345     }
346
347     /* guess channel maps when not explicitly defined */
348     /* first try unused matching channels */
349     for (i = 0; i < s->nb_channels; i++) {
350         ChannelMap *ch = &s->channels[i];
351
352         if (ch->input < 0)
353             guess_map_matching(ctx, ch, inputs);
354     }
355
356     /* if the above failed, try to find _any_ unused input channel */
357     for (i = 0; i < s->nb_channels; i++) {
358         ChannelMap *ch = &s->channels[i];
359
360         if (ch->input < 0)
361             guess_map_any(ctx, ch, inputs);
362
363         if (ch->input < 0) {
364             av_log(ctx, AV_LOG_ERROR, "Could not find input channel for "
365                    "output channel '%s'.\n",
366                    av_get_channel_name(ch->out_channel));
367             goto fail;
368         }
369
370         ch->in_channel_idx = av_get_channel_layout_channel_index(ctx->inputs[ch->input]->channel_layout,
371                                                                  ch->in_channel);
372     }
373
374     /* print mappings */
375     av_log(ctx, AV_LOG_VERBOSE, "mappings: ");
376     for (i = 0; i < s->nb_channels; i++) {
377         ChannelMap *ch = &s->channels[i];
378         av_log(ctx, AV_LOG_VERBOSE, "%d.%s => %s ", ch->input,
379                av_get_channel_name(ch->in_channel),
380                av_get_channel_name(ch->out_channel));
381     }
382     av_log(ctx, AV_LOG_VERBOSE, "\n");
383
384     for (i = 0; i < ctx->nb_inputs; i++) {
385         if (!inputs[i])
386             av_log(ctx, AV_LOG_WARNING, "No channels are used from input "
387                    "stream %d.\n", i);
388     }
389
390 fail:
391     av_freep(&inputs);
392     return ret;
393 }
394
395 static void join_free_buffer(AVFilterBuffer *buf)
396 {
397     JoinBufferPriv *priv = buf->priv;
398
399     if (priv) {
400         int i;
401
402         for (i = 0; i < priv->nb_in_buffers; i++)
403             avfilter_unref_buffer(priv->in_buffers[i]);
404
405         av_freep(&priv->in_buffers);
406         av_freep(&buf->priv);
407     }
408
409     if (buf->extended_data != buf->data)
410         av_freep(&buf->extended_data);
411     av_freep(&buf);
412 }
413
414 static int join_request_frame(AVFilterLink *outlink)
415 {
416     AVFilterContext *ctx = outlink->src;
417     JoinContext *s       = ctx->priv;
418     AVFilterBufferRef *buf;
419     JoinBufferPriv *priv;
420     int linesize   = INT_MAX;
421     int perms      = ~0;
422     int nb_samples;
423     int i, j, ret;
424
425     /* get a frame on each input */
426     for (i = 0; i < ctx->nb_inputs; i++) {
427         AVFilterLink *inlink = ctx->inputs[i];
428
429         if (!s->input_frames[i] &&
430             (ret = ff_request_frame(inlink)) < 0)
431             return ret;
432
433         /* request the same number of samples on all inputs */
434         if (i == 0) {
435             nb_samples = s->input_frames[0]->audio->nb_samples;
436
437             for (j = 1; !i && j < ctx->nb_inputs; j++)
438                 ctx->inputs[j]->request_samples = nb_samples;
439         }
440     }
441
442     for (i = 0; i < s->nb_channels; i++) {
443         ChannelMap *ch = &s->channels[i];
444         AVFilterBufferRef *cur_buf = s->input_frames[ch->input];
445
446         s->data[i] = cur_buf->extended_data[ch->in_channel_idx];
447         linesize   = FFMIN(linesize, cur_buf->linesize[0]);
448         perms     &= cur_buf->perms;
449     }
450
451     buf = avfilter_get_audio_buffer_ref_from_arrays(s->data, linesize, perms,
452                                                     nb_samples, outlink->format,
453                                                     outlink->channel_layout);
454     if (!buf)
455         return AVERROR(ENOMEM);
456
457     buf->buf->free = join_free_buffer;
458     buf->pts       = s->input_frames[0]->pts;
459
460     if (!(priv = av_mallocz(sizeof(*priv))))
461         goto fail;
462     if (!(priv->in_buffers = av_mallocz(sizeof(*priv->in_buffers) * ctx->nb_inputs)))
463         goto fail;
464
465     for (i = 0; i < ctx->nb_inputs; i++)
466         priv->in_buffers[i] = s->input_frames[i];
467     priv->nb_in_buffers = ctx->nb_inputs;
468     buf->buf->priv      = priv;
469
470     ff_filter_samples(outlink, buf);
471
472     memset(s->input_frames, 0, sizeof(*s->input_frames) * ctx->nb_inputs);
473
474     return 0;
475
476 fail:
477     avfilter_unref_buffer(buf);
478     if (priv)
479         av_freep(&priv->in_buffers);
480     av_freep(&priv);
481     return AVERROR(ENOMEM);
482 }
483
484 AVFilter avfilter_af_join = {
485     .name           = "join",
486     .description    = NULL_IF_CONFIG_SMALL("Join multiple audio streams into "
487                                            "multi-channel output"),
488     .priv_size      = sizeof(JoinContext),
489
490     .init           = join_init,
491     .uninit         = join_uninit,
492     .query_formats  = join_query_formats,
493
494     .inputs  = (const AVFilterPad[]){{ NULL }},
495     .outputs = (const AVFilterPad[]){{ .name          = "default",
496                                        .type          = AVMEDIA_TYPE_AUDIO,
497                                        .config_props  = join_config_output,
498                                        .request_frame = join_request_frame, },
499                                      { NULL }},
500 };