diff options
author | Paul B Mahol <onemda@gmail.com> | 2015-11-30 01:22:47 +0300 |
---|---|---|
committer | Paul B Mahol <onemda@gmail.com> | 2015-12-03 13:07:51 +0300 |
commit | bd5afecdcbb678aa24bc13a882cdae6e974e9645 (patch) | |
tree | 5393f8946f4445aa56fc814f233d2ad06294a76f /libavfilter/af_agate.c | |
parent | acc2347cf47bcb2e2246b1a86588c4d292eeb91d (diff) |
avfilter: add sidechaingate filter
Signed-off-by: Paul B Mahol <onemda@gmail.com>
Diffstat (limited to 'libavfilter/af_agate.c')
-rw-r--r-- | libavfilter/af_agate.c | 170 |
1 files changed, 167 insertions, 3 deletions
diff --git a/libavfilter/af_agate.c b/libavfilter/af_agate.c index d3f74fb97f..23e45c6f77 100644 --- a/libavfilter/af_agate.c +++ b/libavfilter/af_agate.c @@ -18,6 +18,12 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +/** + * @file + * Audio (Sidechain) Gate filter + */ + +#include "libavutil/avassert.h" #include "libavutil/channel_layout.h" #include "libavutil/opt.h" #include "avfilter.h" @@ -46,12 +52,14 @@ typedef struct AudioGateContext { double lin_slope; double attack_coeff; double release_coeff; + + AVFrame *input_frame[2]; } AudioGateContext; #define OFFSET(x) offsetof(AudioGateContext, x) #define A AV_OPT_FLAG_AUDIO_PARAM|AV_OPT_FLAG_FILTERING_PARAM -static const AVOption agate_options[] = { +static const AVOption options[] = { { "level_in", "set input level", OFFSET(level_in), AV_OPT_TYPE_DOUBLE, {.dbl=1}, 0.015625, 64, A }, { "range", "set max gain reduction", OFFSET(range), AV_OPT_TYPE_DOUBLE, {.dbl=0.06125}, 0, 1, A }, { "threshold", "set threshold", OFFSET(threshold), AV_OPT_TYPE_DOUBLE, {.dbl=0.125}, 0, 1, A }, @@ -69,6 +77,7 @@ static const AVOption agate_options[] = { { NULL } }; +#define agate_options options AVFILTER_DEFINE_CLASS(agate); static int query_formats(AVFilterContext *ctx) @@ -97,7 +106,7 @@ static int query_formats(AVFilterContext *ctx) return ff_set_common_samplerates(ctx, formats); } -static int config_input(AVFilterLink *inlink) +static int agate_config_input(AVFilterLink *inlink) { AVFilterContext *ctx = inlink->dst; AudioGateContext *s = ctx->priv; @@ -221,7 +230,7 @@ static const AVFilterPad inputs[] = { .name = "default", .type = AVMEDIA_TYPE_AUDIO, .filter_frame = filter_frame, - .config_props = config_input, + .config_props = agate_config_input, }, { NULL } }; @@ -243,3 +252,158 @@ AVFilter ff_af_agate = { .inputs = inputs, .outputs = outputs, }; + +#if CONFIG_SIDECHAINGATE_FILTER + +#define sidechaingate_options options +AVFILTER_DEFINE_CLASS(sidechaingate); + +static int scfilter_frame(AVFilterLink *link, AVFrame *in) +{ + AVFilterContext *ctx = link->dst; + AudioGateContext *s = ctx->priv; + AVFilterLink *outlink = ctx->outputs[0]; + const double *scsrc; + double *sample; + int nb_samples; + int ret, i; + + for (i = 0; i < 2; i++) + if (link == ctx->inputs[i]) + break; + av_assert0(i < 2 && !s->input_frame[i]); + s->input_frame[i] = in; + + if (!s->input_frame[0] || !s->input_frame[1]) + return 0; + + nb_samples = FFMIN(s->input_frame[0]->nb_samples, + s->input_frame[1]->nb_samples); + + sample = (double *)s->input_frame[0]->data[0]; + scsrc = (const double *)s->input_frame[1]->data[0]; + + gate(s, sample, sample, scsrc, nb_samples, + ctx->inputs[0], ctx->inputs[1]); + ret = ff_filter_frame(outlink, s->input_frame[0]); + + s->input_frame[0] = NULL; + av_frame_free(&s->input_frame[1]); + + return ret; +} + +static int screquest_frame(AVFilterLink *outlink) +{ + AVFilterContext *ctx = outlink->src; + AudioGateContext *s = ctx->priv; + int i, ret; + + /* get a frame on each input */ + for (i = 0; i < 2; i++) { + AVFilterLink *inlink = ctx->inputs[i]; + if (!s->input_frame[i] && + (ret = ff_request_frame(inlink)) < 0) + return ret; + + /* request the same number of samples on all inputs */ + if (i == 0) + ctx->inputs[1]->request_samples = s->input_frame[0]->nb_samples; + } + + return 0; +} + +static int scquery_formats(AVFilterContext *ctx) +{ + AVFilterFormats *formats; + AVFilterChannelLayouts *layouts = NULL; + static const enum AVSampleFormat sample_fmts[] = { + AV_SAMPLE_FMT_DBL, + AV_SAMPLE_FMT_NONE + }; + int ret, i; + + if (!ctx->inputs[0]->in_channel_layouts || + !ctx->inputs[0]->in_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) + 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) + return ret; + } + + formats = ff_make_format_list(sample_fmts); + if ((ret = ff_set_common_formats(ctx, formats)) < 0) + return ret; + + formats = ff_all_samplerates(); + return ff_set_common_samplerates(ctx, formats); +} + +static int scconfig_output(AVFilterLink *outlink) +{ + AVFilterContext *ctx = outlink->src; + + if (ctx->inputs[0]->sample_rate != ctx->inputs[1]->sample_rate) { + av_log(ctx, AV_LOG_ERROR, + "Inputs must have the same sample rate " + "%d for in0 vs %d for in1\n", + ctx->inputs[0]->sample_rate, ctx->inputs[1]->sample_rate); + return AVERROR(EINVAL); + } + + outlink->sample_rate = ctx->inputs[0]->sample_rate; + outlink->time_base = ctx->inputs[0]->time_base; + outlink->channel_layout = ctx->inputs[0]->channel_layout; + outlink->channels = ctx->inputs[0]->channels; + + agate_config_input(ctx->inputs[0]); + + return 0; +} + +static const AVFilterPad sidechaingate_inputs[] = { + { + .name = "main", + .type = AVMEDIA_TYPE_AUDIO, + .filter_frame = scfilter_frame, + .needs_writable = 1, + .needs_fifo = 1, + },{ + .name = "sidechain", + .type = AVMEDIA_TYPE_AUDIO, + .filter_frame = scfilter_frame, + .needs_fifo = 1, + }, + { NULL } +}; + +static const AVFilterPad sidechaingate_outputs[] = { + { + .name = "default", + .type = AVMEDIA_TYPE_AUDIO, + .config_props = scconfig_output, + .request_frame = screquest_frame, + }, + { NULL } +}; + +AVFilter ff_af_sidechaingate = { + .name = "sidechaingate", + .description = NULL_IF_CONFIG_SMALL("Audio sidechain gate."), + .priv_size = sizeof(AudioGateContext), + .priv_class = &sidechaingate_class, + .query_formats = scquery_formats, + .inputs = sidechaingate_inputs, + .outputs = sidechaingate_outputs, +}; +#endif /* CONFIG_SIDECHAINGATE_FILTER */ |