From patchwork Thu Nov 3 01:15:13 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Muhammad Faiz X-Patchwork-Id: 1267 Delivered-To: ffmpegpatchwork@gmail.com Received: by 10.103.90.1 with SMTP id o1csp559088vsb; Wed, 2 Nov 2016 18:34:01 -0700 (PDT) X-Received: by 10.194.18.196 with SMTP id y4mr2397510wjd.73.1478136841169; Wed, 02 Nov 2016 18:34:01 -0700 (PDT) Return-Path: Received: from ffbox0-bg.mplayerhq.hu (ffbox0-bg.ffmpeg.org. [79.124.17.100]) by mx.google.com with ESMTP id o6si6154336wjg.73.2016.11.02.18.34.00; Wed, 02 Nov 2016 18:34:01 -0700 (PDT) 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; 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 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 68E00689B74; Thu, 3 Nov 2016 03:33:54 +0200 (EET) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from mail-pf0-f194.google.com (mail-pf0-f194.google.com [209.85.192.194]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id F129C6898B0 for ; Thu, 3 Nov 2016 03:33:47 +0200 (EET) Received: by mail-pf0-f194.google.com with SMTP id y68so3193045pfb.1 for ; Wed, 02 Nov 2016 18:33:51 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=from:to:cc:subject:date:message-id; bh=9H4KEoRimqbcuHdkupcxRcORbENFtGg7nKxnAPZ7caM=; b=0nF0zRI/U2vorR637hewk9EAptXbxZnYH+INwGF5cvx/MZcPQ+NV0MFlTgSvPJ5T// RJgpCl/uUG66RPdB75CKCWQazHM0PzEZo5cveJYgB37P82HTBe+FD7Ekl0hIsiybmxIH KFUaOFGS/eaH7MOVjqQ+4iXIIA2rFBU90cwn6Lf5l96adlRpBmUsDd5oqcONR1WWeJab jrFYKG7h6T9vqKUUALPRf+oE3RYAbnJ0pfeTqgT917EM1krS7uz2zhkRmq1LUtMkYJE4 fbR/G2k4Ivtx2mJ3vZXm9csYbAuJWkW5jf65+NkjlKKrS05F6MfE/l9JkDWyi9bMWaQk evzw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:from:to:cc:subject:date:message-id; bh=9H4KEoRimqbcuHdkupcxRcORbENFtGg7nKxnAPZ7caM=; b=KJWUOKkPWt6qUr4bUwj4WP/JSVa240OM6zLCO+ydmin0jh8J+l/5OPuYfE5umDigWa 79YS618I1n1NNCGp3yyZC5DN9CuV1KGaK6UuOLEmyaaFNt2CY29F2X7jlHYVV8RCUqn5 OnMFGzY1O9eHeFsZ/SwU8otO0Jx3eSjvnde48Or6ai/hTcMbjx5fFVB88H+NwuVHCRrB 8JeJPUaa36UFp4Q+e64AtAWU2aVIaoxhIvtfsiNdWk1fcU6KE0QjarogipALsZTO1u7S QMblWjNBr46CQaytOYRa4LQSxKsNop9SX6u0kc2I0SLumiIhY3tvZvioubEKsX57Jzwm BjYw== X-Gm-Message-State: ABUngvfdt+bEzsM1VwmP5cExt1WIg/t/4oQ9NzJT28bspUrYB3X4MRAiwuaWy2yskT+dyA== X-Received: by 10.98.79.193 with SMTP id f62mr12061413pfj.149.1478135859249; Wed, 02 Nov 2016 18:17:39 -0700 (PDT) Received: from localhost.localdomain.localdomain ([114.121.239.244]) by smtp.gmail.com with ESMTPSA id r10sm7596628paw.2.2016.11.02.18.17.34 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Wed, 02 Nov 2016 18:17:38 -0700 (PDT) From: Muhammad Faiz To: ffmpeg-devel@ffmpeg.org Date: Thu, 3 Nov 2016 08:15:13 +0700 Message-Id: <1478135713-16489-1-git-send-email-mfcc64@gmail.com> X-Mailer: git-send-email 2.5.0 Subject: [FFmpeg-devel] [PATCH] avfilter/af_firequalizer: add fft2 option X-BeenThere: ffmpeg-devel@ffmpeg.org X-Mailman-Version: 2.1.20 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 Cc: Muhammad Faiz MIME-Version: 1.0 Errors-To: ffmpeg-devel-bounces@ffmpeg.org Sender: "ffmpeg-devel" 2-channels convolution using complex fft improves speed significantly not sure if it should be enabled by default so disable it by default Signed-off-by: Muhammad Faiz --- doc/filters.texi | 4 +++ libavfilter/af_firequalizer.c | 80 ++++++++++++++++++++++++++++++++++++++++- tests/filtergraphs/firequalizer | 8 +++-- 3 files changed, 88 insertions(+), 4 deletions(-) diff --git a/doc/filters.texi b/doc/filters.texi index 867b932..5bced37 100644 --- a/doc/filters.texi +++ b/doc/filters.texi @@ -2585,6 +2585,10 @@ Set file for dumping, suitable for gnuplot. @item dumpscale Set scale for dumpfile. Acceptable values are same with scale option. Default is linlog. + +@item fft2 +Enable 2-channel convolution using complex FFT. This improves speed significantly. +Default is disabled. @end table @subsection Examples diff --git a/libavfilter/af_firequalizer.c b/libavfilter/af_firequalizer.c index 4988717..5c6fd54 100644 --- a/libavfilter/af_firequalizer.c +++ b/libavfilter/af_firequalizer.c @@ -69,6 +69,7 @@ typedef struct { RDFTContext *analysis_irdft; RDFTContext *rdft; RDFTContext *irdft; + FFTContext *fft_ctx; int analysis_rdft_len; int rdft_len; @@ -97,6 +98,7 @@ typedef struct { int scale; char *dumpfile; int dumpscale; + int fft2; int nb_gain_entry; int gain_entry_err; @@ -132,6 +134,7 @@ static const AVOption firequalizer_options[] = { { "loglog", "logarithmic-freq logarithmic-gain", 0, AV_OPT_TYPE_CONST, { .i64 = SCALE_LOGLOG }, 0, 0, FLAGS, "scale" }, { "dumpfile", "set dump file", OFFSET(dumpfile), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, FLAGS }, { "dumpscale", "set dump scale", OFFSET(dumpscale), AV_OPT_TYPE_INT, { .i64 = SCALE_LINLOG }, 0, NB_SCALE-1, FLAGS, "scale" }, + { "fft2", "set 2-channels fft", OFFSET(fft2), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, FLAGS }, { NULL } }; @@ -143,7 +146,9 @@ static void common_uninit(FIREqualizerContext *s) av_rdft_end(s->analysis_irdft); av_rdft_end(s->rdft); av_rdft_end(s->irdft); + av_fft_end(s->fft_ctx); s->analysis_rdft = s->analysis_irdft = s->rdft = s->irdft = NULL; + s->fft_ctx = NULL; av_freep(&s->analysis_buf); av_freep(&s->dump_buf); @@ -230,6 +235,70 @@ static void fast_convolute(FIREqualizerContext *s, const float *kernel_buf, floa } } +static void fast_convolute2(FIREqualizerContext *s, const float *kernel_buf, FFTComplex *conv_buf, + OverlapIndex *idx, float *data0, float *data1, int nsamples) +{ + if (nsamples <= s->nsamples_max) { + FFTComplex *buf = conv_buf + idx->buf_idx * s->rdft_len; + FFTComplex *obuf = conv_buf + !idx->buf_idx * s->rdft_len + idx->overlap_idx; + int center = s->fir_len/2; + int k; + float tmp; + + memset(buf, 0, center * sizeof(*buf)); + for (k = 0; k < nsamples; k++) { + buf[center+k].re = data0[k]; + buf[center+k].im = data1[k]; + } + memset(buf + center + nsamples, 0, (s->rdft_len - nsamples - center) * sizeof(*buf)); + av_fft_permute(s->fft_ctx, buf); + av_fft_calc(s->fft_ctx, buf); + + /* swap re <-> im, do backward fft using forward fft_ctx */ + /* normalize with 0.5f */ + tmp = buf[0].re; + buf[0].re = 0.5f * kernel_buf[0] * buf[0].im; + buf[0].im = 0.5f * kernel_buf[0] * tmp; + for (k = 1; k < s->rdft_len/2; k++) { + int m = s->rdft_len - k; + tmp = buf[k].re; + buf[k].re = 0.5f * kernel_buf[k] * buf[k].im; + buf[k].im = 0.5f * kernel_buf[k] * tmp; + tmp = buf[m].re; + buf[m].re = 0.5f * kernel_buf[k] * buf[m].im; + buf[m].im = 0.5f * kernel_buf[k] * tmp; + } + tmp = buf[k].re; + buf[k].re = 0.5f * kernel_buf[k] * buf[k].im; + buf[k].im = 0.5f * kernel_buf[k] * tmp; + + av_fft_permute(s->fft_ctx, buf); + av_fft_calc(s->fft_ctx, buf); + + for (k = 0; k < s->rdft_len - idx->overlap_idx; k++) { + buf[k].re += obuf[k].re; + buf[k].im += obuf[k].im; + } + + /* swapped re <-> im */ + for (k = 0; k < nsamples; k++) { + data0[k] = buf[k].im; + data1[k] = buf[k].re; + } + idx->buf_idx = !idx->buf_idx; + idx->overlap_idx = nsamples; + } else { + while (nsamples > s->nsamples_max * 2) { + fast_convolute2(s, kernel_buf, conv_buf, idx, data0, data1, s->nsamples_max); + data0 += s->nsamples_max; + data1 += s->nsamples_max; + nsamples -= s->nsamples_max; + } + fast_convolute2(s, kernel_buf, conv_buf, idx, data0, data1, nsamples/2); + fast_convolute2(s, kernel_buf, conv_buf, idx, data0 + nsamples/2, data1 + nsamples/2, nsamples - nsamples/2); + } +} + static void dump_fir(AVFilterContext *ctx, FILE *fp, int ch) { FIREqualizerContext *s = ctx->priv; @@ -598,6 +667,9 @@ static int config_input(AVFilterLink *inlink) if (!(s->rdft = av_rdft_init(rdft_bits, DFT_R2C)) || !(s->irdft = av_rdft_init(rdft_bits, IDFT_C2R))) return AVERROR(ENOMEM); + if (s->fft2 && !s->multi && inlink->channels > 1 && !(s->fft_ctx = av_fft_init(rdft_bits, 0))) + return AVERROR(ENOMEM); + for ( ; rdft_bits <= RDFT_BITS_MAX; rdft_bits++) { s->analysis_rdft_len = 1 << rdft_bits; if (inlink->sample_rate <= s->accuracy * s->analysis_rdft_len) @@ -640,7 +712,13 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *frame) FIREqualizerContext *s = ctx->priv; int ch; - for (ch = 0; ch < inlink->channels; ch++) { + for (ch = 0; ch + 1 < inlink->channels && s->fft_ctx; ch += 2) { + fast_convolute2(s, s->kernel_buf, (FFTComplex *)(s->conv_buf + 2 * ch * s->rdft_len), + s->conv_idx + ch, (float *) frame->extended_data[ch], + (float *) frame->extended_data[ch+1], frame->nb_samples); + } + + for ( ; ch < inlink->channels; ch++) { fast_convolute(s, s->kernel_buf + (s->multi ? ch * s->rdft_len : 0), s->conv_buf + 2 * ch * s->rdft_len, s->conv_idx + ch, (float *) frame->extended_data[ch], frame->nb_samples); diff --git a/tests/filtergraphs/firequalizer b/tests/filtergraphs/firequalizer index ee432e2..777dfdd 100644 --- a/tests/filtergraphs/firequalizer +++ b/tests/filtergraphs/firequalizer @@ -1,4 +1,5 @@ firequalizer = + fft2 = on: gain = 'sin(0.001*f) - 1': delay = 0.05, @@ -11,14 +12,15 @@ firequalizer = wfunc = nuttall, firequalizer = + fft2 = on: + gain_entry = 'entry(1000, 0); entry(5000, 0.1); entry(10000, 0.2)', + +firequalizer = gain = 'if (ch, -0.3 * sin(0.001*f), -0.8 * sin(0.001*f)) - 1': delay = 0.05: multi = on, firequalizer = - gain_entry = 'entry(1000, 0); entry(5000, 0.1); entry(10000, 0.2)', - -firequalizer = gain_entry = 'entry(1000, 0.2); entry(5000, 0.1); entry(10000, 0)', volume = 2.8dB,