mirror of
https://github.com/FFmpeg/FFmpeg.git
synced 2025-02-09 14:14:39 +02:00
avfilter/af_afir: add irnorm and irlink options
Deprecate gtype option.
This commit is contained in:
parent
07c303b708
commit
5452cbdc15
@ -1794,33 +1794,24 @@ Set wet gain. This sets final output gain.
|
|||||||
Set Impulse Response filter length. Default is 1, which means whole IR is processed.
|
Set Impulse Response filter length. Default is 1, which means whole IR is processed.
|
||||||
|
|
||||||
@item gtype
|
@item gtype
|
||||||
Enable applying gain measured from power of IR.
|
This option is deprecated, and does nothing.
|
||||||
|
|
||||||
Set which approach to use for auto gain measurement.
|
@item irnorm
|
||||||
|
Set norm to be applied to IR coefficients before filtering.
|
||||||
|
Allowed range is from @var{-1} to @var{2}.
|
||||||
|
IR coefficients are normalized with calculated vector norm set by this option.
|
||||||
|
For negative values, no norm is calculated, and IR coefficients are not modified at all.
|
||||||
|
Default is @var{1}.
|
||||||
|
|
||||||
@table @option
|
@item irlink
|
||||||
@item none
|
For multichannel IR if this option is set to @var{true}. All IR channels will be
|
||||||
Do not apply any gain.
|
normalized with maximal measured gain of all IR channels coefficients as set by @code{irnorm} option.
|
||||||
|
When disabled, all IR coefficients in each IR channel will be normalized independently.
|
||||||
@item peak
|
Default is @var{true}.
|
||||||
select peak gain, very conservative approach. This is default value.
|
|
||||||
|
|
||||||
@item dc
|
|
||||||
select DC gain, limited application.
|
|
||||||
|
|
||||||
@item gn
|
|
||||||
select gain to noise approach, this is most popular one.
|
|
||||||
|
|
||||||
@item ac
|
|
||||||
select AC gain.
|
|
||||||
|
|
||||||
@item rms
|
|
||||||
select RMS gain.
|
|
||||||
@end table
|
|
||||||
|
|
||||||
@item irgain
|
@item irgain
|
||||||
Set gain to be applied to IR coefficients before filtering.
|
Set gain to be applied to IR coefficients before filtering.
|
||||||
Allowed range is 0 to 1. This gain is applied after any gain applied with @var{gtype} option.
|
Allowed range is 0 to 1. This gain is applied after any gain applied with @var{irnorm} option.
|
||||||
|
|
||||||
@item irfmt
|
@item irfmt
|
||||||
Set format of IR stream. Can be @code{mono} or @code{input}.
|
Set format of IR stream. Can be @code{mono} or @code{input}.
|
||||||
@ -1899,7 +1890,7 @@ ffmpeg -i input.wav -i middle_tunnel_1way_mono.wav -lavfi afir output.wav
|
|||||||
Apply true stereo processing given input stereo stream, and two stereo impulse responses for left and right channel,
|
Apply true stereo processing given input stereo stream, and two stereo impulse responses for left and right channel,
|
||||||
the impulse response files are files with names l_ir.wav and r_ir.wav:
|
the impulse response files are files with names l_ir.wav and r_ir.wav:
|
||||||
@example
|
@example
|
||||||
"pan=4C|c0=FL|c1=FL|c2=FR|c3=FR[a];amovie=l_ir.wav[LIR];amovie=r_ir.wav[RIR];[LIR][RIR]amerge[ir];[a][ir]afir=irfmt=input:gtype=gn:irgain=-5dB,pan=stereo|FL<c0+c2|FR<c1+c3"
|
"pan=4C|c0=FL|c1=FL|c2=FR|c3=FR[a];amovie=l_ir.wav[LIR];amovie=r_ir.wav[RIR];[LIR][RIR]amerge[ir];[a][ir]afir=irfmt=input:irgain=-5dB,pan=stereo|FL<c0+c2|FR<c1+c3"
|
||||||
@end example
|
@end example
|
||||||
@end itemize
|
@end itemize
|
||||||
|
|
||||||
|
@ -393,6 +393,22 @@ skip:
|
|||||||
|
|
||||||
switch (s->format) {
|
switch (s->format) {
|
||||||
case AV_SAMPLE_FMT_FLTP:
|
case AV_SAMPLE_FMT_FLTP:
|
||||||
|
for (int ch = 0; ch < s->nb_channels; ch++) {
|
||||||
|
const float *tsrc = (const float *)s->ir[selir]->extended_data[!s->one2many * ch];
|
||||||
|
|
||||||
|
s->ch_gain[ch] = ir_gain_float(ctx, s, nb_taps, tsrc);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (s->ir_link) {
|
||||||
|
float gain = +INFINITY;
|
||||||
|
|
||||||
|
for (int ch = 0; ch < s->nb_channels; ch++)
|
||||||
|
gain = fminf(gain, s->ch_gain[ch]);
|
||||||
|
|
||||||
|
for (int ch = 0; ch < s->nb_channels; ch++)
|
||||||
|
s->ch_gain[ch] = gain;
|
||||||
|
}
|
||||||
|
|
||||||
for (int ch = 0; ch < s->nb_channels; ch++) {
|
for (int ch = 0; ch < s->nb_channels; ch++) {
|
||||||
const float *tsrc = (const float *)s->ir[selir]->extended_data[!s->one2many * ch];
|
const float *tsrc = (const float *)s->ir[selir]->extended_data[!s->one2many * ch];
|
||||||
float *time = (float *)s->norm_ir[selir]->extended_data[ch];
|
float *time = (float *)s->norm_ir[selir]->extended_data[ch];
|
||||||
@ -401,7 +417,7 @@ skip:
|
|||||||
for (int i = FFMAX(1, s->length * nb_taps); i < nb_taps; i++)
|
for (int i = FFMAX(1, s->length * nb_taps); i < nb_taps; i++)
|
||||||
time[i] = 0;
|
time[i] = 0;
|
||||||
|
|
||||||
get_power_float(ctx, s, nb_taps, ch, time);
|
ir_scale_float(ctx, s, nb_taps, ch, time, s->ch_gain[ch]);
|
||||||
|
|
||||||
for (int n = 0; n < s->nb_segments[selir]; n++) {
|
for (int n = 0; n < s->nb_segments[selir]; n++) {
|
||||||
AudioFIRSegment *seg = &s->seg[selir][n];
|
AudioFIRSegment *seg = &s->seg[selir][n];
|
||||||
@ -417,6 +433,22 @@ skip:
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case AV_SAMPLE_FMT_DBLP:
|
case AV_SAMPLE_FMT_DBLP:
|
||||||
|
for (int ch = 0; ch < s->nb_channels; ch++) {
|
||||||
|
const double *tsrc = (const double *)s->ir[selir]->extended_data[!s->one2many * ch];
|
||||||
|
|
||||||
|
s->ch_gain[ch] = ir_gain_double(ctx, s, nb_taps, tsrc);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (s->ir_link) {
|
||||||
|
double gain = +INFINITY;
|
||||||
|
|
||||||
|
for (int ch = 0; ch < s->nb_channels; ch++)
|
||||||
|
gain = fmin(gain, s->ch_gain[ch]);
|
||||||
|
|
||||||
|
for (int ch = 0; ch < s->nb_channels; ch++)
|
||||||
|
s->ch_gain[ch] = gain;
|
||||||
|
}
|
||||||
|
|
||||||
for (int ch = 0; ch < s->nb_channels; ch++) {
|
for (int ch = 0; ch < s->nb_channels; ch++) {
|
||||||
const double *tsrc = (const double *)s->ir[selir]->extended_data[!s->one2many * ch];
|
const double *tsrc = (const double *)s->ir[selir]->extended_data[!s->one2many * ch];
|
||||||
double *time = (double *)s->norm_ir[selir]->extended_data[ch];
|
double *time = (double *)s->norm_ir[selir]->extended_data[ch];
|
||||||
@ -425,7 +457,8 @@ skip:
|
|||||||
for (int i = FFMAX(1, s->length * nb_taps); i < nb_taps; i++)
|
for (int i = FFMAX(1, s->length * nb_taps); i < nb_taps; i++)
|
||||||
time[i] = 0;
|
time[i] = 0;
|
||||||
|
|
||||||
get_power_double(ctx, s, nb_taps, ch, time);
|
ir_scale_double(ctx, s, nb_taps, ch, time, s->ch_gain[ch]);
|
||||||
|
|
||||||
for (int n = 0; n < s->nb_segments[selir]; n++) {
|
for (int n = 0; n < s->nb_segments[selir]; n++) {
|
||||||
AudioFIRSegment *seg = &s->seg[selir][n];
|
AudioFIRSegment *seg = &s->seg[selir][n];
|
||||||
|
|
||||||
@ -627,8 +660,9 @@ FF_ENABLE_DEPRECATION_WARNINGS
|
|||||||
|
|
||||||
s->format = outlink->format;
|
s->format = outlink->format;
|
||||||
s->nb_channels = outlink->ch_layout.nb_channels;
|
s->nb_channels = outlink->ch_layout.nb_channels;
|
||||||
|
s->ch_gain = av_calloc(ctx->inputs[0]->ch_layout.nb_channels, sizeof(*s->ch_gain));
|
||||||
s->loading = av_calloc(ctx->inputs[0]->ch_layout.nb_channels, sizeof(*s->loading));
|
s->loading = av_calloc(ctx->inputs[0]->ch_layout.nb_channels, sizeof(*s->loading));
|
||||||
if (!s->loading)
|
if (!s->loading || !s->ch_gain)
|
||||||
return AVERROR(ENOMEM);
|
return AVERROR(ENOMEM);
|
||||||
|
|
||||||
s->fadein[0] = ff_get_audio_buffer(outlink, s->min_part_size);
|
s->fadein[0] = ff_get_audio_buffer(outlink, s->min_part_size);
|
||||||
@ -674,6 +708,7 @@ static av_cold void uninit(AVFilterContext *ctx)
|
|||||||
AudioFIRContext *s = ctx->priv;
|
AudioFIRContext *s = ctx->priv;
|
||||||
|
|
||||||
av_freep(&s->fdsp);
|
av_freep(&s->fdsp);
|
||||||
|
av_freep(&s->ch_gain);
|
||||||
av_freep(&s->loading);
|
av_freep(&s->loading);
|
||||||
|
|
||||||
for (int i = 0; i < s->nb_irs; i++) {
|
for (int i = 0; i < s->nb_irs; i++) {
|
||||||
@ -812,13 +847,15 @@ static const AVOption afir_options[] = {
|
|||||||
{ "dry", "set dry gain", OFFSET(dry_gain), AV_OPT_TYPE_FLOAT, {.dbl=1}, 0, 10, AFR },
|
{ "dry", "set dry gain", OFFSET(dry_gain), AV_OPT_TYPE_FLOAT, {.dbl=1}, 0, 10, AFR },
|
||||||
{ "wet", "set wet gain", OFFSET(wet_gain), AV_OPT_TYPE_FLOAT, {.dbl=1}, 0, 10, AFR },
|
{ "wet", "set wet gain", OFFSET(wet_gain), AV_OPT_TYPE_FLOAT, {.dbl=1}, 0, 10, AFR },
|
||||||
{ "length", "set IR length", OFFSET(length), AV_OPT_TYPE_FLOAT, {.dbl=1}, 0, 1, AF },
|
{ "length", "set IR length", OFFSET(length), AV_OPT_TYPE_FLOAT, {.dbl=1}, 0, 1, AF },
|
||||||
{ "gtype", "set IR auto gain type",OFFSET(gtype), AV_OPT_TYPE_INT, {.i64=0}, -1, 4, AF, "gtype" },
|
{ "gtype", "set IR auto gain type",OFFSET(gtype), AV_OPT_TYPE_INT, {.i64=0}, -1, 4, AF|AV_OPT_FLAG_DEPRECATED, "gtype" },
|
||||||
{ "none", "without auto gain", 0, AV_OPT_TYPE_CONST, {.i64=-1}, 0, 0, AF, "gtype" },
|
{ "none", "without auto gain", 0, AV_OPT_TYPE_CONST, {.i64=-1}, 0, 0, AF|AV_OPT_FLAG_DEPRECATED, "gtype" },
|
||||||
{ "peak", "peak gain", 0, AV_OPT_TYPE_CONST, {.i64=0}, 0, 0, AF, "gtype" },
|
{ "peak", "peak gain", 0, AV_OPT_TYPE_CONST, {.i64=0}, 0, 0, AF|AV_OPT_FLAG_DEPRECATED, "gtype" },
|
||||||
{ "dc", "DC gain", 0, AV_OPT_TYPE_CONST, {.i64=1}, 0, 0, AF, "gtype" },
|
{ "dc", "DC gain", 0, AV_OPT_TYPE_CONST, {.i64=1}, 0, 0, AF|AV_OPT_FLAG_DEPRECATED, "gtype" },
|
||||||
{ "gn", "gain to noise", 0, AV_OPT_TYPE_CONST, {.i64=2}, 0, 0, AF, "gtype" },
|
{ "gn", "gain to noise", 0, AV_OPT_TYPE_CONST, {.i64=2}, 0, 0, AF|AV_OPT_FLAG_DEPRECATED, "gtype" },
|
||||||
{ "ac", "AC gain", 0, AV_OPT_TYPE_CONST, {.i64=3}, 0, 0, AF, "gtype" },
|
{ "ac", "AC gain", 0, AV_OPT_TYPE_CONST, {.i64=3}, 0, 0, AF|AV_OPT_FLAG_DEPRECATED, "gtype" },
|
||||||
{ "rms", "RMS gain", 0, AV_OPT_TYPE_CONST, {.i64=4}, 0, 0, AF, "gtype" },
|
{ "rms", "RMS gain", 0, AV_OPT_TYPE_CONST, {.i64=4}, 0, 0, AF|AV_OPT_FLAG_DEPRECATED, "gtype" },
|
||||||
|
{ "irnorm", "set IR norm", OFFSET(ir_norm), AV_OPT_TYPE_FLOAT, {.dbl=1}, -1, 2, AF },
|
||||||
|
{ "irlink", "set IR link", OFFSET(ir_link), AV_OPT_TYPE_BOOL, {.i64=1}, 0, 1, AF },
|
||||||
{ "irgain", "set IR gain", OFFSET(ir_gain), AV_OPT_TYPE_FLOAT, {.dbl=1}, 0, 1, AF },
|
{ "irgain", "set IR gain", OFFSET(ir_gain), AV_OPT_TYPE_FLOAT, {.dbl=1}, 0, 1, AF },
|
||||||
{ "irfmt", "set IR format", OFFSET(ir_format), AV_OPT_TYPE_INT, {.i64=1}, 0, 1, AF, "irfmt" },
|
{ "irfmt", "set IR format", OFFSET(ir_format), AV_OPT_TYPE_INT, {.i64=1}, 0, 1, AF, "irfmt" },
|
||||||
{ "mono", "single channel", 0, AV_OPT_TYPE_CONST, {.i64=0}, 0, 0, AF, "irfmt" },
|
{ "mono", "single channel", 0, AV_OPT_TYPE_CONST, {.i64=0}, 0, 0, AF, "irfmt" },
|
||||||
|
@ -63,6 +63,8 @@ typedef struct AudioFIRContext {
|
|||||||
float dry_gain;
|
float dry_gain;
|
||||||
float length;
|
float length;
|
||||||
int gtype;
|
int gtype;
|
||||||
|
float ir_norm;
|
||||||
|
float ir_link;
|
||||||
float ir_gain;
|
float ir_gain;
|
||||||
int ir_format;
|
int ir_format;
|
||||||
int ir_load;
|
int ir_load;
|
||||||
@ -87,6 +89,7 @@ typedef struct AudioFIRContext {
|
|||||||
int nb_channels;
|
int nb_channels;
|
||||||
int one2many;
|
int one2many;
|
||||||
int *loading;
|
int *loading;
|
||||||
|
double *ch_gain;
|
||||||
|
|
||||||
AudioFIRSegment seg[MAX_IR_STREAMS][1024];
|
AudioFIRSegment seg[MAX_IR_STREAMS][1024];
|
||||||
|
|
||||||
|
@ -29,6 +29,8 @@
|
|||||||
#undef HYPOT
|
#undef HYPOT
|
||||||
#undef SAMPLE_FORMAT
|
#undef SAMPLE_FORMAT
|
||||||
#undef TX_TYPE
|
#undef TX_TYPE
|
||||||
|
#undef FABS
|
||||||
|
#undef POW
|
||||||
#if DEPTH == 32
|
#if DEPTH == 32
|
||||||
#define SAMPLE_FORMAT float
|
#define SAMPLE_FORMAT float
|
||||||
#define SQRT sqrtf
|
#define SQRT sqrtf
|
||||||
@ -36,6 +38,8 @@
|
|||||||
#define ctype AVComplexFloat
|
#define ctype AVComplexFloat
|
||||||
#define ftype float
|
#define ftype float
|
||||||
#define TX_TYPE AV_TX_FLOAT_RDFT
|
#define TX_TYPE AV_TX_FLOAT_RDFT
|
||||||
|
#define FABS fabsf
|
||||||
|
#define POW powf
|
||||||
#else
|
#else
|
||||||
#define SAMPLE_FORMAT double
|
#define SAMPLE_FORMAT double
|
||||||
#define SQRT sqrt
|
#define SQRT sqrt
|
||||||
@ -43,6 +47,8 @@
|
|||||||
#define ctype AVComplexDouble
|
#define ctype AVComplexDouble
|
||||||
#define ftype double
|
#define ftype double
|
||||||
#define TX_TYPE AV_TX_DOUBLE_RDFT
|
#define TX_TYPE AV_TX_DOUBLE_RDFT
|
||||||
|
#define FABS fabs
|
||||||
|
#define POW pow
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define fn3(a,b) a##_##b
|
#define fn3(a,b) a##_##b
|
||||||
@ -139,95 +145,32 @@ end:
|
|||||||
av_free(mag);
|
av_free(mag);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int fn(get_power)(AVFilterContext *ctx, AudioFIRContext *s,
|
static ftype fn(ir_gain)(AVFilterContext *ctx, AudioFIRContext *s,
|
||||||
int cur_nb_taps, int ch,
|
int cur_nb_taps, const ftype *time)
|
||||||
ftype *time)
|
|
||||||
{
|
{
|
||||||
ftype ch_gain = 1;
|
ftype ch_gain, sum = 0;
|
||||||
|
|
||||||
switch (s->gtype) {
|
if (s->ir_norm < 0.f) {
|
||||||
case -1:
|
|
||||||
ch_gain = 1;
|
ch_gain = 1;
|
||||||
break;
|
} else if (s->ir_norm == 0.f) {
|
||||||
case 0:
|
for (int i = 0; i < cur_nb_taps; i++)
|
||||||
{
|
sum += time[i];
|
||||||
ftype sum = 0;
|
ch_gain = 1. / sum;
|
||||||
|
} else {
|
||||||
|
ftype ir_norm = s->ir_norm;
|
||||||
|
|
||||||
for (int i = 0; i < cur_nb_taps; i++)
|
for (int i = 0; i < cur_nb_taps; i++)
|
||||||
sum += FFABS(time[i]);
|
sum += POW(FABS(time[i]), ir_norm);
|
||||||
ch_gain = 1. / sum;
|
ch_gain = 1. / POW(sum, 1. / ir_norm);
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
{
|
|
||||||
ftype sum = 0;
|
|
||||||
|
|
||||||
for (int i = 0; i < cur_nb_taps; i++)
|
|
||||||
sum += time[i];
|
|
||||||
ch_gain = 1. / sum;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
{
|
|
||||||
ftype sum = 0;
|
|
||||||
|
|
||||||
for (int i = 0; i < cur_nb_taps; i++)
|
|
||||||
sum += time[i] * time[i];
|
|
||||||
ch_gain = 1. / SQRT(sum);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
case 4:
|
|
||||||
{
|
|
||||||
ftype *inc, *outc, scale, power;
|
|
||||||
AVTXContext *tx;
|
|
||||||
av_tx_fn tx_fn;
|
|
||||||
int ret, size;
|
|
||||||
|
|
||||||
size = 1 << av_ceil_log2_c(cur_nb_taps);
|
|
||||||
inc = av_calloc(size + 2, sizeof(SAMPLE_FORMAT));
|
|
||||||
outc = av_calloc(size + 2, sizeof(SAMPLE_FORMAT));
|
|
||||||
if (!inc || !outc) {
|
|
||||||
av_free(outc);
|
|
||||||
av_free(inc);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
scale = 1.;
|
|
||||||
ret = av_tx_init(&tx, &tx_fn, TX_TYPE, 0, size, &scale, 0);
|
|
||||||
if (ret < 0) {
|
|
||||||
av_free(outc);
|
|
||||||
av_free(inc);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
memcpy(inc, time, cur_nb_taps * sizeof(SAMPLE_FORMAT));
|
|
||||||
tx_fn(tx, outc, inc, sizeof(SAMPLE_FORMAT));
|
|
||||||
|
|
||||||
power = 0;
|
|
||||||
if (s->gtype == 3) {
|
|
||||||
for (int i = 0; i < size / 2 + 1; i++)
|
|
||||||
power = FFMAX(power, HYPOT(outc[i * 2], outc[i * 2 + 1]));
|
|
||||||
} else {
|
|
||||||
ftype sum = 0;
|
|
||||||
for (int i = 0; i < size / 2 + 1; i++)
|
|
||||||
sum += HYPOT(outc[i * 2], outc[i * 2 + 1]);
|
|
||||||
power = SQRT(sum / (size / 2 + 1));
|
|
||||||
}
|
|
||||||
|
|
||||||
ch_gain = 1. / power;
|
|
||||||
}
|
|
||||||
|
|
||||||
av_tx_uninit(&tx);
|
|
||||||
av_free(outc);
|
|
||||||
av_free(inc);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return AVERROR_BUG;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return ch_gain;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void fn(ir_scale)(AVFilterContext *ctx, AudioFIRContext *s,
|
||||||
|
int cur_nb_taps, int ch,
|
||||||
|
ftype *time, ftype ch_gain)
|
||||||
|
{
|
||||||
if (ch_gain != 1. || s->ir_gain != 1.) {
|
if (ch_gain != 1. || s->ir_gain != 1.) {
|
||||||
ftype gain = ch_gain * s->ir_gain;
|
ftype gain = ch_gain * s->ir_gain;
|
||||||
|
|
||||||
@ -238,8 +181,6 @@ static int fn(get_power)(AVFilterContext *ctx, AudioFIRContext *s,
|
|||||||
s->fdsp->vector_dmul_scalar(time, time, gain, FFALIGN(cur_nb_taps, 8));
|
s->fdsp->vector_dmul_scalar(time, time, gain, FFALIGN(cur_nb_taps, 8));
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void fn(convert_channel)(AVFilterContext *ctx, AudioFIRContext *s, int ch,
|
static void fn(convert_channel)(AVFilterContext *ctx, AudioFIRContext *s, int ch,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user