2 * Copyright (c) 2012 Google, Inc.
4 * This file is part of Libav.
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.
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.
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
23 * audio channel mapping filter
28 #include "libavutil/avstring.h"
29 #include "libavutil/channel_layout.h"
30 #include "libavutil/common.h"
31 #include "libavutil/mathematics.h"
32 #include "libavutil/opt.h"
33 #include "libavutil/samplefmt.h"
58 typedef struct ChannelMapContext
{
60 AVFilterChannelLayouts
*channel_layouts
;
62 char *channel_layout_str
;
63 uint64_t output_layout
;
64 struct ChannelMap map
[MAX_CH
];
66 enum MappingMode mode
;
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
},
79 static const AVClass channelmap_class
= {
80 .class_name
= "channel map filter",
81 .item_name
= av_default_item_name
,
83 .version
= LIBAVUTIL_VERSION_INT
,
86 static char* split(char *message
, char delim
) {
87 char *next
= strchr(message
, delim
);
93 static int get_channel_idx(char **map
, int *ch
, char delim
, int max_ch
)
95 char *next
= split(*map
, delim
);
98 if (!next
&& delim
== '-')
99 return AVERROR(EINVAL
);
101 sscanf(*map
, "%d%n", ch
, &n
);
103 return AVERROR(EINVAL
);
104 if (*ch
< 0 || *ch
> max_ch
)
105 return AVERROR(EINVAL
);
110 static int get_channel(char **map
, uint64_t *ch
, char delim
)
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
);
122 static av_cold
int channelmap_init(AVFilterContext
*ctx
, const char *args
)
124 ChannelMapContext
*s
= ctx
->priv
;
129 enum MappingMode mode
;
130 uint64_t out_ch_mask
= 0;
134 av_log(ctx
, AV_LOG_ERROR
, "No parameters supplied.\n");
135 return AVERROR(EINVAL
);
138 s
->class = &channelmap_class
;
139 av_opt_set_defaults(s
);
141 if ((ret
= av_set_options_string(s
, args
, "=", ":")) < 0) {
142 av_log(ctx
, AV_LOG_ERROR
, "Error parsing options string '%s'.\n", args
);
146 mapping
= s
->mapping_str
;
151 char *dash
= strchr(mapping
, '-');
152 if (!dash
) { // short mapping
153 if (isdigit(*mapping
))
157 } else if (isdigit(*mapping
)) {
158 if (isdigit(*(dash
+1)))
159 mode
= MAP_PAIR_INT_INT
;
161 mode
= MAP_PAIR_INT_STR
;
163 if (isdigit(*(dash
+1)))
164 mode
= MAP_PAIR_STR_INT
;
166 mode
= MAP_PAIR_STR_STR
;
170 if (mode
!= MAP_NONE
) {
171 char *comma
= mapping
;
173 while ((comma
= strchr(comma
, ','))) {
174 if (*++comma
) // Allow trailing comma
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
);
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";
191 if (get_channel_idx(&mapping
, &in_ch_idx
, ',', MAX_CH
) < 0) {
192 ret
= AVERROR(EINVAL
);
193 av_log(ctx
, AV_LOG_ERROR
, err
);
196 s
->map
[i
].in_channel_idx
= in_ch_idx
;
197 s
->map
[i
].out_channel_idx
= i
;
200 if (!get_channel(&mapping
, &in_ch
, ',')) {
201 av_log(ctx
, AV_LOG_ERROR
, err
);
202 ret
= AVERROR(EINVAL
);
205 s
->map
[i
].in_channel
= in_ch
;
206 s
->map
[i
].out_channel_idx
= i
;
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
);
215 s
->map
[i
].in_channel_idx
= in_ch_idx
;
216 s
->map
[i
].out_channel_idx
= out_ch_idx
;
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
);
226 s
->map
[i
].in_channel_idx
= in_ch_idx
;
227 s
->map
[i
].out_channel
= out_ch
;
228 out_ch_mask
|= out_ch
;
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
);
237 s
->map
[i
].in_channel
= in_ch
;
238 s
->map
[i
].out_channel_idx
= out_ch_idx
;
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
);
248 s
->map
[i
].in_channel
= in_ch
;
249 s
->map
[i
].out_channel
= out_ch
;
250 out_ch_mask
|= out_ch
;
255 s
->nch
= map_entries
;
256 s
->output_layout
= out_ch_mask
? out_ch_mask
:
257 av_get_default_channel_layout(map_entries
);
259 if (s
->channel_layout_str
) {
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
);
267 if (mode
== MAP_NONE
) {
269 s
->nch
= av_get_channel_layout_nb_channels(fmt
);
270 for (i
= 0; i
< s
->nch
; i
++) {
271 s
->map
[i
].in_channel_idx
= i
;
272 s
->map
[i
].out_channel_idx
= i
;
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
);
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
);
288 s
->output_layout
= fmt
;
290 ff_add_channel_layout(&s
->channel_layouts
, s
->output_layout
);
292 if (mode
== MAP_PAIR_INT_STR
|| mode
== MAP_PAIR_STR_STR
) {
293 for (i
= 0; i
< s
->nch
; i
++) {
294 s
->map
[i
].out_channel_idx
= av_get_channel_layout_channel_index(
295 s
->output_layout
, s
->map
[i
].out_channel
);
304 static int channelmap_query_formats(AVFilterContext
*ctx
)
306 ChannelMapContext
*s
= ctx
->priv
;
308 ff_set_common_formats(ctx
, ff_planar_sample_fmts());
309 ff_set_common_samplerates(ctx
, ff_all_samplerates());
310 ff_channel_layouts_ref(ff_all_channel_layouts(), &ctx
->inputs
[0]->out_channel_layouts
);
311 ff_channel_layouts_ref(s
->channel_layouts
, &ctx
->outputs
[0]->in_channel_layouts
);
316 static int channelmap_filter_frame(AVFilterLink
*inlink
, AVFilterBufferRef
*buf
)
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
;
324 uint8_t *source_planes
[MAX_CH
];
326 memcpy(source_planes
, buf
->extended_data
,
327 nch_in
* sizeof(source_planes
[0]));
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
) {
334 avfilter_unref_buffer(buf
);
335 return AVERROR(ENOMEM
);
337 if (buf
->extended_data
== buf
->data
) {
338 buf
->extended_data
= new_extended_data
;
340 av_free(buf
->extended_data
);
341 buf
->extended_data
= new_extended_data
;
343 } else if (buf
->extended_data
!= buf
->data
) {
344 av_free(buf
->extended_data
);
345 buf
->extended_data
= buf
->data
;
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
];
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]));
358 return ff_filter_frame(outlink
, buf
);
361 static int channelmap_config_input(AVFilterLink
*inlink
)
363 AVFilterContext
*ctx
= inlink
->dst
;
364 ChannelMapContext
*s
= ctx
->priv
;
366 const char *channel_name
;
367 char layout_name
[256];
369 if (s
->mode
== MAP_PAIR_STR_INT
|| s
->mode
== MAP_PAIR_STR_STR
) {
370 for (i
= 0; i
< s
->nch
; i
++) {
371 s
->map
[i
].in_channel_idx
= av_get_channel_layout_channel_index(
372 inlink
->channel_layout
, s
->map
[i
].in_channel
);
373 if (s
->map
[i
].in_channel_idx
< 0) {
374 channel_name
= av_get_channel_name(s
->map
[i
].in_channel
);
375 av_get_channel_layout_string(layout_name
, sizeof(layout_name
),
376 0, inlink
->channel_layout
);
377 av_log(ctx
, AV_LOG_ERROR
,
378 "input channel '%s' not available from input layout '%s'\n",
379 channel_name
, layout_name
);
380 err
= AVERROR(EINVAL
);
388 static const AVFilterPad avfilter_af_channelmap_inputs
[] = {
391 .type
= AVMEDIA_TYPE_AUDIO
,
392 .filter_frame
= channelmap_filter_frame
,
393 .config_props
= channelmap_config_input
398 static const AVFilterPad avfilter_af_channelmap_outputs
[] = {
401 .type
= AVMEDIA_TYPE_AUDIO
406 AVFilter avfilter_af_channelmap
= {
407 .name
= "channelmap",
408 .description
= NULL_IF_CONFIG_SMALL("Remap audio channels."),
409 .init
= channelmap_init
,
410 .query_formats
= channelmap_query_formats
,
411 .priv_size
= sizeof(ChannelMapContext
),
413 .inputs
= avfilter_af_channelmap_inputs
,
414 .outputs
= avfilter_af_channelmap_outputs
,