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>
39
40 #define MAX_CHANNELS 64
41
50
52 /* channel mapping specific */
56
58 {
60
63 }
64
66 {
67 char buf[8];
68 int len, channel_id = 0;
69
71 /* try to parse a channel name, e.g. "FL" */
72 if (sscanf(*
arg,
"%7[A-Z]%n", buf, &
len)) {
74 if (channel_id < 0)
75 return channel_id;
76
77 *rchannel = channel_id;
78 *rnamed = 1;
80 return 0;
81 }
82 /* try to parse a channel number, e.g. "c2" */
83 if (sscanf(*
arg,
"c%d%n", &channel_id, &
len) &&
85 *rchannel = channel_id;
86 *rnamed = 0;
88 return 0;
89 }
91 }
92
94 {
97 int out_ch_id, in_ch_id,
len, named,
ret, sign = 1;
98 int nb_in_channels[2] = { 0, 0 }; // number of unnamed and named input channels
100 double gain;
101
104 "pan filter needs a channel layout and a set "
105 "of channel definitions as parameter\n");
107 }
108 if (!args)
115 }
120
123 "af_pan supports a maximum of %d channels. "
124 "Feel free to ask for a higher limit.\n",
MAX_CHANNELS);
127 }
128
129 /* parse channel specifications */
132 /* channel name */
135 "Expected out channel name, got \"%.8s\"\n",
arg);
138 }
139 if (named) {
142 "Channel \"%.8s\" does not exist in the chosen layout\n", arg0);
145 }
146 }
149 "Invalid out channel name \"%.8s\"\n", arg0);
152 }
153 if (used_out_ch[out_ch_id]) {
155 "Can not reference out channel %d twice\n", out_ch_id);
158 }
159 used_out_ch[out_ch_id] = 1;
163 }
else if (*
arg ==
'<') {
166 } else {
168 "Syntax error after channel name in \"%.8s\"\n", arg0);
171 }
172 /* gains */
173 sign = 1;
174 while (1) {
175 gain = 1;
176 if (sscanf(
arg,
"%lf%n *%n", &gain, &
len, &
len))
180 "Expected in channel name, got \"%.8s\"\n",
arg);
183 }
184 nb_in_channels[named]++;
185 if (nb_in_channels[!named]) {
187 "Can not mix named and numbered channels\n");
190 }
191 if (used_in_ch[in_ch_id]) {
193 "Can not reference in channel %d twice\n", in_ch_id);
196 }
197 used_in_ch[in_ch_id] = 1;
198 pan->
gain[out_ch_id][in_ch_id] = sign * gain;
201 break;
203 sign = -1;
204 }
else if (*
arg !=
'+') {
208 } else {
209 sign = 1;
210 }
212 }
213 }
215
220 }
221
223 {
225
227 int nb_gain = 0;
228
230 double gain = pan->
gain[
i][j];
231
232 /* channel mapping is effective only if 0% or 100% of a channel is
233 * selected... */
234 if (gain != 0. && gain != 1.)
235 return 0;
236 /* ...and if the output channel is only composed of one input */
237 if (gain && nb_gain++)
238 return 0;
239 }
240 }
241 return 1;
242 }
243
245 {
251
253 /* libswr supports any sample and packing formats */
256
259
260 // inlink supports any channel layout
264
265 // outlink supports only requested output channel layout
270 }
271
273 {
276 char buf[1024], *cur;
278 double t;
279
281 // input channels were given by their name: renumber them
286 j++;
287 }
288 }
289 }
290
291 // sanity check; can't be done in query_formats since the inlink
292 // channel layout is unknown at that time
296 "af_pan supports a maximum of %d channels. "
297 "Feel free to ask for a higher limit.\n",
MAX_CHANNELS);
299 }
300
301 // init libswresample context
308
309 // gains are pure, init the channel mapping
311
312 // get channel map from the pure gains
314 int ch_id = -1;
316 if (pan->
gain[
i][j]) {
317 ch_id = j;
318 break;
319 }
320 }
322 }
323
326 } else {
327 // renormalize
330 continue;
331 t = 0;
334 if (t > -1
E-5 && t < 1
E-5) {
335 // t is almost 0 but not exactly, this is probably a mistake
336 if (t)
338 "Degenerate coefficients while renormalizing\n");
339 continue;
340 }
342 pan->
gain[
i][j] /= t;
343 }
345 }
346
350
351 // summary
353 cur = buf;
355 r =
snprintf(cur, buf +
sizeof(buf) - cur,
"%s%.3g i%d",
356 j ?
" + " :
"", pan->
gain[
i][j], j);
357 cur +=
FFMIN(buf +
sizeof(buf) - cur,
r);
358 }
360 }
361 // add channel mapping summary if possible
367 else
370 return 0;
371 }
372 return 0;
373 }
374
376 {
382
383 if (!outsamples) {
386 }
394 }
395
398 }
399
401 {
405 }
406
407 #define OFFSET(x) offsetof(PanContext, x)
408
412 };
413
415
417 {
422 },
423 };
424
429 .priv_class = &pan_class,
435 };