FFmpeg
Loading...
Searching...
No Matches
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"
32#include "libavutil/mem.h"
33#include "libavutil/opt.h"
34#include "libavutil/samplefmt.h"
35
36#include "audio.h"
37#include "avfilter.h"
38#include "filters.h"
39#include "formats.h"
40
41struct ChannelMap {
46};
47
57
68
69#define OFFSET(x) offsetof(ChannelMapContext, x)
70#define A AV_OPT_FLAG_AUDIO_PARAM
71#define F AV_OPT_FLAG_FILTERING_PARAM
72static const AVOption channelmap_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(output_layout), AV_OPT_TYPE_CHLAYOUT, .flags = A|F },
77 { NULL }
78};
79
81
83{
84 ChannelMapContext *s = ctx->priv;
85 av_freep(&s->map);
86 av_freep(&s->source_planes);
87}
88
89static char* split(char *message, char delim) {
90 char *next = strchr(message, delim);
91 if (next)
92 *next++ = '\0';
93 return next;
94}
95
96static int get_channel_idx(char **map, int *ch, char delim)
97{
98 char *next;
99 int len;
100 int n = 0;
101 if (!*map)
102 return AVERROR(EINVAL);
103 next = split(*map, delim);
104 if (!next && delim == '-')
105 return AVERROR(EINVAL);
106 len = strlen(*map);
107 sscanf(*map, "%d%n", ch, &n);
108 if (n != len)
109 return AVERROR(EINVAL);
110 if (*ch < 0)
111 return AVERROR(EINVAL);
112 *map = next;
113 return 0;
114}
115
116static int get_channel(char **map, int *ch, char delim)
117{
118 char *next = split(*map, delim);
119 if (!next && delim == '-')
120 return AVERROR(EINVAL);
122 if (*ch < 0)
123 return AVERROR(EINVAL);
124 *map = next;
125 return 0;
126}
127
128static int check_idx_and_id(AVFilterContext *ctx, int channel_idx, int channel, AVChannelLayout *ch_layout, const char *io)
129{
130 char channel_name[64];
131 char layout_name[256];
132 int nb_channels = ch_layout->nb_channels;
133
134 if (channel_idx < 0 || channel_idx >= nb_channels) {
135 av_channel_layout_describe(ch_layout, layout_name, sizeof(layout_name));
136 if (channel >= 0) {
139 "%sput channel '%s' not available from %sput layout '%s'\n",
140 io, channel_name, io, layout_name);
141 } else {
143 "%sput channel #%d not available from %sput layout '%s'\n",
144 io, channel_idx, io, layout_name);
145 }
146 return AVERROR(EINVAL);
147 }
148
149 return 0;
150}
151
153{
154 ChannelMapContext *s = ctx->priv;
155 char *mapping, separator = '|';
156 int map_entries = 0;
157 enum MappingMode mode;
158 int64_t out_ch_mask = 0;
159 uint8_t *presence_map = NULL;
160 int ret = 0;
161 int i;
162
163 mapping = s->mapping_str;
164
165 if (!mapping) {
166 mode = MAP_NONE;
167 } else {
168 char *dash = strchr(mapping, '-');
169 if (!dash) { // short mapping
170 if (av_isdigit(*mapping))
172 else
174 } else if (av_isdigit(*mapping)) {
175 if (av_isdigit(*(dash+1)))
177 else
179 } else {
180 if (av_isdigit(*(dash+1)))
182 else
184 }
185 }
186
187 if (mode != MAP_NONE) {
188 char *sep = mapping;
189 map_entries = 1;
190 while ((sep = strchr(sep, separator))) {
191 if (*++sep) // Allow trailing comma
192 map_entries++;
193 }
194
195 s->map = av_malloc_array(map_entries, sizeof(*s->map));
196 if (!s->map)
197 return AVERROR(ENOMEM);
198 }
199
200 for (i = 0; i < map_entries; i++) {
201 int in_ch_idx = -1, out_ch_idx = -1;
202 int in_ch = -1, out_ch = -1;
203 static const char err[] = "Failed to parse channel map\n";
204
205 s->map[i].in_channel_idx = -1;
206 s->map[i].out_channel_idx = -1;
207 s->map[i].in_channel = -1;
208 s->map[i].out_channel = -1;
209
210 switch (mode) {
211 case MAP_ONE_INT:
212 if (get_channel_idx(&mapping, &in_ch_idx, separator) < 0) {
213 av_log(ctx, AV_LOG_ERROR, err);
214 return AVERROR(EINVAL);
215 }
216 s->map[i].in_channel_idx = in_ch_idx;
217 s->map[i].out_channel_idx = i;
218 break;
219 case MAP_ONE_STR:
220 if (get_channel(&mapping, &in_ch, separator) < 0) {
221 av_log(ctx, AV_LOG_ERROR, err);
222 return AVERROR(EINVAL);
223 }
224 s->map[i].in_channel = in_ch;
225 s->map[i].out_channel_idx = i;
226 break;
227 case MAP_PAIR_INT_INT:
228 if (get_channel_idx(&mapping, &in_ch_idx, '-') < 0 ||
229 get_channel_idx(&mapping, &out_ch_idx, separator) < 0) {
230 av_log(ctx, AV_LOG_ERROR, err);
231 return AVERROR(EINVAL);
232 }
233 s->map[i].in_channel_idx = in_ch_idx;
234 s->map[i].out_channel_idx = out_ch_idx;
235 break;
236 case MAP_PAIR_INT_STR:
237 if (get_channel_idx(&mapping, &in_ch_idx, '-') < 0 ||
238 get_channel(&mapping, &out_ch, separator) < 0) {
239 av_log(ctx, AV_LOG_ERROR, err);
240 return AVERROR(EINVAL);
241 }
242 s->map[i].in_channel_idx = in_ch_idx;
243 s->map[i].out_channel = out_ch;
244 if (out_ch < 63)
245 out_ch_mask |= 1ULL << out_ch;
246 else
247 out_ch_mask = -1;
248 break;
249 case MAP_PAIR_STR_INT:
250 if (get_channel(&mapping, &in_ch, '-') < 0 ||
251 get_channel_idx(&mapping, &out_ch_idx, separator) < 0) {
252 av_log(ctx, AV_LOG_ERROR, err);
253 return AVERROR(EINVAL);
254 }
255 s->map[i].in_channel = in_ch;
256 s->map[i].out_channel_idx = out_ch_idx;
257 break;
258 case MAP_PAIR_STR_STR:
259 if (get_channel(&mapping, &in_ch, '-') < 0 ||
260 get_channel(&mapping, &out_ch, separator) < 0) {
261 av_log(ctx, AV_LOG_ERROR, err);
262 return AVERROR(EINVAL);
263 }
264 s->map[i].in_channel = in_ch;
265 s->map[i].out_channel = out_ch;
266 if (out_ch < 63)
267 out_ch_mask |= 1ULL << out_ch;
268 else
269 out_ch_mask = -1;
270 break;
271 }
272 }
273 s->mode = mode;
274 s->nch = map_entries;
275 if (s->output_layout.nb_channels == 0) {
276 if (out_ch_mask > 0)
277 av_channel_layout_from_mask(&s->output_layout, out_ch_mask);
278 else if (map_entries)
279 av_channel_layout_default(&s->output_layout, map_entries);
280 }
281
282 if (mode == MAP_NONE) {
283 int i;
284 s->nch = s->output_layout.nb_channels;
285
286 s->map = av_malloc_array(s->nch, sizeof(*s->map));
287 if (!s->map)
288 return AVERROR(ENOMEM);
289
290 for (i = 0; i < s->nch; i++) {
291 s->map[i].in_channel_idx = i;
292 s->map[i].out_channel_idx = i;
293 s->map[i].out_channel = av_channel_layout_channel_from_index(&s->output_layout, i);
294 }
295 } else if (s->nch != s->output_layout.nb_channels) {
296 char buf[256];
297 av_channel_layout_describe(&s->output_layout, buf, sizeof(buf));
299 "Output channel layout %s does not match the number of channels mapped %d.\n",
300 buf, s->nch);
301 return AVERROR(EINVAL);
302 }
303
304 if (!s->output_layout.nb_channels) {
305 av_log(ctx, AV_LOG_ERROR, "Output channel layout is not set and "
306 "cannot be guessed from the maps.\n");
307 return AVERROR(EINVAL);
308 }
309
311 for (i = 0; i < s->nch; i++) {
312 s->map[i].out_channel_idx = av_channel_layout_index_from_channel(
313 &s->output_layout, s->map[i].out_channel);
314 }
315 }
316
317 presence_map = av_calloc(s->nch, sizeof(*presence_map));
318 for (i = 0; i < s->nch; i++) {
319 const int out_idx = s->map[i].out_channel_idx;
320 ret = check_idx_and_id(ctx, out_idx, s->map[i].out_channel, &s->output_layout, "out");
321 if (ret < 0)
322 break;
323 if (presence_map[out_idx]) {
324 char layout_name[256];
325 av_channel_layout_describe(&s->output_layout, layout_name, sizeof(layout_name));
326 av_log(ctx, AV_LOG_ERROR, "Mapping %d assigns channel #%d twice in output layout '%s'.\n",
327 i + 1, s->map[i].out_channel_idx, layout_name);
328 ret = AVERROR(EINVAL);
329 break;
330 }
331 presence_map[out_idx] = 1;
332 }
333 av_freep(&presence_map);
334 if (ret < 0)
335 return ret;
336
337 return 0;
338}
339
341 AVFilterFormatsConfig **cfg_in,
342 AVFilterFormatsConfig **cfg_out)
343{
344 const ChannelMapContext *s = ctx->priv;
346
347 int ret;
348
349 ret = ff_set_common_formats2(ctx, cfg_in, cfg_out, ff_planar_sample_fmts());
350 if (ret < 0)
351 return ret;
352
353 ret = ff_add_channel_layout(&channel_layouts, &s->output_layout);
354 if (ret < 0)
355 return ret;
356
358 if (ret < 0)
359 return ret;
360
361 return 0;
362}
363
365{
366 AVFilterContext *ctx = inlink->dst;
367 AVFilterLink *outlink = ctx->outputs[0];
368 const ChannelMapContext *s = ctx->priv;
369 const int nch_in = inlink->ch_layout.nb_channels;
370 const int nch_out = s->nch;
371 int ch, ret;
372
373 memcpy(s->source_planes, buf->extended_data,
374 nch_in * sizeof(s->source_planes[0]));
375
376 if (nch_out > nch_in) {
377 if (nch_out > FF_ARRAY_ELEMS(buf->data)) {
378 uint8_t **new_extended_data =
379 av_calloc(nch_out, sizeof(*buf->extended_data));
380 if (!new_extended_data) {
381 av_frame_free(&buf);
382 return AVERROR(ENOMEM);
383 }
384 if (buf->extended_data == buf->data) {
385 buf->extended_data = new_extended_data;
386 } else {
388 buf->extended_data = new_extended_data;
389 }
390 } else if (buf->extended_data != buf->data) {
392 buf->extended_data = buf->data;
393 }
394 }
395
396 for (ch = 0; ch < nch_out; ch++) {
397 buf->extended_data[s->map[ch].out_channel_idx] =
398 s->source_planes[s->map[ch].in_channel_idx];
399 }
400
401 if (buf->data != buf->extended_data)
402 memcpy(buf->data, buf->extended_data,
403 FFMIN(FF_ARRAY_ELEMS(buf->data), nch_out) * sizeof(buf->data[0]));
404
405 if ((ret = av_channel_layout_copy(&buf->ch_layout, &outlink->ch_layout)) < 0)
406 return ret;
407
408 return ff_filter_frame(outlink, buf);
409}
410
412{
413 AVFilterContext *ctx = inlink->dst;
414 ChannelMapContext *s = ctx->priv;
415 int i, err = 0;
416
417 for (i = 0; i < s->nch; i++) {
418 struct ChannelMap *m = &s->map[i];
419
420 if (s->mode == MAP_PAIR_STR_INT || s->mode == MAP_PAIR_STR_STR || s->mode == MAP_ONE_STR) {
422 &inlink->ch_layout, m->in_channel);
423 }
424
425 if (check_idx_and_id(ctx, m->in_channel_idx, m->in_channel, &inlink->ch_layout, "in") < 0)
426 err = AVERROR(EINVAL);
427 }
428
429 av_freep(&s->source_planes);
430 s->source_planes = av_calloc(inlink->ch_layout.nb_channels,
431 sizeof(*s->source_planes));
432 if (!s->source_planes)
433 return AVERROR(ENOMEM);
434
435 return err;
436}
437
439 {
440 .name = "default",
441 .type = AVMEDIA_TYPE_AUDIO,
443 .filter_frame = channelmap_filter_frame,
444 .config_props = channelmap_config_input,
445 },
446};
447
449 .p.name = "channelmap",
450 .p.description = NULL_IF_CONFIG_SMALL("Remap audio channels."),
451 .p.priv_class = &channelmap_class,
452 .init = channelmap_init,
453 .uninit = channelmap_uninit,
454 .priv_size = sizeof(ChannelMapContext),
458};
static int get_channel(char **map, int *ch, char delim)
static int channelmap_config_input(AVFilterLink *inlink)
MappingMode
@ MAP_ONE_STR
@ MAP_PAIR_STR_INT
@ MAP_PAIR_STR_STR
@ MAP_ONE_INT
@ MAP_PAIR_INT_STR
@ MAP_NONE
@ MAP_PAIR_INT_INT
static const AVFilterPad avfilter_af_channelmap_inputs[]
static int get_channel_idx(char **map, int *ch, char delim)
static int channelmap_query_formats(const AVFilterContext *ctx, AVFilterFormatsConfig **cfg_in, AVFilterFormatsConfig **cfg_out)
const FFFilter ff_af_channelmap
static av_cold int channelmap_init(AVFilterContext *ctx)
#define OFFSET(x)
static const AVOption channelmap_options[]
static int channelmap_filter_frame(AVFilterLink *inlink, AVFrame *buf)
static char * split(char *message, char delim)
static int check_idx_and_id(AVFilterContext *ctx, int channel_idx, int channel, AVChannelLayout *ch_layout, const char *io)
static void channelmap_uninit(AVFilterContext *ctx)
static AVFormatContext * ctx
#define A(x)
Definition vpx_arith.h:28
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:34
int ff_filter_frame(AVFilterLink *link, AVFrame *frame)
Send a frame of data to the next filter.
Definition avfilter.c:1068
Main libavfilter public API header.
#define i(width, name, range_min, range_max)
Definition cbs_h264.c:63
#define s(width, name)
Definition cbs_vp9.c:198
Public libavutil channel layout APIs header.
common internal and external API header
#define NULL
Definition coverity.c:32
long long int64_t
Definition coverity.c:34
static const uint16_t channel_layouts[7]
Definition dca_lbr.c:112
#define F(x)
channel
Use these values when setting the channel map with ebur128_set_channel().
Definition ebur128.h:39
static char separator(CheckasmFormat format)
Definition checkasm.c:149
int ff_set_common_formats2(const AVFilterContext *ctx, AVFilterFormatsConfig **cfg_in, AVFilterFormatsConfig **cfg_out, AVFilterFormats *formats)
Definition formats.c:1137
AVFilterFormats * ff_planar_sample_fmts(void)
Construct a formats list containing all planar sample formats.
Definition formats.c:660
int ff_add_channel_layout(AVFilterChannelLayouts **l, const AVChannelLayout *channel_layout)
Definition formats.c:588
int ff_channel_layouts_ref(AVFilterChannelLayouts *f, AVFilterChannelLayouts **ref)
Add *ref as a new reference to f.
Definition formats.c:751
@ AV_OPT_TYPE_CHLAYOUT
Underlying C type is AVChannelLayout.
Definition opt.h:330
@ AV_OPT_TYPE_STRING
Underlying C type is a uint8_t* that is either NULL or points to a C string allocated with the av_mal...
Definition opt.h:275
void av_channel_layout_default(AVChannelLayout *ch_layout, int nb_channels)
Get the default channel layout for a given number of channels.
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.
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.
enum AVChannel av_channel_layout_channel_from_index(const AVChannelLayout *channel_layout, unsigned int idx)
Get the channel with the given index in a channel layout.
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.
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.
int av_channel_layout_copy(AVChannelLayout *dst, const AVChannelLayout *src)
Make a copy of a channel layout.
enum AVChannel av_channel_from_string(const char *str)
This is the inverse function of av_channel_name().
#define AVERROR(e)
Definition error.h:45
void av_frame_free(AVFrame **frame)
Free the frame and any dynamically allocated objects in it, e.g.
Definition frame.c:64
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition log.h:210
@ AVMEDIA_TYPE_AUDIO
Definition avutil.h:201
static av_const int av_isdigit(int c)
Locale-independent conversion of ASCII isdigit.
Definition avstring.h:202
const VDPAUPixFmtMap * map
#define FILTER_INPUTS(array)
Definition filters.h:264
#define FILTER_OUTPUTS(array)
Definition filters.h:265
#define AVFILTERPAD_FLAG_NEEDS_WRITABLE
The filter expects writable frames from its input link, duplicating data buffers if needed.
Definition filters.h:59
#define AVFILTER_DEFINE_CLASS(fname)
Definition filters.h:478
#define FILTER_QUERY_FUNC2(func)
Definition filters.h:241
#define av_cold
Definition attributes.h:117
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification.
Definition internal.h:88
#define FFMIN(a, b)
Definition macros.h:49
void * av_calloc(size_t nmemb, size_t size)
Definition mem.c:264
Memory handling functions.
AVOptions.
#define FF_ARRAY_ELEMS(a)
An AVChannelLayout holds information about the channel layout of audio data.
int nb_channels
Number of channels in this layout.
Describe the class of an AVClass context structure.
Definition log.h:76
A list of supported channel layouts.
Definition formats.h:85
An instance of a filter.
Definition avfilter.h:273
Lists of formats / etc.
Definition avfilter.h:120
A filter pad used for either input or output.
Definition filters.h:40
This structure describes decoded (raw) audio or video data.
Definition frame.h:472
uint8_t * data[AV_NUM_DATA_POINTERS]
pointer to the picture/channel planes.
Definition frame.h:493
AVChannelLayout ch_layout
Channel layout of the audio data.
Definition frame.h:815
uint8_t ** extended_data
pointers to the data planes/channels.
Definition frame.h:533
AVOption.
Definition opt.h:428
enum MappingMode mode
struct ChannelMap * map
uint8_t ** source_planes
AVChannelLayout output_layout
int channel_idx
Definition parse.h:50
int in_channel_idx
index of in_channel in the input stream data
int out_channel_idx
Definition swscale.c:71
#define av_free(p)
#define av_malloc_array(a, b)
#define av_freep(p)
#define av_log(a,...)
int len