FFmpeg
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 {
45 };
46 
55 };
56 
57 #define MAX_CH 64
58 typedef struct ChannelMapContext {
59  const AVClass *class;
60  char *mapping_str;
63  int nch;
66 
67 #define OFFSET(x) offsetof(ChannelMapContext, x)
68 #define A AV_OPT_FLAG_AUDIO_PARAM
69 #define F AV_OPT_FLAG_FILTERING_PARAM
70 static const AVOption channelmap_options[] = {
71  { "map", "A comma-separated list of input channel numbers in output order.",
72  OFFSET(mapping_str), AV_OPT_TYPE_STRING, .flags = A|F },
73  { "channel_layout", "Output channel layout.",
74  OFFSET(output_layout), AV_OPT_TYPE_CHLAYOUT, .flags = A|F },
75  { NULL }
76 };
77 
78 AVFILTER_DEFINE_CLASS(channelmap);
79 
80 static char* split(char *message, char delim) {
81  char *next = strchr(message, delim);
82  if (next)
83  *next++ = '\0';
84  return next;
85 }
86 
87 static int get_channel_idx(char **map, int *ch, char delim, int max_ch)
88 {
89  char *next;
90  int len;
91  int n = 0;
92  if (!*map)
93  return AVERROR(EINVAL);
94  next = split(*map, delim);
95  if (!next && delim == '-')
96  return AVERROR(EINVAL);
97  len = strlen(*map);
98  sscanf(*map, "%d%n", ch, &n);
99  if (n != len)
100  return AVERROR(EINVAL);
101  if (*ch < 0 || *ch > max_ch)
102  return AVERROR(EINVAL);
103  *map = next;
104  return 0;
105 }
106 
107 static int get_channel(char **map, int *ch, char delim)
108 {
109  char *next = split(*map, delim);
110  if (!next && delim == '-')
111  return AVERROR(EINVAL);
112  *ch = av_channel_from_string(*map);
113  if (*ch < 0)
114  return AVERROR(EINVAL);
115  *map = next;
116  return 0;
117 }
118 
120 {
121  ChannelMapContext *s = ctx->priv;
122  char *mapping, separator = '|';
123  int map_entries = 0;
124  enum MappingMode mode;
125  uint64_t out_ch_mask = 0;
126  int i;
127 
128  mapping = s->mapping_str;
129 
130  if (!mapping) {
131  mode = MAP_NONE;
132  } else {
133  char *dash = strchr(mapping, '-');
134  if (!dash) { // short mapping
135  if (av_isdigit(*mapping))
136  mode = MAP_ONE_INT;
137  else
138  mode = MAP_ONE_STR;
139  } else if (av_isdigit(*mapping)) {
140  if (av_isdigit(*(dash+1)))
142  else
144  } else {
145  if (av_isdigit(*(dash+1)))
147  else
149  }
150  }
151 
152  if (mode != MAP_NONE) {
153  char *sep = mapping;
154  map_entries = 1;
155  while ((sep = strchr(sep, separator))) {
156  if (*++sep) // Allow trailing comma
157  map_entries++;
158  }
159  }
160 
161  if (map_entries > MAX_CH) {
162  av_log(ctx, AV_LOG_ERROR, "Too many channels mapped: '%d'.\n", map_entries);
163  return AVERROR(EINVAL);
164  }
165 
166  for (i = 0; i < map_entries; i++) {
167  int in_ch_idx = -1, out_ch_idx = -1;
168  int in_ch = 0, out_ch = 0;
169  static const char err[] = "Failed to parse channel map\n";
170  switch (mode) {
171  case MAP_ONE_INT:
172  if (get_channel_idx(&mapping, &in_ch_idx, separator, MAX_CH) < 0) {
173  av_log(ctx, AV_LOG_ERROR, err);
174  return AVERROR(EINVAL);
175  }
176  s->map[i].in_channel_idx = in_ch_idx;
177  s->map[i].out_channel_idx = i;
178  break;
179  case MAP_ONE_STR:
180  if (get_channel(&mapping, &in_ch, separator) < 0) {
181  av_log(ctx, AV_LOG_ERROR, err);
182  return AVERROR(EINVAL);
183  }
184  s->map[i].in_channel = in_ch;
185  s->map[i].out_channel_idx = i;
186  break;
187  case MAP_PAIR_INT_INT:
188  if (get_channel_idx(&mapping, &in_ch_idx, '-', MAX_CH) < 0 ||
189  get_channel_idx(&mapping, &out_ch_idx, separator, MAX_CH) < 0) {
190  av_log(ctx, AV_LOG_ERROR, err);
191  return AVERROR(EINVAL);
192  }
193  s->map[i].in_channel_idx = in_ch_idx;
194  s->map[i].out_channel_idx = out_ch_idx;
195  break;
196  case MAP_PAIR_INT_STR:
197  if (get_channel_idx(&mapping, &in_ch_idx, '-', MAX_CH) < 0 ||
198  get_channel(&mapping, &out_ch, separator) < 0 ||
199  (1ULL << out_ch) & out_ch_mask) {
200  av_log(ctx, AV_LOG_ERROR, err);
201  return AVERROR(EINVAL);
202  }
203  s->map[i].in_channel_idx = in_ch_idx;
204  s->map[i].out_channel = out_ch;
205  out_ch_mask |= 1ULL << out_ch;
206  break;
207  case MAP_PAIR_STR_INT:
208  if (get_channel(&mapping, &in_ch, '-') < 0 ||
209  get_channel_idx(&mapping, &out_ch_idx, separator, MAX_CH) < 0) {
210  av_log(ctx, AV_LOG_ERROR, err);
211  return AVERROR(EINVAL);
212  }
213  s->map[i].in_channel = in_ch;
214  s->map[i].out_channel_idx = out_ch_idx;
215  break;
216  case MAP_PAIR_STR_STR:
217  if (get_channel(&mapping, &in_ch, '-') < 0 ||
218  get_channel(&mapping, &out_ch, separator) < 0 ||
219  (1ULL << out_ch) & out_ch_mask) {
220  av_log(ctx, AV_LOG_ERROR, err);
221  return AVERROR(EINVAL);
222  }
223  s->map[i].in_channel = in_ch;
224  s->map[i].out_channel = out_ch;
225  out_ch_mask |= 1ULL << out_ch;
226  break;
227  }
228  }
229  s->mode = mode;
230  s->nch = map_entries;
231  if (out_ch_mask)
232  av_channel_layout_from_mask(&s->output_layout, out_ch_mask);
233  else if (map_entries && s->output_layout.nb_channels == 0)
234  av_channel_layout_default(&s->output_layout, map_entries);
235 
236  if (mode == MAP_NONE) {
237  int i;
238  s->nch = s->output_layout.nb_channels;
239  for (i = 0; i < s->nch; i++) {
240  s->map[i].in_channel_idx = i;
241  s->map[i].out_channel_idx = i;
242  }
243  } else if (s->nch != s->output_layout.nb_channels) {
244  char buf[256];
245  av_channel_layout_describe(&s->output_layout, buf, sizeof(buf));
247  "Output channel layout %s does not match the number of channels mapped %d.\n",
248  buf, s->nch);
249  return AVERROR(EINVAL);
250  }
251 
252  if (!s->output_layout.nb_channels) {
253  av_log(ctx, AV_LOG_ERROR, "Output channel layout is not set and "
254  "cannot be guessed from the maps.\n");
255  return AVERROR(EINVAL);
256  }
257 
259  for (i = 0; i < s->nch; i++) {
260  s->map[i].out_channel_idx = av_channel_layout_index_from_channel(
261  &s->output_layout, s->map[i].out_channel);
262  }
263  }
264 
265  return 0;
266 }
267 
269 {
270  ChannelMapContext *s = ctx->priv;
272  int ret;
273 
276  (ret = ff_add_channel_layout(&channel_layouts, &s->output_layout)) < 0 ||
278  &ctx->outputs[0]->incfg.channel_layouts)) < 0)
279  return ret;
280 
282  &ctx->inputs[0]->outcfg.channel_layouts);
283 }
284 
286 {
287  AVFilterContext *ctx = inlink->dst;
288  AVFilterLink *outlink = ctx->outputs[0];
289  const ChannelMapContext *s = ctx->priv;
290  const int nch_in = inlink->ch_layout.nb_channels;
291  const int nch_out = s->nch;
292  int ch, ret;
293  uint8_t *source_planes[MAX_CH];
294 
295  memcpy(source_planes, buf->extended_data,
296  nch_in * sizeof(source_planes[0]));
297 
298  if (nch_out > nch_in) {
299  if (nch_out > FF_ARRAY_ELEMS(buf->data)) {
300  uint8_t **new_extended_data =
301  av_calloc(nch_out, sizeof(*buf->extended_data));
302  if (!new_extended_data) {
303  av_frame_free(&buf);
304  return AVERROR(ENOMEM);
305  }
306  if (buf->extended_data == buf->data) {
307  buf->extended_data = new_extended_data;
308  } else {
309  av_free(buf->extended_data);
310  buf->extended_data = new_extended_data;
311  }
312  } else if (buf->extended_data != buf->data) {
313  av_free(buf->extended_data);
314  buf->extended_data = buf->data;
315  }
316  }
317 
318  for (ch = 0; ch < nch_out; ch++) {
319  buf->extended_data[s->map[ch].out_channel_idx] =
320  source_planes[s->map[ch].in_channel_idx];
321  }
322 
323  if (buf->data != buf->extended_data)
324  memcpy(buf->data, buf->extended_data,
325  FFMIN(FF_ARRAY_ELEMS(buf->data), nch_out) * sizeof(buf->data[0]));
326 
327 #if FF_API_OLD_CHANNEL_LAYOUT
329  buf->channels = outlink->ch_layout.nb_channels;
330  buf->channel_layout = outlink->channel_layout;
332 #endif
333  if ((ret = av_channel_layout_copy(&buf->ch_layout, &outlink->ch_layout)) < 0)
334  return ret;
335 
336  return ff_filter_frame(outlink, buf);
337 }
338 
340 {
341  AVFilterContext *ctx = inlink->dst;
342  ChannelMapContext *s = ctx->priv;
343  int nb_channels = inlink->ch_layout.nb_channels;
344  int i, err = 0;
345  char channel_name[64];
346  char layout_name[256];
347 
348  for (i = 0; i < s->nch; i++) {
349  struct ChannelMap *m = &s->map[i];
350 
351  if (s->mode == MAP_PAIR_STR_INT || s->mode == MAP_PAIR_STR_STR) {
353  &inlink->ch_layout, m->in_channel);
354  }
355 
356  if (m->in_channel_idx < 0 || m->in_channel_idx >= nb_channels) {
357  av_channel_layout_describe(&inlink->ch_layout, layout_name, sizeof(layout_name));
358  if (m->in_channel) {
361  "input channel '%s' not available from input layout '%s'\n",
362  channel_name, layout_name);
363  } else {
365  "input channel #%d not available from input layout '%s'\n",
366  m->in_channel_idx, layout_name);
367  }
368  err = AVERROR(EINVAL);
369  }
370  }
371 
372  return err;
373 }
374 
376  {
377  .name = "default",
378  .type = AVMEDIA_TYPE_AUDIO,
380  .filter_frame = channelmap_filter_frame,
381  .config_props = channelmap_config_input,
382  },
383 };
384 
386  .name = "channelmap",
387  .description = NULL_IF_CONFIG_SMALL("Remap audio channels."),
388  .init = channelmap_init,
389  .priv_size = sizeof(ChannelMapContext),
390  .priv_class = &channelmap_class,
394 };
MAX_CH
#define MAX_CH
Definition: af_channelmap.c:57
FF_ENABLE_DEPRECATION_WARNINGS
#define FF_ENABLE_DEPRECATION_WARNINGS
Definition: internal.h:73
AVFilterChannelLayouts
A list of supported channel layouts.
Definition: formats.h:85
AVERROR
Filter the word “frame” indicates either a video frame or a group of audio as stored in an AVFrame 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. Frame references ownership and permissions
opt.h
MAP_PAIR_STR_STR
@ MAP_PAIR_STR_STR
Definition: af_channelmap.c:54
message
Definition: api-threadmessage-test.c:46
ChannelMapContext::mode
enum MappingMode mode
Definition: af_channelmap.c:64
ff_filter_frame
int ff_filter_frame(AVFilterLink *link, AVFrame *frame)
Send a frame of data to the next filter.
Definition: avfilter.c:1007
ff_channel_layouts_ref
int ff_channel_layouts_ref(AVFilterChannelLayouts *f, AVFilterChannelLayouts **ref)
Add *ref as a new reference to f.
Definition: formats.c:673
channelmap_filter_frame
static int channelmap_filter_frame(AVFilterLink *inlink, AVFrame *buf)
Definition: af_channelmap.c:285
F
#define F
Definition: af_channelmap.c:69
channelmap_init
static av_cold int channelmap_init(AVFilterContext *ctx)
Definition: af_channelmap.c:119
inlink
The exact code depends on how similar the blocks are and how related they are to the and needs to apply these operations to the correct inlink or outlink if there are several Macros are available to factor that when no extra processing is inlink
Definition: filter_design.txt:212
av_frame_free
void av_frame_free(AVFrame **frame)
Free the frame and any dynamically allocated objects in it, e.g.
Definition: frame.c:100
ff_all_channel_counts
AVFilterChannelLayouts * ff_all_channel_counts(void)
Construct an AVFilterChannelLayouts coding for any channel layout, with known or unknown disposition.
Definition: formats.c:621
AVFrame
This structure describes decoded (raw) audio or video data.
Definition: frame.h:340
AVOption
AVOption.
Definition: opt.h:294
FILTER_QUERY_FUNC
#define FILTER_QUERY_FUNC(func)
Definition: internal.h:159
get_channel
static int get_channel(char **map, int *ch, char delim)
Definition: af_channelmap.c:107
ff_set_common_all_samplerates
int ff_set_common_all_samplerates(AVFilterContext *ctx)
Equivalent to ff_set_common_samplerates(ctx, ff_all_samplerates())
Definition: formats.c:821
mathematics.h
channel_name
Definition: channel_layout.c:41
AVFilter::name
const char * name
Filter name.
Definition: avfilter.h:170
MAP_NONE
@ MAP_NONE
Definition: af_channelmap.c:48
AVChannelLayout::nb_channels
int nb_channels
Number of channels in this layout.
Definition: channel_layout.h:323
AVFrame::data
uint8_t * data[AV_NUM_DATA_POINTERS]
pointer to the picture/channel planes.
Definition: frame.h:361
formats.h
A
#define A
Definition: af_channelmap.c:68
samplefmt.h
ff_af_channelmap
const AVFilter ff_af_channelmap
Definition: af_channelmap.c:385
AVFrame::ch_layout
AVChannelLayout ch_layout
Channel layout of the audio data.
Definition: frame.h:802
AVFrame::channels
attribute_deprecated int channels
number of audio channels, only used for audio.
Definition: frame.h:731
AVFilterPad
A filter pad used for either input or output.
Definition: internal.h:33
MappingMode
MappingMode
Definition: af_channelmap.c:47
AV_LOG_ERROR
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:180
FF_ARRAY_ELEMS
#define FF_ARRAY_ELEMS(a)
Definition: sinewin_tablegen.c:29
av_cold
#define av_cold
Definition: attributes.h:90
AVFrame::channel_layout
attribute_deprecated uint64_t channel_layout
Channel layout of the audio data.
Definition: frame.h:575
ff_set_common_formats
int 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:867
av_channel_layout_describe
int av_channel_layout_describe(const AVChannelLayout *channel_layout, char *buf, size_t buf_size)
Get a human-readable string describing the channel layout properties.
Definition: channel_layout.c:847
channelmap_options
static const AVOption channelmap_options[]
Definition: af_channelmap.c:70
s
#define s(width, name)
Definition: cbs_vp9.c:198
MAP_PAIR_STR_INT
@ MAP_PAIR_STR_INT
Definition: af_channelmap.c:53
AVMEDIA_TYPE_AUDIO
@ AVMEDIA_TYPE_AUDIO
Definition: avutil.h:202
av_channel_layout_from_mask
int av_channel_layout_from_mask(AVChannelLayout *channel_layout, uint64_t mask)
Initialize a native channel layout from a bitmask indicating which channels are present.
Definition: channel_layout.c:421
ChannelMapContext::nch
int nch
Definition: af_channelmap.c:63
ctx
AVFormatContext * ctx
Definition: movenc.c:48
FILTER_INPUTS
#define FILTER_INPUTS(array)
Definition: internal.h:182
AVClass
Describe the class of an AVClass context structure.
Definition: log.h:66
NULL
#define NULL
Definition: coverity.c:32
ChannelMapContext::output_layout
AVChannelLayout output_layout
Definition: af_channelmap.c:61
ff_audio_default_filterpad
const AVFilterPad ff_audio_default_filterpad[1]
An AVFilterPad array whose only entry has name "default" and is of type AVMEDIA_TYPE_AUDIO.
Definition: audio.c:33
ChannelMap::in_channel
int in_channel
Definition: af_channelmap.c:41
AV_OPT_TYPE_CHLAYOUT
@ AV_OPT_TYPE_CHLAYOUT
Definition: opt.h:245
ff_add_channel_layout
int ff_add_channel_layout(AVFilterChannelLayouts **l, const AVChannelLayout *channel_layout)
Definition: formats.c:521
channelmap_query_formats
static int channelmap_query_formats(AVFilterContext *ctx)
Definition: af_channelmap.c:268
MAP_PAIR_INT_INT
@ MAP_PAIR_INT_INT
Definition: af_channelmap.c:51
NULL_IF_CONFIG_SMALL
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification.
Definition: internal.h:106
AVChannelLayout
An AVChannelLayout holds information about the channel layout of audio data.
Definition: channel_layout.h:313
ChannelMapContext
Definition: af_channelmap.c:58
avfilter_af_channelmap_inputs
static const AVFilterPad avfilter_af_channelmap_inputs[]
Definition: af_channelmap.c:375
MAP_ONE_STR
@ MAP_ONE_STR
Definition: af_channelmap.c:50
MAP_ONE_INT
@ MAP_ONE_INT
Definition: af_channelmap.c:49
MAP_PAIR_INT_STR
@ MAP_PAIR_INT_STR
Definition: af_channelmap.c:52
channelmap_config_input
static int channelmap_config_input(AVFilterLink *inlink)
Definition: af_channelmap.c:339
split
static char * split(char *message, char delim)
Definition: af_channelmap.c:80
av_isdigit
static av_const int av_isdigit(int c)
Locale-independent conversion of ASCII isdigit.
Definition: avstring.h:202
get_channel_idx
static int get_channel_idx(char **map, int *ch, char delim, int max_ch)
Definition: af_channelmap.c:87
ChannelMap::in_channel_idx
int in_channel_idx
index of in_channel in the input stream data
Definition: af_channelmap.c:43
ChannelMapContext::mapping_str
char * mapping_str
Definition: af_channelmap.c:60
ChannelMapContext::map
struct ChannelMap map[MAX_CH]
Definition: af_channelmap.c:62
internal.h
av_channel_layout_default
void av_channel_layout_default(AVChannelLayout *ch_layout, int nb_channels)
Get the default channel layout for a given number of channels.
Definition: channel_layout.c:1033
i
#define i(width, name, range_min, range_max)
Definition: cbs_h2645.c:255
av_channel_name
int av_channel_name(char *buf, size_t buf_size, enum AVChannel channel_id)
Get a human readable string in an abbreviated form describing a given channel.
Definition: channel_layout.c:101
AVFrame::extended_data
uint8_t ** extended_data
pointers to the data planes/channels.
Definition: frame.h:401
common.h
FFMIN
#define FFMIN(a, b)
Definition: macros.h:49
ff_planar_sample_fmts
AVFilterFormats * ff_planar_sample_fmts(void)
Construct a formats list containing all planar sample formats.
Definition: formats.c:593
len
int len
Definition: vorbis_enc_data.h:426
AVFilterPad::name
const char * name
Pad name.
Definition: internal.h:39
av_calloc
void * av_calloc(size_t nmemb, size_t size)
Definition: mem.c:262
ChannelMap::out_channel
int out_channel
Definition: af_channelmap.c:42
AVFilter
Filter definition.
Definition: avfilter.h:166
ret
ret
Definition: filter_design.txt:187
av_channel_from_string
enum AVChannel av_channel_from_string(const char *str)
This is the inverse function of av_channel_name().
Definition: channel_layout.c:145
ChannelMap::out_channel_idx
int out_channel_idx
Definition: af_channelmap.c:44
channel_layout.h
AVFILTER_DEFINE_CLASS
AVFILTER_DEFINE_CLASS(channelmap)
av_channel_layout_index_from_channel
int av_channel_layout_index_from_channel(const AVChannelLayout *channel_layout, enum AVChannel channel)
Get the index of a given channel in a channel layout.
Definition: channel_layout.c:907
mode
mode
Definition: ebur128.h:83
avfilter.h
ChannelMap
Definition: opus_parse.h:48
AVFilterContext
An instance of a filter.
Definition: avfilter.h:409
av_channel_layout_copy
int av_channel_layout_copy(AVChannelLayout *dst, const AVChannelLayout *src)
Make a copy of a channel layout.
Definition: channel_layout.c:669
FF_DISABLE_DEPRECATION_WARNINGS
#define FF_DISABLE_DEPRECATION_WARNINGS
Definition: internal.h:72
OFFSET
#define OFFSET(x)
Definition: af_channelmap.c:67
audio.h
map
const VDPAUPixFmtMap * map
Definition: hwcontext_vdpau.c:71
av_free
#define av_free(p)
Definition: tableprint_vlc.h:33
channel_layouts
static const uint16_t channel_layouts[7]
Definition: dca_lbr.c:111
FILTER_OUTPUTS
#define FILTER_OUTPUTS(array)
Definition: internal.h:183
av_log
#define av_log(a,...)
Definition: tableprint_vlc.h:27
avstring.h
AV_OPT_TYPE_STRING
@ AV_OPT_TYPE_STRING
Definition: opt.h:229
AVFILTERPAD_FLAG_NEEDS_WRITABLE
#define AVFILTERPAD_FLAG_NEEDS_WRITABLE
The filter expects writable frames from its input link, duplicating data buffers if needed.
Definition: internal.h:52