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/audioconvert.h"
00029 #include "libavutil/avstring.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 enum mode;
00129 int map_entries = 0;
00130 char buf[256];
00131 enum MappingMode mode;
00132 uint64_t out_ch_mask = 0;
00133 int i;
00134
00135 if (!args) {
00136 av_log(ctx, AV_LOG_ERROR, "No parameters supplied.\n");
00137 return AVERROR(EINVAL);
00138 }
00139
00140 s->class = &channelmap_class;
00141 av_opt_set_defaults(s);
00142
00143 if ((ret = av_set_options_string(s, args, "=", ":")) < 0)
00144 return ret;
00145
00146 mapping = s->mapping_str;
00147
00148 if (!mapping) {
00149 mode = MAP_NONE;
00150 } else {
00151 char *dash = strchr(mapping, '-');
00152 if (!dash) {
00153 if (isdigit(*mapping))
00154 mode = MAP_ONE_INT;
00155 else
00156 mode = MAP_ONE_STR;
00157 } else if (isdigit(*mapping)) {
00158 if (isdigit(*(dash+1)))
00159 mode = MAP_PAIR_INT_INT;
00160 else
00161 mode = MAP_PAIR_INT_STR;
00162 } else {
00163 if (isdigit(*(dash+1)))
00164 mode = MAP_PAIR_STR_INT;
00165 else
00166 mode = MAP_PAIR_STR_STR;
00167 }
00168 }
00169
00170 if (mode != MAP_NONE) {
00171 char *comma = mapping;
00172 map_entries = 1;
00173 while ((comma = strchr(comma, ','))) {
00174 if (*++comma)
00175 map_entries++;
00176 }
00177 }
00178
00179 if (map_entries > MAX_CH) {
00180 av_log(ctx, AV_LOG_ERROR, "Too many channels mapped: '%d'.\n", map_entries);
00181 ret = AVERROR(EINVAL);
00182 goto fail;
00183 }
00184
00185 for (i = 0; i < map_entries; i++) {
00186 int in_ch_idx = -1, out_ch_idx = -1;
00187 uint64_t in_ch = 0, out_ch = 0;
00188 static const char err[] = "Failed to parse channel map\n";
00189 switch (mode) {
00190 case MAP_ONE_INT:
00191 if (get_channel_idx(&mapping, &in_ch_idx, ',', MAX_CH) < 0) {
00192 ret = AVERROR(EINVAL);
00193 av_log(ctx, AV_LOG_ERROR, err);
00194 goto fail;
00195 }
00196 s->map[i].in_channel_idx = in_ch_idx;
00197 s->map[i].out_channel_idx = i;
00198 break;
00199 case MAP_ONE_STR:
00200 if (!get_channel(&mapping, &in_ch, ',')) {
00201 av_log(ctx, AV_LOG_ERROR, err);
00202 ret = AVERROR(EINVAL);
00203 goto fail;
00204 }
00205 s->map[i].in_channel = in_ch;
00206 s->map[i].out_channel_idx = i;
00207 break;
00208 case MAP_PAIR_INT_INT:
00209 if (get_channel_idx(&mapping, &in_ch_idx, '-', MAX_CH) < 0 ||
00210 get_channel_idx(&mapping, &out_ch_idx, ',', MAX_CH) < 0) {
00211 av_log(ctx, AV_LOG_ERROR, err);
00212 ret = AVERROR(EINVAL);
00213 goto fail;
00214 }
00215 s->map[i].in_channel_idx = in_ch_idx;
00216 s->map[i].out_channel_idx = out_ch_idx;
00217 break;
00218 case MAP_PAIR_INT_STR:
00219 if (get_channel_idx(&mapping, &in_ch_idx, '-', MAX_CH) < 0 ||
00220 get_channel(&mapping, &out_ch, ',') < 0 ||
00221 out_ch & out_ch_mask) {
00222 av_log(ctx, AV_LOG_ERROR, err);
00223 ret = AVERROR(EINVAL);
00224 goto fail;
00225 }
00226 s->map[i].in_channel_idx = in_ch_idx;
00227 s->map[i].out_channel = out_ch;
00228 out_ch_mask |= out_ch;
00229 break;
00230 case MAP_PAIR_STR_INT:
00231 if (get_channel(&mapping, &in_ch, '-') < 0 ||
00232 get_channel_idx(&mapping, &out_ch_idx, ',', MAX_CH) < 0) {
00233 av_log(ctx, AV_LOG_ERROR, err);
00234 ret = AVERROR(EINVAL);
00235 goto fail;
00236 }
00237 s->map[i].in_channel = in_ch;
00238 s->map[i].out_channel_idx = out_ch_idx;
00239 break;
00240 case MAP_PAIR_STR_STR:
00241 if (get_channel(&mapping, &in_ch, '-') < 0 ||
00242 get_channel(&mapping, &out_ch, ',') < 0 ||
00243 out_ch & out_ch_mask) {
00244 av_log(ctx, AV_LOG_ERROR, err);
00245 ret = AVERROR(EINVAL);
00246 goto fail;
00247 }
00248 s->map[i].in_channel = in_ch;
00249 s->map[i].out_channel = out_ch;
00250 out_ch_mask |= out_ch;
00251 break;
00252 }
00253 }
00254 s->mode = mode;
00255 s->nch = map_entries;
00256 s->output_layout = out_ch_mask ? out_ch_mask :
00257 av_get_default_channel_layout(map_entries);
00258
00259 if (s->channel_layout_str) {
00260 uint64_t fmt;
00261 if ((fmt = av_get_channel_layout(s->channel_layout_str)) == 0) {
00262 av_log(ctx, AV_LOG_ERROR, "Error parsing channel layout: '%s'.\n",
00263 s->channel_layout_str);
00264 ret = AVERROR(EINVAL);
00265 goto fail;
00266 }
00267 if (mode == MAP_NONE) {
00268 int i;
00269 s->nch = av_get_channel_layout_nb_channels(fmt);
00270 for (i = 0; i < s->nch; i++) {
00271 s->map[i].in_channel_idx = i;
00272 s->map[i].out_channel_idx = i;
00273 }
00274 } else if (out_ch_mask && out_ch_mask != fmt) {
00275 av_get_channel_layout_string(buf, sizeof(buf), 0, out_ch_mask);
00276 av_log(ctx, AV_LOG_ERROR,
00277 "Output channel layout '%s' does not match the list of channel mapped: '%s'.\n",
00278 s->channel_layout_str, buf);
00279 ret = AVERROR(EINVAL);
00280 goto fail;
00281 } else if (s->nch != av_get_channel_layout_nb_channels(fmt)) {
00282 av_log(ctx, AV_LOG_ERROR,
00283 "Output channel layout %s does not match the number of channels mapped %d.\n",
00284 s->channel_layout_str, s->nch);
00285 ret = AVERROR(EINVAL);
00286 goto fail;
00287 }
00288 s->output_layout = fmt;
00289 }
00290 ff_add_channel_layout(&s->channel_layouts, s->output_layout);
00291
00292 if (mode == MAP_PAIR_INT_STR || mode == MAP_PAIR_STR_STR) {
00293 for (i = 0; i < s->nch; i++) {
00294 s->map[i].out_channel_idx = av_get_channel_layout_channel_index(
00295 s->output_layout, s->map[i].out_channel);
00296 }
00297 }
00298
00299 fail:
00300 av_opt_free(s);
00301 return ret;
00302 }
00303
00304 static int channelmap_query_formats(AVFilterContext *ctx)
00305 {
00306 ChannelMapContext *s = ctx->priv;
00307
00308 ff_set_common_formats(ctx, ff_planar_sample_fmts());
00309 ff_set_common_samplerates(ctx, ff_all_samplerates());
00310 ff_channel_layouts_ref(ff_all_channel_layouts(), &ctx->inputs[0]->out_channel_layouts);
00311 ff_channel_layouts_ref(s->channel_layouts, &ctx->outputs[0]->in_channel_layouts);
00312
00313 return 0;
00314 }
00315
00316 static int channelmap_filter_samples(AVFilterLink *inlink, AVFilterBufferRef *buf)
00317 {
00318 AVFilterContext *ctx = inlink->dst;
00319 AVFilterLink *outlink = ctx->outputs[0];
00320 const ChannelMapContext *s = ctx->priv;
00321 const int nch_in = av_get_channel_layout_nb_channels(inlink->channel_layout);
00322 const int nch_out = s->nch;
00323 int ch;
00324 uint8_t *source_planes[MAX_CH];
00325
00326 memcpy(source_planes, buf->extended_data,
00327 nch_in * sizeof(source_planes[0]));
00328
00329 if (nch_out > nch_in) {
00330 if (nch_out > FF_ARRAY_ELEMS(buf->data)) {
00331 uint8_t **new_extended_data =
00332 av_mallocz(nch_out * sizeof(*buf->extended_data));
00333 if (!new_extended_data) {
00334 avfilter_unref_buffer(buf);
00335 return AVERROR(ENOMEM);
00336 }
00337 if (buf->extended_data == buf->data) {
00338 buf->extended_data = new_extended_data;
00339 } else {
00340 buf->extended_data = new_extended_data;
00341 av_free(buf->extended_data);
00342 }
00343 } else if (buf->extended_data != buf->data) {
00344 av_free(buf->extended_data);
00345 buf->extended_data = buf->data;
00346 }
00347 }
00348
00349 for (ch = 0; ch < nch_out; ch++) {
00350 buf->extended_data[s->map[ch].out_channel_idx] =
00351 source_planes[s->map[ch].in_channel_idx];
00352 }
00353
00354 if (buf->data != buf->extended_data)
00355 memcpy(buf->data, buf->extended_data,
00356 FFMIN(FF_ARRAY_ELEMS(buf->data), nch_out) * sizeof(buf->data[0]));
00357
00358 return ff_filter_samples(outlink, buf);
00359 }
00360
00361 static int channelmap_config_input(AVFilterLink *inlink)
00362 {
00363 AVFilterContext *ctx = inlink->dst;
00364 ChannelMapContext *s = ctx->priv;
00365 int i, err = 0;
00366 const char *channel_name;
00367 char layout_name[256];
00368
00369 if (s->mode == MAP_PAIR_STR_INT || s->mode == MAP_PAIR_STR_STR) {
00370 for (i = 0; i < s->nch; i++) {
00371 s->map[i].in_channel_idx = av_get_channel_layout_channel_index(
00372 inlink->channel_layout, s->map[i].in_channel);
00373 if (s->map[i].in_channel_idx < 0) {
00374 channel_name = av_get_channel_name(s->map[i].in_channel);
00375 av_get_channel_layout_string(layout_name, sizeof(layout_name),
00376 0, inlink->channel_layout);
00377 av_log(ctx, AV_LOG_ERROR,
00378 "input channel '%s' not available from input layout '%s'\n",
00379 channel_name, layout_name);
00380 err = AVERROR(EINVAL);
00381 }
00382 }
00383 }
00384
00385 return err;
00386 }
00387
00388 AVFilter avfilter_af_channelmap = {
00389 .name = "channelmap",
00390 .description = NULL_IF_CONFIG_SMALL("Remap audio channels."),
00391 .init = channelmap_init,
00392 .query_formats = channelmap_query_formats,
00393 .priv_size = sizeof(ChannelMapContext),
00394
00395 .inputs = (const AVFilterPad[]) {{ .name = "default",
00396 .type = AVMEDIA_TYPE_AUDIO,
00397 .min_perms = AV_PERM_READ | AV_PERM_WRITE,
00398 .filter_samples = channelmap_filter_samples,
00399 .config_props = channelmap_config_input },
00400 { .name = NULL }},
00401 .outputs = (const AVFilterPad[]) {{ .name = "default",
00402 .type = AVMEDIA_TYPE_AUDIO },
00403 { .name = NULL }},
00404 .priv_class = &channelmap_class,
00405 };