af_channelmap.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2012 Google, Inc.
3  *
4  * This file is part of FFmpeg.
5  *
6  * FFmpeg 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  * FFmpeg 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 FFmpeg; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19  */
20 
21 /**
22  * @file
23  * audio channel mapping filter
24  */
25 
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;
64  struct ChannelMap map[MAX_CH];
65  int nch;
68 
69 #define OFFSET(x) offsetof(ChannelMapContext, x)
70 #define A AV_OPT_FLAG_AUDIO_PARAM
71 #define F AV_OPT_FLAG_FILTERING_PARAM
72 static const AVOption options[] = {
73  { "map", "A comma-separated list of input channel numbers in output order.",
74  OFFSET(mapping_str), AV_OPT_TYPE_STRING, .flags = A|F },
75  { "channel_layout", "Output channel layout.",
76  OFFSET(channel_layout_str), AV_OPT_TYPE_STRING, .flags = A|F },
77  { NULL },
78 };
79 
80 static const AVClass channelmap_class = {
81  .class_name = "channel map filter",
82  .item_name = av_default_item_name,
83  .option = options,
84  .version = LIBAVUTIL_VERSION_INT,
85 };
86 
87 static char* split(char *message, char delim) {
88  char *next = strchr(message, delim);
89  if (next)
90  *next++ = '\0';
91  return next;
92 }
93 
94 static int get_channel_idx(char **map, int *ch, char delim, int max_ch)
95 {
96  char *next = split(*map, delim);
97  int len;
98  int n = 0;
99  if (!next && delim == '-')
100  return AVERROR(EINVAL);
101  len = strlen(*map);
102  sscanf(*map, "%d%n", ch, &n);
103  if (n != len)
104  return AVERROR(EINVAL);
105  if (*ch < 0 || *ch > max_ch)
106  return AVERROR(EINVAL);
107  *map = next;
108  return 0;
109 }
110 
111 static int get_channel(char **map, uint64_t *ch, char delim)
112 {
113  char *next = split(*map, delim);
114  if (!next && delim == '-')
115  return AVERROR(EINVAL);
116  *ch = av_get_channel_layout(*map);
117  if (av_get_channel_layout_nb_channels(*ch) != 1)
118  return AVERROR(EINVAL);
119  *map = next;
120  return 0;
121 }
122 
124 {
125  ChannelMapContext *s = ctx->priv;
126  int ret = 0;
127  char *mapping, separator = '|';
128  int map_entries = 0;
129  char buf[256];
130  enum MappingMode mode;
131  uint64_t out_ch_mask = 0;
132  int i;
133 
134  mapping = s->mapping_str;
135 
136  if (!mapping) {
137  mode = MAP_NONE;
138  } else {
139  char *dash = strchr(mapping, '-');
140  if (!dash) { // short mapping
141  if (av_isdigit(*mapping))
142  mode = MAP_ONE_INT;
143  else
144  mode = MAP_ONE_STR;
145  } else if (av_isdigit(*mapping)) {
146  if (av_isdigit(*(dash+1)))
147  mode = MAP_PAIR_INT_INT;
148  else
149  mode = MAP_PAIR_INT_STR;
150  } else {
151  if (av_isdigit(*(dash+1)))
152  mode = MAP_PAIR_STR_INT;
153  else
154  mode = MAP_PAIR_STR_STR;
155  }
156 #if FF_API_OLD_FILTER_OPTS
157  if (strchr(mapping, ',')) {
158  av_log(ctx, AV_LOG_WARNING, "This syntax is deprecated, use "
159  "'|' to separate the mappings.\n");
160  separator = ',';
161  }
162 #endif
163  }
164 
165  if (mode != MAP_NONE) {
166  char *sep = mapping;
167  map_entries = 1;
168  while ((sep = strchr(sep, separator))) {
169  if (*++sep) // Allow trailing comma
170  map_entries++;
171  }
172  }
173 
174  if (map_entries > MAX_CH) {
175  av_log(ctx, AV_LOG_ERROR, "Too many channels mapped: '%d'.\n", map_entries);
176  ret = AVERROR(EINVAL);
177  goto fail;
178  }
179 
180  for (i = 0; i < map_entries; i++) {
181  int in_ch_idx = -1, out_ch_idx = -1;
182  uint64_t in_ch = 0, out_ch = 0;
183  static const char err[] = "Failed to parse channel map\n";
184  switch (mode) {
185  case MAP_ONE_INT:
186  if (get_channel_idx(&mapping, &in_ch_idx, separator, MAX_CH) < 0) {
187  ret = AVERROR(EINVAL);
188  av_log(ctx, AV_LOG_ERROR, err);
189  goto fail;
190  }
191  s->map[i].in_channel_idx = in_ch_idx;
192  s->map[i].out_channel_idx = i;
193  break;
194  case MAP_ONE_STR:
195  if (!get_channel(&mapping, &in_ch, separator)) {
196  av_log(ctx, AV_LOG_ERROR, err);
197  ret = AVERROR(EINVAL);
198  goto fail;
199  }
200  s->map[i].in_channel = in_ch;
201  s->map[i].out_channel_idx = i;
202  break;
203  case MAP_PAIR_INT_INT:
204  if (get_channel_idx(&mapping, &in_ch_idx, '-', MAX_CH) < 0 ||
205  get_channel_idx(&mapping, &out_ch_idx, separator, MAX_CH) < 0) {
206  av_log(ctx, AV_LOG_ERROR, err);
207  ret = AVERROR(EINVAL);
208  goto fail;
209  }
210  s->map[i].in_channel_idx = in_ch_idx;
211  s->map[i].out_channel_idx = out_ch_idx;
212  break;
213  case MAP_PAIR_INT_STR:
214  if (get_channel_idx(&mapping, &in_ch_idx, '-', MAX_CH) < 0 ||
215  get_channel(&mapping, &out_ch, separator) < 0 ||
216  out_ch & out_ch_mask) {
217  av_log(ctx, AV_LOG_ERROR, err);
218  ret = AVERROR(EINVAL);
219  goto fail;
220  }
221  s->map[i].in_channel_idx = in_ch_idx;
222  s->map[i].out_channel = out_ch;
223  out_ch_mask |= out_ch;
224  break;
225  case MAP_PAIR_STR_INT:
226  if (get_channel(&mapping, &in_ch, '-') < 0 ||
227  get_channel_idx(&mapping, &out_ch_idx, separator, MAX_CH) < 0) {
228  av_log(ctx, AV_LOG_ERROR, err);
229  ret = AVERROR(EINVAL);
230  goto fail;
231  }
232  s->map[i].in_channel = in_ch;
233  s->map[i].out_channel_idx = out_ch_idx;
234  break;
235  case MAP_PAIR_STR_STR:
236  if (get_channel(&mapping, &in_ch, '-') < 0 ||
237  get_channel(&mapping, &out_ch, separator) < 0 ||
238  out_ch & out_ch_mask) {
239  av_log(ctx, AV_LOG_ERROR, err);
240  ret = AVERROR(EINVAL);
241  goto fail;
242  }
243  s->map[i].in_channel = in_ch;
244  s->map[i].out_channel = out_ch;
245  out_ch_mask |= out_ch;
246  break;
247  }
248  }
249  s->mode = mode;
250  s->nch = map_entries;
251  s->output_layout = out_ch_mask ? out_ch_mask :
252  av_get_default_channel_layout(map_entries);
253 
254  if (s->channel_layout_str) {
255  uint64_t fmt;
256  if ((fmt = av_get_channel_layout(s->channel_layout_str)) == 0) {
257  av_log(ctx, AV_LOG_ERROR, "Error parsing channel layout: '%s'.\n",
258  s->channel_layout_str);
259  ret = AVERROR(EINVAL);
260  goto fail;
261  }
262  if (mode == MAP_NONE) {
263  int i;
265  for (i = 0; i < s->nch; i++) {
266  s->map[i].in_channel_idx = i;
267  s->map[i].out_channel_idx = i;
268  }
269  } else if (out_ch_mask && out_ch_mask != fmt) {
270  av_get_channel_layout_string(buf, sizeof(buf), 0, out_ch_mask);
271  av_log(ctx, AV_LOG_ERROR,
272  "Output channel layout '%s' does not match the list of channel mapped: '%s'.\n",
273  s->channel_layout_str, buf);
274  ret = AVERROR(EINVAL);
275  goto fail;
276  } else if (s->nch != av_get_channel_layout_nb_channels(fmt)) {
277  av_log(ctx, AV_LOG_ERROR,
278  "Output channel layout %s does not match the number of channels mapped %d.\n",
279  s->channel_layout_str, s->nch);
280  ret = AVERROR(EINVAL);
281  goto fail;
282  }
283  s->output_layout = fmt;
284  }
286 
287  if (mode == MAP_PAIR_INT_STR || mode == MAP_PAIR_STR_STR) {
288  for (i = 0; i < s->nch; i++) {
290  s->output_layout, s->map[i].out_channel);
291  }
292  }
293 
294 fail:
295  av_opt_free(s);
296  return ret;
297 }
298 
300 {
301  ChannelMapContext *s = ctx->priv;
302 
307 
308  return 0;
309 }
310 
312 {
313  AVFilterContext *ctx = inlink->dst;
314  AVFilterLink *outlink = ctx->outputs[0];
315  const ChannelMapContext *s = ctx->priv;
316  const int nch_in = av_get_channel_layout_nb_channels(inlink->channel_layout);
317  const int nch_out = s->nch;
318  int ch;
319  uint8_t *source_planes[MAX_CH];
320 
321  memcpy(source_planes, buf->extended_data,
322  nch_in * sizeof(source_planes[0]));
323 
324  if (nch_out > nch_in) {
325  if (nch_out > FF_ARRAY_ELEMS(buf->data)) {
326  uint8_t **new_extended_data =
327  av_mallocz(nch_out * sizeof(*buf->extended_data));
328  if (!new_extended_data) {
329  av_frame_free(&buf);
330  return AVERROR(ENOMEM);
331  }
332  if (buf->extended_data == buf->data) {
333  buf->extended_data = new_extended_data;
334  } else {
335  av_free(buf->extended_data);
336  buf->extended_data = new_extended_data;
337  }
338  } else if (buf->extended_data != buf->data) {
339  av_free(buf->extended_data);
340  buf->extended_data = buf->data;
341  }
342  }
343 
344  for (ch = 0; ch < nch_out; ch++) {
345  buf->extended_data[s->map[ch].out_channel_idx] =
346  source_planes[s->map[ch].in_channel_idx];
347  }
348 
349  if (buf->data != buf->extended_data)
350  memcpy(buf->data, buf->extended_data,
351  FFMIN(FF_ARRAY_ELEMS(buf->data), nch_out) * sizeof(buf->data[0]));
352 
353  return ff_filter_frame(outlink, buf);
354 }
355 
357 {
358  AVFilterContext *ctx = inlink->dst;
359  ChannelMapContext *s = ctx->priv;
361  int i, err = 0;
362  const char *channel_name;
363  char layout_name[256];
364 
365  for (i = 0; i < s->nch; i++) {
366  struct ChannelMap *m = &s->map[i];
367 
368  if (s->mode == MAP_PAIR_STR_INT || s->mode == MAP_PAIR_STR_STR) {
370  inlink->channel_layout, m->in_channel);
371  }
372 
373  if (m->in_channel_idx < 0 || m->in_channel_idx >= nb_channels) {
374  av_get_channel_layout_string(layout_name, sizeof(layout_name),
375  0, inlink->channel_layout);
376  if (m->in_channel) {
377  channel_name = av_get_channel_name(m->in_channel);
378  av_log(ctx, AV_LOG_ERROR,
379  "input channel '%s' not available from input layout '%s'\n",
380  channel_name, layout_name);
381  } else {
382  av_log(ctx, AV_LOG_ERROR,
383  "input channel #%d not available from input layout '%s'\n",
384  m->in_channel_idx, layout_name);
385  }
386  err = AVERROR(EINVAL);
387  }
388  }
389 
390  return err;
391 }
392 
394  {
395  .name = "default",
396  .type = AVMEDIA_TYPE_AUDIO,
397  .filter_frame = channelmap_filter_frame,
398  .config_props = channelmap_config_input,
399  .needs_writable = 1,
400  },
401  { NULL }
402 };
403 
405  {
406  .name = "default",
407  .type = AVMEDIA_TYPE_AUDIO
408  },
409  { NULL }
410 };
411 
413  .name = "channelmap",
414  .description = NULL_IF_CONFIG_SMALL("Remap audio channels."),
415  .init = channelmap_init,
416  .query_formats = channelmap_query_formats,
417  .priv_size = sizeof(ChannelMapContext),
418  .priv_class = &channelmap_class,
419 
420  .inputs = avfilter_af_channelmap_inputs,
421  .outputs = avfilter_af_channelmap_outputs,
422 };
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:205
const char * s
Definition: avisynth_c.h:668
static const AVOption options[]
Definition: af_channelmap.c:72
uint64_t in_channel
layout describing the input channel
Definition: af_channelmap.c:41
This structure describes decoded (raw) audio or video data.
Definition: frame.h:76
AVOption.
Definition: opt.h:251
av_default_item_name
const char * fmt
Definition: avisynth_c.h:669
#define OFFSET(x)
Definition: af_channelmap.c:69
static const AVFilterPad outputs[]
Definition: af_ashowinfo.c:117
external API header
#define AV_LOG_WARNING
Something somehow does not look correct.
Definition: log.h:154
uint64_t output_layout
Definition: af_channelmap.c:63
int av_isdigit(int c)
Locale-independent conversion of ASCII isdigit.
Definition: avstring.c:288
#define FF_ARRAY_ELEMS(a)
AVFilter avfilter_af_channelmap
const char * name
Pad name.
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:55
AVFilterLink ** inputs
array of pointers to input links
Definition: avfilter.h:532
uint8_t
it can be given away to ff_start_frame *A reference passed to ff_filter_frame(or the deprecated ff_start_frame) is given away and must no longer be used.*A reference created with avfilter_ref_buffer belongs to the code that created it.*A reference obtained with ff_get_video_buffer or ff_get_audio_buffer belongs to the code that requested it.*A reference given as return value by the get_video_buffer or get_audio_buffer method is given away and must no longer be used.Link reference fields---------------------The AVFilterLink structure has a few AVFilterBufferRef fields.The cur_buf and out_buf were used with the deprecated start_frame/draw_slice/end_frame API and should no longer be used.src_buf
#define av_cold
Definition: attributes.h:78
mode
Definition: f_perms.c:27
AVOptions.
window constants for m
enum MappingMode mode
Definition: af_channelmap.c:66
static int channelmap_filter_frame(AVFilterLink *inlink, AVFrame *buf)
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:427
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:545
A filter pad used for either input or output.
void av_free(void *ptr)
Free a memory block which has been allocated with av_malloc(z)() or av_realloc(). ...
Definition: mem.c:183
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:350
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification. ...
void * priv
private data for use by the filter
Definition: avfilter.h:545
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:246
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:87
MappingMode
Definition: af_channelmap.c:47
audio channel layout utility functions
#define FFMIN(a, b)
Definition: common.h:58
ret
Definition: avfilter.c:821
Harmonics mapping(fx) Xmag(ploc)
AVFilterFormats * ff_planar_sample_fmts(void)
Construct a formats list containing all planar sample formats.
Definition: formats.c:384
LIBAVUTIL_VERSION_INT
Definition: eval.c:55
AVFilterChannelLayouts * ff_all_channel_layouts(void)
Construct an empty AVFilterChannelLayouts/AVFilterFormats struct – representing any channel layout (...
Definition: formats.c:402
int in_channel_idx
index of in_channel in the input stream data
Definition: af_channelmap.c:43
A list of supported channel layouts.
Definition: formats.h:85
NULL
Definition: eval.c:55
static const AVClass channelmap_class
Definition: af_channelmap.c:80
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:148
void * buf
Definition: avisynth_c.h:594
struct ChannelMap map[MAX_CH]
Definition: af_channelmap.c:64
Describe the class of an AVClass context structure.
Definition: log.h:50
Filter definition.
Definition: avfilter.h:436
synthesis window for stochastic i
uint64_t out_channel
layout describing the output channel
Definition: af_channelmap.c:42
const char * name
filter name
Definition: avfilter.h:437
Filter the word “frame” indicates either a video frame or a group of audio as stored in an AVFilterBuffer structure Format for each input and each output the list of supported formats For video that means pixel format For audio that means channel sample they are references to shared objects When the negotiation mechanism computes the intersection of the formats supported at each end of a all references to both lists are replaced with a reference to the intersection And when a single format is eventually chosen for a link amongst the remaining all references to the list are updated That means that if a filter requires that its input and output have the same format amongst a supported all it has to do is use a reference to the same list of formats query_formats can leave some formats unset and return AVERROR(EAGAIN) to cause the negotiation mechanism toagain later.That can be used by filters with complex requirements to use the format negotiated on one link to set the formats supported on another.Buffer references ownership and permissions
AVFilterLink ** outputs
array of pointers to output links
Definition: avfilter.h:539
AVFilterFormats * ff_all_samplerates(void)
Definition: formats.c:396
static int channelmap_config_input(AVFilterLink *inlink)
uint8_t * data[AV_NUM_DATA_POINTERS]
pointer to the picture/channel planes.
Definition: frame.h:87
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:94
void ff_set_common_samplerates(AVFilterContext *ctx, AVFilterFormats *samplerates)
Definition: formats.c:533
void av_opt_free(void *obj)
Free all string and binary options in obj.
Definition: opt.c:1194
#define MAX_CH
Definition: af_channelmap.c:57
common internal and external API header
void av_frame_free(AVFrame **frame)
Free the frame and any dynamically allocated objects in it, e.g.
Definition: frame.c:108
#define F
Definition: af_channelmap.c:71
int len
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:524
static av_cold int channelmap_init(AVFilterContext *ctx)
static const AVFilterPad avfilter_af_channelmap_outputs[]
int nb_channels
int out_channel_idx
Definition: af_channelmap.c:44
internal API functions
uint8_t ** extended_data
pointers to the data planes/channels.
Definition: frame.h:117
these buffered frames must be flushed immediately if a new input produces new the filter must not call request_frame to get more It must just process the frame or queue it The task of requesting more frames is left to the filter s request_frame method or the application If a filter has several inputs
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.
int64_t av_get_default_channel_layout(int nb_channels)
Return default channel layout for a given number of channels.