Commit | Line | Data |
---|---|---|
2ba45a60 DM |
1 | /* |
2 | * Copyright (c) 2002 Anders Johansson <ajh@atri.curtin.edu.au> | |
3 | * Copyright (c) 2011 Clément Bœsch <u pkh me> | |
4 | * Copyright (c) 2011 Nicolas George <nicolas.george@normalesup.org> | |
5 | * | |
6 | * This file is part of FFmpeg. | |
7 | * | |
8 | * FFmpeg is free software; you can redistribute it and/or | |
9 | * modify it under the terms of the GNU Lesser General Public | |
10 | * License as published by the Free Software Foundation; either | |
11 | * version 2.1 of the License, or (at your option) any later version. | |
12 | * | |
13 | * FFmpeg is distributed in the hope that it will be useful, | |
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
16 | * GNU Lesser General Public License for more details. | |
17 | * | |
18 | * You should have received a copy of the GNU Lesser General Public | |
19 | * License along with FFmpeg; if not, write to the Free Software | |
20 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
21 | */ | |
22 | ||
23 | /** | |
24 | * @file | |
25 | * Audio panning filter (channels mixing) | |
26 | * Original code written by Anders Johansson for MPlayer, | |
27 | * reimplemented for FFmpeg. | |
28 | */ | |
29 | ||
30 | #include <stdio.h> | |
31 | #include "libavutil/avstring.h" | |
32 | #include "libavutil/channel_layout.h" | |
33 | #include "libavutil/opt.h" | |
34 | #include "libswresample/swresample.h" | |
35 | #include "audio.h" | |
36 | #include "avfilter.h" | |
37 | #include "formats.h" | |
38 | #include "internal.h" | |
39 | ||
40 | #define MAX_CHANNELS 63 | |
41 | ||
42 | typedef struct PanContext { | |
43 | const AVClass *class; | |
44 | char *args; | |
45 | int64_t out_channel_layout; | |
46 | double gain[MAX_CHANNELS][MAX_CHANNELS]; | |
47 | int64_t need_renorm; | |
48 | int need_renumber; | |
49 | int nb_output_channels; | |
50 | ||
51 | int pure_gains; | |
52 | /* channel mapping specific */ | |
53 | int channel_map[MAX_CHANNELS]; | |
54 | struct SwrContext *swr; | |
55 | } PanContext; | |
56 | ||
57 | static void skip_spaces(char **arg) | |
58 | { | |
59 | int len = 0; | |
60 | ||
61 | sscanf(*arg, " %n", &len); | |
62 | *arg += len; | |
63 | } | |
64 | ||
65 | static int parse_channel_name(char **arg, int *rchannel, int *rnamed) | |
66 | { | |
67 | char buf[8]; | |
68 | int len, i, channel_id = 0; | |
69 | int64_t layout, layout0; | |
70 | ||
71 | skip_spaces(arg); | |
72 | /* try to parse a channel name, e.g. "FL" */ | |
73 | if (sscanf(*arg, "%7[A-Z]%n", buf, &len)) { | |
74 | layout0 = layout = av_get_channel_layout(buf); | |
75 | /* channel_id <- first set bit in layout */ | |
76 | for (i = 32; i > 0; i >>= 1) { | |
77 | if (layout >= (int64_t)1 << i) { | |
78 | channel_id += i; | |
79 | layout >>= i; | |
80 | } | |
81 | } | |
82 | /* reject layouts that are not a single channel */ | |
83 | if (channel_id >= MAX_CHANNELS || layout0 != (int64_t)1 << channel_id) | |
84 | return AVERROR(EINVAL); | |
85 | *rchannel = channel_id; | |
86 | *rnamed = 1; | |
87 | *arg += len; | |
88 | return 0; | |
89 | } | |
90 | /* try to parse a channel number, e.g. "c2" */ | |
91 | if (sscanf(*arg, "c%d%n", &channel_id, &len) && | |
92 | channel_id >= 0 && channel_id < MAX_CHANNELS) { | |
93 | *rchannel = channel_id; | |
94 | *rnamed = 0; | |
95 | *arg += len; | |
96 | return 0; | |
97 | } | |
98 | return AVERROR(EINVAL); | |
99 | } | |
100 | ||
101 | static av_cold int init(AVFilterContext *ctx) | |
102 | { | |
103 | PanContext *const pan = ctx->priv; | |
104 | char *arg, *arg0, *tokenizer, *args = av_strdup(pan->args); | |
105 | int out_ch_id, in_ch_id, len, named, ret; | |
106 | int nb_in_channels[2] = { 0, 0 }; // number of unnamed and named input channels | |
107 | double gain; | |
108 | ||
109 | if (!pan->args) { | |
110 | av_log(ctx, AV_LOG_ERROR, | |
111 | "pan filter needs a channel layout and a set " | |
112 | "of channels definitions as parameter\n"); | |
113 | return AVERROR(EINVAL); | |
114 | } | |
115 | if (!args) | |
116 | return AVERROR(ENOMEM); | |
117 | arg = av_strtok(args, "|", &tokenizer); | |
118 | ret = ff_parse_channel_layout(&pan->out_channel_layout, | |
119 | &pan->nb_output_channels, arg, ctx); | |
120 | if (ret < 0) | |
121 | goto fail; | |
122 | ||
123 | /* parse channel specifications */ | |
124 | while ((arg = arg0 = av_strtok(NULL, "|", &tokenizer))) { | |
125 | /* channel name */ | |
126 | if (parse_channel_name(&arg, &out_ch_id, &named)) { | |
127 | av_log(ctx, AV_LOG_ERROR, | |
128 | "Expected out channel name, got \"%.8s\"\n", arg); | |
129 | ret = AVERROR(EINVAL); | |
130 | goto fail; | |
131 | } | |
132 | if (named) { | |
133 | if (!((pan->out_channel_layout >> out_ch_id) & 1)) { | |
134 | av_log(ctx, AV_LOG_ERROR, | |
135 | "Channel \"%.8s\" does not exist in the chosen layout\n", arg0); | |
136 | ret = AVERROR(EINVAL); | |
137 | goto fail; | |
138 | } | |
139 | /* get the channel number in the output channel layout: | |
140 | * out_channel_layout & ((1 << out_ch_id) - 1) are all the | |
141 | * channels that come before out_ch_id, | |
142 | * so their count is the index of out_ch_id */ | |
143 | out_ch_id = av_get_channel_layout_nb_channels(pan->out_channel_layout & (((int64_t)1 << out_ch_id) - 1)); | |
144 | } | |
145 | if (out_ch_id < 0 || out_ch_id >= pan->nb_output_channels) { | |
146 | av_log(ctx, AV_LOG_ERROR, | |
147 | "Invalid out channel name \"%.8s\"\n", arg0); | |
148 | ret = AVERROR(EINVAL); | |
149 | goto fail; | |
150 | } | |
151 | skip_spaces(&arg); | |
152 | if (*arg == '=') { | |
153 | arg++; | |
154 | } else if (*arg == '<') { | |
155 | pan->need_renorm |= (int64_t)1 << out_ch_id; | |
156 | arg++; | |
157 | } else { | |
158 | av_log(ctx, AV_LOG_ERROR, | |
159 | "Syntax error after channel name in \"%.8s\"\n", arg0); | |
160 | ret = AVERROR(EINVAL); | |
161 | goto fail; | |
162 | } | |
163 | /* gains */ | |
164 | while (1) { | |
165 | gain = 1; | |
166 | if (sscanf(arg, "%lf%n *%n", &gain, &len, &len)) | |
167 | arg += len; | |
168 | if (parse_channel_name(&arg, &in_ch_id, &named)){ | |
169 | av_log(ctx, AV_LOG_ERROR, | |
170 | "Expected in channel name, got \"%.8s\"\n", arg); | |
171 | ret = AVERROR(EINVAL); | |
172 | goto fail; | |
173 | } | |
174 | nb_in_channels[named]++; | |
175 | if (nb_in_channels[!named]) { | |
176 | av_log(ctx, AV_LOG_ERROR, | |
177 | "Can not mix named and numbered channels\n"); | |
178 | ret = AVERROR(EINVAL); | |
179 | goto fail; | |
180 | } | |
181 | pan->gain[out_ch_id][in_ch_id] = gain; | |
182 | skip_spaces(&arg); | |
183 | if (!*arg) | |
184 | break; | |
185 | if (*arg != '+') { | |
186 | av_log(ctx, AV_LOG_ERROR, "Syntax error near \"%.8s\"\n", arg); | |
187 | ret = AVERROR(EINVAL); | |
188 | goto fail; | |
189 | } | |
190 | arg++; | |
191 | } | |
192 | } | |
193 | pan->need_renumber = !!nb_in_channels[1]; | |
194 | ||
195 | ret = 0; | |
196 | fail: | |
197 | av_free(args); | |
198 | return ret; | |
199 | } | |
200 | ||
201 | static int are_gains_pure(const PanContext *pan) | |
202 | { | |
203 | int i, j; | |
204 | ||
205 | for (i = 0; i < MAX_CHANNELS; i++) { | |
206 | int nb_gain = 0; | |
207 | ||
208 | for (j = 0; j < MAX_CHANNELS; j++) { | |
209 | double gain = pan->gain[i][j]; | |
210 | ||
211 | /* channel mapping is effective only if 0% or 100% of a channel is | |
212 | * selected... */ | |
213 | if (gain != 0. && gain != 1.) | |
214 | return 0; | |
215 | /* ...and if the output channel is only composed of one input */ | |
216 | if (gain && nb_gain++) | |
217 | return 0; | |
218 | } | |
219 | } | |
220 | return 1; | |
221 | } | |
222 | ||
223 | static int query_formats(AVFilterContext *ctx) | |
224 | { | |
225 | PanContext *pan = ctx->priv; | |
226 | AVFilterLink *inlink = ctx->inputs[0]; | |
227 | AVFilterLink *outlink = ctx->outputs[0]; | |
228 | AVFilterFormats *formats = NULL; | |
229 | AVFilterChannelLayouts *layouts; | |
230 | ||
231 | pan->pure_gains = are_gains_pure(pan); | |
232 | /* libswr supports any sample and packing formats */ | |
233 | ff_set_common_formats(ctx, ff_all_formats(AVMEDIA_TYPE_AUDIO)); | |
234 | ||
235 | formats = ff_all_samplerates(); | |
236 | if (!formats) | |
237 | return AVERROR(ENOMEM); | |
238 | ff_set_common_samplerates(ctx, formats); | |
239 | ||
240 | // inlink supports any channel layout | |
241 | layouts = ff_all_channel_counts(); | |
242 | ff_channel_layouts_ref(layouts, &inlink->out_channel_layouts); | |
243 | ||
244 | // outlink supports only requested output channel layout | |
245 | layouts = NULL; | |
246 | ff_add_channel_layout(&layouts, | |
247 | pan->out_channel_layout ? pan->out_channel_layout : | |
248 | FF_COUNT2LAYOUT(pan->nb_output_channels)); | |
249 | ff_channel_layouts_ref(layouts, &outlink->in_channel_layouts); | |
250 | return 0; | |
251 | } | |
252 | ||
253 | static int config_props(AVFilterLink *link) | |
254 | { | |
255 | AVFilterContext *ctx = link->dst; | |
256 | PanContext *pan = ctx->priv; | |
257 | char buf[1024], *cur; | |
258 | int i, j, k, r; | |
259 | double t; | |
260 | ||
261 | if (pan->need_renumber) { | |
262 | // input channels were given by their name: renumber them | |
263 | for (i = j = 0; i < MAX_CHANNELS; i++) { | |
264 | if ((link->channel_layout >> i) & 1) { | |
265 | for (k = 0; k < pan->nb_output_channels; k++) | |
266 | pan->gain[k][j] = pan->gain[k][i]; | |
267 | j++; | |
268 | } | |
269 | } | |
270 | } | |
271 | ||
272 | // sanity check; can't be done in query_formats since the inlink | |
273 | // channel layout is unknown at that time | |
274 | if (link->channels > MAX_CHANNELS || | |
275 | pan->nb_output_channels > MAX_CHANNELS) { | |
276 | av_log(ctx, AV_LOG_ERROR, | |
277 | "af_pan support a maximum of %d channels. " | |
278 | "Feel free to ask for a higher limit.\n", MAX_CHANNELS); | |
279 | return AVERROR_PATCHWELCOME; | |
280 | } | |
281 | ||
282 | // init libswresample context | |
283 | pan->swr = swr_alloc_set_opts(pan->swr, | |
284 | pan->out_channel_layout, link->format, link->sample_rate, | |
285 | link->channel_layout, link->format, link->sample_rate, | |
286 | 0, ctx); | |
287 | if (!pan->swr) | |
288 | return AVERROR(ENOMEM); | |
289 | if (!link->channel_layout) { | |
290 | if (av_opt_set_int(pan->swr, "ich", link->channels, 0) < 0) | |
291 | return AVERROR(EINVAL); | |
292 | } | |
293 | if (!pan->out_channel_layout) { | |
294 | if (av_opt_set_int(pan->swr, "och", pan->nb_output_channels, 0) < 0) | |
295 | return AVERROR(EINVAL); | |
296 | } | |
297 | ||
298 | // gains are pure, init the channel mapping | |
299 | if (pan->pure_gains) { | |
300 | ||
301 | // get channel map from the pure gains | |
302 | for (i = 0; i < pan->nb_output_channels; i++) { | |
303 | int ch_id = -1; | |
304 | for (j = 0; j < link->channels; j++) { | |
305 | if (pan->gain[i][j]) { | |
306 | ch_id = j; | |
307 | break; | |
308 | } | |
309 | } | |
310 | pan->channel_map[i] = ch_id; | |
311 | } | |
312 | ||
313 | av_opt_set_int(pan->swr, "icl", pan->out_channel_layout, 0); | |
314 | av_opt_set_int(pan->swr, "uch", pan->nb_output_channels, 0); | |
315 | swr_set_channel_mapping(pan->swr, pan->channel_map); | |
316 | } else { | |
317 | // renormalize | |
318 | for (i = 0; i < pan->nb_output_channels; i++) { | |
319 | if (!((pan->need_renorm >> i) & 1)) | |
320 | continue; | |
321 | t = 0; | |
322 | for (j = 0; j < link->channels; j++) | |
323 | t += pan->gain[i][j]; | |
324 | if (t > -1E-5 && t < 1E-5) { | |
325 | // t is almost 0 but not exactly, this is probably a mistake | |
326 | if (t) | |
327 | av_log(ctx, AV_LOG_WARNING, | |
328 | "Degenerate coefficients while renormalizing\n"); | |
329 | continue; | |
330 | } | |
331 | for (j = 0; j < link->channels; j++) | |
332 | pan->gain[i][j] /= t; | |
333 | } | |
334 | av_opt_set_int(pan->swr, "icl", link->channel_layout, 0); | |
335 | av_opt_set_int(pan->swr, "ocl", pan->out_channel_layout, 0); | |
336 | swr_set_matrix(pan->swr, pan->gain[0], pan->gain[1] - pan->gain[0]); | |
337 | } | |
338 | ||
339 | r = swr_init(pan->swr); | |
340 | if (r < 0) | |
341 | return r; | |
342 | ||
343 | // summary | |
344 | for (i = 0; i < pan->nb_output_channels; i++) { | |
345 | cur = buf; | |
346 | for (j = 0; j < link->channels; j++) { | |
347 | r = snprintf(cur, buf + sizeof(buf) - cur, "%s%.3g i%d", | |
348 | j ? " + " : "", pan->gain[i][j], j); | |
349 | cur += FFMIN(buf + sizeof(buf) - cur, r); | |
350 | } | |
351 | av_log(ctx, AV_LOG_VERBOSE, "o%d = %s\n", i, buf); | |
352 | } | |
353 | // add channel mapping summary if possible | |
354 | if (pan->pure_gains) { | |
355 | av_log(ctx, AV_LOG_INFO, "Pure channel mapping detected:"); | |
356 | for (i = 0; i < pan->nb_output_channels; i++) | |
357 | if (pan->channel_map[i] < 0) | |
358 | av_log(ctx, AV_LOG_INFO, " M"); | |
359 | else | |
360 | av_log(ctx, AV_LOG_INFO, " %d", pan->channel_map[i]); | |
361 | av_log(ctx, AV_LOG_INFO, "\n"); | |
362 | return 0; | |
363 | } | |
364 | return 0; | |
365 | } | |
366 | ||
367 | static int filter_frame(AVFilterLink *inlink, AVFrame *insamples) | |
368 | { | |
369 | int ret; | |
370 | int n = insamples->nb_samples; | |
371 | AVFilterLink *const outlink = inlink->dst->outputs[0]; | |
372 | AVFrame *outsamples = ff_get_audio_buffer(outlink, n); | |
373 | PanContext *pan = inlink->dst->priv; | |
374 | ||
375 | if (!outsamples) | |
376 | return AVERROR(ENOMEM); | |
377 | swr_convert(pan->swr, outsamples->extended_data, n, | |
378 | (void *)insamples->extended_data, n); | |
379 | av_frame_copy_props(outsamples, insamples); | |
380 | outsamples->channel_layout = outlink->channel_layout; | |
381 | av_frame_set_channels(outsamples, outlink->channels); | |
382 | ||
383 | ret = ff_filter_frame(outlink, outsamples); | |
384 | av_frame_free(&insamples); | |
385 | return ret; | |
386 | } | |
387 | ||
388 | static av_cold void uninit(AVFilterContext *ctx) | |
389 | { | |
390 | PanContext *pan = ctx->priv; | |
391 | swr_free(&pan->swr); | |
392 | } | |
393 | ||
394 | #define OFFSET(x) offsetof(PanContext, x) | |
395 | ||
396 | static const AVOption pan_options[] = { | |
397 | { "args", NULL, OFFSET(args), AV_OPT_TYPE_STRING, { .str = NULL }, CHAR_MIN, CHAR_MAX, AV_OPT_FLAG_AUDIO_PARAM | AV_OPT_FLAG_FILTERING_PARAM }, | |
398 | { NULL } | |
399 | }; | |
400 | ||
401 | AVFILTER_DEFINE_CLASS(pan); | |
402 | ||
403 | static const AVFilterPad pan_inputs[] = { | |
404 | { | |
405 | .name = "default", | |
406 | .type = AVMEDIA_TYPE_AUDIO, | |
407 | .config_props = config_props, | |
408 | .filter_frame = filter_frame, | |
409 | }, | |
410 | { NULL } | |
411 | }; | |
412 | ||
413 | static const AVFilterPad pan_outputs[] = { | |
414 | { | |
415 | .name = "default", | |
416 | .type = AVMEDIA_TYPE_AUDIO, | |
417 | }, | |
418 | { NULL } | |
419 | }; | |
420 | ||
421 | AVFilter ff_af_pan = { | |
422 | .name = "pan", | |
423 | .description = NULL_IF_CONFIG_SMALL("Remix channels with coefficients (panning)."), | |
424 | .priv_size = sizeof(PanContext), | |
425 | .priv_class = &pan_class, | |
426 | .init = init, | |
427 | .uninit = uninit, | |
428 | .query_formats = query_formats, | |
429 | .inputs = pan_inputs, | |
430 | .outputs = pan_outputs, | |
431 | }; |