From patchwork Sat Feb 5 13:47:44 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul B Mahol X-Patchwork-Id: 34141 Delivered-To: ffmpegpatchwork2@gmail.com Received: by 2002:a05:6602:2c4e:0:0:0:0 with SMTP id x14csp4291888iov; Sat, 5 Feb 2022 05:47:26 -0800 (PST) X-Google-Smtp-Source: ABdhPJzk8oQyrCFQM2kJ6QzH9QunRUci5y7pfcNiVa1TrEhyLRw6o7yuvi9Y3HEU81/OPehk6Ta6 X-Received: by 2002:a17:907:3e9c:: with SMTP id hs28mr3156074ejc.735.1644068846303; Sat, 05 Feb 2022 05:47:26 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1644068846; cv=none; d=google.com; s=arc-20160816; b=QKQcD8CfuhuWrHPBxldCtAzIChgslVOrlJ2p3r8toeqCzZ7iJMHtN5QVa9EscA7W5L KW+OfPKTWquOEgFHplcUJb3OkN7x20zyXcEEPd78IcpgfREEffkpKR5ExCfHGpFXYkes zGpu75y3tn5KlZqbg/E/J4AJaka4ksGmvwwFPAIqWUeJ0gWucxCAc7iXr8dUpKSivUWs 6NwWIMv8QMnHRv6hPJHCahNAL3RSg/jAuqs/o3vxKlmYOxSkguVZLr7/9eERxj08VbK6 bnI+Av9+smXEZ0u1O30r5hWRjEpWSuEsja2YmCeu8JoossFjrxJAiaJdrbqsWgMs9gmc BV4Q== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:content-transfer-encoding:reply-to:list-subscribe :list-help:list-post:list-archive:list-unsubscribe:list-id :precedence:subject:mime-version:message-id:date:to:from :dkim-signature:delivered-to; bh=2F69Vr8w0f1a9uQ5RRmeDkPbQZBhZepSn6dd6eDnsCw=; b=ssYhY4Ljxb20ykVCwtFNxHdptYPxlciD2askFsdBSl5Gx+J9ik/7Py2sKsWKLbMCLF WMaszoXi40RX8gL2bbx49XV16jig/Bt355wGxSbOQ4OITF4xsk/jKk/Mc/t7DBkRx6w8 uCAil+5lmx0d+Pr8oOIpdqHUR9CmXiOflgyhEjG38UbaEs3gkLZXYu0kgZIKHYs9GZjq YXeZDydhZ2p8+3NbzpSk+o9WUfD7Yr3SCZ0TNJLQLLsDVHQTOK4aC89da2WN9qaGoM+4 +t6MRSXGntw8AOjMOzUE0v6pg/sAcDi0cefCY8vPSFzDDykf2CDx+lv1Xxzf8KBSvHBC R6Gg== ARC-Authentication-Results: i=1; mx.google.com; dkim=neutral (body hash did not verify) header.i=@gmail.com header.s=20210112 header.b=Ld69jHtd; spf=pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) smtp.mailfrom=ffmpeg-devel-bounces@ffmpeg.org; dmarc=fail (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com Return-Path: Received: from ffbox0-bg.mplayerhq.hu (ffbox0-bg.ffmpeg.org. [79.124.17.100]) by mx.google.com with ESMTP id dp10si3668067ejc.558.2022.02.05.05.47.25; Sat, 05 Feb 2022 05:47:26 -0800 (PST) Received-SPF: pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) client-ip=79.124.17.100; Authentication-Results: mx.google.com; dkim=neutral (body hash did not verify) header.i=@gmail.com header.s=20210112 header.b=Ld69jHtd; spf=pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) smtp.mailfrom=ffmpeg-devel-bounces@ffmpeg.org; dmarc=fail (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id 20C4168B399; Sat, 5 Feb 2022 15:47:22 +0200 (EET) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from mail-ed1-f51.google.com (mail-ed1-f51.google.com [209.85.208.51]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id 529C268B332 for ; Sat, 5 Feb 2022 15:47:15 +0200 (EET) Received: by mail-ed1-f51.google.com with SMTP id cf2so3484370edb.9 for ; Sat, 05 Feb 2022 05:47:15 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=from:to:subject:date:message-id:mime-version :content-transfer-encoding; bh=Vnj5o5k6y0xW7W5rKyQS37FQvl8645fQNToMfanDNyk=; b=Ld69jHtdr+xTv+UER+ExhFRDNJDr1AuiP6G2eVgi4aaHBQt7gLRymZVg+iBiIqUdyY DGF/pOTa4BZgNc3axnbatOvcCnry2Qa8CoNimYQ24loDlBXrcYt9WN1MydOmLd9pKnPF ed5Iyl+T5hRBB1BLNgMji3RsoTpSaA6jOrvaV53PTpmBnWre01aAiGeTRxZ0t799mE+W cZ+ejYR7ma8BvrYZG2hGO8Z2vzYqvpJTezFCW54TVdbeusLGp2xWh5Lq2ct0IQygUZE9 fkCFWk4zPkZFyoj6MPHIuf6YLb94iVMEljJesdsGkpZW9dwyCKjv2DdH6HYJeYPbc015 Ea7g== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:subject:date:message-id:mime-version :content-transfer-encoding; bh=Vnj5o5k6y0xW7W5rKyQS37FQvl8645fQNToMfanDNyk=; b=YcZxkyq16sy587hiNfklY/O8qvLfZLsVSKZx8McD3II3GrKTPe63YJ2XRMdXQQTy+9 mmQh0WLoQ+KOhuAD0o4tcbi/8GFPGGqbtfMF2NLSBtbWc3kS8ZTkaQnY0cHhFDLAZdd0 7GwTOjeCbWa7cnQBHiNGofq+UZnVVN7gzAJZ9oEf39CueNk3BHlZOwohdme/4frhcJQT bgC1hs29cjx+XYTTWxGOVSVgdOo7jovT6kVOVxGgHVCI9QrtYwcxZFNCGQUtCX3nj4FK m4OHRvIxGk4y6I3tEmQWV9kYmVLG3RFuKCFvTpCHBoQ2bndE8lZlLKdIhkwGzqdDMNpV z19w== X-Gm-Message-State: AOAM531US4G4lOfMOFCmc5qbPwrdCkcSTXMd1zOGq7S2P9m1Ky07ZNou 7uxUKQG0Es6GhQ58Qt1yx7nbdKrpwf8= X-Received: by 2002:a50:eb46:: with SMTP id z6mr4389034edp.229.1644068834620; Sat, 05 Feb 2022 05:47:14 -0800 (PST) Received: from localhost.localdomain ([95.168.120.2]) by smtp.gmail.com with ESMTPSA id cr8sm2213377edb.47.2022.02.05.05.47.13 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sat, 05 Feb 2022 05:47:14 -0800 (PST) From: Paul B Mahol To: ffmpeg-devel@ffmpeg.org Date: Sat, 5 Feb 2022 14:47:44 +0100 Message-Id: <20220205134744.1407065-1-onemda@gmail.com> X-Mailer: git-send-email 2.33.0 MIME-Version: 1.0 Subject: [FFmpeg-devel] [PATCH] avfilter: add dialog enhance audio filter X-BeenThere: ffmpeg-devel@ffmpeg.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: FFmpeg development discussions and patches List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-To: FFmpeg development discussions and patches Errors-To: ffmpeg-devel-bounces@ffmpeg.org Sender: "ffmpeg-devel" X-TUID: 07rOaup+2Tk+ Signed-off-by: Paul B Mahol --- libavfilter/Makefile | 1 + libavfilter/af_dialogenhance.c | 420 +++++++++++++++++++++++++++++++++ libavfilter/allfilters.c | 1 + 3 files changed, 422 insertions(+) create mode 100644 libavfilter/af_dialogenhance.c diff --git a/libavfilter/Makefile b/libavfilter/Makefile index 282967144b..c4dfb9a41b 100644 --- a/libavfilter/Makefile +++ b/libavfilter/Makefile @@ -124,6 +124,7 @@ OBJS-$(CONFIG_CROSSFEED_FILTER) += af_crossfeed.o OBJS-$(CONFIG_CRYSTALIZER_FILTER) += af_crystalizer.o OBJS-$(CONFIG_DCSHIFT_FILTER) += af_dcshift.o OBJS-$(CONFIG_DEESSER_FILTER) += af_deesser.o +OBJS-$(CONFIG_DIALOGENHANCE_FILTER) += af_dialogenhance.o OBJS-$(CONFIG_DRMETER_FILTER) += af_drmeter.o OBJS-$(CONFIG_DYNAUDNORM_FILTER) += af_dynaudnorm.o OBJS-$(CONFIG_EARWAX_FILTER) += af_earwax.o diff --git a/libavfilter/af_dialogenhance.c b/libavfilter/af_dialogenhance.c new file mode 100644 index 0000000000..a22594ed67 --- /dev/null +++ b/libavfilter/af_dialogenhance.c @@ -0,0 +1,420 @@ +/* + * Copyright (c) 2022 Paul B Mahol + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with FFmpeg; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavutil/channel_layout.h" +#include "libavutil/opt.h" +#include "libavutil/tx.h" +#include "audio.h" +#include "avfilter.h" +#include "filters.h" +#include "internal.h" +#include "window_func.h" + +#include + +typedef struct AudioDialogEnhanceContext { + const AVClass *class; + + double original, enhance; + + int fft_size; + int overlap; + int channels; + + float *window; + float prev_vad; + + AVFrame *in; + AVFrame *in_frame; + AVFrame *out_dist_frame; + AVFrame *windowed_frame; + AVFrame *windowed_out; + AVFrame *windowed_prev; + AVFrame *center_frame; + + AVTXContext **tx_ctx, **itx_ctx; + av_tx_fn tx_fn, itx_fn; +} AudioDialogEnhanceContext; + +#define OFFSET(x) offsetof(AudioDialogEnhanceContext, x) +#define FLAGS AV_OPT_FLAG_AUDIO_PARAM | AV_OPT_FLAG_FILTERING_PARAM | AV_OPT_FLAG_RUNTIME_PARAM + +static const AVOption dialogenhance_options[] = { + { "original", "set original center ratio", OFFSET(original), AV_OPT_TYPE_DOUBLE, {.dbl=1}, 0, 1, FLAGS }, + { "enhance", "set dialog enhance ratio", OFFSET(enhance), AV_OPT_TYPE_DOUBLE, {.dbl=1}, 0, 1, FLAGS }, + {NULL} +}; + +AVFILTER_DEFINE_CLASS(dialogenhance); + +static int query_formats(AVFilterContext *ctx) +{ + AVFilterFormats *formats = NULL; + AVFilterChannelLayouts *layout = NULL; + int ret; + + if ((ret = ff_add_format (&formats, AV_SAMPLE_FMT_FLTP )) < 0 || + (ret = ff_set_common_formats (ctx , formats )) < 0 || + (ret = ff_add_channel_layout (&layout , AV_CH_LAYOUT_STEREO)) < 0 || + (ret = ff_set_common_channel_layouts (ctx , layout )) < 0) + return ret; + + return ff_set_common_all_samplerates(ctx); +} + +static int config_input(AVFilterLink *inlink) +{ + AVFilterContext *ctx = inlink->dst; + AudioDialogEnhanceContext *s = ctx->priv; + float scale = 1.f, iscale, overlap; + int ret; + + s->fft_size = inlink->sample_rate > 100000 ? 8192 : inlink->sample_rate > 50000 ? 4096 : 2048; + s->overlap = s->fft_size / 4; + + s->window = av_calloc(s->fft_size, sizeof(*s->window)); + if (!s->window) + return AVERROR(ENOMEM); + + s->in_frame = ff_get_audio_buffer(inlink, s->fft_size * 4); + s->center_frame = ff_get_audio_buffer(inlink, s->fft_size * 4); + s->out_dist_frame = ff_get_audio_buffer(inlink, s->fft_size * 4); + s->windowed_frame = ff_get_audio_buffer(inlink, s->fft_size * 4); + s->windowed_out = ff_get_audio_buffer(inlink, s->fft_size * 4); + s->windowed_prev = ff_get_audio_buffer(inlink, s->fft_size * 4); + if (!s->in_frame || !s->windowed_out || !s->windowed_prev || + !s->out_dist_frame || !s->windowed_frame || !s->center_frame) + return AVERROR(ENOMEM); + + generate_window_func(s->window, s->fft_size, WFUNC_SINE, &overlap); + + s->channels = inlink->channels; + + s->tx_ctx = av_calloc(s->channels, sizeof(*s->tx_ctx)); + s->itx_ctx = av_calloc(s->channels, sizeof(*s->itx_ctx)); + if (!s->tx_ctx || !s->itx_ctx) + return AVERROR(ENOMEM); + + iscale = 1.f / s->fft_size; + + for (int ch = 0; ch < s->channels; ch++) { + ret = av_tx_init(&s->tx_ctx[ch], &s->tx_fn, AV_TX_FLOAT_RDFT, 0, s->fft_size, &scale, 0); + if (ret < 0) + return ret; + + ret = av_tx_init(&s->itx_ctx[ch], &s->itx_fn, AV_TX_FLOAT_RDFT, 1, s->fft_size, &iscale, 0); + if (ret < 0) + return ret; + } + + return 0; +} + +static void apply_window(AudioDialogEnhanceContext *s, + const float *in_frame, float *out_frame, const int add_to_out_frame) +{ + const float *window = s->window; + + for (int i = 0; i < s->fft_size; i++) { + if (add_to_out_frame) { + out_frame[i] += in_frame[i] * window[i]; + } else { + out_frame[i] = in_frame[i] * window[i]; + } + } +} + +static float sqrf(float x) +{ + return x * x; +} + +static void get_centere(AVComplexFloat *left, AVComplexFloat *right, + AVComplexFloat *center, int N) +{ + for (int i = 0; i < N; i++) { + const float l_re = left[i].re; + const float l_im = left[i].im; + const float r_re = right[i].re; + const float r_im = right[i].im; + const float a = 0.5f * (1.f - sqrtf((sqrf(l_re - r_re) + sqrf(l_im - r_im))/ + (sqrf(l_re + r_re) + sqrf(l_im + r_im) + FLT_EPSILON))); + + center[i].re = a * (l_re + r_re); + center[i].im = a * (l_im + r_im); + } +} + +static float flux(float *curf, float *prevf, int N) +{ + AVComplexFloat *cur = (AVComplexFloat *)curf; + AVComplexFloat *prev = (AVComplexFloat *)prevf; + float sum = 0.f; + + for (int i = 0; i < N; i++) { + float c_re = cur[i].re; + float c_im = cur[i].im; + float p_re = prev[i].re; + float p_im = prev[i].im; + + sum += sqrf(hypotf(c_re, c_im) - hypotf(p_re, p_im)); + } + + return sum; +} + +static float fluxlr(float *lf, float *lpf, + float *rf, float *rpf, + int N) +{ + AVComplexFloat *l = (AVComplexFloat *)lf; + AVComplexFloat *lp = (AVComplexFloat *)lpf; + AVComplexFloat *r = (AVComplexFloat *)rf; + AVComplexFloat *rp = (AVComplexFloat *)rpf; + float sum = 0.f; + + for (int i = 0; i < N; i++) { + float c_re = l[i].re - r[i].re; + float c_im = l[i].im - r[i].im; + float p_re = lp[i].re - rp[i].re; + float p_im = lp[i].im - rp[i].im; + + sum += sqrf(hypotf(c_re, c_im) - hypotf(p_re, p_im)); + } + + return sum; +} + +static float calc_vad(float fc, float flr, float a) +{ + const float vad = a * (fc / (fc + flr) - 0.5f); + + return av_clipf(vad, 0.f, 1.f); +} + +static void get_final(float *c, float *l, + float *r, float vad, int N, + float original, float enhance) +{ + AVComplexFloat *center = (AVComplexFloat *)c; + AVComplexFloat *left = (AVComplexFloat *)l; + AVComplexFloat *right = (AVComplexFloat *)r; + + for (int i = 0; i < N; i++) { + float cP = sqrf(center[i].re) + sqrf(center[i].im); + float lrP = sqrf(left[i].re - right[i].re) + sqrf(left[i].im - right[i].im); + float G = cP / (cP + lrP + FLT_EPSILON); + float re, im; + + re = center[i].re * (original + vad * G * enhance); + im = center[i].im * (original + vad * G * enhance); + + center[i].re = re; + center[i].im = im; + } +} + +static int de_stereo(AVFilterContext *ctx, AVFrame *out) +{ + AudioDialogEnhanceContext *s = ctx->priv; + float *center = (float *)s->center_frame->extended_data[0]; + float *center_prev = (float *)s->center_frame->extended_data[1]; + float *left_in = (float *)s->in_frame->extended_data[0]; + float *right_in = (float *)s->in_frame->extended_data[1]; + float *left_out = (float *)s->out_dist_frame->extended_data[0]; + float *right_out = (float *)s->out_dist_frame->extended_data[1]; + float *left_samples = (float *)s->in->extended_data[0]; + float *right_samples = (float *)s->in->extended_data[1]; + float *windowed_left = (float *)s->windowed_frame->extended_data[0]; + float *windowed_right = (float *)s->windowed_frame->extended_data[1]; + float *windowed_oleft = (float *)s->windowed_out->extended_data[0]; + float *windowed_oright= (float *)s->windowed_out->extended_data[1]; + float *windowed_pleft = (float *)s->windowed_prev->extended_data[0]; + float *windowed_pright= (float *)s->windowed_prev->extended_data[1]; + float *left_osamples = (float *)out->extended_data[0]; + float *right_osamples = (float *)out->extended_data[1]; + float vad; + + // shift in/out buffers + for (int i = 0; i < s->fft_size - s->overlap; i++) { + left_in[i] = left_in[i + s->overlap]; + right_in[i] = right_in[i + s->overlap]; + left_out[i] = left_out[i + s->overlap]; + right_out[i] = right_out[i + s->overlap]; + } + + for (int i = 0; i < s->overlap; i++) { + left_in[i + s->fft_size - s->overlap] = left_samples[i]; + right_in[i + s->fft_size - s->overlap] = right_samples[i]; + left_out[i + s->fft_size - s->overlap] = 0.f; + right_out[i + s->fft_size - s->overlap] = 0.f; + } + + apply_window(s, left_in, windowed_left, 0); + apply_window(s, right_in, windowed_right, 0); + + s->tx_fn(s->tx_ctx[0], windowed_oleft, windowed_left, sizeof(float)); + s->tx_fn(s->tx_ctx[1], windowed_oright, windowed_right, sizeof(float)); + + get_centere((AVComplexFloat *)windowed_oleft, + (AVComplexFloat *)windowed_oright, + (AVComplexFloat *)center, + s->fft_size / 2 + 1); + + vad = calc_vad(flux(center, center_prev, s->fft_size / 2 + 1), + fluxlr(windowed_oleft, windowed_pleft, + windowed_oright, windowed_pright, s->fft_size / 2 + 1), 2.f); + vad = vad * 0.1 + 0.9 * s->prev_vad; + s->prev_vad = vad; + + memcpy(center_prev, center, s->fft_size * sizeof(float)); + memcpy(windowed_pleft, windowed_oleft, s->fft_size * sizeof(float)); + memcpy(windowed_pright, windowed_oright, s->fft_size * sizeof(float)); + + get_final(center, windowed_oleft, windowed_oright, vad, s->fft_size / 2 + 1, + s->original, s->enhance); + + s->itx_fn(s->itx_ctx[0], windowed_oleft, center, sizeof(float)); + + apply_window(s, windowed_oleft, left_out, 1); + apply_window(s, windowed_oleft, right_out, 1); + + for (int i = 0; i < s->overlap; i++) { + // 4 times overlap with squared hanning window results in 1.5 time increase in amplitude + if (!ctx->is_disabled) { + left_osamples[i] = left_out[i] / 1.5f; + right_osamples[i] = right_out[i] / 1.5f; + } else { + left_osamples[i] = left_in[i]; + right_osamples[i] = right_in[i]; + } + } + + return 0; +} + +static int filter_frame(AVFilterLink *inlink, AVFrame *in) +{ + AVFilterContext *ctx = inlink->dst; + AVFilterLink *outlink = ctx->outputs[0]; + AudioDialogEnhanceContext *s = ctx->priv; + AVFrame *out; + int ret; + + out = ff_get_audio_buffer(outlink, s->overlap); + if (!out) { + ret = AVERROR(ENOMEM); + goto fail; + } + + s->in = in; + de_stereo(ctx, out); + + out->pts = in->pts; + out->nb_samples = in->nb_samples; + ret = ff_filter_frame(outlink, out); +fail: + av_frame_free(&in); + s->in = NULL; + return ret < 0 ? ret : 0; +} + +static int activate(AVFilterContext *ctx) +{ + AVFilterLink *inlink = ctx->inputs[0]; + AVFilterLink *outlink = ctx->outputs[0]; + AudioDialogEnhanceContext *s = ctx->priv; + AVFrame *in = NULL; + int ret = 0, status; + int64_t pts; + + FF_FILTER_FORWARD_STATUS_BACK(outlink, inlink); + + ret = ff_inlink_consume_samples(inlink, s->overlap, s->overlap, &in); + if (ret < 0) + return ret; + + if (ret > 0) { + return filter_frame(inlink, in); + } else if (ff_inlink_acknowledge_status(inlink, &status, &pts)) { + ff_outlink_set_status(outlink, status, pts); + return 0; + } else { + if (ff_inlink_queued_samples(inlink) >= s->overlap) { + ff_filter_set_ready(ctx, 10); + } else if (ff_outlink_frame_wanted(outlink)) { + ff_inlink_request_frame(inlink); + } + return 0; + } +} + +static av_cold void uninit(AVFilterContext *ctx) +{ + AudioDialogEnhanceContext *s = ctx->priv; + + av_freep(&s->window); + + av_frame_free(&s->in_frame); + av_frame_free(&s->center_frame); + av_frame_free(&s->out_dist_frame); + av_frame_free(&s->windowed_frame); + av_frame_free(&s->windowed_out); + av_frame_free(&s->windowed_prev); + + for (int ch = 0; ch < s->channels; ch++) { + if (s->tx_ctx) + av_tx_uninit(&s->tx_ctx[ch]); + if (s->itx_ctx) + av_tx_uninit(&s->itx_ctx[ch]); + } + + av_freep(&s->tx_ctx); + av_freep(&s->itx_ctx); +} + +static const AVFilterPad inputs[] = { + { + .name = "default", + .type = AVMEDIA_TYPE_AUDIO, + .config_props = config_input, + }, +}; + +static const AVFilterPad outputs[] = { + { + .name = "default", + .type = AVMEDIA_TYPE_AUDIO, + }, +}; + +const AVFilter ff_af_dialogenhance = { + .name = "dialogenhance", + .description = NULL_IF_CONFIG_SMALL("Audio Dialog Enhancement."), + .priv_size = sizeof(AudioDialogEnhanceContext), + .priv_class = &dialogenhance_class, + .uninit = uninit, + FILTER_INPUTS(inputs), + FILTER_OUTPUTS(outputs), + FILTER_QUERY_FUNC(query_formats), + .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL, + .activate = activate, + .process_command = ff_filter_process_command, +}; diff --git a/libavfilter/allfilters.c b/libavfilter/allfilters.c index 714468afce..f503ac4c37 100644 --- a/libavfilter/allfilters.c +++ b/libavfilter/allfilters.c @@ -115,6 +115,7 @@ extern const AVFilter ff_af_crossfeed; extern const AVFilter ff_af_crystalizer; extern const AVFilter ff_af_dcshift; extern const AVFilter ff_af_deesser; +extern const AVFilter ff_af_dialogenhance; extern const AVFilter ff_af_drmeter; extern const AVFilter ff_af_dynaudnorm; extern const AVFilter ff_af_earwax;