|
|
|
@ -70,6 +70,7 @@ |
|
|
|
|
#include "libavutil/opt.h" |
|
|
|
|
#include "audio.h" |
|
|
|
|
#include "avfilter.h" |
|
|
|
|
#include "filters.h" |
|
|
|
|
#include "internal.h" |
|
|
|
|
|
|
|
|
|
enum FilterType { |
|
|
|
@ -109,6 +110,8 @@ enum TransformType { |
|
|
|
|
typedef struct ChanCache { |
|
|
|
|
double i1, i2; |
|
|
|
|
double o1, o2; |
|
|
|
|
double ri1, ri2; |
|
|
|
|
double ro1, ro2; |
|
|
|
|
int clippings; |
|
|
|
|
} ChanCache; |
|
|
|
|
|
|
|
|
@ -121,6 +124,7 @@ typedef struct BiquadsContext { |
|
|
|
|
int csg; |
|
|
|
|
int transform_type; |
|
|
|
|
int precision; |
|
|
|
|
int block_samples; |
|
|
|
|
|
|
|
|
|
int bypass; |
|
|
|
|
|
|
|
|
@ -139,6 +143,8 @@ typedef struct BiquadsContext { |
|
|
|
|
double oa0, oa1, oa2; |
|
|
|
|
double ob0, ob1, ob2; |
|
|
|
|
|
|
|
|
|
AVFrame *block[3]; |
|
|
|
|
|
|
|
|
|
ChanCache *cache; |
|
|
|
|
int block_align; |
|
|
|
|
|
|
|
|
@ -782,6 +788,14 @@ static int config_filter(AVFilterLink *outlink, int reset) |
|
|
|
|
if (reset) |
|
|
|
|
memset(s->cache, 0, sizeof(ChanCache) * inlink->ch_layout.nb_channels); |
|
|
|
|
|
|
|
|
|
if (reset && s->block_samples > 0) { |
|
|
|
|
for (int i = 0; i < 3; i++) { |
|
|
|
|
s->block[i] = ff_get_audio_buffer(outlink, s->block_samples * 2); |
|
|
|
|
if (!s->block[i]) |
|
|
|
|
return AVERROR(ENOMEM); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
switch (s->transform_type) { |
|
|
|
|
case DI: |
|
|
|
|
switch (inlink->format) { |
|
|
|
@ -908,6 +922,41 @@ typedef struct ThreadData { |
|
|
|
|
AVFrame *in, *out; |
|
|
|
|
} ThreadData; |
|
|
|
|
|
|
|
|
|
static void reverse_samples(AVFrame *out, AVFrame *in, int p, |
|
|
|
|
int oo, int io, int nb_samples) |
|
|
|
|
{ |
|
|
|
|
switch (out->format) { |
|
|
|
|
case AV_SAMPLE_FMT_S16P: { |
|
|
|
|
const int16_t *src = ((const int16_t *)out->extended_data[p]) + io; |
|
|
|
|
int16_t *dst = ((int16_t *)out->extended_data[p]) + oo; |
|
|
|
|
for (int i = 0, j = nb_samples - 1; i < nb_samples; i++, j--) |
|
|
|
|
dst[i] = src[j]; |
|
|
|
|
} |
|
|
|
|
break; |
|
|
|
|
case AV_SAMPLE_FMT_S32P: { |
|
|
|
|
const int32_t *src = ((const int32_t *)out->extended_data[p]) + io; |
|
|
|
|
int32_t *dst = ((int32_t *)out->extended_data[p]) + oo; |
|
|
|
|
for (int i = 0, j = nb_samples - 1; i < nb_samples; i++, j--) |
|
|
|
|
dst[i] = src[j]; |
|
|
|
|
} |
|
|
|
|
break; |
|
|
|
|
case AV_SAMPLE_FMT_FLTP: { |
|
|
|
|
const float *src = ((const float *)in->extended_data[p]) + io; |
|
|
|
|
float *dst = ((float *)out->extended_data[p]) + oo; |
|
|
|
|
for (int i = 0, j = nb_samples - 1; i < nb_samples; i++, j--) |
|
|
|
|
dst[i] = src[j]; |
|
|
|
|
} |
|
|
|
|
break; |
|
|
|
|
case AV_SAMPLE_FMT_DBLP: { |
|
|
|
|
const double *src = ((const double *)in->extended_data[p]) + io; |
|
|
|
|
double *dst = ((double *)out->extended_data[p]) + oo; |
|
|
|
|
for (int i = 0, j = nb_samples - 1; i < nb_samples; i++, j--) |
|
|
|
|
dst[i] = src[j]; |
|
|
|
|
} |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static int filter_channel(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) |
|
|
|
|
{ |
|
|
|
|
AVFilterLink *inlink = ctx->inputs[0]; |
|
|
|
@ -930,9 +979,37 @@ static int filter_channel(AVFilterContext *ctx, void *arg, int jobnr, int nb_job |
|
|
|
|
continue; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
s->filter(s, buf->extended_data[ch], out_buf->extended_data[ch], buf->nb_samples, |
|
|
|
|
&s->cache[ch].i1, &s->cache[ch].i2, &s->cache[ch].o1, &s->cache[ch].o2, |
|
|
|
|
s->b0, s->b1, s->b2, s->a1, s->a2, &s->cache[ch].clippings, ctx->is_disabled); |
|
|
|
|
if (!s->block_samples) { |
|
|
|
|
s->filter(s, buf->extended_data[ch], out_buf->extended_data[ch], buf->nb_samples, |
|
|
|
|
&s->cache[ch].i1, &s->cache[ch].i2, &s->cache[ch].o1, &s->cache[ch].o2, |
|
|
|
|
s->b0, s->b1, s->b2, s->a1, s->a2, &s->cache[ch].clippings, ctx->is_disabled); |
|
|
|
|
} else { |
|
|
|
|
memcpy(s->block[0]->extended_data[ch] + s->block_align * s->block_samples, buf->extended_data[ch], |
|
|
|
|
buf->nb_samples * s->block_align); |
|
|
|
|
s->filter(s, s->block[0]->extended_data[ch], s->block[1]->extended_data[ch], s->block_samples, |
|
|
|
|
&s->cache[ch].i1, &s->cache[ch].i2, &s->cache[ch].o1, &s->cache[ch].o2, |
|
|
|
|
s->b0, s->b1, s->b2, s->a1, s->a2, &s->cache[ch].clippings, ctx->is_disabled); |
|
|
|
|
s->cache[ch].ri1 = s->cache[ch].i1; |
|
|
|
|
s->cache[ch].ri2 = s->cache[ch].i2; |
|
|
|
|
s->cache[ch].ro1 = s->cache[ch].o1; |
|
|
|
|
s->cache[ch].ro2 = s->cache[ch].o2; |
|
|
|
|
s->filter(s, s->block[0]->extended_data[ch] + s->block_samples * s->block_align, |
|
|
|
|
s->block[1]->extended_data[ch] + s->block_samples * s->block_align, |
|
|
|
|
s->block_samples, |
|
|
|
|
&s->cache[ch].ri1, &s->cache[ch].ri2, &s->cache[ch].ro1, &s->cache[ch].ro2, |
|
|
|
|
s->b0, s->b1, s->b2, s->a1, s->a2, &s->cache[ch].clippings, ctx->is_disabled); |
|
|
|
|
reverse_samples(s->block[2], s->block[1], ch, 0, 0, s->block_samples * 2); |
|
|
|
|
s->cache[ch].ri1 = 0.; |
|
|
|
|
s->cache[ch].ri2 = 0.; |
|
|
|
|
s->cache[ch].ro1 = 0.; |
|
|
|
|
s->cache[ch].ro2 = 0.; |
|
|
|
|
s->filter(s, s->block[2]->extended_data[ch], s->block[2]->extended_data[ch], s->block[2]->nb_samples, |
|
|
|
|
&s->cache[ch].ri1, &s->cache[ch].ri2, &s->cache[ch].ro1, &s->cache[ch].ro2, |
|
|
|
|
s->b0, s->b1, s->b2, s->a1, s->a2, &s->cache[ch].clippings, ctx->is_disabled); |
|
|
|
|
reverse_samples(out_buf, s->block[2], ch, 0, s->block_samples, out_buf->nb_samples); |
|
|
|
|
memmove(s->block[0]->extended_data[ch], s->block[0]->extended_data[ch] + s->block_align * s->block_samples, |
|
|
|
|
s->block_samples * s->block_align); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return 0; |
|
|
|
@ -988,6 +1065,37 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *buf) |
|
|
|
|
return ff_filter_frame(outlink, out_buf); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static int activate(AVFilterContext *ctx) |
|
|
|
|
{ |
|
|
|
|
AVFilterLink *inlink = ctx->inputs[0]; |
|
|
|
|
AVFilterLink *outlink = ctx->outputs[0]; |
|
|
|
|
BiquadsContext *s = ctx->priv; |
|
|
|
|
AVFrame *in = NULL; |
|
|
|
|
int ret; |
|
|
|
|
|
|
|
|
|
FF_FILTER_FORWARD_STATUS_BACK(outlink, inlink); |
|
|
|
|
|
|
|
|
|
if (s->block_samples > 0) { |
|
|
|
|
ret = ff_inlink_consume_samples(inlink, s->block_samples, s->block_samples, &in); |
|
|
|
|
} else { |
|
|
|
|
ret = ff_inlink_consume_frame(inlink, &in); |
|
|
|
|
} |
|
|
|
|
if (ret < 0) |
|
|
|
|
return ret; |
|
|
|
|
if (ret > 0) |
|
|
|
|
return filter_frame(inlink, in); |
|
|
|
|
|
|
|
|
|
if (s->block_samples > 0 && ff_inlink_queued_samples(inlink) >= s->block_samples) { |
|
|
|
|
ff_filter_set_ready(ctx, 10); |
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
FF_FILTER_FORWARD_STATUS(inlink, outlink); |
|
|
|
|
FF_FILTER_FORWARD_WANTED(outlink, inlink); |
|
|
|
|
|
|
|
|
|
return FFERROR_NOT_READY; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static int process_command(AVFilterContext *ctx, const char *cmd, const char *args, |
|
|
|
|
char *res, int res_len, int flags) |
|
|
|
|
{ |
|
|
|
@ -1005,6 +1113,8 @@ static av_cold void uninit(AVFilterContext *ctx) |
|
|
|
|
{ |
|
|
|
|
BiquadsContext *s = ctx->priv; |
|
|
|
|
|
|
|
|
|
for (int i = 0; i < 3; i++) |
|
|
|
|
av_frame_free(&s->block[i]); |
|
|
|
|
av_freep(&s->cache); |
|
|
|
|
av_channel_layout_uninit(&s->ch_layout); |
|
|
|
|
} |
|
|
|
@ -1013,7 +1123,6 @@ static const AVFilterPad inputs[] = { |
|
|
|
|
{ |
|
|
|
|
.name = "default", |
|
|
|
|
.type = AVMEDIA_TYPE_AUDIO, |
|
|
|
|
.filter_frame = filter_frame, |
|
|
|
|
}, |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
@ -1043,6 +1152,7 @@ const AVFilter ff_af_##name_ = { \ |
|
|
|
|
.priv_class = &priv_class_##_class, \
|
|
|
|
|
.priv_size = sizeof(BiquadsContext), \
|
|
|
|
|
.init = name_##_init, \
|
|
|
|
|
.activate = activate, \
|
|
|
|
|
.uninit = uninit, \
|
|
|
|
|
FILTER_INPUTS(inputs), \
|
|
|
|
|
FILTER_OUTPUTS(outputs), \
|
|
|
|
@ -1091,6 +1201,8 @@ static const AVOption equalizer_options[] = { |
|
|
|
|
{"s32", "signed 32-bit", 0, AV_OPT_TYPE_CONST, {.i64=1}, 0, 0, AF, "precision"}, |
|
|
|
|
{"f32", "floating-point single", 0, AV_OPT_TYPE_CONST, {.i64=2}, 0, 0, AF, "precision"}, |
|
|
|
|
{"f64", "floating-point double", 0, AV_OPT_TYPE_CONST, {.i64=3}, 0, 0, AF, "precision"}, |
|
|
|
|
{"blocksize", "set the block size", OFFSET(block_samples), AV_OPT_TYPE_INT, {.i64=0}, 0, 32768, AF}, |
|
|
|
|
{"b", "set the block size", OFFSET(block_samples), AV_OPT_TYPE_INT, {.i64=0}, 0, 32768, AF}, |
|
|
|
|
{NULL} |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
@ -1134,6 +1246,8 @@ static const AVOption bass_lowshelf_options[] = { |
|
|
|
|
{"s32", "signed 32-bit", 0, AV_OPT_TYPE_CONST, {.i64=1}, 0, 0, AF, "precision"}, |
|
|
|
|
{"f32", "floating-point single", 0, AV_OPT_TYPE_CONST, {.i64=2}, 0, 0, AF, "precision"}, |
|
|
|
|
{"f64", "floating-point double", 0, AV_OPT_TYPE_CONST, {.i64=3}, 0, 0, AF, "precision"}, |
|
|
|
|
{"blocksize", "set the block size", OFFSET(block_samples), AV_OPT_TYPE_INT, {.i64=0}, 0, 32768, AF}, |
|
|
|
|
{"b", "set the block size", OFFSET(block_samples), AV_OPT_TYPE_INT, {.i64=0}, 0, 32768, AF}, |
|
|
|
|
{NULL} |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
@ -1184,6 +1298,8 @@ static const AVOption treble_highshelf_options[] = { |
|
|
|
|
{"s32", "signed 32-bit", 0, AV_OPT_TYPE_CONST, {.i64=1}, 0, 0, AF, "precision"}, |
|
|
|
|
{"f32", "floating-point single", 0, AV_OPT_TYPE_CONST, {.i64=2}, 0, 0, AF, "precision"}, |
|
|
|
|
{"f64", "floating-point double", 0, AV_OPT_TYPE_CONST, {.i64=3}, 0, 0, AF, "precision"}, |
|
|
|
|
{"blocksize", "set the block size", OFFSET(block_samples), AV_OPT_TYPE_INT, {.i64=0}, 0, 32768, AF}, |
|
|
|
|
{"b", "set the block size", OFFSET(block_samples), AV_OPT_TYPE_INT, {.i64=0}, 0, 32768, AF}, |
|
|
|
|
{NULL} |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
@ -1233,6 +1349,8 @@ static const AVOption bandpass_options[] = { |
|
|
|
|
{"s32", "signed 32-bit", 0, AV_OPT_TYPE_CONST, {.i64=1}, 0, 0, AF, "precision"}, |
|
|
|
|
{"f32", "floating-point single", 0, AV_OPT_TYPE_CONST, {.i64=2}, 0, 0, AF, "precision"}, |
|
|
|
|
{"f64", "floating-point double", 0, AV_OPT_TYPE_CONST, {.i64=3}, 0, 0, AF, "precision"}, |
|
|
|
|
{"blocksize", "set the block size", OFFSET(block_samples), AV_OPT_TYPE_INT, {.i64=0}, 0, 32768, AF}, |
|
|
|
|
{"b", "set the block size", OFFSET(block_samples), AV_OPT_TYPE_INT, {.i64=0}, 0, 32768, AF}, |
|
|
|
|
{NULL} |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
@ -1272,6 +1390,8 @@ static const AVOption bandreject_options[] = { |
|
|
|
|
{"s32", "signed 32-bit", 0, AV_OPT_TYPE_CONST, {.i64=1}, 0, 0, AF, "precision"}, |
|
|
|
|
{"f32", "floating-point single", 0, AV_OPT_TYPE_CONST, {.i64=2}, 0, 0, AF, "precision"}, |
|
|
|
|
{"f64", "floating-point double", 0, AV_OPT_TYPE_CONST, {.i64=3}, 0, 0, AF, "precision"}, |
|
|
|
|
{"blocksize", "set the block size", OFFSET(block_samples), AV_OPT_TYPE_INT, {.i64=0}, 0, 32768, AF}, |
|
|
|
|
{"b", "set the block size", OFFSET(block_samples), AV_OPT_TYPE_INT, {.i64=0}, 0, 32768, AF}, |
|
|
|
|
{NULL} |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
@ -1313,6 +1433,8 @@ static const AVOption lowpass_options[] = { |
|
|
|
|
{"s32", "signed 32-bit", 0, AV_OPT_TYPE_CONST, {.i64=1}, 0, 0, AF, "precision"}, |
|
|
|
|
{"f32", "floating-point single", 0, AV_OPT_TYPE_CONST, {.i64=2}, 0, 0, AF, "precision"}, |
|
|
|
|
{"f64", "floating-point double", 0, AV_OPT_TYPE_CONST, {.i64=3}, 0, 0, AF, "precision"}, |
|
|
|
|
{"blocksize", "set the block size", OFFSET(block_samples), AV_OPT_TYPE_INT, {.i64=0}, 0, 32768, AF}, |
|
|
|
|
{"b", "set the block size", OFFSET(block_samples), AV_OPT_TYPE_INT, {.i64=0}, 0, 32768, AF}, |
|
|
|
|
{NULL} |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
@ -1354,6 +1476,8 @@ static const AVOption highpass_options[] = { |
|
|
|
|
{"s32", "signed 32-bit", 0, AV_OPT_TYPE_CONST, {.i64=1}, 0, 0, AF, "precision"}, |
|
|
|
|
{"f32", "floating-point single", 0, AV_OPT_TYPE_CONST, {.i64=2}, 0, 0, AF, "precision"}, |
|
|
|
|
{"f64", "floating-point double", 0, AV_OPT_TYPE_CONST, {.i64=3}, 0, 0, AF, "precision"}, |
|
|
|
|
{"blocksize", "set the block size", OFFSET(block_samples), AV_OPT_TYPE_INT, {.i64=0}, 0, 32768, AF}, |
|
|
|
|
{"b", "set the block size", OFFSET(block_samples), AV_OPT_TYPE_INT, {.i64=0}, 0, 32768, AF}, |
|
|
|
|
{NULL} |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
@ -1429,6 +1553,8 @@ static const AVOption biquad_options[] = { |
|
|
|
|
{"s32", "signed 32-bit", 0, AV_OPT_TYPE_CONST, {.i64=1}, 0, 0, AF, "precision"}, |
|
|
|
|
{"f32", "floating-point single", 0, AV_OPT_TYPE_CONST, {.i64=2}, 0, 0, AF, "precision"}, |
|
|
|
|
{"f64", "floating-point double", 0, AV_OPT_TYPE_CONST, {.i64=3}, 0, 0, AF, "precision"}, |
|
|
|
|
{"blocksize", "set the block size", OFFSET(block_samples), AV_OPT_TYPE_INT, {.i64=0}, 0, 32768, AF}, |
|
|
|
|
{"b", "set the block size", OFFSET(block_samples), AV_OPT_TYPE_INT, {.i64=0}, 0, 32768, AF}, |
|
|
|
|
{NULL} |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|