FFmpeg
Loading...
Searching...
No Matches
af_pan.c
Go to the documentation of this file.
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"
33#include "libavutil/mem.h"
34#include "libavutil/opt.h"
36#include "audio.h"
37#include "avfilter.h"
38#include "filters.h"
39#include "formats.h"
40
41#define MAX_CHANNELS 64
42
57
58static void skip_spaces(char **arg)
59{
60 int len = 0;
61
62 sscanf(*arg, " %n", &len);
63 *arg += len;
64}
65
66static int parse_channel_name(char **arg, int *rchannel, int *rnamed)
67{
68 char buf[8];
69 int len, channel_id = 0;
70
72 /* try to parse a channel name, e.g. "FL" */
73 if (sscanf(*arg, "%7[A-Z]%n", buf, &len) >= 1) {
74 channel_id = av_channel_from_string(buf);
75 if (channel_id < 0)
76 return channel_id;
77
78 *rchannel = channel_id;
79 *rnamed = 1;
80 *arg += len;
81 return 0;
82 }
83 /* try to parse a channel number, e.g. "c2" */
84 if (sscanf(*arg, "c%d%n", &channel_id, &len) >= 1 &&
85 channel_id >= 0 && channel_id < MAX_CHANNELS) {
86 *rchannel = channel_id;
87 *rnamed = 0;
88 *arg += len;
89 return 0;
90 }
91 return AVERROR(EINVAL);
92}
93
94static int are_gains_pure(const PanContext *pan)
95{
96 int i, j;
97
98 for (i = 0; i < MAX_CHANNELS; i++) {
99 int nb_gain = 0;
100
101 for (j = 0; j < MAX_CHANNELS; j++) {
102 double gain = pan->gain[i][j];
103
104 /* channel mapping is effective only if 0% or 100% of a channel is
105 * selected... */
106 if (gain != 0. && gain != 1.)
107 return 0;
108 /* ...and if the output channel is only composed of one input */
109 if (gain && nb_gain++)
110 return 0;
111 }
112 }
113 return 1;
114}
115
117{
118 PanContext *const pan = ctx->priv;
119 char *arg, *arg0, *tokenizer, *args = av_strdup(pan->args);
120 int out_ch_id, in_ch_id, len, named, ret, sign = 1;
121 int nb_in_channels[2] = { 0, 0 }; // number of unnamed and named input channels
122 int used_out_ch[MAX_CHANNELS] = {0};
123 double gain;
124
125 if (!pan->args) {
127 "pan filter needs a channel layout and a set "
128 "of channel definitions as parameter\n");
129 return AVERROR(EINVAL);
130 }
131 if (!args)
132 return AVERROR(ENOMEM);
133 arg = av_strtok(args, "|", &tokenizer);
134 if (!arg) {
135 av_log(ctx, AV_LOG_ERROR, "Channel layout not specified\n");
136 ret = AVERROR(EINVAL);
137 goto fail;
138 }
140 &pan->nb_output_channels, arg, ctx);
141 if (ret < 0)
142 goto fail;
143
144 if (pan->nb_output_channels > MAX_CHANNELS) {
146 "af_pan supports a maximum of %d channels. "
147 "Feel free to ask for a higher limit.\n", MAX_CHANNELS);
149 goto fail;
150 }
151
152 /* parse channel specifications */
153 while ((arg = arg0 = av_strtok(NULL, "|", &tokenizer))) {
154 int used_in_ch[MAX_CHANNELS] = {0};
155 /* channel name */
156 if (parse_channel_name(&arg, &out_ch_id, &named)) {
158 "Expected out channel name, got \"%.8s\"\n", arg);
159 ret = AVERROR(EINVAL);
160 goto fail;
161 }
162 if (named) {
163 if ((out_ch_id = av_channel_layout_index_from_channel(&pan->out_channel_layout, out_ch_id)) < 0) {
165 "Channel \"%.8s\" does not exist in the chosen layout\n", arg0);
166 ret = AVERROR(EINVAL);
167 goto fail;
168 }
169 }
170 if (out_ch_id < 0 || out_ch_id >= pan->nb_output_channels) {
172 "Invalid out channel name \"%.8s\"\n", arg0);
173 ret = AVERROR(EINVAL);
174 goto fail;
175 }
176 if (used_out_ch[out_ch_id]) {
178 "Can not reference out channel %d twice\n", out_ch_id);
179 ret = AVERROR(EINVAL);
180 goto fail;
181 }
182 used_out_ch[out_ch_id] = 1;
184 if (*arg == '=') {
185 arg++;
186 } else if (*arg == '<') {
187 pan->need_renorm |= (int64_t)1 << out_ch_id;
188 arg++;
189 } else {
191 "Syntax error after channel name in \"%.8s\"\n", arg0);
192 ret = AVERROR(EINVAL);
193 goto fail;
194 }
195 /* gains */
196 sign = 1;
197 while (1) {
198 gain = 1;
199 if (sscanf(arg, "%lf%n *%n", &gain, &len, &len) >= 1)
200 arg += len;
201 if (parse_channel_name(&arg, &in_ch_id, &named)){
203 "Expected in channel name, got \"%.8s\"\n", arg);
204 ret = AVERROR(EINVAL);
205 goto fail;
206 }
207 nb_in_channels[named]++;
208 if (nb_in_channels[!named]) {
210 "Can not mix named and numbered channels\n");
211 ret = AVERROR(EINVAL);
212 goto fail;
213 }
214 if (in_ch_id < 0 || in_ch_id >= MAX_CHANNELS) {
216 "Input channel id %d is not supported\n", in_ch_id);
218 goto fail;
219 }
220 if (used_in_ch[in_ch_id]) {
222 "Can not reference in channel %d twice\n", in_ch_id);
223 ret = AVERROR(EINVAL);
224 goto fail;
225 }
226 used_in_ch[in_ch_id] = 1;
227 pan->gain[out_ch_id][in_ch_id] = sign * gain;
229 if (!*arg)
230 break;
231 if (*arg == '-') {
232 sign = -1;
233 } else if (*arg != '+') {
234 av_log(ctx, AV_LOG_ERROR, "Syntax error near \"%.8s\"\n", arg);
235 ret = AVERROR(EINVAL);
236 goto fail;
237 } else {
238 sign = 1;
239 }
240 arg++;
241 }
242 }
243 pan->need_renumber = !!nb_in_channels[1];
244 pan->pure_gains = are_gains_pure(pan);
245
246 ret = 0;
247fail:
248 av_free(args);
249 return ret;
250}
251
253 AVFilterFormatsConfig **cfg_in,
254 AVFilterFormatsConfig **cfg_out)
255{
256 const PanContext *pan = ctx->priv;
258 int ret;
259
260 // inlink supports any channel layout
262 if ((ret = ff_channel_layouts_ref(layouts, &cfg_in[0]->channel_layouts)) < 0)
263 return ret;
264
265 // outlink supports only requested output channel layout
266 layouts = NULL;
267 if ((ret = ff_add_channel_layout(&layouts, &pan->out_channel_layout)) < 0)
268 return ret;
269 return ff_channel_layouts_ref(layouts, &cfg_out[0]->channel_layouts);
270}
271
272static int config_props(AVFilterLink *link)
273{
274 AVFilterContext *ctx = link->dst;
275 PanContext *pan = ctx->priv;
276 char buf[1024], *cur;
277 int i, j, k, r, ret;
278 double t;
279
280 if (pan->need_renumber) {
281 // input channels were given by their name: renumber them
282 for (i = j = 0; i < MAX_CHANNELS; i++) {
284 for (k = 0; k < pan->nb_output_channels; k++)
285 pan->gain[k][j] = pan->gain[k][i];
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
293 if (link->ch_layout.nb_channels > MAX_CHANNELS ||
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
302 ret = swr_alloc_set_opts2(&pan->swr,
303 &pan->out_channel_layout, link->format, link->sample_rate,
304 &link->ch_layout, link->format, link->sample_rate,
305 0, ctx);
306 if (ret < 0)
307 return AVERROR(ENOMEM);
308
309 // gains are pure, init the channel mapping
310 if (pan->pure_gains) {
311
312 // get channel map from the pure gains
313 for (i = 0; i < pan->nb_output_channels; i++) {
314 int ch_id = -1;
315 for (j = 0; j < link->ch_layout.nb_channels; j++) {
316 if (pan->gain[i][j]) {
317 ch_id = j;
318 break;
319 }
320 }
321 pan->channel_map[i] = ch_id;
322 }
323
324 av_opt_set_chlayout(pan->swr, "uchl", &pan->out_channel_layout, 0);
326 } else {
327 // renormalize
328 for (i = 0; i < pan->nb_output_channels; i++) {
329 if (!((pan->need_renorm >> i) & 1))
330 continue;
331 t = 0;
332 for (j = 0; j < link->ch_layout.nb_channels; j++)
333 t += fabs(pan->gain[i][j]);
334 if (t > -1E-5 && t < 1E-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 }
341 for (j = 0; j < link->ch_layout.nb_channels; j++)
342 pan->gain[i][j] /= t;
343 }
344 swr_set_matrix(pan->swr, pan->gain[0], pan->gain[1] - pan->gain[0]);
345 }
346
347 r = swr_init(pan->swr);
348 if (r < 0)
349 return r;
350
351 // summary
352 for (i = 0; i < pan->nb_output_channels; i++) {
353 cur = buf;
354 for (j = 0; j < link->ch_layout.nb_channels; j++) {
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 }
359 av_log(ctx, AV_LOG_VERBOSE, "o%d = %s\n", i, buf);
360 }
361 // add channel mapping summary if possible
362 if (pan->pure_gains) {
363 av_log(ctx, AV_LOG_INFO, "Pure channel mapping detected:");
364 for (i = 0; i < pan->nb_output_channels; i++)
365 if (pan->channel_map[i] < 0)
366 av_log(ctx, AV_LOG_INFO, " M");
367 else
368 av_log(ctx, AV_LOG_INFO, " %d", pan->channel_map[i]);
369 av_log(ctx, AV_LOG_INFO, "\n");
370 return 0;
371 }
372 return 0;
373}
374
375static int filter_frame(AVFilterLink *inlink, AVFrame *insamples)
376{
377 int ret;
378 int n = insamples->nb_samples;
379 AVFilterLink *const outlink = inlink->dst->outputs[0];
380 AVFrame *outsamples = ff_get_audio_buffer(outlink, n);
381 PanContext *pan = inlink->dst->priv;
382
383 if (!outsamples) {
384 av_frame_free(&insamples);
385 return AVERROR(ENOMEM);
386 }
387 swr_convert(pan->swr, outsamples->extended_data, n,
388 (void *)insamples->extended_data, n);
389 av_frame_copy_props(outsamples, insamples);
390 if ((ret = av_channel_layout_copy(&outsamples->ch_layout, &outlink->ch_layout)) < 0) {
391 av_frame_free(&outsamples);
392 av_frame_free(&insamples);
393 return ret;
394 }
395
396 av_frame_free(&insamples);
397 return ff_filter_frame(outlink, outsamples);
398}
399
401{
402 PanContext *pan = ctx->priv;
403 swr_free(&pan->swr);
405}
406
407#define OFFSET(x) offsetof(PanContext, x)
408
409static const AVOption pan_options[] = {
411 { NULL }
412};
413
415
416static const AVFilterPad pan_inputs[] = {
417 {
418 .name = "default",
419 .type = AVMEDIA_TYPE_AUDIO,
420 .config_props = config_props,
421 .filter_frame = filter_frame,
422 },
423};
424
426 .p.name = "pan",
427 .p.description = NULL_IF_CONFIG_SMALL("Remix channels with coefficients (panning)."),
428 .p.priv_class = &pan_class,
429 .priv_size = sizeof(PanContext),
430 .init = init,
431 .uninit = uninit,
435};
#define MAX_CHANNELS
Definition aac.h:33
static int query_formats(const AVFilterContext *ctx, AVFilterFormatsConfig **cfg_in, AVFilterFormatsConfig **cfg_out)
Definition aeval.c:246
static int parse_channel_name(char **arg, int *rchannel, int *rnamed)
Definition af_pan.c:66
static int filter_frame(AVFilterLink *inlink, AVFrame *insamples)
Definition af_pan.c:375
static const AVFilterPad pan_inputs[]
Definition af_pan.c:416
static int query_formats(const AVFilterContext *ctx, AVFilterFormatsConfig **cfg_in, AVFilterFormatsConfig **cfg_out)
Definition af_pan.c:252
const FFFilter ff_af_pan
Definition af_pan.c:425
static av_cold void uninit(AVFilterContext *ctx)
Definition af_pan.c:400
static const AVOption pan_options[]
Definition af_pan.c:409
#define MAX_CHANNELS
Definition af_pan.c:41
static void skip_spaces(char **arg)
Definition af_pan.c:58
#define OFFSET(x)
Definition af_pan.c:407
static int are_gains_pure(const PanContext *pan)
Definition af_pan.c:94
static int config_props(AVFilterLink *link)
Definition af_pan.c:272
static AVFormatContext * ctx
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_parse_channel_layout(AVChannelLayout *ret, int *nret, const char *arg, void *log_ctx)
Parse a channel layout or a corresponding integer representation.
Definition audio.c:99
AVFrame * ff_get_audio_buffer(AVFilterLink *link, int nb_samples)
Request an audio samples buffer with a specific set of permissions.
Definition audio.c:74
#define E
Definition avdct.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
Public libavutil channel layout APIs header.
#define NULL
Definition coverity.c:32
long long int64_t
Definition coverity.c:34
static __device__ float fabs(float a)
static const uint16_t channel_layouts[7]
Definition dca_lbr.c:112
static int filter_frame(DBEDecodeContext *s, AVFrame *frame)
Definition dolby_e.c:1067
int(* init)(AVBSFContext *ctx)
Definition dts2pts.c:608
int ff_add_channel_layout(AVFilterChannelLayouts **l, const AVChannelLayout *channel_layout)
Definition formats.c:588
AVFilterChannelLayouts * ff_all_channel_counts(void)
Construct an AVFilterChannelLayouts coding for any channel layout, with known or unknown disposition.
Definition formats.c:688
int ff_channel_layouts_ref(AVFilterChannelLayouts *f, AVFilterChannelLayouts **ref)
Add *ref as a new reference to f.
Definition formats.c:751
#define fail
Definition test.h:479
#define AV_OPT_FLAG_FILTERING_PARAM
A generic parameter which can be set by the user for filtering.
Definition opt.h:380
#define AV_OPT_FLAG_AUDIO_PARAM
Definition opt.h:356
@ 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
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.
void av_channel_layout_uninit(AVChannelLayout *channel_layout)
Free any allocated data in the channel layout and reset the channel count to 0.
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_PATCHWELCOME
Not yet implemented in FFmpeg, patches welcome.
Definition error.h:64
#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
int av_frame_copy_props(AVFrame *dst, const AVFrame *src)
Copy only "metadata" fields from src to dst.
Definition frame.c:599
#define AV_LOG_WARNING
Something somehow does not look correct.
Definition log.h:216
#define AV_LOG_VERBOSE
Detailed information.
Definition log.h:226
#define AV_LOG_INFO
Standard information.
Definition log.h:221
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition log.h:210
@ AVMEDIA_TYPE_AUDIO
Definition avutil.h:201
char * av_strtok(char *s, const char *delim, char **saveptr)
Split the string into several tokens which can be accessed by successive calls to av_strtok().
Definition avstring.c:179
int swr_set_channel_mapping(struct SwrContext *s, const int *channel_map)
Set a customized input channel mapping.
Definition swresample.c:47
int swr_alloc_set_opts2(struct SwrContext **ps, const AVChannelLayout *out_ch_layout, enum AVSampleFormat out_sample_fmt, int out_sample_rate, const AVChannelLayout *in_ch_layout, enum AVSampleFormat in_sample_fmt, int in_sample_rate, int log_offset, void *log_ctx)
Allocate SwrContext if needed and set/reset common parameters.
Definition swresample.c:54
av_cold void swr_free(SwrContext **ss)
Free the given SwrContext and set the pointer to NULL.
Definition swresample.c:137
int attribute_align_arg swr_convert(struct SwrContext *s, uint8_t *const *out_arg, int out_count, const uint8_t *const *in_arg, int in_count)
Convert audio.
Definition swresample.c:725
av_cold int swr_init(struct SwrContext *s)
Initialize context after user parameters have been set.
Definition swresample.c:156
int swr_set_matrix(struct SwrContext *s, const double *matrix, int stride)
Set a customized remix matrix.
Definition rematrix.c:71
int av_opt_set_chlayout(void *obj, const char *name, const AVChannelLayout *channel_layout, int search_flags)
Definition opt.c:1071
#define r
Definition input.c:42
static av_cold void uninit(AVBitStreamFilterContext *ctx)
const char * arg
Definition jacosubdec.c:65
#define FILTER_INPUTS(array)
Definition filters.h:264
#define FILTER_OUTPUTS(array)
Definition filters.h:265
#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
Memory handling functions.
enum MovChannelLayoutTag * layouts
Definition mov_chan.c:335
#define av_strdup(s)
Definition ops_static.c:55
AVOptions.
#define snprintf
Definition snprintf.h:34
static int config_props(AVBitStreamFilterLink *link)
Definition source.c:181
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
void * priv
private data for use by the filter
Definition avfilter.h:288
AVFilterLink ** outputs
array of pointers to output links
Definition avfilter.h:285
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
int nb_samples
number of audio samples (per channel) described by this frame
Definition frame.h:552
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
double gain[MAX_CHANNELS][MAX_CHANNELS]
Definition af_pan.c:47
int need_renumber
Definition af_pan.c:49
int64_t need_renorm
Definition af_pan.c:48
struct SwrContext * swr
Definition af_pan.c:55
char * args
Definition af_pan.c:45
int channel_map[MAX_CHANNELS]
Definition af_pan.c:54
int nb_output_channels
Definition af_pan.c:50
AVChannelLayout out_channel_layout
Definition af_pan.c:46
int pure_gains
Definition af_pan.c:52
The libswresample context.
libswresample public header
#define av_free(p)
#define av_log(a,...)
int len