From 5bf6dc93339a231bd82f09cc6a2b9becb5af0f4a Mon Sep 17 00:00:00 2001
From: Lynne <dev@lynne.ee>
Date: Fri, 15 Mar 2019 14:35:03 +0000
Subject: [PATCH 3/5] opusdsp: create and move deemphasis and postfiltering
 from opus_celt

---
 libavcodec/Makefile    |  3 ++-
 libavcodec/opus_celt.c | 53 ++++++++----------------------------
 libavcodec/opus_celt.h |  3 ++-
 libavcodec/opusdsp.c   | 61 ++++++++++++++++++++++++++++++++++++++++++
 libavcodec/opusdsp.h   | 33 +++++++++++++++++++++++
 5 files changed, 109 insertions(+), 44 deletions(-)
 create mode 100644 libavcodec/opusdsp.c
 create mode 100644 libavcodec/opusdsp.h

diff --git a/libavcodec/Makefile b/libavcodec/Makefile
index 15c43a8a6a..d13eef8a20 100644
--- a/libavcodec/Makefile
+++ b/libavcodec/Makefile
@@ -495,7 +495,8 @@ OBJS-$(CONFIG_NELLYMOSER_ENCODER)      += nellymoserenc.o nellymoser.o
 OBJS-$(CONFIG_NUV_DECODER)             += nuv.o rtjpeg.o
 OBJS-$(CONFIG_ON2AVC_DECODER)          += on2avc.o on2avcdata.o
 OBJS-$(CONFIG_OPUS_DECODER)            += opusdec.o opus.o opus_celt.o opus_rc.o \
-                                          opus_pvq.o opus_silk.o opustab.o vorbis_data.o
+                                          opus_pvq.o opus_silk.o opustab.o vorbis_data.o \
+                                          opusdsp.o
 OBJS-$(CONFIG_OPUS_ENCODER)            += opusenc.o opus.o opus_rc.o opustab.o opus_pvq.o \
                                           opusenc_psy.o
 OBJS-$(CONFIG_PAF_AUDIO_DECODER)       += pafaudio.o
diff --git a/libavcodec/opus_celt.c b/libavcodec/opus_celt.c
index 115dd8c63e..4655172b09 100644
--- a/libavcodec/opus_celt.c
+++ b/libavcodec/opus_celt.c
@@ -202,40 +202,10 @@ static void celt_postfilter_apply_transition(CeltBlock *block, float *data)
     }
 }
 
-static void celt_postfilter_apply(CeltBlock *block, float *data, int len)
-{
-    const int T = block->pf_period;
-    float g0, g1, g2;
-    float x0, x1, x2, x3, x4;
-    int i;
-
-    if (block->pf_gains[0] == 0.0 || len <= 0)
-        return;
-
-    g0 = block->pf_gains[0];
-    g1 = block->pf_gains[1];
-    g2 = block->pf_gains[2];
-
-    x4 = data[-T - 2];
-    x3 = data[-T - 1];
-    x2 = data[-T];
-    x1 = data[-T + 1];
-
-    for (i = 0; i < len; i++) {
-        x0 = data[i - T + 2];
-        data[i] += g0 * x2        +
-                   g1 * (x1 + x3) +
-                   g2 * (x0 + x4);
-        x4 = x3;
-        x3 = x2;
-        x2 = x1;
-        x1 = x0;
-    }
-}
-
 static void celt_postfilter(CeltFrame *f, CeltBlock *block)
 {
     int len = f->blocksize * f->blocks;
+    const int filter_len = len - 2 * CELT_OVERLAP;
 
     celt_postfilter_apply_transition(block, block->buf + 1024);
 
@@ -247,8 +217,11 @@ static void celt_postfilter(CeltFrame *f, CeltBlock *block)
 
     if (len > CELT_OVERLAP) {
         celt_postfilter_apply_transition(block, block->buf + 1024 + CELT_OVERLAP);
-        celt_postfilter_apply(block, block->buf + 1024 + 2 * CELT_OVERLAP,
-                              len - 2 * CELT_OVERLAP);
+
+        if (block->pf_gains[0] > FLT_EPSILON && filter_len > 0)
+            f->opusdsp.postfilter(block->buf + 1024 + 2 * CELT_OVERLAP,
+                                  block->pf_period, block->pf_gains,
+                                  filter_len);
 
         block->pf_period_old = block->pf_period;
         memcpy(block->pf_gains_old, block->pf_gains, sizeof(block->pf_gains));
@@ -462,7 +435,6 @@ int ff_celt_decode_frame(CeltFrame *f, OpusRangeCoder *rc,
     /* transform and output for each output channel */
     for (i = 0; i < f->output_channels; i++) {
         CeltBlock *block = &f->block[i];
-        float m = block->emph_coeff;
 
         /* iMDCT and overlap-add */
         for (j = 0; j < f->blocks; j++) {
@@ -480,14 +452,10 @@ int ff_celt_decode_frame(CeltFrame *f, OpusRangeCoder *rc,
         /* postfilter */
         celt_postfilter(f, block);
 
-        /* deemphasis and output scaling */
-        for (j = 0; j < frame_size; j++) {
-            const float tmp = block->buf[1024 - frame_size + j] + m;
-            m = tmp * CELT_EMPH_COEFF;
-            output[i][j] = tmp;
-        }
-
-        block->emph_coeff = m;
+        /* deemphasis */
+        block->emph_coeff = f->opusdsp.deemphasis(output[i],
+                                                  &block->buf[1024 - frame_size],
+                                                  block->emph_coeff, frame_size);
     }
 
     if (channels == 1)
@@ -596,6 +564,7 @@ int ff_celt_init(AVCodecContext *avctx, CeltFrame **f, int output_channels,
         goto fail;
     }
 
+    ff_opus_dsp_init(&frm->opusdsp);
     ff_celt_flush(frm);
 
     *f = frm;
diff --git a/libavcodec/opus_celt.h b/libavcodec/opus_celt.h
index 9289a1867a..7c1c5316b9 100644
--- a/libavcodec/opus_celt.h
+++ b/libavcodec/opus_celt.h
@@ -28,6 +28,7 @@
 
 #include "opus.h"
 #include "opus_pvq.h"
+#include "opusdsp.h"
 
 #include "mdct15.h"
 #include "libavutil/float_dsp.h"
@@ -40,7 +41,6 @@
 #define CELT_NORM_SCALE              16384
 #define CELT_QTHETA_OFFSET           4
 #define CELT_QTHETA_OFFSET_TWOPHASE  16
-#define CELT_EMPH_COEFF              0.85000610f
 #define CELT_POSTFILTER_MINPERIOD    15
 #define CELT_ENERGY_SILENCE          (-28.0f)
 
@@ -96,6 +96,7 @@ struct CeltFrame {
     AVFloatDSPContext   *dsp;
     CeltBlock           block[2];
     CeltPVQ             *pvq;
+    OpusDSP             opusdsp;
     int channels;
     int output_channels;
     int apply_phase_inv;
diff --git a/libavcodec/opusdsp.c b/libavcodec/opusdsp.c
new file mode 100644
index 0000000000..615e7d6816
--- /dev/null
+++ b/libavcodec/opusdsp.c
@@ -0,0 +1,61 @@
+/*
+ * 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 "opusdsp.h"
+
+static void postfilter_c(float *data, int period, float *gains, int len)
+{
+    const float g0 = gains[0];
+    const float g1 = gains[1];
+    const float g2 = gains[2];
+
+    float x4 = data[-period - 2];
+    float x3 = data[-period - 1];
+    float x2 = data[-period + 0];
+    float x1 = data[-period + 1];
+
+    for (int i = 0; i < len; i++) {
+        float x0 = data[i - period + 2];
+        data[i] += g0 * x2        +
+                   g1 * (x1 + x3) +
+                   g2 * (x0 + x4);
+        x4 = x3;
+        x3 = x2;
+        x2 = x1;
+        x1 = x0;
+    }
+}
+
+static float deemphasis_c(float *y, float *x, float coeff, int len)
+{
+    float state = coeff;
+
+    for (int i = 0; i < len; i++) {
+        const float tmp = x[i] + state;
+        state = tmp * CELT_EMPH_COEFF;
+        y[i] = tmp;
+    }
+
+    return state;
+}
+
+av_cold void ff_opus_dsp_init(OpusDSP *ctx)
+{
+    ctx->postfilter = postfilter_c;
+    ctx->deemphasis = deemphasis_c;
+}
diff --git a/libavcodec/opusdsp.h b/libavcodec/opusdsp.h
new file mode 100644
index 0000000000..74adfe6859
--- /dev/null
+++ b/libavcodec/opusdsp.h
@@ -0,0 +1,33 @@
+/*
+ * 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
+ */
+
+#ifndef AVCODEC_OPUS_DSP_H
+#define AVCODEC_OPUS_DSP_H
+
+#include "libavutil/common.h"
+
+#define CELT_EMPH_COEFF 0.8500061035f
+
+typedef struct OpusDSP {
+    void (*postfilter)(float *data, int period, float *gains, int len);
+    float (*deemphasis)(float *out, float *in, float coeff, int len);
+} OpusDSP;
+
+void ff_opus_dsp_init(OpusDSP *ctx);
+
+#endif /* AVCODEC_OPUS_DSP_H */
-- 
2.21.0

