00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00026 #include <ctype.h>
00027
00028 #include "libavutil/avstring.h"
00029 #include "libavutil/channel_layout.h"
00030 #include "libavutil/common.h"
00031 #include "libavutil/mathematics.h"
00032 #include "libavutil/opt.h"
00033 #include "libavutil/samplefmt.h"
00034
00035 #include "audio.h"
00036 #include "avfilter.h"
00037 #include "formats.h"
00038 #include "internal.h"
00039
00040 struct ChannelMap {
00041 uint64_t in_channel;
00042 uint64_t out_channel;
00043 int in_channel_idx;
00044 int out_channel_idx;
00045 };
00046
00047 enum MappingMode {
00048 MAP_NONE,
00049 MAP_ONE_INT,
00050 MAP_ONE_STR,
00051 MAP_PAIR_INT_INT,
00052 MAP_PAIR_INT_STR,
00053 MAP_PAIR_STR_INT,
00054 MAP_PAIR_STR_STR
00055 };
00056
00057 #define MAX_CH 64
00058 typedef struct ChannelMapContext {
00059 const AVClass *class;
00060 AVFilterChannelLayouts *channel_layouts;
00061 char *mapping_str;
00062 char *channel_layout_str;
00063 uint64_t output_layout;
00064 struct ChannelMap map[MAX_CH];
00065 int nch;
00066 enum MappingMode mode;
00067 } ChannelMapContext;
00068
00069 #define OFFSET(x) offsetof(ChannelMapContext, x)
00070 #define A AV_OPT_FLAG_AUDIO_PARAM
00071 #define F AV_OPT_FLAG_FILTERING_PARAM
00072 static const AVOption options[] = {
00073 { "map", "A comma-separated list of input channel numbers in output order.",
00074 OFFSET(mapping_str), AV_OPT_TYPE_STRING, .flags = A|F },
00075 { "channel_layout", "Output channel layout.",
00076 OFFSET(channel_layout_str), AV_OPT_TYPE_STRING, .flags = A|F },
00077 { NULL },
00078 };
00079
00080 static const AVClass channelmap_class = {
00081 .class_name = "channel map filter",
00082 .item_name = av_default_item_name,
00083 .option = options,
00084 .version = LIBAVUTIL_VERSION_INT,
00085 };
00086
00087 static char* split(char *message, char delim) {
00088 char *next = strchr(message, delim);
00089 if (next)
00090 *next++ = '\0';
00091 return next;
00092 }
00093
00094 static int get_channel_idx(char **map, int *ch, char delim, int max_ch)
00095 {
00096 char *next = split(*map, delim);
00097 int len;
00098 int n = 0;
00099 if (!next && delim == '-')
00100 return AVERROR(EINVAL);
00101 len = strlen(*map);
00102 sscanf(*map, "%d%n", ch, &n);
00103 if (n != len)
00104 return AVERROR(EINVAL);
00105 if (*ch < 0 || *ch > max_ch)
00106 return AVERROR(EINVAL);
00107 *map = next;
00108 return 0;
00109 }
00110
00111 static int get_channel(char **map, uint64_t *ch, char delim)
00112 {
00113 char *next = split(*map, delim);
00114 if (!next && delim == '-')
00115 return AVERROR(EINVAL);
00116 *ch = av_get_channel_layout(*map);
00117 if (av_get_channel_layout_nb_channels(*ch) != 1)
00118 return AVERROR(EINVAL);
00119 *map = next;
00120 return 0;
00121 }
00122
00123 static av_cold int channelmap_init(AVFilterContext *ctx, const char *args)
00124 {
00125 ChannelMapContext *s = ctx->priv;
00126 int ret;
00127 char *mapping;
00128 int map_entries = 0;
00129 char buf[256];
00130 enum MappingMode mode;
00131 uint64_t out_ch_mask = 0;
00132 int i;
00133
00134 if (!args) {
00135 av_log(ctx, AV_LOG_ERROR, "No parameters supplied.\n");
00136 return AVERROR(EINVAL);
00137 }
00138
00139 s->class = &channelmap_class;
00140 av_opt_set_defaults(s);
00141
00142 if ((ret = av_set_options_string(s, args, "=", ":")) < 0)
00143 return ret;
00144
00145 mapping = s->mapping_str;
00146
00147 if (!mapping) {
00148 mode = MAP_NONE;
00149 } else {
00150 char *dash = strchr(mapping, '-');
00151 if (!dash) {
00152 if (isdigit(*mapping))
00153 mode = MAP_ONE_INT;
00154 else
00155 mode = MAP_ONE_STR;
00156 } else if (isdigit(*mapping)) {
00157 if (isdigit(*(dash+1)))
00158 mode = MAP_PAIR_INT_INT;
00159 else
00160 mode = MAP_PAIR_INT_STR;
00161 } else {
00162 if (isdigit(*(dash+1)))
00163 mode = MAP_PAIR_STR_INT;
00164 else
00165 mode = MAP_PAIR_STR_STR;
00166 }
00167 }
00168
00169 if (mode != MAP_NONE) {
00170 char *comma = mapping;
00171 map_entries = 1;
00172 while ((comma = strchr(comma, ','))) {
00173 if (*++comma)
00174 map_entries++;
00175 }
00176 }
00177
00178 if (map_entries > MAX_CH) {
00179 av_log(ctx, AV_LOG_ERROR, "Too many channels mapped: '%d'.\n", map_entries);
00180 ret = AVERROR(EINVAL);
00181 goto fail;
00182 }
00183
00184 for (i = 0; i < map_entries; i++) {
00185 int in_ch_idx = -1, out_ch_idx = -1;
00186 uint64_t in_ch = 0, out_ch = 0;
00187 static const char err[] = "Failed to parse channel map\n";
00188 switch (mode) {
00189 case MAP_ONE_INT:
00190 if (get_channel_idx(&mapping, &in_ch_idx, ',', MAX_CH) < 0) {
00191 ret = AVERROR(EINVAL);
00192 av_log(ctx, AV_LOG_ERROR, err);
00193 goto fail;
00194 }
00195 s->map[i].in_channel_idx = in_ch_idx;
00196 s->map[i].out_channel_idx = i;
00197 break;
00198 case MAP_ONE_STR:
00199 if (!get_channel(&mapping, &in_ch, ',')) {
00200 av_log(ctx, AV_LOG_ERROR, err);
00201 ret = AVERROR(EINVAL);
00202 goto fail;
00203 }
00204 s->map[i].in_channel = in_ch;
00205 s->map[i].out_channel_idx = i;
00206 break;
00207 case MAP_PAIR_INT_INT:
00208 if (get_channel_idx(&mapping, &in_ch_idx, '-', MAX_CH) < 0 ||
00209 get_channel_idx(&mapping, &out_ch_idx, ',', MAX_CH) < 0) {
00210 av_log(ctx, AV_LOG_ERROR, err);
00211 ret = AVERROR(EINVAL);
00212 goto fail;
00213 }
00214 s->map[i].in_channel_idx = in_ch_idx;
00215 s->map[i].out_channel_idx = out_ch_idx;
00216 break;
00217 case MAP_PAIR_INT_STR:
00218 if (get_channel_idx(&mapping, &in_ch_idx, '-', MAX_CH) < 0 ||
00219 get_channel(&mapping, &out_ch, ',') < 0 ||
00220 out_ch & out_ch_mask) {
00221 av_log(ctx, AV_LOG_ERROR, err);
00222 ret = AVERROR(EINVAL);
00223 goto fail;
00224 }
00225 s->map[i].in_channel_idx = in_ch_idx;
00226 s->map[i].out_channel = out_ch;
00227 out_ch_mask |= out_ch;
00228 break;
00229 case MAP_PAIR_STR_INT:
00230 if (get_channel(&mapping, &in_ch, '-') < 0 ||
00231 get_channel_idx(&mapping, &out_ch_idx, ',', MAX_CH) < 0) {
00232 av_log(ctx, AV_LOG_ERROR, err);
00233 ret = AVERROR(EINVAL);
00234 goto fail;
00235 }
00236 s->map[i].in_channel = in_ch;
00237 s->map[i].out_channel_idx = out_ch_idx;
00238 break;
00239 case MAP_PAIR_STR_STR:
00240 if (get_channel(&mapping, &in_ch, '-') < 0 ||
00241 get_channel(&mapping, &out_ch, ',') < 0 ||
00242 out_ch & out_ch_mask) {
00243 av_log(ctx, AV_LOG_ERROR, err);
00244 ret = AVERROR(EINVAL);
00245 goto fail;
00246 }
00247 s->map[i].in_channel = in_ch;
00248 s->map[i].out_channel = out_ch;
00249 out_ch_mask |= out_ch;
00250 break;
00251 }
00252 }
00253 s->mode = mode;
00254 s->nch = map_entries;
00255 s->output_layout = out_ch_mask ? out_ch_mask :
00256 av_get_default_channel_layout(map_entries);
00257
00258 if (s->channel_layout_str) {
00259 uint64_t fmt;
00260 if ((fmt = av_get_channel_layout(s->channel_layout_str)) == 0) {
00261 av_log(ctx, AV_LOG_ERROR, "Error parsing channel layout: '%s'.\n",
00262 s->channel_layout_str);
00263 ret = AVERROR(EINVAL);
00264 goto fail;
00265 }
00266 if (mode == MAP_NONE) {
00267 int i;
00268 s->nch = av_get_channel_layout_nb_channels(fmt);
00269 for (i = 0; i < s->nch; i++) {
00270 s->map[i].in_channel_idx = i;
00271 s->map[i].out_channel_idx = i;
00272 }
00273 } else if (out_ch_mask && out_ch_mask != fmt) {
00274 av_get_channel_layout_string(buf, sizeof(buf), 0, out_ch_mask);
00275 av_log(ctx, AV_LOG_ERROR,
00276 "Output channel layout '%s' does not match the list of channel mapped: '%s'.\n",
00277 s->channel_layout_str, buf);
00278 ret = AVERROR(EINVAL);
00279 goto fail;
00280 } else if (s->nch != av_get_channel_layout_nb_channels(fmt)) {
00281 av_log(ctx, AV_LOG_ERROR,
00282 "Output channel layout %s does not match the number of channels mapped %d.\n",
00283 s->channel_layout_str, s->nch);
00284 ret = AVERROR(EINVAL);
00285 goto fail;
00286 }
00287 s->output_layout = fmt;
00288 }
00289 ff_add_channel_layout(&s->channel_layouts, s->output_layout);
00290
00291 if (mode == MAP_PAIR_INT_STR || mode == MAP_PAIR_STR_STR) {
00292 for (i = 0; i < s->nch; i++) {
00293 s->map[i].out_channel_idx = av_get_channel_layout_channel_index(
00294 s->output_layout, s->map[i].out_channel);
00295 }
00296 }
00297
00298 fail:
00299 av_opt_free(s);
00300 return ret;
00301 }
00302
00303 static int channelmap_query_formats(AVFilterContext *ctx)
00304 {
00305 ChannelMapContext *s = ctx->priv;
00306
00307 ff_set_common_formats(ctx, ff_planar_sample_fmts());
00308 ff_set_common_samplerates(ctx, ff_all_samplerates());
00309 ff_channel_layouts_ref(ff_all_channel_layouts(), &ctx->inputs[0]->out_channel_layouts);
00310 ff_channel_layouts_ref(s->channel_layouts, &ctx->outputs[0]->in_channel_layouts);
00311
00312 return 0;
00313 }
00314
00315 static int channelmap_filter_frame(AVFilterLink *inlink, AVFilterBufferRef *buf)
00316 {
00317 AVFilterContext *ctx = inlink->dst;
00318 AVFilterLink *outlink = ctx->outputs[0];
00319 const ChannelMapContext *s = ctx->priv;
00320 const int nch_in = av_get_channel_layout_nb_channels(inlink->channel_layout);
00321 const int nch_out = s->nch;
00322 int ch;
00323 uint8_t *source_planes[MAX_CH];
00324
00325 memcpy(source_planes, buf->extended_data,
00326 nch_in * sizeof(source_planes[0]));
00327
00328 if (nch_out > nch_in) {
00329 if (nch_out > FF_ARRAY_ELEMS(buf->data)) {
00330 uint8_t **new_extended_data =
00331 av_mallocz(nch_out * sizeof(*buf->extended_data));
00332 if (!new_extended_data) {
00333 avfilter_unref_buffer(buf);
00334 return AVERROR(ENOMEM);
00335 }
00336 if (buf->extended_data == buf->data) {
00337 buf->extended_data = new_extended_data;
00338 } else {
00339 av_free(buf->extended_data);
00340 buf->extended_data = new_extended_data;
00341 }
00342 } else if (buf->extended_data != buf->data) {
00343 av_free(buf->extended_data);
00344 buf->extended_data = buf->data;
00345 }
00346 }
00347
00348 for (ch = 0; ch < nch_out; ch++) {
00349 buf->extended_data[s->map[ch].out_channel_idx] =
00350 source_planes[s->map[ch].in_channel_idx];
00351 }
00352
00353 if (buf->data != buf->extended_data)
00354 memcpy(buf->data, buf->extended_data,
00355 FFMIN(FF_ARRAY_ELEMS(buf->data), nch_out) * sizeof(buf->data[0]));
00356
00357 return ff_filter_frame(outlink, buf);
00358 }
00359
00360 static int channelmap_config_input(AVFilterLink *inlink)
00361 {
00362 AVFilterContext *ctx = inlink->dst;
00363 ChannelMapContext *s = ctx->priv;
00364 int i, err = 0;
00365 const char *channel_name;
00366 char layout_name[256];
00367
00368 if (s->mode == MAP_PAIR_STR_INT || s->mode == MAP_PAIR_STR_STR) {
00369 for (i = 0; i < s->nch; i++) {
00370 s->map[i].in_channel_idx = av_get_channel_layout_channel_index(
00371 inlink->channel_layout, s->map[i].in_channel);
00372 if (s->map[i].in_channel_idx < 0) {
00373 channel_name = av_get_channel_name(s->map[i].in_channel);
00374 av_get_channel_layout_string(layout_name, sizeof(layout_name),
00375 0, inlink->channel_layout);
00376 av_log(ctx, AV_LOG_ERROR,
00377 "input channel '%s' not available from input layout '%s'\n",
00378 channel_name, layout_name);
00379 err = AVERROR(EINVAL);
00380 }
00381 }
00382 }
00383
00384 return err;
00385 }
00386
00387 static const AVFilterPad avfilter_af_channelmap_inputs[] = {
00388 {
00389 .name = "default",
00390 .type = AVMEDIA_TYPE_AUDIO,
00391 .min_perms = AV_PERM_READ | AV_PERM_WRITE,
00392 .filter_frame = channelmap_filter_frame,
00393 .config_props = channelmap_config_input
00394 },
00395 { NULL }
00396 };
00397
00398 static const AVFilterPad avfilter_af_channelmap_outputs[] = {
00399 {
00400 .name = "default",
00401 .type = AVMEDIA_TYPE_AUDIO
00402 },
00403 { NULL }
00404 };
00405
00406 AVFilter avfilter_af_channelmap = {
00407 .name = "channelmap",
00408 .description = NULL_IF_CONFIG_SMALL("Remap audio channels."),
00409 .init = channelmap_init,
00410 .query_formats = channelmap_query_formats,
00411 .priv_size = sizeof(ChannelMapContext),
00412
00413 .inputs = avfilter_af_channelmap_inputs,
00414 .outputs = avfilter_af_channelmap_outputs,
00415 .priv_class = &channelmap_class,
00416 };