00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00028 #include "libavutil/audioconvert.h"
00029 #include "libavutil/avassert.h"
00030 #include "libavutil/common.h"
00031 #include "libavutil/opt.h"
00032
00033 #include "audio.h"
00034 #include "avfilter.h"
00035 #include "formats.h"
00036 #include "internal.h"
00037
00038 typedef struct ChannelMap {
00039 int input;
00040 int in_channel_idx;
00041 uint64_t in_channel;
00042 uint64_t out_channel;
00043 } ChannelMap;
00044
00045 typedef struct JoinContext {
00046 const AVClass *class;
00047
00048 int inputs;
00049 char *map;
00050 char *channel_layout_str;
00051 uint64_t channel_layout;
00052
00053 int nb_channels;
00054 ChannelMap *channels;
00055
00059 AVFilterBufferRef **input_frames;
00060
00064 uint8_t **data;
00065 } JoinContext;
00066
00072 typedef struct JoinBufferPriv {
00073 AVFilterBufferRef **in_buffers;
00074 int nb_in_buffers;
00075 } JoinBufferPriv;
00076
00077 #define OFFSET(x) offsetof(JoinContext, x)
00078 #define A AV_OPT_FLAG_AUDIO_PARAM
00079 #define F AV_OPT_FLAG_FILTERING_PARAM
00080 static const AVOption join_options[] = {
00081 { "inputs", "Number of input streams.", OFFSET(inputs), AV_OPT_TYPE_INT, { .i64 = 2 }, 1, INT_MAX, A|F },
00082 { "channel_layout", "Channel layout of the "
00083 "output stream.", OFFSET(channel_layout_str), AV_OPT_TYPE_STRING, {.str = "stereo"}, 0, 0, A|F },
00084 { "map", "A comma-separated list of channels maps in the format "
00085 "'input_stream.input_channel-output_channel.",
00086 OFFSET(map), AV_OPT_TYPE_STRING, .flags = A|F },
00087 { NULL },
00088 };
00089
00090 static const AVClass join_class = {
00091 .class_name = "join filter",
00092 .item_name = av_default_item_name,
00093 .option = join_options,
00094 .version = LIBAVUTIL_VERSION_INT,
00095 };
00096
00097 static int filter_samples(AVFilterLink *link, AVFilterBufferRef *buf)
00098 {
00099 AVFilterContext *ctx = link->dst;
00100 JoinContext *s = ctx->priv;
00101 int i;
00102
00103 for (i = 0; i < ctx->nb_inputs; i++)
00104 if (link == ctx->inputs[i])
00105 break;
00106 av_assert0(i < ctx->nb_inputs);
00107 av_assert0(!s->input_frames[i]);
00108 s->input_frames[i] = buf;
00109
00110 return 0;
00111 }
00112
00113 static int parse_maps(AVFilterContext *ctx)
00114 {
00115 JoinContext *s = ctx->priv;
00116 char *cur = s->map;
00117
00118 while (cur && *cur) {
00119 char *sep, *next, *p;
00120 uint64_t in_channel = 0, out_channel = 0;
00121 int input_idx, out_ch_idx, in_ch_idx;
00122
00123 next = strchr(cur, ',');
00124 if (next)
00125 *next++ = 0;
00126
00127
00128 if (!(sep = strchr(cur, '-'))) {
00129 av_log(ctx, AV_LOG_ERROR, "Missing separator '-' in channel "
00130 "map '%s'\n", cur);
00131 return AVERROR(EINVAL);
00132 }
00133 *sep++ = 0;
00134
00135 #define PARSE_CHANNEL(str, var, inout) \
00136 if (!(var = av_get_channel_layout(str))) { \
00137 av_log(ctx, AV_LOG_ERROR, "Invalid " inout " channel: %s.\n", str);\
00138 return AVERROR(EINVAL); \
00139 } \
00140 if (av_get_channel_layout_nb_channels(var) != 1) { \
00141 av_log(ctx, AV_LOG_ERROR, "Channel map describes more than one " \
00142 inout " channel.\n"); \
00143 return AVERROR(EINVAL); \
00144 }
00145
00146
00147 PARSE_CHANNEL(sep, out_channel, "output");
00148 if (!(out_channel & s->channel_layout)) {
00149 av_log(ctx, AV_LOG_ERROR, "Output channel '%s' is not present in "
00150 "requested channel layout.\n", sep);
00151 return AVERROR(EINVAL);
00152 }
00153
00154 out_ch_idx = av_get_channel_layout_channel_index(s->channel_layout,
00155 out_channel);
00156 if (s->channels[out_ch_idx].input >= 0) {
00157 av_log(ctx, AV_LOG_ERROR, "Multiple maps for output channel "
00158 "'%s'.\n", sep);
00159 return AVERROR(EINVAL);
00160 }
00161
00162
00163 input_idx = strtol(cur, &cur, 0);
00164 if (input_idx < 0 || input_idx >= s->inputs) {
00165 av_log(ctx, AV_LOG_ERROR, "Invalid input stream index: %d.\n",
00166 input_idx);
00167 return AVERROR(EINVAL);
00168 }
00169
00170 if (*cur)
00171 cur++;
00172
00173 in_ch_idx = strtol(cur, &p, 0);
00174 if (p == cur) {
00175
00176
00177 PARSE_CHANNEL(cur, in_channel, "input");
00178 }
00179
00180 s->channels[out_ch_idx].input = input_idx;
00181 if (in_channel)
00182 s->channels[out_ch_idx].in_channel = in_channel;
00183 else
00184 s->channels[out_ch_idx].in_channel_idx = in_ch_idx;
00185
00186 cur = next;
00187 }
00188 return 0;
00189 }
00190
00191 static int join_init(AVFilterContext *ctx, const char *args)
00192 {
00193 JoinContext *s = ctx->priv;
00194 int ret, i;
00195
00196 s->class = &join_class;
00197 av_opt_set_defaults(s);
00198 if ((ret = av_set_options_string(s, args, "=", ":")) < 0)
00199 return ret;
00200
00201 if (!(s->channel_layout = av_get_channel_layout(s->channel_layout_str))) {
00202 av_log(ctx, AV_LOG_ERROR, "Error parsing channel layout '%s'.\n",
00203 s->channel_layout_str);
00204 ret = AVERROR(EINVAL);
00205 goto fail;
00206 }
00207
00208 s->nb_channels = av_get_channel_layout_nb_channels(s->channel_layout);
00209 s->channels = av_mallocz(sizeof(*s->channels) * s->nb_channels);
00210 s->data = av_mallocz(sizeof(*s->data) * s->nb_channels);
00211 s->input_frames = av_mallocz(sizeof(*s->input_frames) * s->inputs);
00212 if (!s->channels || !s->data || !s->input_frames) {
00213 ret = AVERROR(ENOMEM);
00214 goto fail;
00215 }
00216
00217 for (i = 0; i < s->nb_channels; i++) {
00218 s->channels[i].out_channel = av_channel_layout_extract_channel(s->channel_layout, i);
00219 s->channels[i].input = -1;
00220 }
00221
00222 if ((ret = parse_maps(ctx)) < 0)
00223 goto fail;
00224
00225 for (i = 0; i < s->inputs; i++) {
00226 char name[32];
00227 AVFilterPad pad = { 0 };
00228
00229 snprintf(name, sizeof(name), "input%d", i);
00230 pad.type = AVMEDIA_TYPE_AUDIO;
00231 pad.name = av_strdup(name);
00232 pad.filter_samples = filter_samples;
00233
00234 pad.needs_fifo = 1;
00235
00236 ff_insert_inpad(ctx, i, &pad);
00237 }
00238
00239 fail:
00240 av_opt_free(s);
00241 return ret;
00242 }
00243
00244 static void join_uninit(AVFilterContext *ctx)
00245 {
00246 JoinContext *s = ctx->priv;
00247 int i;
00248
00249 for (i = 0; i < ctx->nb_inputs; i++) {
00250 av_freep(&ctx->input_pads[i].name);
00251 avfilter_unref_bufferp(&s->input_frames[i]);
00252 }
00253
00254 av_freep(&s->channels);
00255 av_freep(&s->data);
00256 av_freep(&s->input_frames);
00257 }
00258
00259 static int join_query_formats(AVFilterContext *ctx)
00260 {
00261 JoinContext *s = ctx->priv;
00262 AVFilterChannelLayouts *layouts = NULL;
00263 int i;
00264
00265 ff_add_channel_layout(&layouts, s->channel_layout);
00266 ff_channel_layouts_ref(layouts, &ctx->outputs[0]->in_channel_layouts);
00267
00268 for (i = 0; i < ctx->nb_inputs; i++)
00269 ff_channel_layouts_ref(ff_all_channel_layouts(),
00270 &ctx->inputs[i]->out_channel_layouts);
00271
00272 ff_set_common_formats (ctx, ff_planar_sample_fmts());
00273 ff_set_common_samplerates(ctx, ff_all_samplerates());
00274
00275 return 0;
00276 }
00277
00278 static void guess_map_matching(AVFilterContext *ctx, ChannelMap *ch,
00279 uint64_t *inputs)
00280 {
00281 int i;
00282
00283 for (i = 0; i < ctx->nb_inputs; i++) {
00284 AVFilterLink *link = ctx->inputs[i];
00285
00286 if (ch->out_channel & link->channel_layout &&
00287 !(ch->out_channel & inputs[i])) {
00288 ch->input = i;
00289 ch->in_channel = ch->out_channel;
00290 inputs[i] |= ch->out_channel;
00291 return;
00292 }
00293 }
00294 }
00295
00296 static void guess_map_any(AVFilterContext *ctx, ChannelMap *ch,
00297 uint64_t *inputs)
00298 {
00299 int i;
00300
00301 for (i = 0; i < ctx->nb_inputs; i++) {
00302 AVFilterLink *link = ctx->inputs[i];
00303
00304 if ((inputs[i] & link->channel_layout) != link->channel_layout) {
00305 uint64_t unused = link->channel_layout & ~inputs[i];
00306
00307 ch->input = i;
00308 ch->in_channel = av_channel_layout_extract_channel(unused, 0);
00309 inputs[i] |= ch->in_channel;
00310 return;
00311 }
00312 }
00313 }
00314
00315 static int join_config_output(AVFilterLink *outlink)
00316 {
00317 AVFilterContext *ctx = outlink->src;
00318 JoinContext *s = ctx->priv;
00319 uint64_t *inputs;
00320 int i, ret = 0;
00321
00322
00323 if (!(inputs = av_mallocz(sizeof(*inputs) * ctx->nb_inputs)))
00324 return AVERROR(ENOMEM);
00325 for (i = 0; i < s->nb_channels; i++) {
00326 ChannelMap *ch = &s->channels[i];
00327 AVFilterLink *inlink;
00328
00329 if (ch->input < 0)
00330 continue;
00331
00332 inlink = ctx->inputs[ch->input];
00333
00334 if (!ch->in_channel)
00335 ch->in_channel = av_channel_layout_extract_channel(inlink->channel_layout,
00336 ch->in_channel_idx);
00337
00338 if (!(ch->in_channel & inlink->channel_layout)) {
00339 av_log(ctx, AV_LOG_ERROR, "Requested channel %s is not present in "
00340 "input stream #%d.\n", av_get_channel_name(ch->in_channel),
00341 ch->input);
00342 ret = AVERROR(EINVAL);
00343 goto fail;
00344 }
00345
00346 inputs[ch->input] |= ch->in_channel;
00347 }
00348
00349
00350
00351 for (i = 0; i < s->nb_channels; i++) {
00352 ChannelMap *ch = &s->channels[i];
00353
00354 if (ch->input < 0)
00355 guess_map_matching(ctx, ch, inputs);
00356 }
00357
00358
00359 for (i = 0; i < s->nb_channels; i++) {
00360 ChannelMap *ch = &s->channels[i];
00361
00362 if (ch->input < 0)
00363 guess_map_any(ctx, ch, inputs);
00364
00365 if (ch->input < 0) {
00366 av_log(ctx, AV_LOG_ERROR, "Could not find input channel for "
00367 "output channel '%s'.\n",
00368 av_get_channel_name(ch->out_channel));
00369 goto fail;
00370 }
00371
00372 ch->in_channel_idx = av_get_channel_layout_channel_index(ctx->inputs[ch->input]->channel_layout,
00373 ch->in_channel);
00374 }
00375
00376
00377 av_log(ctx, AV_LOG_VERBOSE, "mappings: ");
00378 for (i = 0; i < s->nb_channels; i++) {
00379 ChannelMap *ch = &s->channels[i];
00380 av_log(ctx, AV_LOG_VERBOSE, "%d.%s => %s ", ch->input,
00381 av_get_channel_name(ch->in_channel),
00382 av_get_channel_name(ch->out_channel));
00383 }
00384 av_log(ctx, AV_LOG_VERBOSE, "\n");
00385
00386 for (i = 0; i < ctx->nb_inputs; i++) {
00387 if (!inputs[i])
00388 av_log(ctx, AV_LOG_WARNING, "No channels are used from input "
00389 "stream %d.\n", i);
00390 }
00391
00392 fail:
00393 av_freep(&inputs);
00394 return ret;
00395 }
00396
00397 static void join_free_buffer(AVFilterBuffer *buf)
00398 {
00399 JoinBufferPriv *priv = buf->priv;
00400
00401 if (priv) {
00402 int i;
00403
00404 for (i = 0; i < priv->nb_in_buffers; i++)
00405 avfilter_unref_bufferp(&priv->in_buffers[i]);
00406
00407 av_freep(&priv->in_buffers);
00408 av_freep(&buf->priv);
00409 }
00410
00411 if (buf->extended_data != buf->data)
00412 av_freep(&buf->extended_data);
00413 av_freep(&buf);
00414 }
00415
00416 static int join_request_frame(AVFilterLink *outlink)
00417 {
00418 AVFilterContext *ctx = outlink->src;
00419 JoinContext *s = ctx->priv;
00420 AVFilterBufferRef *buf;
00421 JoinBufferPriv *priv;
00422 int linesize = INT_MAX;
00423 int perms = ~0;
00424 int nb_samples = 0;
00425 int i, j, ret;
00426
00427
00428 for (i = 0; i < ctx->nb_inputs; i++) {
00429 AVFilterLink *inlink = ctx->inputs[i];
00430
00431 if (!s->input_frames[i] &&
00432 (ret = ff_request_frame(inlink)) < 0)
00433 return ret;
00434
00435
00436 if (i == 0) {
00437 nb_samples = s->input_frames[0]->audio->nb_samples;
00438
00439 for (j = 1; !i && j < ctx->nb_inputs; j++)
00440 ctx->inputs[j]->request_samples = nb_samples;
00441 }
00442 }
00443
00444 for (i = 0; i < s->nb_channels; i++) {
00445 ChannelMap *ch = &s->channels[i];
00446 AVFilterBufferRef *cur_buf = s->input_frames[ch->input];
00447
00448 s->data[i] = cur_buf->extended_data[ch->in_channel_idx];
00449 linesize = FFMIN(linesize, cur_buf->linesize[0]);
00450 perms &= cur_buf->perms;
00451 }
00452
00453 av_assert0(nb_samples > 0);
00454 buf = avfilter_get_audio_buffer_ref_from_arrays(s->data, linesize, perms,
00455 nb_samples, outlink->format,
00456 outlink->channel_layout);
00457 if (!buf)
00458 return AVERROR(ENOMEM);
00459
00460 buf->buf->free = join_free_buffer;
00461 buf->pts = s->input_frames[0]->pts;
00462
00463 if (!(priv = av_mallocz(sizeof(*priv))))
00464 goto fail;
00465 if (!(priv->in_buffers = av_mallocz(sizeof(*priv->in_buffers) * ctx->nb_inputs)))
00466 goto fail;
00467
00468 for (i = 0; i < ctx->nb_inputs; i++)
00469 priv->in_buffers[i] = s->input_frames[i];
00470 priv->nb_in_buffers = ctx->nb_inputs;
00471 buf->buf->priv = priv;
00472
00473 ret = ff_filter_samples(outlink, buf);
00474
00475 memset(s->input_frames, 0, sizeof(*s->input_frames) * ctx->nb_inputs);
00476
00477 return ret;
00478
00479 fail:
00480 avfilter_unref_buffer(buf);
00481 if (priv)
00482 av_freep(&priv->in_buffers);
00483 av_freep(&priv);
00484 return AVERROR(ENOMEM);
00485 }
00486
00487 AVFilter avfilter_af_join = {
00488 .name = "join",
00489 .description = NULL_IF_CONFIG_SMALL("Join multiple audio streams into "
00490 "multi-channel output"),
00491 .priv_size = sizeof(JoinContext),
00492
00493 .init = join_init,
00494 .uninit = join_uninit,
00495 .query_formats = join_query_formats,
00496
00497 .inputs = NULL,
00498 .outputs = (const AVFilterPad[]){{ .name = "default",
00499 .type = AVMEDIA_TYPE_AUDIO,
00500 .config_props = join_config_output,
00501 .request_frame = join_request_frame, },
00502 { NULL }},
00503 .priv_class = &join_class,
00504 };