[FFmpeg-soc] [soc] G.723.1 Decoder f196bd6fcf38af4f59036cedac800da076932aa2

naufal11 at gmail.com naufal11 at gmail.com
Sun Jul 4 23:50:48 CEST 2010



- Log -----------------------------------------------------------------
commit f196bd6fcf38af4f59036cedac800da076932aa2
Author: Naufal <naufal11 at gmail.com>
Date:   Mon Jul 5 03:14:03 2010 +0530

    Perform pitch postfiltering

diff --git a/libavcodec/g723_1.c b/libavcodec/g723_1.c
index 9a363bb..c85a1a9 100755
--- a/libavcodec/g723_1.c
+++ b/libavcodec/g723_1.c
@@ -142,6 +142,22 @@ static int unpack_bitstream(G723_1_Context *p, const uint8_t *buf,
     return 0;
 }
 
+static int normalize_int32(int x)
+{
+    int i;
+    int y = x;
+    if (x) {
+        if (x == -1)
+            return INT32_MIN;
+        if (x < 0)
+            x = ~x;
+        for (i = 0; x < 0x40000000; i++)
+            x <<= 1;
+        y = av_clipl_int32((int64_t)y << i);
+    }
+    return y;
+}
+
 /*
  * Perform inverse quantization of LSP frequencies.
  *
@@ -370,13 +386,190 @@ static void gen_acb_excitation(int16_t *vector, int16_t *prev_excitation,
     }
 }
 
+/*
+ * Search for pitch postfilter forward/backward lag
+ * and compute cross-correlation.
+ *
+ * @param buf decoded excitation
+ * @param ccr cross-correlation
+ * @param dir forward(1) or backward(-1)
+ */
+static int16_t get_ppf_lag(int16_t *buf, int *ccr, int16_t pitch_lag, int index,
+                           int dir)
+{
+    int temp1, temp2, i, j;
+    int offset = SUBFRAME_LEN * index;
+    int lag = 0;
+
+    pitch_lag = FFMIN(PITCH_MAX - 3, pitch_lag);
+
+    for (i = pitch_lag - 3; i <= pitch_lag + 3; i++) {
+        temp1 = 0;
+        for (j = 0; j < SUBFRAME_LEN; j++) {
+            temp2 = av_clipl_int32((int64_t)buf[offset + j] *
+                                   buf[offset + j + dir * i] << 1);
+            temp1 = av_clipl_int32(temp1 + temp2);
+
+            if (temp1 > *ccr) {
+                *ccr = temp1;
+                lag  = i;
+            }
+        }
+    }
+    return lag;
+}
+
+/*
+ * Calculate pitch postfilter optimal and scaling gains.
+ *
+ * @param lag     pitch postfilter forward/backward lag
+ * @param ppf     pitch postfilter parameters
+ * @param tgt_eng target energy
+ * @param ccr     cross-correlation
+ * @param res_eng residual energy
+ */
+static void comp_ppf_gains(int16_t lag, PPFParam *ppf, Rate cur_rate,
+                           int tgt_eng, int ccr, int res_eng)
+{
+    int pf_residual;     // square of postfiltered residual
+    int64_t temp1, temp2;
+
+    ppf->index = lag;
+
+    temp1 = tgt_eng * res_eng >> 1;
+    temp2 = av_clipl_int32((int64_t)ccr * ccr << 1);
+
+    if (temp2 > temp1) {
+        if (ccr >= res_eng) {
+            ppf->opt_gain = ppf_gain_weight[cur_rate];
+        } else {
+            ppf->opt_gain = av_clip_int16(ccr * (1 << 15) / res_eng);
+            ppf->opt_gain = av_clip_int16(ppf->opt_gain *
+                                          ppf_gain_weight[cur_rate]);
+        }
+        // pf_res^2 = tgt_eng + 2*ccr*gain + res_eng*gain^2
+        temp1       = tgt_eng << 15;
+        temp2       = av_clipl_int32((int64_t)ccr * ppf->opt_gain << 1);
+        pf_residual = av_clipl_int32(temp1 + temp2);
+        temp1       = av_clip_int16(ppf->opt_gain * ppf->opt_gain);
+        temp2       = av_clipl_int32(temp1 * res_eng);
+        pf_residual = av_clipl_int32(pf_residual + temp2 + (1 << 15));
+
+        temp1 = tgt_eng << 15;
+        temp2 = pf_residual & 0xffff0000;
+
+        if (temp1 >= temp2) {
+            temp1 = 0x7fff;
+        } else {
+            temp1 = av_clip_int16((int64_t)temp1 * (1 << 15) /
+                                  (temp2 << 16));
+        }
+
+        //scaling_gain = sqrt(tgt_eng/pf_res^2)
+        ppf->sc_gain = ff_sqrt(temp1 << 15);
+    } else {
+        ppf->opt_gain = 0;
+        ppf->sc_gain  = 0x7fff;
+    }
+
+    ppf->opt_gain = av_clip_int16(ppf->opt_gain * ppf->opt_gain);
+}
+
+/*
+ * Calculate pitch postfilter parameters.
+ *
+ * @param buf   decoded excitation
+ * @param ppf   pitch postfilter parameters
+ * @param index current subframe index
+ */
+static void comp_ppf_coeff(int16_t *buf, int16_t pitch_lag, PPFParam *ppf,
+                           Rate cur_rate, int index)
+{
+    /*
+     * 0 - target energy
+     * 1 - forward cross-correlation
+     * 2 - forward residual energy
+     * 3 - backward cross-correlation
+     * 4 - backward residual energy
+     */
+    int energy[5] = {0, 0, 0, 0, 0};
+
+    int16_t fwd_lag =  get_ppf_lag(buf, &energy[1], pitch_lag, index, -1);
+    int16_t back_lag = get_ppf_lag(buf, &energy[3], pitch_lag, index,  1);
+
+    int offset = SUBFRAME_LEN * index;
+    int i;
+    int64_t temp1, temp2;
+
+    ppf->index    = 0;
+    ppf->opt_gain = 0;
+    ppf->sc_gain  = 0x7fff;
+
+    // Case 0, Section 3.6
+    if (!back_lag && !fwd_lag)
+        return;
+
+    // Compute target energy
+    for (i = 0; i < SUBFRAME_LEN; i++) {
+        temp1     = av_clipl_int32((int64_t)buf[offset + i] *
+                                   buf[offset + i] << 1);
+        energy[0] = av_clipl_int32(energy[0] + temp1);
+    }
+
+    // Compute forward residual energy
+    if (fwd_lag) {
+        for (i = 0; i < SUBFRAME_LEN; i++) {
+            temp1     = av_clipl_int32((int64_t)buf[offset + fwd_lag + i] *
+                                       buf[offset + fwd_lag + i] << 1);
+            energy[2] = av_clipl_int32(energy[2] + temp1);
+        }
+    }
+
+    // Compute backward residual energy
+    if (back_lag) {
+        for (i = 0; i < SUBFRAME_LEN; i++) {
+            temp1     = av_clipl_int32((int64_t)buf[offset - back_lag + i] *
+                                       buf[offset - back_lag + i] << 1);
+            energy[4] = av_clipl_int32(energy[4] + temp1);
+        }
+    }
+
+    for (i = 0; i < 5; i++)
+        energy[i] = normalize_int32(energy[i]) >> 16;
+
+    if (fwd_lag && !back_lag) {  // Case 1
+        comp_ppf_gains(fwd_lag,  ppf, cur_rate, energy[0], energy[1],
+                       energy[2]);
+    } else if (!fwd_lag) {       // Case 2
+        comp_ppf_gains(back_lag, ppf, cur_rate, energy[0], energy[3],
+                       energy[4]);
+    } else {                     // Case 3
+
+        // Select the largest of energy[1]^2/energy[2] and energy[3]^2/energy[4]
+        temp1 = av_clip_int16((energy[1] * energy[1] + (1 << 14)) >> 15);
+        temp1 = av_clipl_int32(temp1 * energy[4]);
+        temp2 = av_clip_int16((energy[3] * energy[3] + (1 << 14)) >> 15);
+        temp2 = av_clipl_int32(temp2 * energy[2]);
+
+        if (temp1 >= temp2) {
+            comp_ppf_gains(fwd_lag,  ppf, cur_rate, energy[0], energy[1],
+                           energy[2]);
+        } else {
+            comp_ppf_gains(back_lag, ppf, cur_rate, energy[0], energy[3],
+                           energy[4]);
+        }
+    }
+}
+
 static int g723_1_decode_frame(AVCodecContext *avctx, void *data,
                               int *data_size, AVPacket *avpkt)
 {
     G723_1_Context *p  = avctx->priv_data;
     const uint8_t *buf = avpkt->data;
     int buf_size       = avpkt->size;
+    int16_t *out       = data;
 
+    PPFParam ppf[SUBFRAMES];
     int16_t cur_lsp[LPC_ORDER];
     int16_t lpc[SUBFRAMES * LPC_ORDER + 4];
     int16_t temp_vector[FRAME_LEN + PITCH_MAX];
@@ -425,6 +618,17 @@ static int g723_1_decode_frame(AVCodecContext *avctx, void *data,
                 }
                 vector_ptr += SUBFRAME_LEN;
             }
+            // Perform pitch postfiltering
+            vector_ptr = temp_vector + PITCH_MAX;
+            for (i = 0; i < SUBFRAMES; i++) {
+                int offset = SUBFRAME_LEN * i;
+                comp_ppf_coeff(vector_ptr, p->pitch_lag[i >> 1],
+                               ppf + i, p->cur_rate, i);
+                ff_acelp_weighted_vector_sum(out, vector_ptr + offset,
+                                             vector_ptr + offset + ppf[i].index,
+                                             ppf[i].sc_gain, ppf[i].opt_gain,
+                                             1 << 15, 16, SUBFRAME_LEN);
+            }
         }
     }
 
diff --git a/libavcodec/g723_1_data.h b/libavcodec/g723_1_data.h
index fc20054..6e93d6c 100644
--- a/libavcodec/g723_1_data.h
+++ b/libavcodec/g723_1_data.h
@@ -41,6 +41,20 @@ typedef struct {
 } G723_1_Subframe;
 
 /*
+ * Pitch postfilter parameters
+ */
+typedef struct {
+    int16_t index;    ///< postfilter backward/forward lag
+    int16_t opt_gain; ///< optimal gain
+    int16_t sc_gain;  ///< scaling gain
+} PPFParam;
+
+/*
+ * Postfilter gain weighting factors scaled by 2^15
+ */
+static const int16_t ppf_gain_weight[2] = {0x1800, 0x2000};
+
+/*
  * LSP DC component
  */
 static const int16_t dc_lsp[LPC_ORDER] = {

-----------------------------------------------------------------------

Summary of changes:
 libavcodec/g723_1.c      |  204 ++++++++++++++++++++++++++++++++++++++++++++++
 libavcodec/g723_1_data.h |   14 +++
 2 files changed, 218 insertions(+), 0 deletions(-)


-- 
http://github.com/naufal/ffmpeg-soc


More information about the FFmpeg-soc mailing list