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, ',') < 0) {
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 };
uint8_t ** extended_data
pointers to the data planes/channels.
Definition: avfilter.h:156
uint64_t av_get_default_channel_layout(int nb_channels)
Return default channel layout for a given number of channels.
static const AVOption options[]
Definition: af_channelmap.c:71
uint64_t in_channel
layout describing the input channel
Definition: af_channelmap.c:41
AVOption.
Definition: opt.h:233
#define OFFSET(x)
Definition: af_channelmap.c:69
static const AVFilterPad outputs[]
Definition: af_ashowinfo.c:122
void av_opt_set_defaults(void *s)
Set the values of all AVOption fields to their default values.
Definition: opt.c:505
int ff_filter_frame(AVFilterLink *link, AVFilterBufferRef *frame)
Send a frame of data to the next filter.
Definition: avfilter.c:459
int av_set_options_string(void *ctx, const char *opts, const char *key_val_sep, const char *pairs_sep)
Parse the key/value pairs list in opts.
Definition: opt.c:587
uint64_t output_layout
Definition: af_channelmap.c:63
AVFilter avfilter_af_channelmap
void avfilter_unref_buffer(AVFilterBufferRef *ref)
Remove a reference to a buffer.
Definition: buffer.c:75
const char * name
Pad name.
Definition: internal.h:39
const char * class_name
The name of the class; usually it is the same name as the context structure type to which the AVClass...
Definition: log.h:38
AVFilterLink ** inputs
array of pointers to input links
Definition: avfilter.h:426
uint8_t
AVOptions.
enum MappingMode mode
Definition: af_channelmap.c:66
char * channel_layout_str
Definition: af_channelmap.c:62
void ff_channel_layouts_ref(AVFilterChannelLayouts *f, AVFilterChannelLayouts **ref)
Add *ref as a new reference to f.
Definition: formats.c:257
static int channelmap_query_formats(AVFilterContext *ctx)
int av_get_channel_layout_channel_index(uint64_t channel_layout, uint64_t channel)
Get the index of a channel in channel_layout.
void ff_set_common_formats(AVFilterContext *ctx, AVFilterFormats *formats)
A helper for query_formats() which sets all links to the same list of formats.
Definition: formats.c:375
A filter pad used for either input or output.
Definition: internal.h:33
void av_free(void *ptr)
Free a memory block which has been allocated with av_malloc(z)() or av_realloc(). ...
Definition: mem.c:139
AVFilterChannelLayouts * channel_layouts
Definition: af_channelmap.c:60
struct ChannelMapContext ChannelMapContext
int ff_add_channel_layout(AVFilterChannelLayouts **l, uint64_t channel_layout)
Definition: formats.c:204
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification. ...
Definition: internal.h:88
void * priv
private data for use by the filter
Definition: avfilter.h:439
int av_get_channel_layout_nb_channels(uint64_t channel_layout)
Return the number of channels in the channel layout.
void av_log(void *avcl, int level, const char *fmt,...)
Definition: log.c:146
const char * av_get_channel_name(uint64_t channel)
Get the name of a given channel.
#define A
Definition: af_channelmap.c:70
static char * split(char *message, char delim)
Definition: af_channelmap.c:86
MappingMode
Definition: af_channelmap.c:47
audio channel layout utility functions
static av_cold int channelmap_init(AVFilterContext *ctx, const char *args)
AVFilterFormats * ff_planar_sample_fmts(void)
Construct a formats list containing all planar sample formats.
Definition: formats.c:226
static int channelmap_filter_frame(AVFilterLink *inlink, AVFilterBufferRef *buf)
LIBAVUTIL_VERSION_INT
Definition: eval.c:52
AVFilterChannelLayouts * ff_all_channel_layouts(void)
Construct an empty AVFilterChannelLayouts/AVFilterFormats struct – representing any channel layout/sa...
Definition: formats.c:244
int in_channel_idx
index of in_channel in the input stream data
Definition: af_channelmap.c:43
A reference to an AVFilterBuffer.
Definition: avfilter.h:139
NULL
Definition: eval.c:52
av_default_item_name
Definition: dnxhdenc.c:43
static const AVClass channelmap_class
Definition: af_channelmap.c:79
struct ChannelMap map[MAX_CH]
Definition: af_channelmap.c:64
Describe the class of an AVClass context structure.
Definition: log.h:33
Filter definition.
Definition: avfilter.h:371
static const AVFilterPad inputs[]
Definition: af_ashowinfo.c:110
uint64_t out_channel
layout describing the output channel
Definition: af_channelmap.c:42
const AVClass * class
Definition: af_channelmap.c:59
const char * name
filter name
Definition: avfilter.h:372
AVFilterLink ** outputs
array of pointers to output links
Definition: avfilter.h:433
AVFilterFormats * ff_all_samplerates(void)
Definition: formats.c:238
static int channelmap_config_input(AVFilterLink *inlink)
static const AVFilterPad avfilter_af_channelmap_inputs[]
static int get_channel_idx(char **map, int *ch, char delim, int max_ch)
Definition: af_channelmap.c:93
void ff_set_common_samplerates(AVFilterContext *ctx, AVFilterFormats *samplerates)
Definition: formats.c:363
void av_opt_free(void *obj)
Free all string and binary options in obj.
Definition: opt.c:607
#define MAX_CH
Definition: af_channelmap.c:57
common internal and external API header
int len
uint8_t * data[8]
picture/audio data for each plane
Definition: avfilter.h:141
uint64_t av_get_channel_layout(const char *name)
Return a channel layout id that matches name, or 0 if no match is found.
static int get_channel(char **map, uint64_t *ch, char delim)
An instance of a filter.
Definition: avfilter.h:418
static const AVFilterPad avfilter_af_channelmap_outputs[]
int nb_channels
int out_channel_idx
Definition: af_channelmap.c:44
internal API functions
void * av_mallocz(size_t size)
Allocate a block of size bytes with alignment suitable for all memory accesses (including vectors if ...
Definition: mem.c:158
void av_get_channel_layout_string(char *buf, int buf_size, int nb_channels, uint64_t channel_layout)
Return a description of a channel layout.