af_channelmap.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2012 Google, Inc.
3  *
4  * This file is part of Libav.
5  *
6  * Libav is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * Libav is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with Libav; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19  */
20 
26 #include <ctype.h>
27 
28 #include "libavutil/avstring.h"
30 #include "libavutil/common.h"
31 #include "libavutil/mathematics.h"
32 #include "libavutil/opt.h"
33 #include "libavutil/samplefmt.h"
34 
35 #include "audio.h"
36 #include "avfilter.h"
37 #include "formats.h"
38 #include "internal.h"
39 
40 struct ChannelMap {
41  uint64_t in_channel;
42  uint64_t out_channel;
45 };
46 
55 };
56 
57 #define MAX_CH 64
58 typedef struct ChannelMapContext {
59  const AVClass *class;
61  char *mapping_str;
63  uint64_t output_layout;
65  int nch;
68 
69 #define OFFSET(x) offsetof(ChannelMapContext, x)
70 #define A AV_OPT_FLAG_AUDIO_PARAM
71 static const AVOption options[] = {
72  { "map", "A comma-separated list of input channel numbers in output order.",
73  OFFSET(mapping_str), AV_OPT_TYPE_STRING, .flags = A },
74  { "channel_layout", "Output channel layout.",
75  OFFSET(channel_layout_str), AV_OPT_TYPE_STRING, .flags = A },
76  { NULL },
77 };
78 
79 static const AVClass channelmap_class = {
80  .class_name = "channel map filter",
81  .item_name = av_default_item_name,
82  .option = options,
83  .version = LIBAVUTIL_VERSION_INT,
84 };
85 
86 static char* split(char *message, char delim) {
87  char *next = strchr(message, delim);
88  if (next)
89  *next++ = '\0';
90  return next;
91 }
92 
93 static int get_channel_idx(char **map, int *ch, char delim, int max_ch)
94 {
95  char *next = split(*map, delim);
96  int len;
97  int n = 0;
98  if (!next && delim == '-')
99  return AVERROR(EINVAL);
100  len = strlen(*map);
101  sscanf(*map, "%d%n", ch, &n);
102  if (n != len)
103  return AVERROR(EINVAL);
104  if (*ch < 0 || *ch > max_ch)
105  return AVERROR(EINVAL);
106  *map = next;
107  return 0;
108 }
109 
110 static int get_channel(char **map, uint64_t *ch, char delim)
111 {
112  char *next = split(*map, delim);
113  if (!next && delim == '-')
114  return AVERROR(EINVAL);
115  *ch = av_get_channel_layout(*map);
116  if (av_get_channel_layout_nb_channels(*ch) != 1)
117  return AVERROR(EINVAL);
118  *map = next;
119  return 0;
120 }
121 
122 static av_cold int channelmap_init(AVFilterContext *ctx, const char *args)
123 {
124  ChannelMapContext *s = ctx->priv;
125  int ret;
126  char *mapping;
127  int map_entries = 0;
128  char buf[256];
129  enum MappingMode mode;
130  uint64_t out_ch_mask = 0;
131  int i;
132 
133  if (!args) {
134  av_log(ctx, AV_LOG_ERROR, "No parameters supplied.\n");
135  return AVERROR(EINVAL);
136  }
137 
138  s->class = &channelmap_class;
140 
141  if ((ret = av_set_options_string(s, args, "=", ":")) < 0) {
142  av_log(ctx, AV_LOG_ERROR, "Error parsing options string '%s'.\n", args);
143  return ret;
144  }
145 
146  mapping = s->mapping_str;
147 
148  if (!mapping) {
149  mode = MAP_NONE;
150  } else {
151  char *dash = strchr(mapping, '-');
152  if (!dash) { // short mapping
153  if (isdigit(*mapping))
154  mode = MAP_ONE_INT;
155  else
156  mode = MAP_ONE_STR;
157  } else if (isdigit(*mapping)) {
158  if (isdigit(*(dash+1)))
159  mode = MAP_PAIR_INT_INT;
160  else
161  mode = MAP_PAIR_INT_STR;
162  } else {
163  if (isdigit(*(dash+1)))
164  mode = MAP_PAIR_STR_INT;
165  else
166  mode = MAP_PAIR_STR_STR;
167  }
168  }
169 
170  if (mode != MAP_NONE) {
171  char *comma = mapping;
172  map_entries = 1;
173  while ((comma = strchr(comma, ','))) {
174  if (*++comma) // Allow trailing comma
175  map_entries++;
176  }
177  }
178 
179  if (map_entries > MAX_CH) {
180  av_log(ctx, AV_LOG_ERROR, "Too many channels mapped: '%d'.\n", map_entries);
181  ret = AVERROR(EINVAL);
182  goto fail;
183  }
184 
185  for (i = 0; i < map_entries; i++) {
186  int in_ch_idx = -1, out_ch_idx = -1;
187  uint64_t in_ch = 0, out_ch = 0;
188  static const char err[] = "Failed to parse channel map\n";
189  switch (mode) {
190  case MAP_ONE_INT:
191  if (get_channel_idx(&mapping, &in_ch_idx, ',', MAX_CH) < 0) {
192  ret = AVERROR(EINVAL);
193  av_log(ctx, AV_LOG_ERROR, err);
194  goto fail;
195  }
196  s->map[i].in_channel_idx = in_ch_idx;
197  s->map[i].out_channel_idx = i;
198  break;
199  case MAP_ONE_STR:
200  if (!get_channel(&mapping, &in_ch, ',')) {
201  av_log(ctx, AV_LOG_ERROR, err);
202  ret = AVERROR(EINVAL);
203  goto fail;
204  }
205  s->map[i].in_channel = in_ch;
206  s->map[i].out_channel_idx = i;
207  break;
208  case MAP_PAIR_INT_INT:
209  if (get_channel_idx(&mapping, &in_ch_idx, '-', MAX_CH) < 0 ||
210  get_channel_idx(&mapping, &out_ch_idx, ',', MAX_CH) < 0) {
211  av_log(ctx, AV_LOG_ERROR, err);
212  ret = AVERROR(EINVAL);
213  goto fail;
214  }
215  s->map[i].in_channel_idx = in_ch_idx;
216  s->map[i].out_channel_idx = out_ch_idx;
217  break;
218  case MAP_PAIR_INT_STR:
219  if (get_channel_idx(&mapping, &in_ch_idx, '-', MAX_CH) < 0 ||
220  get_channel(&mapping, &out_ch, ',') < 0 ||
221  out_ch & out_ch_mask) {
222  av_log(ctx, AV_LOG_ERROR, err);
223  ret = AVERROR(EINVAL);
224  goto fail;
225  }
226  s->map[i].in_channel_idx = in_ch_idx;
227  s->map[i].out_channel = out_ch;
228  out_ch_mask |= out_ch;
229  break;
230  case MAP_PAIR_STR_INT:
231  if (get_channel(&mapping, &in_ch, '-') < 0 ||
232  get_channel_idx(&mapping, &out_ch_idx, ',', MAX_CH) < 0) {
233  av_log(ctx, AV_LOG_ERROR, err);
234  ret = AVERROR(EINVAL);
235  goto fail;
236  }
237  s->map[i].in_channel = in_ch;
238  s->map[i].out_channel_idx = out_ch_idx;
239  break;
240  case MAP_PAIR_STR_STR:
241  if (get_channel(&mapping, &in_ch, '-') < 0 ||
242  get_channel(&mapping, &out_ch, ',') < 0 ||
243  out_ch & out_ch_mask) {
244  av_log(ctx, AV_LOG_ERROR, err);
245  ret = AVERROR(EINVAL);
246  goto fail;
247  }
248  s->map[i].in_channel = in_ch;
249  s->map[i].out_channel = out_ch;
250  out_ch_mask |= out_ch;
251  break;
252  }
253  }
254  s->mode = mode;
255  s->nch = map_entries;
256  s->output_layout = out_ch_mask ? out_ch_mask :
257  av_get_default_channel_layout(map_entries);
258 
259  if (s->channel_layout_str) {
260  uint64_t fmt;
261  if ((fmt = av_get_channel_layout(s->channel_layout_str)) == 0) {
262  av_log(ctx, AV_LOG_ERROR, "Error parsing channel layout: '%s'.\n",
263  s->channel_layout_str);
264  ret = AVERROR(EINVAL);
265  goto fail;
266  }
267  if (mode == MAP_NONE) {
268  int i;
270  for (i = 0; i < s->nch; i++) {
271  s->map[i].in_channel_idx = i;
272  s->map[i].out_channel_idx = i;
273  }
274  } else if (out_ch_mask && out_ch_mask != fmt) {
275  av_get_channel_layout_string(buf, sizeof(buf), 0, out_ch_mask);
276  av_log(ctx, AV_LOG_ERROR,
277  "Output channel layout '%s' does not match the list of channel mapped: '%s'.\n",
278  s->channel_layout_str, buf);
279  ret = AVERROR(EINVAL);
280  goto fail;
281  } else if (s->nch != av_get_channel_layout_nb_channels(fmt)) {
282  av_log(ctx, AV_LOG_ERROR,
283  "Output channel layout %s does not match the number of channels mapped %d.\n",
284  s->channel_layout_str, s->nch);
285  ret = AVERROR(EINVAL);
286  goto fail;
287  }
288  s->output_layout = fmt;
289  }
291 
292  if (mode == MAP_PAIR_INT_STR || mode == MAP_PAIR_STR_STR) {
293  for (i = 0; i < s->nch; i++) {
295  s->output_layout, s->map[i].out_channel);
296  }
297  }
298 
299 fail:
300  av_opt_free(s);
301  return ret;
302 }
303 
305 {
306  ChannelMapContext *s = ctx->priv;
307 
312 
313  return 0;
314 }
315 
317 {
318  AVFilterContext *ctx = inlink->dst;
319  AVFilterLink *outlink = ctx->outputs[0];
320  const ChannelMapContext *s = ctx->priv;
321  const int nch_in = av_get_channel_layout_nb_channels(inlink->channel_layout);
322  const int nch_out = s->nch;
323  int ch;
324  uint8_t *source_planes[MAX_CH];
325 
326  memcpy(source_planes, buf->extended_data,
327  nch_in * sizeof(source_planes[0]));
328 
329  if (nch_out > nch_in) {
330  if (nch_out > FF_ARRAY_ELEMS(buf->data)) {
331  uint8_t **new_extended_data =
332  av_mallocz(nch_out * sizeof(*buf->extended_data));
333  if (!new_extended_data) {
335  return AVERROR(ENOMEM);
336  }
337  if (buf->extended_data == buf->data) {
338  buf->extended_data = new_extended_data;
339  } else {
340  av_free(buf->extended_data);
341  buf->extended_data = new_extended_data;
342  }
343  } else if (buf->extended_data != buf->data) {
344  av_free(buf->extended_data);
345  buf->extended_data = buf->data;
346  }
347  }
348 
349  for (ch = 0; ch < nch_out; ch++) {
350  buf->extended_data[s->map[ch].out_channel_idx] =
351  source_planes[s->map[ch].in_channel_idx];
352  }
353 
354  if (buf->data != buf->extended_data)
355  memcpy(buf->data, buf->extended_data,
356  FFMIN(FF_ARRAY_ELEMS(buf->data), nch_out) * sizeof(buf->data[0]));
357 
358  return ff_filter_frame(outlink, buf);
359 }
360 
362 {
363  AVFilterContext *ctx = inlink->dst;
364  ChannelMapContext *s = ctx->priv;
366  int i, err = 0;
367  const char *channel_name;
368  char layout_name[256];
369 
370  for (i = 0; i < s->nch; i++) {
371  if (s->mode == MAP_PAIR_STR_INT || s->mode == MAP_PAIR_STR_STR) {
373  inlink->channel_layout, s->map[i].in_channel);
374  }
375 
376  if (s->map[i].in_channel_idx < 0 ||
377  s->map[i].in_channel_idx >= nb_channels) {
378  av_get_channel_layout_string(layout_name, sizeof(layout_name),
379  0, inlink->channel_layout);
380  if (s->map[i].in_channel) {
381  channel_name = av_get_channel_name(s->map[i].in_channel);
382  av_log(ctx, AV_LOG_ERROR,
383  "input channel '%s' not available from input layout '%s'\n",
384  channel_name, layout_name);
385  } else {
386  av_log(ctx, AV_LOG_ERROR,
387  "input channel #%d not available from input layout '%s'\n",
388  s->map[i].in_channel_idx, layout_name);
389  }
390  err = AVERROR(EINVAL);
391  }
392  }
393 
394  return err;
395 }
396 
398  {
399  .name = "default",
400  .type = AVMEDIA_TYPE_AUDIO,
401  .filter_frame = channelmap_filter_frame,
402  .config_props = channelmap_config_input
403  },
404  { NULL }
405 };
406 
408  {
409  .name = "default",
410  .type = AVMEDIA_TYPE_AUDIO
411  },
412  { NULL }
413 };
414 
416  .name = "channelmap",
417  .description = NULL_IF_CONFIG_SMALL("Remap audio channels."),
418  .init = channelmap_init,
419  .query_formats = channelmap_query_formats,
420  .priv_size = sizeof(ChannelMapContext),
421 
422  .inputs = avfilter_af_channelmap_inputs,
423  .outputs = avfilter_af_channelmap_outputs,
424 };