X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=libavfilter%2Faf_sidechaincompress.c;h=d20ab5799021fec5b355725b4e35c128976ec5c5;hb=a04ad248a05e7b613abe09b3bb067f555108d794;hp=888049eaf0e0fbca7eb03deb48c697c8a2f41adc;hpb=14fe81b3a88dfe4dbac12e8715f9a3f05b5ef1bf;p=ffmpeg diff --git a/libavfilter/af_sidechaincompress.c b/libavfilter/af_sidechaincompress.c index 888049eaf0e..d20ab579902 100644 --- a/libavfilter/af_sidechaincompress.c +++ b/libavfilter/af_sidechaincompress.c @@ -54,10 +54,14 @@ typedef struct SidechainCompressContext { double knee_start; double knee_stop; double lin_knee_start; + double lin_knee_stop; double adj_knee_start; + double adj_knee_stop; + double compressed_knee_start; double compressed_knee_stop; int link; int detection; + int mode; AVAudioFifo *fifo[2]; int64_t pts; @@ -66,23 +70,27 @@ typedef struct SidechainCompressContext { #define OFFSET(x) offsetof(SidechainCompressContext, x) #define A AV_OPT_FLAG_AUDIO_PARAM #define F AV_OPT_FLAG_FILTERING_PARAM +#define R AV_OPT_FLAG_RUNTIME_PARAM static const AVOption options[] = { - { "level_in", "set input gain", OFFSET(level_in), AV_OPT_TYPE_DOUBLE, {.dbl=1}, 0.015625, 64, A|F }, - { "threshold", "set threshold", OFFSET(threshold), AV_OPT_TYPE_DOUBLE, {.dbl=0.125}, 0.000976563, 1, A|F }, - { "ratio", "set ratio", OFFSET(ratio), AV_OPT_TYPE_DOUBLE, {.dbl=2}, 1, 20, A|F }, - { "attack", "set attack", OFFSET(attack), AV_OPT_TYPE_DOUBLE, {.dbl=20}, 0.01, 2000, A|F }, - { "release", "set release", OFFSET(release), AV_OPT_TYPE_DOUBLE, {.dbl=250}, 0.01, 9000, A|F }, - { "makeup", "set make up gain", OFFSET(makeup), AV_OPT_TYPE_DOUBLE, {.dbl=1}, 1, 64, A|F }, - { "knee", "set knee", OFFSET(knee), AV_OPT_TYPE_DOUBLE, {.dbl=2.82843}, 1, 8, A|F }, - { "link", "set link type", OFFSET(link), AV_OPT_TYPE_INT, {.i64=0}, 0, 1, A|F, "link" }, - { "average", 0, 0, AV_OPT_TYPE_CONST, {.i64=0}, 0, 0, A|F, "link" }, - { "maximum", 0, 0, AV_OPT_TYPE_CONST, {.i64=1}, 0, 0, A|F, "link" }, - { "detection", "set detection", OFFSET(detection), AV_OPT_TYPE_INT, {.i64=1}, 0, 1, A|F, "detection" }, - { "peak", 0, 0, AV_OPT_TYPE_CONST, {.i64=0}, 0, 0, A|F, "detection" }, - { "rms", 0, 0, AV_OPT_TYPE_CONST, {.i64=1}, 0, 0, A|F, "detection" }, - { "level_sc", "set sidechain gain", OFFSET(level_sc), AV_OPT_TYPE_DOUBLE, {.dbl=1}, 0.015625, 64, A|F }, - { "mix", "set mix", OFFSET(mix), AV_OPT_TYPE_DOUBLE, {.dbl=1}, 0, 1, A|F }, + { "level_in", "set input gain", OFFSET(level_in), AV_OPT_TYPE_DOUBLE, {.dbl=1}, 0.015625, 64, A|F|R }, + { "mode", "set mode", OFFSET(mode), AV_OPT_TYPE_INT, {.i64=0}, 0, 1, A|F|R, "mode" }, + { "downward",0, 0, AV_OPT_TYPE_CONST, {.i64=0}, 0, 0, A|F|R, "mode" }, + { "upward", 0, 0, AV_OPT_TYPE_CONST, {.i64=1}, 0, 0, A|F|R, "mode" }, + { "threshold", "set threshold", OFFSET(threshold), AV_OPT_TYPE_DOUBLE, {.dbl=0.125}, 0.000976563, 1, A|F|R }, + { "ratio", "set ratio", OFFSET(ratio), AV_OPT_TYPE_DOUBLE, {.dbl=2}, 1, 20, A|F|R }, + { "attack", "set attack", OFFSET(attack), AV_OPT_TYPE_DOUBLE, {.dbl=20}, 0.01, 2000, A|F|R }, + { "release", "set release", OFFSET(release), AV_OPT_TYPE_DOUBLE, {.dbl=250}, 0.01, 9000, A|F|R }, + { "makeup", "set make up gain", OFFSET(makeup), AV_OPT_TYPE_DOUBLE, {.dbl=1}, 1, 64, A|F|R }, + { "knee", "set knee", OFFSET(knee), AV_OPT_TYPE_DOUBLE, {.dbl=2.82843}, 1, 8, A|F|R }, + { "link", "set link type", OFFSET(link), AV_OPT_TYPE_INT, {.i64=0}, 0, 1, A|F|R, "link" }, + { "average", 0, 0, AV_OPT_TYPE_CONST, {.i64=0}, 0, 0, A|F|R, "link" }, + { "maximum", 0, 0, AV_OPT_TYPE_CONST, {.i64=1}, 0, 0, A|F|R, "link" }, + { "detection", "set detection", OFFSET(detection), AV_OPT_TYPE_INT, {.i64=1}, 0, 1, A|F|R, "detection" }, + { "peak", 0, 0, AV_OPT_TYPE_CONST, {.i64=0}, 0, 0, A|F|R, "detection" }, + { "rms", 0, 0, AV_OPT_TYPE_CONST, {.i64=1}, 0, 0, A|F|R, "detection" }, + { "level_sc", "set sidechain gain", OFFSET(level_sc), AV_OPT_TYPE_DOUBLE, {.dbl=1}, 0.015625, 64, A|F|R }, + { "mix", "set mix", OFFSET(mix), AV_OPT_TYPE_DOUBLE, {.dbl=1}, 0, 1, A|F|R }, { NULL } }; @@ -97,7 +105,9 @@ AVFILTER_DEFINE_CLASS(sidechaincompress); static double output_gain(double lin_slope, double ratio, double thres, double knee, double knee_start, double knee_stop, - double compressed_knee_stop, int detection) + double compressed_knee_start, + double compressed_knee_stop, + int detection, int mode) { double slope = log(lin_slope); double gain = 0.0; @@ -114,10 +124,17 @@ static double output_gain(double lin_slope, double ratio, double thres, delta = 1.0 / ratio; } - if (knee > 1.0 && slope < knee_stop) - gain = hermite_interpolation(slope, knee_start, knee_stop, - knee_start, compressed_knee_stop, - 1.0, delta); + if (mode) { + if (knee > 1.0 && slope > knee_start) + gain = hermite_interpolation(slope, knee_stop, knee_start, + knee_stop, compressed_knee_start, + 1.0, delta); + } else { + if (knee > 1.0 && slope < knee_stop) + gain = hermite_interpolation(slope, knee_start, knee_stop, + knee_start, compressed_knee_stop, + 1.0, delta); + } return exp(gain - slope); } @@ -129,9 +146,12 @@ static int compressor_config_output(AVFilterLink *outlink) s->thres = log(s->threshold); s->lin_knee_start = s->threshold / sqrt(s->knee); + s->lin_knee_stop = s->threshold * sqrt(s->knee); s->adj_knee_start = s->lin_knee_start * s->lin_knee_start; + s->adj_knee_stop = s->lin_knee_stop * s->lin_knee_stop; s->knee_start = log(s->lin_knee_start); - s->knee_stop = log(s->threshold * sqrt(s->knee)); + s->knee_stop = log(s->lin_knee_stop); + s->compressed_knee_start = (s->knee_start - s->thres) / s->ratio + s->thres; s->compressed_knee_stop = (s->knee_stop - s->thres) / s->ratio + s->thres; s->attack_coeff = FFMIN(1., 1. / (s->attack * outlink->sample_rate / 4000.)); @@ -151,6 +171,8 @@ static void compressor(SidechainCompressContext *s, for (i = 0; i < nb_samples; i++) { double abs_sample, gain = 1.0; + double detector; + int detected; abs_sample = fabs(scsrc[0] * level_sc); @@ -169,10 +191,20 @@ static void compressor(SidechainCompressContext *s, s->lin_slope += (abs_sample - s->lin_slope) * (abs_sample > s->lin_slope ? s->attack_coeff : s->release_coeff); - if (s->lin_slope > 0.0 && s->lin_slope > (s->detection ? s->adj_knee_start : s->lin_knee_start)) + if (s->mode) { + detector = (s->detection ? s->adj_knee_stop : s->lin_knee_stop); + detected = s->lin_slope < detector; + } else { + detector = (s->detection ? s->adj_knee_start : s->lin_knee_start); + detected = s->lin_slope > detector; + } + + if (s->lin_slope > 0.0 && detected) gain = output_gain(s->lin_slope, s->ratio, s->thres, s->knee, s->knee_start, s->knee_stop, - s->compressed_knee_stop, s->detection); + s->compressed_knee_start, + s->compressed_knee_stop, + s->detection, s->mode); for (c = 0; c < inlink->channels; c++) dst[c] = src[c] * level_in * (gain * makeup * mix + (1. - mix)); @@ -183,6 +215,20 @@ static void compressor(SidechainCompressContext *s, } } +static int process_command(AVFilterContext *ctx, const char *cmd, const char *args, + char *res, int res_len, int flags) +{ + int ret; + + ret = ff_filter_process_command(ctx, cmd, args, res, res_len, flags); + if (ret < 0) + return ret; + + compressor_config_output(ctx->outputs[0]); + + return 0; +} + #if CONFIG_SIDECHAINCOMPRESS_FILTER static int activate(AVFilterContext *ctx) { @@ -225,7 +271,7 @@ static int activate(AVFilterContext *ctx) dst = (double *)out->data[0]; out->pts = s->pts; - s->pts += nb_samples; + s->pts += av_rescale_q(nb_samples, (AVRational){1, ctx->outputs[0]->sample_rate}, ctx->outputs[0]->time_base); compressor(s, (double *)in[0]->data[0], dst, (double *)in[1]->data[0], nb_samples, @@ -260,20 +306,20 @@ static int query_formats(AVFilterContext *ctx) }; int ret, i; - if (!ctx->inputs[0]->in_channel_layouts || - !ctx->inputs[0]->in_channel_layouts->nb_channel_layouts) { + if (!ctx->inputs[0]->incfg.channel_layouts || + !ctx->inputs[0]->incfg.channel_layouts->nb_channel_layouts) { av_log(ctx, AV_LOG_WARNING, "No channel layout for input 1\n"); return AVERROR(EAGAIN); } - if ((ret = ff_add_channel_layout(&layouts, ctx->inputs[0]->in_channel_layouts->channel_layouts[0])) < 0 || - (ret = ff_channel_layouts_ref(layouts, &ctx->outputs[0]->in_channel_layouts)) < 0) + if ((ret = ff_add_channel_layout(&layouts, ctx->inputs[0]->incfg.channel_layouts->channel_layouts[0])) < 0 || + (ret = ff_channel_layouts_ref(layouts, &ctx->outputs[0]->incfg.channel_layouts)) < 0) return ret; for (i = 0; i < 2; i++) { layouts = ff_all_channel_counts(); - if ((ret = ff_channel_layouts_ref(layouts, &ctx->inputs[i]->out_channel_layouts)) < 0) + if ((ret = ff_channel_layouts_ref(layouts, &ctx->inputs[i]->outcfg.channel_layouts)) < 0) return ret; } @@ -341,7 +387,7 @@ static const AVFilterPad sidechaincompress_outputs[] = { { NULL } }; -AVFilter ff_af_sidechaincompress = { +const AVFilter ff_af_sidechaincompress = { .name = "sidechaincompress", .description = NULL_IF_CONFIG_SMALL("Sidechain compressor."), .priv_size = sizeof(SidechainCompressContext), @@ -351,6 +397,7 @@ AVFilter ff_af_sidechaincompress = { .uninit = uninit, .inputs = sidechaincompress_inputs, .outputs = sidechaincompress_outputs, + .process_command = process_command, }; #endif /* CONFIG_SIDECHAINCOMPRESS_FILTER */ @@ -436,7 +483,7 @@ static const AVFilterPad acompressor_outputs[] = { { NULL } }; -AVFilter ff_af_acompressor = { +const AVFilter ff_af_acompressor = { .name = "acompressor", .description = NULL_IF_CONFIG_SMALL("Audio compressor."), .priv_size = sizeof(SidechainCompressContext), @@ -444,5 +491,6 @@ AVFilter ff_af_acompressor = { .query_formats = acompressor_query_formats, .inputs = acompressor_inputs, .outputs = acompressor_outputs, + .process_command = process_command, }; #endif /* CONFIG_ACOMPRESSOR_FILTER */