2 * Copyright (c) 2012 Google, Inc.
4 * This file is part of FFmpeg.
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.
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.
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
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 #define F AV_OPT_FLAG_FILTERING_PARAM
72 static 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(channel_layout_str
), AV_OPT_TYPE_STRING
, .flags
= A
|F
},
80 AVFILTER_DEFINE_CLASS(channelmap
);
82 static char* split(char *message
, char delim
) {
83 char *next
= strchr(message
, delim
);
89 static int get_channel_idx(char **map
, int *ch
, char delim
, int max_ch
)
91 char *next
= split(*map
, delim
);
94 if (!next
&& delim
== '-')
95 return AVERROR(EINVAL
);
97 sscanf(*map
, "%d%n", ch
, &n
);
99 return AVERROR(EINVAL
);
100 if (*ch
< 0 || *ch
> max_ch
)
101 return AVERROR(EINVAL
);
106 static int get_channel(char **map
, uint64_t *ch
, char delim
)
108 char *next
= split(*map
, delim
);
109 if (!next
&& delim
== '-')
110 return AVERROR(EINVAL
);
111 *ch
= av_get_channel_layout(*map
);
112 if (av_get_channel_layout_nb_channels(*ch
) != 1)
113 return AVERROR(EINVAL
);
118 static av_cold
int channelmap_init(AVFilterContext
*ctx
)
120 ChannelMapContext
*s
= ctx
->priv
;
121 char *mapping
, separator
= '|';
124 enum MappingMode mode
;
125 uint64_t out_ch_mask
= 0;
128 mapping
= s
->mapping_str
;
133 char *dash
= strchr(mapping
, '-');
134 if (!dash
) { // short mapping
135 if (av_isdigit(*mapping
))
139 } else if (av_isdigit(*mapping
)) {
140 if (av_isdigit(*(dash
+1)))
141 mode
= MAP_PAIR_INT_INT
;
143 mode
= MAP_PAIR_INT_STR
;
145 if (av_isdigit(*(dash
+1)))
146 mode
= MAP_PAIR_STR_INT
;
148 mode
= MAP_PAIR_STR_STR
;
150 #if FF_API_OLD_FILTER_OPTS
151 if (strchr(mapping
, ',')) {
152 av_log(ctx
, AV_LOG_WARNING
, "This syntax is deprecated, use "
153 "'|' to separate the mappings.\n");
159 if (mode
!= MAP_NONE
) {
162 while ((sep
= strchr(sep
, separator
))) {
163 if (*++sep
) // Allow trailing comma
168 if (map_entries
> MAX_CH
) {
169 av_log(ctx
, AV_LOG_ERROR
, "Too many channels mapped: '%d'.\n", map_entries
);
170 return AVERROR(EINVAL
);
173 for (i
= 0; i
< map_entries
; i
++) {
174 int in_ch_idx
= -1, out_ch_idx
= -1;
175 uint64_t in_ch
= 0, out_ch
= 0;
176 static const char err
[] = "Failed to parse channel map\n";
179 if (get_channel_idx(&mapping
, &in_ch_idx
, separator
, MAX_CH
) < 0) {
180 av_log(ctx
, AV_LOG_ERROR
, err
);
181 return AVERROR(EINVAL
);
183 s
->map
[i
].in_channel_idx
= in_ch_idx
;
184 s
->map
[i
].out_channel_idx
= i
;
187 if (get_channel(&mapping
, &in_ch
, separator
) < 0) {
188 av_log(ctx
, AV_LOG_ERROR
, err
);
189 return AVERROR(EINVAL
);
191 s
->map
[i
].in_channel
= in_ch
;
192 s
->map
[i
].out_channel_idx
= i
;
194 case MAP_PAIR_INT_INT
:
195 if (get_channel_idx(&mapping
, &in_ch_idx
, '-', MAX_CH
) < 0 ||
196 get_channel_idx(&mapping
, &out_ch_idx
, separator
, MAX_CH
) < 0) {
197 av_log(ctx
, AV_LOG_ERROR
, err
);
198 return AVERROR(EINVAL
);
200 s
->map
[i
].in_channel_idx
= in_ch_idx
;
201 s
->map
[i
].out_channel_idx
= out_ch_idx
;
203 case MAP_PAIR_INT_STR
:
204 if (get_channel_idx(&mapping
, &in_ch_idx
, '-', MAX_CH
) < 0 ||
205 get_channel(&mapping
, &out_ch
, separator
) < 0 ||
206 out_ch
& out_ch_mask
) {
207 av_log(ctx
, AV_LOG_ERROR
, err
);
208 return AVERROR(EINVAL
);
210 s
->map
[i
].in_channel_idx
= in_ch_idx
;
211 s
->map
[i
].out_channel
= out_ch
;
212 out_ch_mask
|= out_ch
;
214 case MAP_PAIR_STR_INT
:
215 if (get_channel(&mapping
, &in_ch
, '-') < 0 ||
216 get_channel_idx(&mapping
, &out_ch_idx
, separator
, MAX_CH
) < 0) {
217 av_log(ctx
, AV_LOG_ERROR
, err
);
218 return AVERROR(EINVAL
);
220 s
->map
[i
].in_channel
= in_ch
;
221 s
->map
[i
].out_channel_idx
= out_ch_idx
;
223 case MAP_PAIR_STR_STR
:
224 if (get_channel(&mapping
, &in_ch
, '-') < 0 ||
225 get_channel(&mapping
, &out_ch
, separator
) < 0 ||
226 out_ch
& out_ch_mask
) {
227 av_log(ctx
, AV_LOG_ERROR
, err
);
228 return AVERROR(EINVAL
);
230 s
->map
[i
].in_channel
= in_ch
;
231 s
->map
[i
].out_channel
= out_ch
;
232 out_ch_mask
|= out_ch
;
237 s
->nch
= map_entries
;
238 s
->output_layout
= out_ch_mask
? out_ch_mask
:
239 av_get_default_channel_layout(map_entries
);
241 if (s
->channel_layout_str
) {
243 if ((fmt
= av_get_channel_layout(s
->channel_layout_str
)) == 0) {
244 av_log(ctx
, AV_LOG_ERROR
, "Error parsing channel layout: '%s'.\n",
245 s
->channel_layout_str
);
246 return AVERROR(EINVAL
);
248 if (mode
== MAP_NONE
) {
250 s
->nch
= av_get_channel_layout_nb_channels(fmt
);
251 for (i
= 0; i
< s
->nch
; i
++) {
252 s
->map
[i
].in_channel_idx
= i
;
253 s
->map
[i
].out_channel_idx
= i
;
255 } else if (out_ch_mask
&& out_ch_mask
!= fmt
) {
256 av_get_channel_layout_string(buf
, sizeof(buf
), 0, out_ch_mask
);
257 av_log(ctx
, AV_LOG_ERROR
,
258 "Output channel layout '%s' does not match the list of channel mapped: '%s'.\n",
259 s
->channel_layout_str
, buf
);
260 return AVERROR(EINVAL
);
261 } else if (s
->nch
!= av_get_channel_layout_nb_channels(fmt
)) {
262 av_log(ctx
, AV_LOG_ERROR
,
263 "Output channel layout %s does not match the number of channels mapped %d.\n",
264 s
->channel_layout_str
, s
->nch
);
265 return AVERROR(EINVAL
);
267 s
->output_layout
= fmt
;
269 if (!s
->output_layout
) {
270 av_log(ctx
, AV_LOG_ERROR
, "Output channel layout is not set and "
271 "cannot be guessed from the maps.\n");
272 return AVERROR(EINVAL
);
275 ff_add_channel_layout(&s
->channel_layouts
, s
->output_layout
);
277 if (mode
== MAP_PAIR_INT_STR
|| mode
== MAP_PAIR_STR_STR
) {
278 for (i
= 0; i
< s
->nch
; i
++) {
279 s
->map
[i
].out_channel_idx
= av_get_channel_layout_channel_index(
280 s
->output_layout
, s
->map
[i
].out_channel
);
287 static int channelmap_query_formats(AVFilterContext
*ctx
)
289 ChannelMapContext
*s
= ctx
->priv
;
290 AVFilterChannelLayouts
*layouts
;
292 ff_set_common_formats(ctx
, ff_planar_sample_fmts());
293 ff_set_common_samplerates(ctx
, ff_all_samplerates());
295 layouts
= ff_all_channel_layouts();
297 return AVERROR(ENOMEM
);
299 ff_channel_layouts_ref(layouts
, &ctx
->inputs
[0]->out_channel_layouts
);
300 ff_channel_layouts_ref(s
->channel_layouts
, &ctx
->outputs
[0]->in_channel_layouts
);
305 static int channelmap_filter_frame(AVFilterLink
*inlink
, AVFrame
*buf
)
307 AVFilterContext
*ctx
= inlink
->dst
;
308 AVFilterLink
*outlink
= ctx
->outputs
[0];
309 const ChannelMapContext
*s
= ctx
->priv
;
310 const int nch_in
= av_get_channel_layout_nb_channels(inlink
->channel_layout
);
311 const int nch_out
= s
->nch
;
313 uint8_t *source_planes
[MAX_CH
];
315 memcpy(source_planes
, buf
->extended_data
,
316 nch_in
* sizeof(source_planes
[0]));
318 if (nch_out
> nch_in
) {
319 if (nch_out
> FF_ARRAY_ELEMS(buf
->data
)) {
320 uint8_t **new_extended_data
=
321 av_mallocz_array(nch_out
, sizeof(*buf
->extended_data
));
322 if (!new_extended_data
) {
324 return AVERROR(ENOMEM
);
326 if (buf
->extended_data
== buf
->data
) {
327 buf
->extended_data
= new_extended_data
;
329 av_free(buf
->extended_data
);
330 buf
->extended_data
= new_extended_data
;
332 } else if (buf
->extended_data
!= buf
->data
) {
333 av_free(buf
->extended_data
);
334 buf
->extended_data
= buf
->data
;
338 for (ch
= 0; ch
< nch_out
; ch
++) {
339 buf
->extended_data
[s
->map
[ch
].out_channel_idx
] =
340 source_planes
[s
->map
[ch
].in_channel_idx
];
343 if (buf
->data
!= buf
->extended_data
)
344 memcpy(buf
->data
, buf
->extended_data
,
345 FFMIN(FF_ARRAY_ELEMS(buf
->data
), nch_out
) * sizeof(buf
->data
[0]));
347 buf
->channel_layout
= outlink
->channel_layout
;
349 return ff_filter_frame(outlink
, buf
);
352 static int channelmap_config_input(AVFilterLink
*inlink
)
354 AVFilterContext
*ctx
= inlink
->dst
;
355 ChannelMapContext
*s
= ctx
->priv
;
356 int nb_channels
= av_get_channel_layout_nb_channels(inlink
->channel_layout
);
358 const char *channel_name
;
359 char layout_name
[256];
361 for (i
= 0; i
< s
->nch
; i
++) {
362 struct ChannelMap
*m
= &s
->map
[i
];
364 if (s
->mode
== MAP_PAIR_STR_INT
|| s
->mode
== MAP_PAIR_STR_STR
) {
365 m
->in_channel_idx
= av_get_channel_layout_channel_index(
366 inlink
->channel_layout
, m
->in_channel
);
369 if (m
->in_channel_idx
< 0 || m
->in_channel_idx
>= nb_channels
) {
370 av_get_channel_layout_string(layout_name
, sizeof(layout_name
),
371 0, inlink
->channel_layout
);
373 channel_name
= av_get_channel_name(m
->in_channel
);
374 av_log(ctx
, AV_LOG_ERROR
,
375 "input channel '%s' not available from input layout '%s'\n",
376 channel_name
, layout_name
);
378 av_log(ctx
, AV_LOG_ERROR
,
379 "input channel #%d not available from input layout '%s'\n",
380 m
->in_channel_idx
, layout_name
);
382 err
= AVERROR(EINVAL
);
389 static const AVFilterPad avfilter_af_channelmap_inputs
[] = {
392 .type
= AVMEDIA_TYPE_AUDIO
,
393 .filter_frame
= channelmap_filter_frame
,
394 .config_props
= channelmap_config_input
,
400 static const AVFilterPad avfilter_af_channelmap_outputs
[] = {
403 .type
= AVMEDIA_TYPE_AUDIO
408 AVFilter ff_af_channelmap
= {
409 .name
= "channelmap",
410 .description
= NULL_IF_CONFIG_SMALL("Remap audio channels."),
411 .init
= channelmap_init
,
412 .query_formats
= channelmap_query_formats
,
413 .priv_size
= sizeof(ChannelMapContext
),
414 .priv_class
= &channelmap_class
,
415 .inputs
= avfilter_af_channelmap_inputs
,
416 .outputs
= avfilter_af_channelmap_outputs
,