From patchwork Sun Feb 6 10:25:15 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: 34146 Delivered-To: ffmpegpatchwork2@gmail.com Received: by 2002:a05:6602:2c4e:0:0:0:0 with SMTP id x14csp4902197iov; Sun, 6 Feb 2022 02:24:54 -0800 (PST) X-Google-Smtp-Source: ABdhPJzwGrD+mEj4Bx5vdEMpG5eFnoH6VDMOIYP5LzbA7fGHEsQ0cauvJhzyUyoHvc9LUKT1PlnU X-Received: by 2002:aa7:d416:: with SMTP id z22mr7391790edq.454.1644143094418; Sun, 06 Feb 2022 02:24:54 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1644143094; cv=none; d=google.com; s=arc-20160816; b=ftE3GrXKMd+6ojF0Dq8AQpdwPSie6LsOmHs4cd+yBIwB09Ib6Wc1DotlCjlDZiZLHL dft1doTG95NbndwZuVFb21tDdrpntSOpGg7/uEvAJrEkl7/3WLr2ch9AKz76pgHG1sf2 J7xlUncvqSpOGvJRexQ3FNUcb80IzangeaN542ot9RtSyLKpoRDPIxIuDCKMODFM/Wgf OXxLHdnKftFihtpADpbBVEsQ5UfOvK1WFQHXE1pzSa1iSTgSnpmG8iyaOXjYwfEbBaAb DvFWWUwIAM9ATgWrt4C1Y38o9zsWDt4K1mqYdklpeca6j7eQuwM5bZInhfhLzqnwDh3G LNQQ== 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=i5W396zs5q9UgnQHBnhHf5o1hQ1vsudfyM40Kj+VYko=; b=g/7FCMOuuFLwYdq6FNF1Bm3+GmDGW/ICi5KGbwabbZ/JUNjS9XP2NH7JaXfVecp4Cz 0cgqu8+/B8NQBOEwbejXvDc655V0AJBMT2PFVAWUI2a5v/Gi/SJFkL2kE6XXEoT2hKaB njTO059xxtpfQ7Ta55ovhYBxQMhfuQcwlzqzrQwGASPJWk3b2ymF6Z94FbEnROj78tY9 ucGvEyWT9OoSED/adcNWRF4PFayUMTynK6eu8BC23mb1uA1iGfL16t0aBmlMfmv0xTqC pKvwMykrYu+uQPvMPO5H42WZkAKMrwybO7kMb74Ds0PV4fRdNeq483Oe20yHnF55VA4m pbmg== ARC-Authentication-Results: i=1; mx.google.com; dkim=neutral (body hash did not verify) header.i=@gmail.com header.s=20210112 header.b=Em4YyoT5; 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 f15si4897949ejl.162.2022.02.06.02.24.53; Sun, 06 Feb 2022 02:24:54 -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=Em4YyoT5; 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 226CF68B151; Sun, 6 Feb 2022 12:24:50 +0200 (EET) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from mail-ej1-f54.google.com (mail-ej1-f54.google.com [209.85.218.54]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id 98A6368AF87 for ; Sun, 6 Feb 2022 12:24:43 +0200 (EET) Received: by mail-ej1-f54.google.com with SMTP id og43so9611693ejc.0 for ; Sun, 06 Feb 2022 02:24:43 -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=Rsr2zq6LuuUsrSA2p4Zv9f61HU/NFP1qcpp8Ag3dZi4=; b=Em4YyoT5o+8yKE8q/laBzlmv0n1lsMdhEszFU1lm+1qRAOnpTsF2xuDiN0RDKECOfb l8BFExBt98eFEyQoDjTcFjwLoXsGc7kcCgTDp4mzEfYaHexM405z0L0h8Auo4mQ2Dpn+ D0NwYKPSNOLjuuhg8/3Kq9MCdO5ILH33qSJdLEHe6nzC0iK4n0VZ3EHMJWbk9A2qb71i fAfbMftuVLspR0t73WwnGXSh0Ljtvf49+CuPqx82jiGCu9uOy1M2n5cWrPchQq5t5Kjj SOm8wPIxOHX5/EYt8lac/739E5aaBvcp8JQzDbdxuo3l9dpPrYbKgz89gJYb794V0eGQ +zGA== 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=Rsr2zq6LuuUsrSA2p4Zv9f61HU/NFP1qcpp8Ag3dZi4=; b=MHqSPh16syUPvPPTliITclBDhNkfEF+ndsA6Css6AHCWRl5IWiyHkYm/511ooPq0wl xlXhOn8d76t0vSR8p6YY0ZqlndeLAsPnTB8GPnuooSdfYVcoELyVmXD/u6HdYq8+5Puu QBqsLqy9jmHlK+UkeZ9GyhMtv4reKlpHhSiqWk44IaRDxN4MsBe9ai9CsczPVVwNAGI+ xNnfm0o5tQe3hwt60F/QG5tSlSLdPZ4FBRpeTXAB2jchVWQaoySHyveLGCoLutnQFfzT TmJ+bX7nP2tYuS0E+rxx4Y6d0QNNYZcFcN0gvtOPDAEphufra9u4TB8GLtoHo3Vm7YDx KTqQ== X-Gm-Message-State: AOAM5335mw0nfUy4OroEE5/7FTOqat4oMtsLqcil1dUP+LGj8IKDlS5o 6RQx6bsK2sWrn5Ft8I1lu1qQnNjaQyQ= X-Received: by 2002:a17:906:d553:: with SMTP id cr19mr5853276ejc.700.1644143082552; Sun, 06 Feb 2022 02:24:42 -0800 (PST) Received: from localhost.localdomain ([95.168.120.2]) by smtp.gmail.com with ESMTPSA id k24sm2467780ejv.179.2022.02.06.02.24.41 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 06 Feb 2022 02:24:42 -0800 (PST) From: Paul B Mahol To: ffmpeg-devel@ffmpeg.org Date: Sun, 6 Feb 2022 11:25:15 +0100 Message-Id: <20220206102515.1418456-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: /0TOgmRyX5Jy Signed-off-by: Paul B Mahol --- doc/filters.texi | 24 ++ libavfilter/Makefile | 1 + libavfilter/af_dialogenhance.c | 409 +++++++++++++++++++++++++++++++++ libavfilter/allfilters.c | 1 + 4 files changed, 435 insertions(+) create mode 100644 libavfilter/af_dialogenhance.c diff --git a/doc/filters.texi b/doc/filters.texi index 04c34cb1fb..5ba9a35673 100644 --- a/doc/filters.texi +++ b/doc/filters.texi @@ -4178,6 +4178,30 @@ Default value is @var{o}. @end table +@section dialogenhance +Enhance dialog in stereo audio. + +This filter accepts stereo input and produce surround (3.0) channels output. +The newly produced front center channel have enhanced speech dialog originally +available in both stereo channels. +This filter outputs front left and front right channels same as available in stereo input. + +The filter accepts the following options: + +@table @option +@item original +Set the original center factor to keep in front center channel output. +Allowed range is from 0 to 1. Default value is 1. + +@item enhance +Set the dialog enhance factor to put in front center channel output. +Allowed range is from 0 to 3. Default value is 1. +@end table + +@subsection Commands + +This filter supports the all above options as @ref{commands}. + @section drmeter Measure audio dynamic range. 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..2f259fcd1d --- /dev/null +++ b/libavfilter/af_dialogenhance.c @@ -0,0 +1,409 @@ +/* + * 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; + + 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[2], *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 factor", OFFSET(original), AV_OPT_TYPE_DOUBLE, {.dbl=1}, 0, 1, FLAGS }, + { "enhance", "set dialog enhance factor", OFFSET(enhance), AV_OPT_TYPE_DOUBLE, {.dbl=1}, 0, 3, FLAGS }, + {NULL} +}; + +AVFILTER_DEFINE_CLASS(dialogenhance); + +static int query_formats(AVFilterContext *ctx) +{ + AVFilterFormats *formats = NULL; + AVFilterChannelLayouts *in_layout = NULL, *out_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 (&in_layout , AV_CH_LAYOUT_STEREO)) < 0 || + (ret = ff_channel_layouts_ref(in_layout, &ctx->inputs[0]->outcfg.channel_layouts)) < 0 || + (ret = ff_add_channel_layout (&out_layout , AV_CH_LAYOUT_SURROUND)) < 0 || + (ret = ff_channel_layouts_ref(out_layout, &ctx->outputs[0]->incfg.channel_layouts)) < 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); + + iscale = 1.f / s->fft_size; + + ret = av_tx_init(&s->tx_ctx[0], &s->tx_fn, AV_TX_FLOAT_RDFT, 0, s->fft_size, &scale, 0); + if (ret < 0) + return ret; + + ret = av_tx_init(&s->tx_ctx[1], &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, &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 *center_osamples = (float *)out->extended_data[2]; + 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, windowed_oleft, center, sizeof(float)); + + apply_window(s, windowed_oleft, left_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) + center_osamples[i] = left_out[i] / 1.5f; + else + center_osamples[i] = 0.f; + 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); + + av_tx_uninit(&s->tx_ctx[0]); + av_tx_uninit(&s->tx_ctx[1]); + av_tx_uninit(&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;