[FFmpeg-devel] [PATCH 2/2] mips: Optimization of AAC psychoacoustic model functions

Bojan Zivkovic bojan at mips.com
Thu Nov 22 14:11:54 CET 2012


Signed-off-by: Bojan Zivkovic <bojan at mips.com>
---
 doc/mips.txt                  |    1 +
 libavcodec/aacpsy.c           |   80 +++++++++-----
 libavcodec/mips/aacpsy_mips.h |  230 +++++++++++++++++++++++++++++++++++++++++
 3 files changed, 282 insertions(+), 29 deletions(-)
 create mode 100644 libavcodec/mips/aacpsy_mips.h

diff --git a/doc/mips.txt b/doc/mips.txt
index aabdef0..cfc6f17 100644
--- a/doc/mips.txt
+++ b/doc/mips.txt
@@ -48,6 +48,7 @@ Files that have MIPS copyright notice in them:
       float_dsp_mips.c
       libm_mips.h
 * libavcodec/mips/
+      aacpsy_mips.h
       ac3dsp_mips.c
       acelp_filters_mips.c
       acelp_vectors_mips.c
diff --git a/libavcodec/aacpsy.c b/libavcodec/aacpsy.c
index 8a57d86..78ccd5f 100644
--- a/libavcodec/aacpsy.c
+++ b/libavcodec/aacpsy.c
@@ -217,6 +217,10 @@ static const float psy_fir_coeffs[] = {
     -5.52212e-17 * 2, -0.313819 * 2
 };
 
+#if ARCH_MIPS
+#   include "mips/aacpsy_mips.h"
+#endif /* ARCH_MIPS */
+
 /**
  * Calculate the ABR attack threshold from the above LAME psymodel table.
  */
@@ -557,25 +561,12 @@ static float calc_reduced_thr_3gpp(AacPsyBand *band, float min_snr,
     return thr;
 }
 
-/**
- * Calculate band thresholds as suggested in 3GPP TS26.403
- */
-static void psy_3gpp_analyze_channel(FFPsyContext *ctx, int channel,
-                                     const float *coefs, const FFPsyWindowInfo *wi)
+#ifndef calc_thr_3gpp
+static void calc_thr_3gpp(const FFPsyWindowInfo *wi, const int num_bands, AacPsyChannel *pch,
+                          const uint8_t *band_sizes, const float *coefs)
 {
-    AacPsyContext *pctx = (AacPsyContext*) ctx->model_priv_data;
-    AacPsyChannel *pch  = &pctx->ch[channel];
-    int start = 0;
     int i, w, g;
-    float desired_bits, desired_pe, delta_pe, reduction= NAN, spread_en[128] = {0};
-    float a = 0.0f, active_lines = 0.0f, norm_fac = 0.0f;
-    float pe = pctx->chan_bitrate > 32000 ? 0.0f : FFMAX(50.0f, 100.0f - pctx->chan_bitrate * 100.0f / 32000.0f);
-    const int      num_bands   = ctx->num_bands[wi->num_windows == 8];
-    const uint8_t *band_sizes  = ctx->bands[wi->num_windows == 8];
-    AacPsyCoeffs  *coeffs      = pctx->psy_coef[wi->num_windows == 8];
-    const float avoid_hole_thr = wi->num_windows == 8 ? PSY_3GPP_AH_THR_SHORT : PSY_3GPP_AH_THR_LONG;
-
-    //calculate energies, initial thresholds and related values - 5.4.2 "Threshold Calculation"
+    int start = 0;
     for (w = 0; w < wi->num_windows*16; w += 16) {
         for (g = 0; g < num_bands; g++) {
             AacPsyBand *band = &pch->band[w+g];
@@ -594,6 +585,47 @@ static void psy_3gpp_analyze_channel(FFPsyContext *ctx, int channel,
             start += band_sizes[g];
         }
     }
+}
+#endif /* calc_thr_3gpp */
+
+#ifndef psy_hp_filter
+static void psy_hp_filter(const float *firbuf, float *hpfsmpl)
+{
+    int i, j;
+    for (i = 0; i < AAC_BLOCK_SIZE_LONG; i++) {
+        float sum1, sum2;
+        sum1 = firbuf[i + (PSY_LAME_FIR_LEN - 1) / 2];
+        sum2 = 0.0;
+        for (j = 0; j < ((PSY_LAME_FIR_LEN - 1) / 2) - 1; j += 2) {
+            sum1 += psy_fir_coeffs[j] * (firbuf[i + j] + firbuf[i + PSY_LAME_FIR_LEN - j]);
+            sum2 += psy_fir_coeffs[j + 1] * (firbuf[i + j + 1] + firbuf[i + PSY_LAME_FIR_LEN - j - 1]);
+        }
+        /* NOTE: The LAME psymodel expects it's input in the range -32768 to 32768. Tuning this for normalized floats would be difficult. */
+        hpfsmpl[i] = (sum1 + sum2) * 32768.0f;
+    }
+}
+#endif /* psy_hp_filter */
+
+/**
+ * Calculate band thresholds as suggested in 3GPP TS26.403
+ */
+static void psy_3gpp_analyze_channel(FFPsyContext *ctx, int channel,
+                                     const float *coefs, const FFPsyWindowInfo *wi)
+{
+    AacPsyContext *pctx = (AacPsyContext*) ctx->model_priv_data;
+    AacPsyChannel *pch  = &pctx->ch[channel];
+    int i, w, g;
+    float desired_bits, desired_pe, delta_pe, reduction= NAN, spread_en[128] = {0};
+    float a = 0.0f, active_lines = 0.0f, norm_fac = 0.0f;
+    float pe = pctx->chan_bitrate > 32000 ? 0.0f : FFMAX(50.0f, 100.0f - pctx->chan_bitrate * 100.0f / 32000.0f);
+    const int      num_bands   = ctx->num_bands[wi->num_windows == 8];
+    const uint8_t *band_sizes  = ctx->bands[wi->num_windows == 8];
+    AacPsyCoeffs  *coeffs      = pctx->psy_coef[wi->num_windows == 8];
+    const float avoid_hole_thr = wi->num_windows == 8 ? PSY_3GPP_AH_THR_SHORT : PSY_3GPP_AH_THR_LONG;
+
+    //calculate energies, initial thresholds and related values - 5.4.2 "Threshold Calculation"
+    calc_thr_3gpp(wi, num_bands, pch, band_sizes, coefs);
+
     //modify thresholds and energies - spread, threshold in quiet, pre-echo control
     for (w = 0; w < wi->num_windows*16; w += 16) {
         AacPsyBand *bands = &pch->band[w];
@@ -799,20 +831,10 @@ static FFPsyWindowInfo psy_lame_window(FFPsyContext *ctx, const float *audio,
         float energy_subshort[(AAC_NUM_BLOCKS_SHORT + 1) * PSY_LAME_NUM_SUBBLOCKS];
         float energy_short[AAC_NUM_BLOCKS_SHORT + 1] = { 0 };
         const float *firbuf = la + (AAC_BLOCK_SIZE_SHORT/4 - PSY_LAME_FIR_LEN);
-        int j, att_sum = 0;
+        int att_sum = 0;
 
         /* LAME comment: apply high pass filter of fs/4 */
-        for (i = 0; i < AAC_BLOCK_SIZE_LONG; i++) {
-            float sum1, sum2;
-            sum1 = firbuf[i + (PSY_LAME_FIR_LEN - 1) / 2];
-            sum2 = 0.0;
-            for (j = 0; j < ((PSY_LAME_FIR_LEN - 1) / 2) - 1; j += 2) {
-                sum1 += psy_fir_coeffs[j] * (firbuf[i + j] + firbuf[i + PSY_LAME_FIR_LEN - j]);
-                sum2 += psy_fir_coeffs[j + 1] * (firbuf[i + j + 1] + firbuf[i + PSY_LAME_FIR_LEN - j - 1]);
-            }
-            /* NOTE: The LAME psymodel expects it's input in the range -32768 to 32768. Tuning this for normalized floats would be difficult. */
-            hpfsmpl[i] = (sum1 + sum2) * 32768.0f;
-        }
+        psy_hp_filter(firbuf, hpfsmpl);
 
         /* Calculate the energies of each sub-shortblock */
         for (i = 0; i < PSY_LAME_NUM_SUBBLOCKS; i++) {
diff --git a/libavcodec/mips/aacpsy_mips.h b/libavcodec/mips/aacpsy_mips.h
new file mode 100644
index 0000000..d5a4e57
--- /dev/null
+++ b/libavcodec/mips/aacpsy_mips.h
@@ -0,0 +1,230 @@
+/*
+ * Copyright (c) 2012
+ *      MIPS Technologies, Inc., California.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the MIPS Technologies, Inc., nor the names of its
+ *    contributors may be used to endorse or promote products derived from
+ *    this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE MIPS TECHNOLOGIES, INC. ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE MIPS TECHNOLOGIES, INC. BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Author:  Bojan Zivkovic   (bojan at mips.com)
+ *
+ * AAC encoder psychoacoustic model routines optimized
+ * for MIPS floating-point architecture
+ *
+ * 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
+ */
+
+/**
+ * @file
+ * Reference: libavcodec/aacpsy.c
+ */
+
+#ifndef AVCODEC_MIPS_AACPSY_MIPS_H
+#define AVCODEC_MIPS_AACPSY_MIPS_H
+
+#if HAVE_INLINE_ASM && HAVE_MIPSFPU
+static void calc_thr_3gpp_mips(const FFPsyWindowInfo *wi, const int num_bands,
+                               AacPsyChannel *pch, const uint8_t *band_sizes,
+                               const float *coefs)
+{
+    int i, w, g;
+    int start = 0;
+    for (w = 0; w < wi->num_windows*16; w += 16) {
+        for (g = 0; g < num_bands; g++) {
+            AacPsyBand *band = &pch->band[w+g];
+
+            float form_factor = 0.0f;
+            float Temp;
+            band->energy = 0.0f;
+            for (i = 0; i < band_sizes[g]; i+=4) {
+                float a, b, c, d;
+                float ax, bx, cx, dx;
+                float *cf = (float *)&coefs[start+i];
+
+                __asm__ volatile (
+                    "lwc1   %[a],   0(%[cf])                \n\t"
+                    "lwc1   %[b],   4(%[cf])                \n\t"
+                    "lwc1   %[c],   8(%[cf])                \n\t"
+                    "lwc1   %[d],   12(%[cf])               \n\t"
+                    "abs.s  %[a],   %[a]                    \n\t"
+                    "abs.s  %[b],   %[b]                    \n\t"
+                    "abs.s  %[c],   %[c]                    \n\t"
+                    "abs.s  %[d],   %[d]                    \n\t"
+                    "sqrt.s %[ax],  %[a]                    \n\t"
+                    "sqrt.s %[bx],  %[b]                    \n\t"
+                    "sqrt.s %[cx],  %[c]                    \n\t"
+                    "sqrt.s %[dx],  %[d]                    \n\t"
+                    "madd.s %[e],   %[e],   %[a],   %[a]    \n\t"
+                    "madd.s %[e],   %[e],   %[b],   %[b]    \n\t"
+                    "madd.s %[e],   %[e],   %[c],   %[c]    \n\t"
+                    "madd.s %[e],   %[e],   %[d],   %[d]    \n\t"
+                    "add.s  %[f],   %[f],   %[ax]           \n\t"
+                    "add.s  %[f],   %[f],   %[bx]           \n\t"
+                    "add.s  %[f],   %[f],   %[cx]           \n\t"
+                    "add.s  %[f],   %[f],   %[dx]           \n\t"
+
+                    : [a]"=&f"(a), [b]"=&f"(b),
+                      [c]"=&f"(c), [d]"=&f"(d),
+                      [e]"+f"(band->energy), [f]"+f"(form_factor),
+                      [ax]"=&f"(ax), [bx]"=&f"(bx),
+                      [cx]"=&f"(cx), [dx]"=&f"(dx)
+                    : [cf]"r"(cf)
+                    : "memory"
+                );
+            }
+
+            Temp = sqrtf((float)band_sizes[g] / band->energy);
+            band->thr      = band->energy * 0.001258925f;
+            band->nz_lines = form_factor * sqrtf(Temp);
+            start += band_sizes[g];
+        }
+    }
+}
+
+static void psy_hp_filter_mips(const float *firbuf, float *hpfsmpl)
+{
+    float sum1, sum2, sum3, sum4;
+    float *fb = (float*)firbuf;
+    float *fb_end = fb + 1024;
+    float *hp = hpfsmpl;
+
+    float coeff0 = psy_fir_coeffs[1];
+    float coeff1 = psy_fir_coeffs[3];
+    float coeff2 = psy_fir_coeffs[5];
+    float coeff3 = psy_fir_coeffs[7];
+    float coeff4 = psy_fir_coeffs[9];
+
+    __asm__ volatile (
+        ".set push                                          \n\t"
+        ".set noreorder                                     \n\t"
+
+        "li.s   $f12,       32768                           \n\t"
+        "1:                                                 \n\t"
+        "lwc1   $f0,        40(%[fb])                       \n\t"
+        "lwc1   $f1,        4(%[fb])                        \n\t"
+        "lwc1   $f2,        80(%[fb])                       \n\t"
+        "lwc1   $f3,        44(%[fb])                       \n\t"
+        "lwc1   $f4,        8(%[fb])                        \n\t"
+        "madd.s %[sum1],    $f0,        $f1,    %[coeff0]   \n\t"
+        "lwc1   $f5,        84(%[fb])                       \n\t"
+        "lwc1   $f6,        48(%[fb])                       \n\t"
+        "madd.s %[sum2],    $f3,        $f4,    %[coeff0]   \n\t"
+        "lwc1   $f7,        12(%[fb])                       \n\t"
+        "madd.s %[sum1],    %[sum1],    $f2,    %[coeff0]   \n\t"
+        "lwc1   $f8,        88(%[fb])                       \n\t"
+        "lwc1   $f9,        52(%[fb])                       \n\t"
+        "madd.s %[sum2],    %[sum2],    $f5,    %[coeff0]   \n\t"
+        "madd.s %[sum3],    $f6,        $f7,    %[coeff0]   \n\t"
+        "lwc1   $f10,       16(%[fb])                       \n\t"
+        "lwc1   $f11,       92(%[fb])                       \n\t"
+        "madd.s %[sum1],    %[sum1],    $f7,    %[coeff1]   \n\t"
+        "lwc1   $f1,        72(%[fb])                       \n\t"
+        "madd.s %[sum3],    %[sum3],    $f8,    %[coeff0]   \n\t"
+        "madd.s %[sum4],    $f9,        $f10,   %[coeff0]   \n\t"
+        "madd.s %[sum2],    %[sum2],    $f10,   %[coeff1]   \n\t"
+        "madd.s %[sum1],    %[sum1],    $f1,    %[coeff1]   \n\t"
+        "lwc1   $f4,        76(%[fb])                       \n\t"
+        "lwc1   $f8,        20(%[fb])                       \n\t"
+        "madd.s %[sum4],    %[sum4],    $f11,   %[coeff0]   \n\t"
+        "lwc1   $f11,       24(%[fb])                       \n\t"
+        "madd.s %[sum2],    %[sum2],    $f4,    %[coeff1]   \n\t"
+        "madd.s %[sum1],    %[sum1],    $f8,    %[coeff2]   \n\t"
+        "madd.s %[sum3],    %[sum3],    $f8,    %[coeff1]   \n\t"
+        "madd.s %[sum4],    %[sum4],    $f11,   %[coeff1]   \n\t"
+        "lwc1   $f7,        64(%[fb])                       \n\t"
+        "madd.s %[sum2],    %[sum2],    $f11,   %[coeff2]   \n\t"
+        "lwc1   $f10,       68(%[fb])                       \n\t"
+        "madd.s %[sum3],    %[sum3],    $f2,    %[coeff1]   \n\t"
+        "madd.s %[sum4],    %[sum4],    $f5,    %[coeff1]   \n\t"
+        "madd.s %[sum1],    %[sum1],    $f7,    %[coeff2]   \n\t"
+        "madd.s %[sum2],    %[sum2],    $f10,   %[coeff2]   \n\t"
+        "lwc1   $f2,        28(%[fb])                       \n\t"
+        "lwc1   $f5,        32(%[fb])                       \n\t"
+        "lwc1   $f8,        56(%[fb])                       \n\t"
+        "lwc1   $f11,       60(%[fb])                       \n\t"
+        "madd.s %[sum3],    %[sum3],    $f2,    %[coeff2]   \n\t"
+        "madd.s %[sum4],    %[sum4],    $f5,    %[coeff2]   \n\t"
+        "madd.s %[sum1],    %[sum1],    $f2,    %[coeff3]   \n\t"
+        "madd.s %[sum2],    %[sum2],    $f5,    %[coeff3]   \n\t"
+        "madd.s %[sum3],    %[sum3],    $f1,    %[coeff2]   \n\t"
+        "madd.s %[sum4],    %[sum4],    $f4,    %[coeff2]   \n\t"
+        "madd.s %[sum1],    %[sum1],    $f8,    %[coeff3]   \n\t"
+        "madd.s %[sum2],    %[sum2],    $f11,   %[coeff3]   \n\t"
+        "lwc1   $f1,        36(%[fb])                       \n\t"
+        "addiu  %[fb],      %[fb],      16                  \n\t"
+        "madd.s %[sum4],    %[sum4],    $f0,    %[coeff3]   \n\t"
+        "madd.s %[sum3],    %[sum3],    $f1,    %[coeff3]   \n\t"
+        "madd.s %[sum1],    %[sum1],    $f1,    %[coeff4]   \n\t"
+        "madd.s %[sum2],    %[sum2],    $f0,    %[coeff4]   \n\t"
+        "madd.s %[sum4],    %[sum4],    $f10,   %[coeff3]   \n\t"
+        "madd.s %[sum3],    %[sum3],    $f7,    %[coeff3]   \n\t"
+        "madd.s %[sum1],    %[sum1],    $f6,    %[coeff4]   \n\t"
+        "madd.s %[sum2],    %[sum2],    $f9,    %[coeff4]   \n\t"
+        "madd.s %[sum4],    %[sum4],    $f6,    %[coeff4]   \n\t"
+        "madd.s %[sum3],    %[sum3],    $f3,    %[coeff4]   \n\t"
+        "mul.s  %[sum1],    %[sum1],    $f12                \n\t"
+        "mul.s  %[sum2],    %[sum2],    $f12                \n\t"
+        "madd.s %[sum4],    %[sum4],    $f11,   %[coeff4]   \n\t"
+        "madd.s %[sum3],    %[sum3],    $f8,    %[coeff4]   \n\t"
+        "swc1   %[sum1],    0(%[hp])                        \n\t"
+        "swc1   %[sum2],    4(%[hp])                        \n\t"
+        "mul.s  %[sum4],    %[sum4],    $f12                \n\t"
+        "mul.s  %[sum3],    %[sum3],    $f12                \n\t"
+        "swc1   %[sum4],    12(%[hp])                       \n\t"
+        "swc1   %[sum3],    8(%[hp])                        \n\t"
+        "bne    %[fb],      %[fb_end],  1b                  \n\t"
+        " addiu %[hp],      %[hp],      16                  \n\t"
+
+        ".set pop                                           \n\t"
+
+        : [sum1]"=&f"(sum1), [sum2]"=&f"(sum2),
+          [sum3]"=&f"(sum3), [sum4]"=&f"(sum4),
+          [fb]"+r"(fb), [hp]"+r"(hp)
+        : [coeff0]"f"(coeff0), [coeff1]"f"(coeff1),
+          [coeff2]"f"(coeff2), [coeff3]"f"(coeff3),
+          [coeff4]"f"(coeff4), [fb_end]"r"(fb_end)
+        : "$f0", "$f1", "$f2", "$f3", "$f4", "$f5", "$f6",
+          "$f7", "$f8", "$f9", "$f10", "$f11", "$f12",
+          "memory"
+    );
+}
+
+#define calc_thr_3gpp calc_thr_3gpp_mips
+#define psy_hp_filter psy_hp_filter_mips
+
+#endif /* HAVE_INLINE_ASM && HAVE_MIPSFPU */
+#endif /* AVCODEC_MIPS_AACPSY_MIPS_H */
-- 
1.7.3.4



More information about the ffmpeg-devel mailing list