[FFmpeg-devel] [PATCH 1/4] libavcodec: Implementation of AC3 fixed point decoder.

Nedeljko Babic nbabic at mips.com
Tue Sep 25 16:10:54 CEST 2012


AC3 fixed point decoder is based on AC3 floating point
 decoder that is already part of FFmpeg.

It does not use FFmpegs FFT. It uses  FFT  developed for
 optimization of floating point AC3 decoder and because
 of that currently some of the files that implement this
 FFT are located in libavcodec/mips folder.

Signed-off-by: Nedeljko Babic <nbabic at mips.com>
---
 libavcodec/Makefile           |    3 +-
 libavcodec/ac3.h              |   59 +++++++++
 libavcodec/ac3dec.c           |  232 +++++++++++++++++-------------------
 libavcodec/ac3dec.h           |   22 ++--
 libavcodec/ac3dec_fixed.c     |  167 ++++++++++++++++++++++++++
 libavcodec/ac3dec_float.c     |  105 ++++++++++++++++
 libavcodec/ac3dsp.c           |   26 ++++
 libavcodec/ac3dsp.h           |    2 +
 libavcodec/allcodecs.c        |    1 +
 libavcodec/dsputil.c          |   19 +++
 libavcodec/dsputil.h          |    1 +
 libavcodec/fft.h              |    3 +
 libavcodec/fft_ac3_fixed.c    |  265 +++++++++++++++++++++++++++++++++++++++++
 libavcodec/fft_ac3_init_tab.c |   67 +++++++++++
 libavcodec/fmtconvert.c       |   72 +++++++++++
 libavcodec/fmtconvert.h       |   52 ++++++++
 libavcodec/kbdwin.c           |   30 +++++
 libavcodec/kbdwin.h           |    2 +-
 libavutil/common.h            |   10 ++
 19 files changed, 1004 insertions(+), 134 deletions(-)
 create mode 100644 libavcodec/ac3dec_fixed.c
 create mode 100644 libavcodec/ac3dec_float.c
 create mode 100644 libavcodec/fft_ac3_fixed.c
 create mode 100644 libavcodec/fft_ac3_init_tab.c

diff --git a/libavcodec/Makefile b/libavcodec/Makefile
index 9b86f7c..cf88e48 100644
--- a/libavcodec/Makefile
+++ b/libavcodec/Makefile
@@ -80,7 +80,8 @@ OBJS-$(CONFIG_AAC_ENCODER)             += aacenc.o aaccoder.o    \
                                           mpeg4audio.o kbdwin.o  \
                                           audio_frame_queue.o
 OBJS-$(CONFIG_AASC_DECODER)            += aasc.o msrledec.o
-OBJS-$(CONFIG_AC3_DECODER)             += ac3dec.o ac3dec_data.o ac3.o kbdwin.o
+OBJS-$(CONFIG_AC3_DECODER)             += ac3dec_float.o ac3dec_data.o ac3.o kbdwin.o
+OBJS-$(CONFIG_AC3_FIXED_DECODER)       += fft_ac3_init_tab.o fft_ac3_fixed.o ac3dec_fixed.o ac3dec_data.o ac3.o kbdwin.o
 OBJS-$(CONFIG_AC3_ENCODER)             += ac3enc_float.o ac3enc.o ac3tab.o \
                                           ac3.o kbdwin.o
 OBJS-$(CONFIG_AC3_FIXED_ENCODER)       += ac3enc_fixed.o ac3enc.o ac3tab.o ac3.o
diff --git a/libavcodec/ac3.h b/libavcodec/ac3.h
index b9f34b9..0a1ff23 100644
--- a/libavcodec/ac3.h
+++ b/libavcodec/ac3.h
@@ -27,6 +27,10 @@
 #ifndef AVCODEC_AC3_H
 #define AVCODEC_AC3_H
 
+#ifndef CONFIG_AC3_FIXED
+#   define CONFIG_AC3_FIXED 0
+#endif
+
 #define AC3_MAX_CODED_FRAME_SIZE 3840 /* in bytes */
 #define AC3_MAX_CHANNELS 7            /**< maximum number of channels, including coupling channel */
 #define CPL_CH 0                      /**< coupling channel index */
@@ -51,6 +55,41 @@
 #define EXP_D25   2
 #define EXP_D45   3
 
+#if CONFIG_AC3_FIXED
+
+#define CONFIG_FFT_FLOAT 0
+
+/* pre-defined gain values */
+#define LEVEL_PLUS_3DB          5793
+#define LEVEL_PLUS_1POINT5DB    4871
+#define LEVEL_MINUS_1POINT5DB   3444
+#define LEVEL_MINUS_3DB         2896
+#define LEVEL_MINUS_4POINT5DB   2435
+#define LEVEL_MINUS_6DB         2048
+#define LEVEL_MINUS_9DB         1448
+#define LEVEL_ZERO              0
+#define LEVEL_ONE               4096
+
+#define MUL_BIAS1 65536
+#define MUL_BIAS2 2147418112
+
+#define AC3_RENAME(x)           x ## _fixed
+#define AC3_CENTER(x)           center_levels[x]
+#define AC3_SURROUND(x)         surround_levels[x]
+#define AC3_LEVEL(x)            ((x)*23170 + 0x4000) >> 15
+#define AC3_NORM(x,norm)        ((x)<<12)/norm
+#define AC3_DYNAMIC_RANGE(x)    (x)
+#define AC3_SPX_BLEND(x)        (x)
+#define TYPE_PREFIX(x)          fixed_ ## x
+
+#define AC3_DYNAMIC_RANGE1   0
+#define INTFLOAT int
+#define SHORTFLOAT int16_t
+
+#define ROUND12(x) ((x)+2048)>>12
+
+#else
+
 /* pre-defined gain values */
 #define LEVEL_PLUS_3DB          1.4142135623730950
 #define LEVEL_PLUS_1POINT5DB    1.1892071150027209
@@ -62,6 +101,26 @@
 #define LEVEL_ZERO              0.0000000000000000
 #define LEVEL_ONE               1.0000000000000000
 
+#define MUL_BIAS1 1.0f
+#define MUL_BIAS2 32767.0f
+
+#define AC3_RENAME(x)           x
+#define AC3_CENTER(x)           (x)
+#define AC3_SURROUND(x)         (x)
+#define AC3_LEVEL(x)            (x)*LEVEL_MINUS_3DB
+#define AC3_NORM(x,norm)        (x)*(1.0f/norm)
+#define AC3_DYNAMIC_RANGE(x)    ((dynamic_range_tab[x] - 1.0) * s->drc_scale) + 1.0
+#define AC3_SPX_BLEND(x)        (x)* (1.0f/32)
+#define TYPE_PREFIX(x)          float_ ## x
+
+#define AC3_DYNAMIC_RANGE1   1.0f
+#define INTFLOAT float
+#define SHORTFLOAT float
+
+#define ROUND12(x) (x)
+
+#endif /* CONFIG_AC3_FIXED */
+
 /** Delta bit allocation strategy */
 typedef enum {
     DBA_REUSE = 0,
diff --git a/libavcodec/ac3dec.c b/libavcodec/ac3dec.c
index c608de8..5d82e23 100644
--- a/libavcodec/ac3dec.c
+++ b/libavcodec/ac3dec.c
@@ -64,7 +64,7 @@ static const uint8_t quantization_tab[16] = {
 static float dynamic_range_tab[256];
 
 /** Adjustments in dB gain */
-static const float gain_levels[9] = {
+static const INTFLOAT AC3_RENAME(gain_levels)[9] = {
     LEVEL_PLUS_3DB,
     LEVEL_PLUS_1POINT5DB,
     LEVEL_ONE,
@@ -157,27 +157,32 @@ static av_cold void ac3_tables_init(void)
 /**
  * AVCodec initialization
  */
-static av_cold int ac3_decode_init(AVCodecContext *avctx)
+static av_cold int AC3_RENAME(ac3_decode_init)(AVCodecContext *avctx)
 {
     AC3DecodeContext *s = avctx->priv_data;
     s->avctx = avctx;
 
     ff_ac3_common_init();
     ac3_tables_init();
-    ff_mdct_init(&s->imdct_256, 8, 1, 1.0);
-    ff_mdct_init(&s->imdct_512, 9, 1, 1.0);
-    ff_kbd_window_init(s->window, 5.0, 256);
+    AC3_RENAME(ff_mdct_init)(&s->imdct_256, 8, 1, 1.0);
+    AC3_RENAME(ff_mdct_init)(&s->imdct_512, 9, 1, 1.0);\
+    AC3_RENAME(ff_kbd_window_init)(s->window, 5.0, 256);
     ff_dsputil_init(&s->dsp, avctx);
     ff_ac3dsp_init(&s->ac3dsp, avctx->flags & CODEC_FLAG_BITEXACT);
     ff_fmt_convert_init(&s->fmt_conv, avctx);
     av_lfg_init(&s->dith_state, 0);
 
+#if CONFIG_AC3_FIXED
+    ff_ac3_fft_init_fixed(&s->imdct_256);
+    ff_ac3_fft_init_fixed(&s->imdct_512);
+#endif
+
     /* set scale value for float to int16 conversion */
     if (avctx->request_sample_fmt == AV_SAMPLE_FMT_FLT) {
-        s->mul_bias = 1.0f;
+        s->mul_bias = MUL_BIAS1;
         avctx->sample_fmt = AV_SAMPLE_FMT_FLT;
     } else {
-        s->mul_bias = 32767.0f;
+        s->mul_bias = MUL_BIAS2;
         avctx->sample_fmt = AV_SAMPLE_FMT_S16;
     }
 
@@ -300,23 +305,23 @@ static int parse_frame_header(AC3DecodeContext *s)
  * Set stereo downmixing coefficients based on frame header info.
  * reference: Section 7.8.2 Downmixing Into Two Channels
  */
-static void set_downmix_coeffs(AC3DecodeContext *s)
+static void AC3_RENAME(set_downmix_coeffs)(AC3DecodeContext *s)
 {
     int i;
-    float cmix = gain_levels[s->  center_mix_level];
-    float smix = gain_levels[s->surround_mix_level];
-    float norm0, norm1;
+    INTFLOAT cmix = AC3_RENAME(gain_levels)[s->  center_mix_level];
+    INTFLOAT smix = AC3_RENAME(gain_levels)[s->surround_mix_level];
+    INTFLOAT norm0, norm1;
 
     for (i = 0; i < s->fbw_channels; i++) {
-        s->downmix_coeffs[i][0] = gain_levels[ac3_default_coeffs[s->channel_mode][i][0]];
-        s->downmix_coeffs[i][1] = gain_levels[ac3_default_coeffs[s->channel_mode][i][1]];
+        s->downmix_coeffs[i][0] = AC3_RENAME(gain_levels)[ac3_default_coeffs[s->channel_mode][i][0]];
+        s->downmix_coeffs[i][1] = AC3_RENAME(gain_levels)[ac3_default_coeffs[s->channel_mode][i][1]];
     }
     if (s->channel_mode > 1 && s->channel_mode & 1) {
         s->downmix_coeffs[1][0] = s->downmix_coeffs[1][1] = cmix;
     }
     if (s->channel_mode == AC3_CHMODE_2F1R || s->channel_mode == AC3_CHMODE_3F1R) {
         int nf = s->channel_mode - 2;
-        s->downmix_coeffs[nf][0] = s->downmix_coeffs[nf][1] = smix * LEVEL_MINUS_3DB;
+        s->downmix_coeffs[nf][0] = s->downmix_coeffs[nf][1] = AC3_LEVEL(smix);
     }
     if (s->channel_mode == AC3_CHMODE_2F2R || s->channel_mode == AC3_CHMODE_3F2R) {
         int nf = s->channel_mode - 4;
@@ -324,22 +329,20 @@ static void set_downmix_coeffs(AC3DecodeContext *s)
     }
 
     /* renormalize */
-    norm0 = norm1 = 0.0;
+    norm0 = norm1 = (INTFLOAT)0.0;
     for (i = 0; i < s->fbw_channels; i++) {
         norm0 += s->downmix_coeffs[i][0];
         norm1 += s->downmix_coeffs[i][1];
     }
-    norm0 = 1.0f / norm0;
-    norm1 = 1.0f / norm1;
+
     for (i = 0; i < s->fbw_channels; i++) {
-        s->downmix_coeffs[i][0] *= norm0;
-        s->downmix_coeffs[i][1] *= norm1;
+        s->downmix_coeffs[i][0] = AC3_NORM(s->downmix_coeffs[i][0],norm0);
+        s->downmix_coeffs[i][1] = AC3_NORM(s->downmix_coeffs[i][1],norm1);
     }
 
     if (s->output_mode == AC3_CHMODE_MONO) {
         for (i = 0; i < s->fbw_channels; i++)
-            s->downmix_coeffs[i][0] = (s->downmix_coeffs[i][0] +
-                                       s->downmix_coeffs[i][1]) * LEVEL_MINUS_3DB;
+            s->downmix_coeffs[i][0] = AC3_LEVEL(s->downmix_coeffs[i][0] + s->downmix_coeffs[i][1]);
     }
 }
 
@@ -602,51 +605,25 @@ static inline void do_imdct(AC3DecodeContext *s, int channels)
     for (ch = 1; ch <= channels; ch++) {
         if (s->block_switch[ch]) {
             int i;
-            float *x = s->tmp_output + 128;
+            FFTSample *x = s->tmp_output+128;
             for (i = 0; i < 128; i++)
                 x[i] = s->transform_coeffs[ch][2 * i];
-            s->imdct_256.imdct_half(&s->imdct_256, s->tmp_output, x);
-            s->dsp.vector_fmul_window(s->output[ch - 1], s->delay[ch - 1],
+            s->imdct_256.AC3_RENAME(imdct_half)(&s->imdct_256, s->tmp_output, x);
+            s->dsp.AC3_RENAME(vector_fmul_window)(s->output[ch - 1], s->delay[ch - 1],
                                       s->tmp_output, s->window, 128);
             for (i = 0; i < 128; i++)
                 x[i] = s->transform_coeffs[ch][2 * i + 1];
-            s->imdct_256.imdct_half(&s->imdct_256, s->delay[ch - 1], x);
+            s->imdct_256.AC3_RENAME(imdct_half)(&s->imdct_256, s->delay[ch - 1], x);
         } else {
-            s->imdct_512.imdct_half(&s->imdct_512, s->tmp_output, s->transform_coeffs[ch]);
-            s->dsp.vector_fmul_window(s->output[ch - 1], s->delay[ch - 1],
+            s->imdct_512.AC3_RENAME(imdct_half)(&s->imdct_512, s->tmp_output, s->transform_coeffs[ch]);
+            s->dsp.AC3_RENAME(vector_fmul_window)(s->output[ch - 1], s->delay[ch - 1],
                                       s->tmp_output, s->window, 128);
-            memcpy(s->delay[ch - 1], s->tmp_output + 128, 128 * sizeof(float));
+            memcpy(s->delay[ch - 1], s->tmp_output + 128, 128 * sizeof(FFTSample));
         }
     }
 }
 
-/**
- * Upmix delay samples from stereo to original channel layout.
- */
-static void ac3_upmix_delay(AC3DecodeContext *s)
-{
-    int channel_data_size = sizeof(s->delay[0]);
-    switch (s->channel_mode) {
-    case AC3_CHMODE_DUALMONO:
-    case AC3_CHMODE_STEREO:
-        /* upmix mono to stereo */
-        memcpy(s->delay[1], s->delay[0], channel_data_size);
-        break;
-    case AC3_CHMODE_2F2R:
-        memset(s->delay[3], 0, channel_data_size);
-    case AC3_CHMODE_2F1R:
-        memset(s->delay[2], 0, channel_data_size);
-        break;
-    case AC3_CHMODE_3F2R:
-        memset(s->delay[4], 0, channel_data_size);
-    case AC3_CHMODE_3F1R:
-        memset(s->delay[3], 0, channel_data_size);
-    case AC3_CHMODE_3F:
-        memcpy(s->delay[2], s->delay[1], channel_data_size);
-        memset(s->delay[1], 0, channel_data_size);
-        break;
-    }
-}
+
 
 /**
  * Decode band structure for coupling, spectral extension, or enhanced coupling.
@@ -748,10 +725,9 @@ static int decode_audio_block(AC3DecodeContext *s, int blk)
     i = !s->channel_mode;
     do {
         if (get_bits1(gbc)) {
-            s->dynamic_range[i] = ((dynamic_range_tab[get_bits(gbc, 8)] - 1.0) *
-                                  s->drc_scale) + 1.0;
+            s->dynamic_range[i] = AC3_DYNAMIC_RANGE(get_bits(gbc, 8));
         } else if (blk == 0) {
-            s->dynamic_range[i] = 1.0f;
+            s->dynamic_range[i] = AC3_DYNAMIC_RANGE1;
         }
     } while (i--);
 
@@ -777,6 +753,10 @@ static int decode_audio_block(AC3DecodeContext *s, int blk)
             if (start_subband > 7)
                 start_subband += start_subband - 7;
             end_subband    = get_bits(gbc, 3) + 5;
+#if CONFIG_AC3_FIXED
+            s->spx_dst_end_freq = end_freq_inv_tab[end_subband];
+            end_subband += 5;
+#endif
             if (end_subband   > 7)
                 end_subband   += end_subband   - 7;
             dst_start_freq = dst_start_freq * 12 + 25;
@@ -797,7 +777,9 @@ static int decode_audio_block(AC3DecodeContext *s, int blk)
 
             s->spx_dst_start_freq = dst_start_freq;
             s->spx_src_start_freq = src_start_freq;
+#if !CONFIG_AC3_FIXED
             s->spx_dst_end_freq   = dst_end_freq;
+#endif
 
             decode_band_structure(gbc, blk, s->eac3, 0,
                                   start_subband, end_subband,
@@ -817,18 +799,45 @@ static int decode_audio_block(AC3DecodeContext *s, int blk)
         for (ch = 1; ch <= fbw_channels; ch++) {
             if (s->channel_uses_spx[ch]) {
                 if (s->first_spx_coords[ch] || get_bits1(gbc)) {
-                    float spx_blend;
+                    INTFLOAT spx_blend;
                     int bin, master_spx_coord;
 
                     s->first_spx_coords[ch] = 0;
-                    spx_blend = get_bits(gbc, 5) * (1.0f/32);
+                    spx_blend = AC3_SPX_BLEND(get_bits(gbc, 5));
                     master_spx_coord = get_bits(gbc, 2) * 3;
 
                     bin = s->spx_src_start_freq;
                     for (bnd = 0; bnd < s->num_spx_bands; bnd++) {
                         int bandsize;
                         int spx_coord_exp, spx_coord_mant;
-                        float nratio, sblend, nblend, spx_coord;
+                        INTFLOAT nratio, sblend, nblend;
+#if CONFIG_AC3_FIXED
+                        int64_t accu;
+                        /* calculate blending factors */
+                        bandsize = s->spx_band_sizes[bnd];
+                        accu = (long long)((bin << 23) + (bandsize << 22)) * s->spx_dst_end_freq;
+                        nratio = (int)(accu >> 32);
+                        nratio -= spx_blend << 18;
+
+                        if (nratio < 0)
+                        {
+                          nblend = 0;
+                          sblend = 0x800000;
+                        }
+                        else if (nratio > 0x7fffff)
+                        {
+                          nblend = 0x800000;
+                          sblend = 0;
+                        }
+                        else
+                        {
+                          nblend = ac3_fixed_sqrt(nratio);
+                          accu = (long long)nblend * 1859775393;
+                          nblend = (int)((accu + (1<<29)) >> 30);
+                          sblend = ac3_fixed_sqrt(0x800000 - nratio);
+                        }
+#else
+                        float spx_coord;
 
                         /* calculate blending factors */
                         bandsize = s->spx_band_sizes[bnd];
@@ -837,6 +846,7 @@ static int decode_audio_block(AC3DecodeContext *s, int blk)
                         nblend = sqrtf(3.0f * nratio); // noise is scaled by sqrt(3)
                                                        // to give unity variance
                         sblend = sqrtf(1.0f - nratio);
+#endif
                         bin += bandsize;
 
                         /* decode spx coordinates */
@@ -845,11 +855,18 @@ static int decode_audio_block(AC3DecodeContext *s, int blk)
                         if (spx_coord_exp == 15) spx_coord_mant <<= 1;
                         else                     spx_coord_mant += 4;
                         spx_coord_mant <<= (25 - spx_coord_exp - master_spx_coord);
-                        spx_coord = spx_coord_mant * (1.0f / (1 << 23));
 
                         /* multiply noise and signal blending factors by spx coordinate */
+#if CONFIG_AC3_FIXED
+                        accu = (long long)nblend * spx_coord_mant;
+                        s->spx_noise_blend[ch][bnd]  = (int)((accu + (1<<22)) >> 23);
+                        accu = (long long)sblend * spx_coord_mant;
+                        s->spx_signal_blend[ch][bnd] = (int)((accu + (1<<22)) >> 23);
+#else
+                        spx_coord = spx_coord_mant * (1.0f / (1 << 23));
                         s->spx_noise_blend [ch][bnd] = nblend * spx_coord;
                         s->spx_signal_blend[ch][bnd] = sblend * spx_coord;
+#endif
                     }
                 }
             } else {
@@ -1206,7 +1223,28 @@ static int decode_audio_block(AC3DecodeContext *s, int blk)
 
     /* apply scaling to coefficients (headroom, dynrng) */
     for (ch = 1; ch <= s->channels; ch++) {
+#if CONFIG_AC3_FIXED
+        int dynrng;
+
+        if(s->channel_mode == AC3_CHMODE_DUALMONO) {
+            dynrng = s->dynamic_range[2-ch];
+        } else {
+            dynrng = s->dynamic_range[0];
+        }
+        scale_coefs(s->transform_coeffs[ch], s->fixed_coeffs[ch], dynrng, 256);
+    }
+
+    do_imdct(s, s->channels);
+
+    downmix_output = s->channels != s->out_channels &&
+                     !((s->output_mode & AC3_OUTPUT_LFEON) &&
+                     s->fbw_channels == s->out_channels);
+
+    if (downmix_output)
+      s->ac3dsp.downmix_fixed(s->output, s->downmix_coeffs, s->out_channels, s->fbw_channels, 256);
+#else
         float gain = s->mul_bias / 4194304.0f;
+
         if (s->channel_mode == AC3_CHMODE_DUALMONO) {
             gain *= s->dynamic_range[2 - ch];
         } else {
@@ -1255,24 +1293,24 @@ static int decode_audio_block(AC3DecodeContext *s, int blk)
 
         do_imdct(s, s->out_channels);
     }
-
+#endif
     return 0;
 }
 
 /**
  * Decode a single AC-3 frame.
  */
-static int ac3_decode_frame(AVCodecContext * avctx, void *data,
+static int AC3_RENAME(ac3_decode_frame)(AVCodecContext * avctx, void *data,
                             int *got_frame_ptr, AVPacket *avpkt)
 {
     const uint8_t *buf = avpkt->data;
     int buf_size = avpkt->size;
     AC3DecodeContext *s = avctx->priv_data;
-    float   *out_samples_flt;
+    INTFLOAT   *out_samples_flt;
     int16_t *out_samples_s16;
     int blk, ch, err, ret;
     const uint8_t *channel_map;
-    const float *output[AC3_MAX_CHANNELS];
+    const INTFLOAT *output[AC3_MAX_CHANNELS];
 
     /* copy input buffer to decoder context to avoid reading past the end
        of the buffer, which can be caused by a damaged input stream. */
@@ -1353,14 +1391,14 @@ static int ac3_decode_frame(AVCodecContext * avctx, void *data,
         avctx->channels       = s->out_channels;
         avctx->channel_layout = s->channel_layout;
 
-        s->loro_center_mix_level   = gain_levels[s->  center_mix_level];
-        s->loro_surround_mix_level = gain_levels[s->surround_mix_level];
+        s->loro_center_mix_level   = AC3_RENAME(gain_levels)[s->  center_mix_level];
+        s->loro_surround_mix_level = AC3_RENAME(gain_levels)[s->surround_mix_level];
         s->ltrt_center_mix_level   = LEVEL_MINUS_3DB;
         s->ltrt_surround_mix_level = LEVEL_MINUS_3DB;
         /* set downmixing coefficients if needed */
         if (s->channels != s->out_channels && !((s->output_mode & AC3_OUTPUT_LFEON) &&
                 s->fbw_channels == s->out_channels)) {
-            set_downmix_coeffs(s);
+            AC3_RENAME(set_downmix_coeffs)(s);
         }
     } else if (!s->out_channels) {
         s->out_channels = avctx->channels;
@@ -1382,7 +1420,7 @@ static int ac3_decode_frame(AVCodecContext * avctx, void *data,
         av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
         return ret;
     }
-    out_samples_flt = (float   *)s->frame.data[0];
+    out_samples_flt = (INTFLOAT *)s->frame.data[0];
     out_samples_s16 = (int16_t *)s->frame.data[0];
 
     /* decode the audio blocks */
@@ -1395,11 +1433,11 @@ static int ac3_decode_frame(AVCodecContext * avctx, void *data,
             err = 1;
         }
         if (avctx->sample_fmt == AV_SAMPLE_FMT_FLT) {
-            s->fmt_conv.float_interleave(out_samples_flt, output, 256,
+            s->fmt_conv.TYPE_PREFIX(interleave)(out_samples_flt, output, 256,
                                          s->out_channels);
             out_samples_flt += 256 * s->out_channels;
         } else {
-            s->fmt_conv.float_to_int16_interleave(out_samples_s16, output, 256,
+            s->fmt_conv.TYPE_PREFIX(to_int16_interleave)(out_samples_s16, output, 256,
                                                   s->out_channels);
             out_samples_s16 += 256 * s->out_channels;
         }
@@ -1416,7 +1454,7 @@ static int ac3_decode_frame(AVCodecContext * avctx, void *data,
 /**
  * Uninitialize the AC-3 decoder.
  */
-static av_cold int ac3_decode_end(AVCodecContext *avctx)
+static av_cold int AC3_RENAME(ac3_decode_end)(AVCodecContext *avctx)
 {
     AC3DecodeContext *s = avctx->priv_data;
     ff_mdct_end(&s->imdct_512);
@@ -1438,51 +1476,3 @@ static const AVOption options[] = {
 
     { NULL},
 };
-
-static const AVClass ac3_decoder_class = {
-    .class_name = "AC3 decoder",
-    .item_name  = av_default_item_name,
-    .option     = options,
-    .version    = LIBAVUTIL_VERSION_INT,
-};
-
-AVCodec ff_ac3_decoder = {
-    .name           = "ac3",
-    .type           = AVMEDIA_TYPE_AUDIO,
-    .id             = AV_CODEC_ID_AC3,
-    .priv_data_size = sizeof (AC3DecodeContext),
-    .init           = ac3_decode_init,
-    .close          = ac3_decode_end,
-    .decode         = ac3_decode_frame,
-    .capabilities   = CODEC_CAP_DR1,
-    .long_name      = NULL_IF_CONFIG_SMALL("ATSC A/52A (AC-3)"),
-    .sample_fmts    = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_FLT,
-                                                      AV_SAMPLE_FMT_S16,
-                                                      AV_SAMPLE_FMT_NONE },
-    .priv_class     = &ac3_decoder_class,
-};
-
-#if CONFIG_EAC3_DECODER
-static const AVClass eac3_decoder_class = {
-    .class_name = "E-AC3 decoder",
-    .item_name  = av_default_item_name,
-    .option     = options,
-    .version    = LIBAVUTIL_VERSION_INT,
-};
-
-AVCodec ff_eac3_decoder = {
-    .name           = "eac3",
-    .type           = AVMEDIA_TYPE_AUDIO,
-    .id             = AV_CODEC_ID_EAC3,
-    .priv_data_size = sizeof (AC3DecodeContext),
-    .init           = ac3_decode_init,
-    .close          = ac3_decode_end,
-    .decode         = ac3_decode_frame,
-    .capabilities   = CODEC_CAP_DR1,
-    .long_name      = NULL_IF_CONFIG_SMALL("ATSC A/52B (AC-3, E-AC-3)"),
-    .sample_fmts    = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_FLT,
-                                                      AV_SAMPLE_FMT_S16,
-                                                      AV_SAMPLE_FMT_NONE },
-    .priv_class     = &eac3_decoder_class,
-};
-#endif
diff --git a/libavcodec/ac3dec.h b/libavcodec/ac3dec.h
index e0f3dc7..a215878 100644
--- a/libavcodec/ac3dec.h
+++ b/libavcodec/ac3dec.h
@@ -130,8 +130,8 @@ typedef struct {
     int num_spx_bands;                          ///< number of spx bands                    (nspxbnds)
     uint8_t spx_band_sizes[SPX_MAX_BANDS];      ///< number of bins in each spx band
     uint8_t first_spx_coords[AC3_MAX_CHANNELS]; ///< first spx coordinates states           (firstspxcos)
-    float spx_noise_blend[AC3_MAX_CHANNELS][SPX_MAX_BANDS]; ///< spx noise blending factor  (nblendfact)
-    float spx_signal_blend[AC3_MAX_CHANNELS][SPX_MAX_BANDS];///< spx signal blending factor (sblendfact)
+    INTFLOAT spx_noise_blend[AC3_MAX_CHANNELS][SPX_MAX_BANDS]; ///< spx noise blending factor  (nblendfact)
+    INTFLOAT spx_signal_blend[AC3_MAX_CHANNELS][SPX_MAX_BANDS];///< spx signal blending factor (sblendfact)
 ///@}
 
 ///@name Adaptive hybrid transform
@@ -143,15 +143,15 @@ typedef struct {
     int fbw_channels;                           ///< number of full-bandwidth channels
     int channels;                               ///< number of total channels
     int lfe_ch;                                 ///< index of LFE channel
-    float downmix_coeffs[AC3_MAX_CHANNELS][2];  ///< stereo downmix coefficients
+    INTFLOAT downmix_coeffs[AC3_MAX_CHANNELS][2];  ///< stereo downmix coefficients
     int downmixed;                              ///< indicates if coeffs are currently downmixed
     int output_mode;                            ///< output channel configuration
     int out_channels;                           ///< number of output channels
 ///@}
 
 ///@name Dynamic range
-    float dynamic_range[2];                 ///< dynamic range
-    float drc_scale;                        ///< percentage of dynamic range compression to be applied
+    INTFLOAT dynamic_range[2];                 ///< dynamic range
+    INTFLOAT drc_scale;                        ///< percentage of dynamic range compression to be applied
 ///@}
 
 ///@name Bandwidth
@@ -201,16 +201,16 @@ typedef struct {
     DSPContext dsp;                         ///< for optimization
     AC3DSPContext ac3dsp;
     FmtConvertContext fmt_conv;             ///< optimized conversion functions
-    float mul_bias;                         ///< scaling for float_to_int16 conversion
+    INTFLOAT mul_bias;                         ///< scaling for float_to_int16 conversion
 ///@}
 
 ///@name Aligned arrays
     DECLARE_ALIGNED(16, int,   fixed_coeffs)[AC3_MAX_CHANNELS][AC3_MAX_COEFS];       ///< fixed-point transform coefficients
-    DECLARE_ALIGNED(32, float, transform_coeffs)[AC3_MAX_CHANNELS][AC3_MAX_COEFS];   ///< transform coefficients
-    DECLARE_ALIGNED(32, float, delay)[AC3_MAX_CHANNELS][AC3_BLOCK_SIZE];             ///< delay - added to the next block
-    DECLARE_ALIGNED(32, float, window)[AC3_BLOCK_SIZE];                              ///< window coefficients
-    DECLARE_ALIGNED(32, float, tmp_output)[AC3_BLOCK_SIZE];                          ///< temporary storage for output before windowing
-    DECLARE_ALIGNED(32, float, output)[AC3_MAX_CHANNELS][AC3_BLOCK_SIZE];            ///< output after imdct transform and windowing
+    DECLARE_ALIGNED(32, FFTSample, transform_coeffs)[AC3_MAX_CHANNELS][AC3_MAX_COEFS];   ///< transform coefficients
+    DECLARE_ALIGNED(32, SHORTFLOAT, delay)[AC3_MAX_CHANNELS][AC3_BLOCK_SIZE];             ///< delay - added to the next block
+    DECLARE_ALIGNED(32, SHORTFLOAT, window)[AC3_BLOCK_SIZE];                              ///< window coefficients
+    DECLARE_ALIGNED(32, SHORTFLOAT, tmp_output)[AC3_BLOCK_SIZE];                          ///< temporary storage for output before windowing
+    DECLARE_ALIGNED(32, INTFLOAT, output)[AC3_MAX_CHANNELS][AC3_BLOCK_SIZE];            ///< output after imdct transform and windowing
     DECLARE_ALIGNED(32, uint8_t, input_buffer)[AC3_FRAME_BUFFER_SIZE + FF_INPUT_BUFFER_PADDING_SIZE]; ///< temp buffer to prevent overread
 ///@}
 } AC3DecodeContext;
diff --git a/libavcodec/ac3dec_fixed.c b/libavcodec/ac3dec_fixed.c
new file mode 100644
index 0000000..ffe9f7c
--- /dev/null
+++ b/libavcodec/ac3dec_fixed.c
@@ -0,0 +1,167 @@
+/*
+ * 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:  Stanislav Ocovaj (socovaj at mips.com)
+ *
+ * AC3 fixed-point decoder for MIPS platforms
+ *
+ * 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
+ */
+
+#define CONFIG_FFT_FLOAT 0
+#define CONFIG_AC3_FIXED 1
+#include "ac3dec.h"
+
+
+/**
+ * Table for center mix levels
+ * reference: Section 5.4.2.4 cmixlev
+ */
+static const uint8_t center_levels[4] = { 4, 5, 6, 5 };
+
+/**
+ * Table for surround mix levels
+ * reference: Section 5.4.2.5 surmixlev
+ */
+static const uint8_t surround_levels[4] = { 4, 6, 7, 6 };
+
+int end_freq_inv_tab[8] =
+{
+  50529027, 44278013, 39403370, 32292987, 27356480, 23729101, 20951060, 18755316
+};
+
+static void scale_coefs (
+    int16_t *dst,
+    const int *src,
+    int dynrng,
+    int len)
+{
+    int i, shift, round;
+    int16_t mul;
+    int temp, temp1, temp2, temp3, temp4, temp5, temp6, temp7;
+
+    mul = (dynrng & 0x1f) + 0x20;
+    shift = 12 - ((dynrng << 24) >> 29);
+    round = 1 << (shift-1);
+    for (i=0; i<len; i+=8) {
+
+        temp = src[i] * mul;
+        temp1 = src[i+1] * mul;
+        temp = temp + round;
+        temp2 = src[i+2] * mul;
+
+        temp1 = temp1 + round;
+        dst[i] = temp >> shift;
+        temp3 = src[i+3] * mul;
+        temp2 = temp2 + round;
+
+        dst[i+1] = temp1 >> shift;
+        temp4 = src[i + 4] * mul;
+        temp3 = temp3 + round;
+        dst[i+2] = temp2 >> shift;
+
+        temp5 = src[i+5] * mul;
+        temp4 = temp4 + round;
+        dst[i+3] = temp3 >> shift;
+        temp6 = src[i+6] * mul;
+
+        dst[i+4] = temp4 >> shift;
+        temp5 = temp5 + round;
+        temp7 = src[i+7] * mul;
+        temp6 = temp6 + round;
+
+        dst[i+5] = temp5 >> shift;
+        temp7 = temp7 + round;
+        dst[i+6] = temp6 >> shift;
+        dst[i+7] = temp7 >> shift;
+
+    }
+}
+
+static int ac3_fixed_sqrt(int x)
+{
+  int retval;
+  int bit_mask;
+  int guess;
+  int square;
+  int   i;
+  long long accu;
+
+    retval = 0;
+    bit_mask = 0x400000;
+
+    for (i=0; i<23; i++)
+    {
+        guess = retval + bit_mask;
+        accu = (long long)guess * guess;
+        square = (int)(accu >> 23);
+        if (x >= square)
+            retval += bit_mask;
+        bit_mask >>= 1;
+    }
+  return retval;
+}
+
+#include "ac3dec.c"
+
+static const AVClass ac3_decoder_class = {
+    .class_name = "AC3 fixed decoder",
+    .item_name  = av_default_item_name,
+    .option     = options,
+    .version    = LIBAVUTIL_VERSION_INT,
+};
+
+AVCodec ff_ac3_fixed_decoder = {
+    .name           = "ac3_fixed",
+    .type           = AVMEDIA_TYPE_AUDIO,
+    .id             = CODEC_ID_AC3,
+    .priv_data_size = sizeof (AC3DecodeContext),
+    .init           = ac3_decode_init_fixed,
+    .close          = ac3_decode_end_fixed,
+    .decode         = ac3_decode_frame_fixed,
+    .capabilities   = CODEC_CAP_DR1,
+    .long_name      = NULL_IF_CONFIG_SMALL("ATSC A/52A (AC-3)"),
+    .sample_fmts    = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_FLT,
+                                                      AV_SAMPLE_FMT_S16,
+                                                      AV_SAMPLE_FMT_NONE },
+    .priv_class     = &ac3_decoder_class,
+};
diff --git a/libavcodec/ac3dec_float.c b/libavcodec/ac3dec_float.c
new file mode 100644
index 0000000..f051cc0
--- /dev/null
+++ b/libavcodec/ac3dec_float.c
@@ -0,0 +1,105 @@
+/*
+ * AC-3 Audio Decoder
+ * This code was developed as part of Google Summer of Code 2006.
+ * E-AC-3 support was added as part of Google Summer of Code 2007.
+ *
+ * Copyright (c) 2006 Kartikey Mahendra BHATT (bhattkm at gmail dot com)
+ * Copyright (c) 2007-2008 Bartlomiej Wolowiec <bartek.wolowiec at gmail.com>
+ * Copyright (c) 2007 Justin Ruggles <justin.ruggles at gmail.com>
+ *
+ * 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
+ */
+
+/**
+ * Upmix delay samples from stereo to original channel layout.
+ */
+#include "ac3dec.h"
+
+static void ac3_upmix_delay(AC3DecodeContext *s)
+{
+    int channel_data_size = sizeof(s->delay[0]);
+    switch (s->channel_mode) {
+    case AC3_CHMODE_DUALMONO:
+    case AC3_CHMODE_STEREO:
+        /* upmix mono to stereo */
+        memcpy(s->delay[1], s->delay[0], channel_data_size);
+        break;
+    case AC3_CHMODE_2F2R:
+        memset(s->delay[3], 0, channel_data_size);
+    case AC3_CHMODE_2F1R:
+        memset(s->delay[2], 0, channel_data_size);
+        break;
+    case AC3_CHMODE_3F2R:
+        memset(s->delay[4], 0, channel_data_size);
+    case AC3_CHMODE_3F1R:
+        memset(s->delay[3], 0, channel_data_size);
+    case AC3_CHMODE_3F:
+        memcpy(s->delay[2], s->delay[1], channel_data_size);
+        memset(s->delay[1], 0, channel_data_size);
+        break;
+    }
+}
+
+#include "ac3dec.c"
+
+static const AVClass ac3_decoder_class = {
+    .class_name = "AC3 decoder",
+    .item_name  = av_default_item_name,
+    .option     = options,
+    .version    = LIBAVUTIL_VERSION_INT,
+};
+
+AVCodec ff_ac3_decoder = {
+    .name           = "ac3",
+    .type           = AVMEDIA_TYPE_AUDIO,
+    .id             = AV_CODEC_ID_AC3,
+    .priv_data_size = sizeof (AC3DecodeContext),
+    .init           = ac3_decode_init,
+    .close          = ac3_decode_end,
+    .decode         = ac3_decode_frame,
+    .capabilities   = CODEC_CAP_DR1,
+    .long_name      = NULL_IF_CONFIG_SMALL("ATSC A/52A (AC-3)"),
+    .sample_fmts    = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_FLT,
+                                                      AV_SAMPLE_FMT_S16,
+                                                      AV_SAMPLE_FMT_NONE },
+    .priv_class     = &ac3_decoder_class,
+};
+
+#if CONFIG_EAC3_DECODER
+static const AVClass eac3_decoder_class = {
+    .class_name = "E-AC3 decoder",
+    .item_name  = av_default_item_name,
+    .option     = options,
+    .version    = LIBAVUTIL_VERSION_INT,
+};
+
+AVCodec ff_eac3_decoder = {
+    .name           = "eac3",
+    .type           = AVMEDIA_TYPE_AUDIO,
+    .id             = AV_CODEC_ID_EAC3,
+    .priv_data_size = sizeof (AC3DecodeContext),
+    .init           = ac3_decode_init,
+    .close          = ac3_decode_end,
+    .decode         = ac3_decode_frame,
+    .capabilities   = CODEC_CAP_DR1,
+    .long_name      = NULL_IF_CONFIG_SMALL("ATSC A/52B (AC-3, E-AC-3)"),
+    .sample_fmts    = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_FLT,
+                                                      AV_SAMPLE_FMT_S16,
+                                                      AV_SAMPLE_FMT_NONE },
+    .priv_class     = &eac3_decoder_class,
+};
+#endif
diff --git a/libavcodec/ac3dsp.c b/libavcodec/ac3dsp.c
index 4e1e4bd..e044ce1 100644
--- a/libavcodec/ac3dsp.c
+++ b/libavcodec/ac3dsp.c
@@ -239,6 +239,31 @@ static void ac3_downmix_c(float (*samples)[256], float (*matrix)[2],
     }
 }
 
+static void ac3_downmix_c_fixed(int (*samples)[256], int (*matrix)[2],
+                      int out_ch, int in_ch, int len)
+{
+    int i, j;
+    int v0, v1;
+    if (out_ch == 2) {
+        for (i = 0; i < len; i++) {
+            v0 = v1 = 0;
+            for (j = 0; j < in_ch; j++) {
+                v0 += samples[j][i] * matrix[j][0];
+                v1 += samples[j][i] * matrix[j][1];
+            }
+            samples[0][i] = (v0+2048)>>12;
+            samples[1][i] = (v1+2048)>>12;
+        }
+    } else if (out_ch == 1) {
+        for (i = 0; i < len; i++) {
+            v0 = 0;
+            for (j = 0; j < in_ch; j++)
+                v0 += samples[j][i] * matrix[j][0];
+            samples[0][i] = (v0+2048)>>12;
+        }
+    }
+}
+
 av_cold void ff_ac3dsp_init(AC3DSPContext *c, int bit_exact)
 {
     c->ac3_exponent_min = ac3_exponent_min_c;
@@ -253,6 +278,7 @@ av_cold void ff_ac3dsp_init(AC3DSPContext *c, int bit_exact)
     c->sum_square_butterfly_int32 = ac3_sum_square_butterfly_int32_c;
     c->sum_square_butterfly_float = ac3_sum_square_butterfly_float_c;
     c->downmix = ac3_downmix_c;
+    c->downmix_fixed = ac3_downmix_c_fixed;
 
     if (ARCH_ARM)
         ff_ac3dsp_init_arm(c, bit_exact);
diff --git a/libavcodec/ac3dsp.h b/libavcodec/ac3dsp.h
index fbc63f6..eb51d84 100644
--- a/libavcodec/ac3dsp.h
+++ b/libavcodec/ac3dsp.h
@@ -134,6 +134,8 @@ typedef struct AC3DSPContext {
 
     void (*downmix)(float (*samples)[256], float (*matrix)[2], int out_ch,
                     int in_ch, int len);
+    void (*downmix_fixed)(int (*samples)[256], int (*matrix)[2], int out_ch,
+                    int in_ch, int len);
 } AC3DSPContext;
 
 void ff_ac3dsp_init    (AC3DSPContext *c, int bit_exact);
diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c
index cba953f..1341565 100644
--- a/libavcodec/allcodecs.c
+++ b/libavcodec/allcodecs.c
@@ -278,6 +278,7 @@ void avcodec_register_all(void)
     REGISTER_DECODER (AAC_LATM, aac_latm);
     REGISTER_ENCDEC  (AC3, ac3);
     REGISTER_ENCODER (AC3_FIXED, ac3_fixed);
+    REGISTER_DECODER (AC3_FIXED, ac3_fixed);
     REGISTER_ENCDEC  (ALAC, alac);
     REGISTER_DECODER (ALS, als);
     REGISTER_DECODER (AMRNB, amrnb);
diff --git a/libavcodec/dsputil.c b/libavcodec/dsputil.c
index af939b1..f813bb8 100644
--- a/libavcodec/dsputil.c
+++ b/libavcodec/dsputil.c
@@ -2514,6 +2514,24 @@ static void vector_fmul_window_c(float *dst, const float *src0,
     }
 }
 
+static void vector_fmul_window_fixed_c(int *dst, const int16_t *src0,
+                                       const int16_t *src1, const int16_t *win, int len)
+{
+    int i,j;
+    dst += len;
+    win += len;
+    src0+= len;
+
+    for (i=-len, j=len-1; i<0; i++, j--) {
+        int s0 = src0[i];
+        int s1 = src1[j];
+        int wi = win[i];
+        int wj = win[j];
+        dst[i] = (s0*wj - s1*wi + 0x4000) >> 15;
+        dst[j] = (s0*wi + s1*wj + 0x4000) >> 15;
+    }
+}
+
 static void vector_fmul_scalar_c(float *dst, const float *src, float mul,
                                  int len)
 {
@@ -3035,6 +3053,7 @@ av_cold void ff_dsputil_init(DSPContext* c, AVCodecContext *avctx)
     c->vector_fmul_reverse = vector_fmul_reverse_c;
     c->vector_fmul_add = vector_fmul_add_c;
     c->vector_fmul_window = vector_fmul_window_c;
+    c->vector_fmul_window_fixed = vector_fmul_window_fixed_c;
     c->vector_clipf = vector_clipf_c;
     c->scalarproduct_int16 = scalarproduct_int16_c;
     c->scalarproduct_and_madd_int16 = scalarproduct_and_madd_int16_c;
diff --git a/libavcodec/dsputil.h b/libavcodec/dsputil.h
index 2173508..0eb1023 100644
--- a/libavcodec/dsputil.h
+++ b/libavcodec/dsputil.h
@@ -390,6 +390,7 @@ typedef struct DSPContext {
     void (*vector_fmul_add)(float *dst, const float *src0, const float *src1, const float *src2, int len);
     /* assume len is a multiple of 4, and arrays are 16-byte aligned */
     void (*vector_fmul_window)(float *dst, const float *src0, const float *src1, const float *win, int len);
+    void (*vector_fmul_window_fixed)(int *dst, const int16_t *src0, const int16_t *src1, const int16_t *win, int len);
     /* assume len is a multiple of 8, and arrays are 16-byte aligned */
     void (*vector_clipf)(float *dst /* align 16 */, const float *src /* align 16 */, float min, float max, int len /* align 16 */);
     /**
diff --git a/libavcodec/fft.h b/libavcodec/fft.h
index 15e5a12..c7d2cfb 100644
--- a/libavcodec/fft.h
+++ b/libavcodec/fft.h
@@ -80,6 +80,8 @@ struct FFTContext {
     void (*fft_calc)(struct FFTContext *s, FFTComplex *z);
     void (*imdct_calc)(struct FFTContext *s, FFTSample *output, const FFTSample *input);
     void (*imdct_half)(struct FFTContext *s, FFTSample *output, const FFTSample *input);
+    void (*fft_fixed_calc)(struct FFTContext *s, FFTComplex *z);
+    void (*imdct_half_fixed)(struct FFTContext *s, FFTSample *output, const FFTSample *input);
     void (*mdct_calc)(struct FFTContext *s, FFTSample *output, const FFTSample *input);
     void (*mdct_calcw)(struct FFTContext *s, FFTDouble *output, const FFTSample *input);
     int fft_permutation;
@@ -140,6 +142,7 @@ void ff_fft_init_arm(FFTContext *s);
 void ff_fft_init_mips(FFTContext *s);
 #else
 void ff_fft_fixed_init_arm(FFTContext *s);
+void ff_ac3_fft_init_fixed(FFTContext *s);
 #endif
 
 void ff_fft_end(FFTContext *s);
diff --git a/libavcodec/fft_ac3_fixed.c b/libavcodec/fft_ac3_fixed.c
new file mode 100644
index 0000000..2796cb5
--- /dev/null
+++ b/libavcodec/fft_ac3_fixed.c
@@ -0,0 +1,265 @@
+/*
+ * 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.
+ *
+ * Authors:  Stanislav Ocovaj (socovaj at mips.com)
+ *           Dragan Mrdjan    (dmrdjan at mips.com)
+ *           Zoran Lukic      (zlukic at mips.com)
+ *           Bojan Zivkovic   (bojan at mips.com)
+ *
+ * Optimization of FFT and MDCT/IMDCT transforms for MIPS fixed-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
+ */
+
+#define CONFIG_FFT_FLOAT 0
+#include "libavcodec/fft.h"
+#include "libavcodec/mips/fft_table.h"
+
+#define CMUL_SR(dre, dim, are, aim, bre, bim) do { \
+        (dre) = ( ((are) * (bre) - (aim) * (bim) + 0x4000) >> 15 );  \
+        (dim) = ( ((are) * (bim) + (aim) * (bre) + 0x4000) >> 15 );  \
+    } while(0)
+
+static void ff_imdct_fixed_half_mips(FFTContext *s, FFTSample *output, const FFTSample *input)
+{
+    int k, n8, n4, n2, n, j;
+    const uint16_t *revtab = s->revtab;
+    const FFTSample *tcos = s->tcos;
+    const FFTSample *tsin = s->tsin;
+    const FFTSample *in1, *in2;
+    FFTComplex *z = (FFTComplex *)output;
+
+    n = 1 << s->mdct_bits;
+    n2 = n >> 1;
+    n4 = n >> 2;
+    n8 = n >> 3;
+
+    /* pre rotation */
+    in1 = input;
+    in2 = input + n2 - 1;
+    for(k=0; k<n4; k++) {
+        j=revtab[k];
+        CMUL_SR(z[j].re, z[j].im, *in2, *in1, tcos[k], tsin[k]);
+        in1 += 2;
+        in2 -= 2;
+    }
+    s->fft_fixed_calc(s, z);
+
+    /* post rotation + reordering */
+    for(k=0; k<n8; k++) {
+
+        FFTSample r0, i0, r1, i1;
+        CMUL_SR(r0, i1, z[n8-k-1].im, z[n8-k-1].re, tsin[n8-k-1], tcos[n8-k-1]);
+        CMUL_SR(r1, i0, z[n8+k  ].im, z[n8+k  ].re, tsin[n8+k  ], tcos[n8+k  ]);
+        z[n8-k-1].re = r0;
+        z[n8-k-1].im = i0;
+        z[n8+k  ].re = r1;
+        z[n8+k  ].im = i1;
+    }
+}
+
+static void ff_fft_fixed_calc_mips(FFTContext *s, FFTComplex *z) {
+
+    int nbits, i, n, num_transforms, offset, step;
+    int n4, n2, n34;
+    int tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7, tmp8;
+
+    FFTComplex *tmpz;
+
+    int w_re, w_im;
+    FFTSample *w_re_ptr, *w_im_ptr;
+    int pom;
+    const int fft_size = (1 << s->nbits);
+
+    num_transforms = (0x2aab >> (16 - s->nbits)) | 1;
+    for (n=0; n<num_transforms; n++)
+    {
+        offset = fft_offsets_lut[n] << 2;
+        tmpz = z + offset;
+
+        tmp1 = tmpz[0].re + tmpz[1].re;
+        tmp5 = tmpz[2].re + tmpz[3].re;
+        tmp2 = tmpz[0].im + tmpz[1].im;
+        tmp6 = tmpz[2].im + tmpz[3].im;
+        tmp3 = tmpz[0].re - tmpz[1].re;
+        tmp8 = tmpz[2].im - tmpz[3].im;
+        tmp4 = tmpz[0].im - tmpz[1].im;
+        tmp7 = tmpz[2].re - tmpz[3].re;
+
+        tmpz[0].re = tmp1 + tmp5;
+        tmpz[2].re = tmp1 - tmp5;
+        tmpz[0].im = tmp2 + tmp6;
+        tmpz[2].im = tmp2 - tmp6;
+        tmpz[1].re = tmp3 + tmp8;
+        tmpz[3].re = tmp3 - tmp8;
+        tmpz[1].im = tmp4 - tmp7;
+        tmpz[3].im = tmp4 + tmp7;
+
+    }
+    if (fft_size < 8)
+    return;
+
+    num_transforms = (num_transforms >> 1) | 1;
+    for (n=0; n<num_transforms; n++)
+    {
+        offset = fft_offsets_lut[n] << 3;
+        tmpz = z + offset;
+
+        tmp1 = tmpz[4].re + tmpz[5].re;
+        tmp3 = tmpz[6].re + tmpz[7].re;
+        tmp2 = tmpz[4].im + tmpz[5].im;
+        tmp4 = tmpz[6].im + tmpz[7].im;
+
+        tmp5 = tmp1 + tmp3;
+        tmp7 = tmp1 - tmp3;
+        tmp6 = tmp2 + tmp4;
+        tmp8 = tmp2 - tmp4;
+
+        tmp1 = tmpz[4].re - tmpz[5].re;
+        tmp2 = tmpz[4].im - tmpz[5].im;
+        tmp3 = tmpz[6].re - tmpz[7].re;
+        tmp4 = tmpz[6].im - tmpz[7].im;
+
+        tmpz[4].re = tmpz[0].re - tmp5;
+        tmpz[0].re = tmpz[0].re + tmp5;
+        tmpz[4].im = tmpz[0].im - tmp6;
+        tmpz[0].im = tmpz[0].im + tmp6;
+        tmpz[6].re = tmpz[2].re - tmp8;
+        tmpz[2].re = tmpz[2].re + tmp8;
+        tmpz[6].im = tmpz[2].im + tmp7;
+        tmpz[2].im = tmpz[2].im - tmp7;
+
+        pom = 23170;
+
+        tmp5 = (pom * (tmp1 + tmp2) + 0x4000) >> 15;
+        tmp7 = (pom * (tmp3 - tmp4) + 0x4000) >> 15;
+        tmp6 = (pom * (tmp2 - tmp1) + 0x4000) >> 15;
+        tmp8 = (pom * (tmp3 + tmp4) + 0x4000) >> 15;
+
+        tmp1 = tmp5 + tmp7;
+        tmp3 = tmp5 - tmp7;
+        tmp2 = tmp6 + tmp8;
+        tmp4 = tmp6 - tmp8;
+
+        tmpz[5].re = tmpz[1].re - tmp1;
+        tmpz[1].re = tmpz[1].re + tmp1;
+        tmpz[5].im = tmpz[1].im - tmp2;
+        tmpz[1].im = tmpz[1].im + tmp2;
+        tmpz[7].re = tmpz[3].re - tmp4;
+        tmpz[3].re = tmpz[3].re + tmp4;
+        tmpz[7].im = tmpz[3].im + tmp3;
+        tmpz[3].im = tmpz[3].im - tmp3;
+    }
+
+    step = 1 << (MAX_LOG2_NFFT - 4);
+    n4 = 4;
+    for (nbits=4; nbits<=s->nbits; nbits++)
+    {
+        n2 = 2*n4;
+        n34 = 3*n4;
+        num_transforms = (num_transforms >> 1) | 1;
+        for (n=0; n<num_transforms; n++)
+        {
+            offset = fft_offsets_lut[n] << nbits;
+            tmpz = z + offset;
+
+            tmp5 = tmpz[ n2].re + tmpz[n34].re;
+            tmp1 = tmpz[ n2].re - tmpz[n34].re;
+            tmp6 = tmpz[ n2].im + tmpz[n34].im;
+            tmp2 = tmpz[ n2].im - tmpz[n34].im;
+
+            tmpz[ n2].re = tmpz[ 0].re - tmp5;
+            tmpz[ 0].re  = tmpz[ 0].re + tmp5;
+            tmpz[ n2].im = tmpz[ 0].im - tmp6;
+            tmpz[ 0].im  = tmpz[ 0].im + tmp6;
+            tmpz[n34].re = tmpz[n4].re - tmp2;
+            tmpz[ n4].re = tmpz[n4].re + tmp2;
+            tmpz[n34].im = tmpz[n4].im + tmp1;
+            tmpz[ n4].im = tmpz[n4].im - tmp1;
+
+            w_re_ptr = (FFTSample*)(ff_cos_65536_fixed + step);
+            w_im_ptr = (FFTSample*)(ff_cos_65536_fixed + MAX_FFT_SIZE/4 - step);
+
+            for (i=1; i<n4; i++)
+            {
+                w_re = w_re_ptr[0];
+                w_im = w_im_ptr[0];
+
+                tmp1 = (w_re * tmpz[ n2+i].re + w_im * tmpz[ n2+i].im + 0x4000) >> 15;
+                tmp2 = (w_re * tmpz[ n2+i].im - w_im * tmpz[ n2+i].re + 0x4000) >> 15;
+                tmp3 = (w_re * tmpz[n34+i].re - w_im * tmpz[n34+i].im + 0x4000) >> 15;
+                tmp4 = (w_re * tmpz[n34+i].im + w_im * tmpz[n34+i].re + 0x4000) >> 15;
+
+                tmp5 = tmp1 + tmp3;
+                tmp1 = tmp1 - tmp3;
+                tmp6 = tmp2 + tmp4;
+                tmp2 = tmp2 - tmp4;
+
+                tmpz[n2+i ].re = av_clip_int16(tmpz[i   ].re - tmp5);
+                tmpz[i    ].re = av_clip_int16(tmpz[i   ].re + tmp5);
+                tmpz[n2+i ].im = av_clip_int16(tmpz[i   ].im - tmp6);
+                tmpz[i    ].im = av_clip_int16(tmpz[i   ].im + tmp6);
+                tmpz[n34+i].re = av_clip_int16(tmpz[n4+i].re - tmp2);
+                tmpz[n4+i ].re = av_clip_int16(tmpz[n4+i].re + tmp2);
+                tmpz[n34+i].im = av_clip_int16(tmpz[n4+i].im + tmp1);
+                tmpz[n4+i ].im = av_clip_int16(tmpz[n4+i].im - tmp1);
+
+                w_re_ptr += step;
+                w_im_ptr -= step;
+            }
+        }
+        step >>= 1;
+        n4 <<= 1;
+    }
+}
+
+void ff_ac3_fft_init_fixed(FFTContext *s) {
+
+    int n=0;
+    ff_fft_lut_init(fft_offsets_lut, 0, 1 << 16, &n);
+
+#if CONFIG_MDCT
+    s->imdct_half_fixed = ff_imdct_fixed_half_mips;
+#endif /* CONFIG_MDCT */
+    s->fft_fixed_calc   = ff_fft_fixed_calc_mips;
+}
diff --git a/libavcodec/fft_ac3_init_tab.c b/libavcodec/fft_ac3_init_tab.c
new file mode 100644
index 0000000..61a1919
--- /dev/null
+++ b/libavcodec/fft_ac3_init_tab.c
@@ -0,0 +1,67 @@
+/*
+ * 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:  Stanislav Ocovaj (socovaj at mips.com)
+ *
+ * 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
+ * definitions and initialization of LUT table for MIPS FFT
+ */
+#include "libavcodec/mips/fft_table.h"
+
+uint16_t fft_offsets_lut[0x2aab];
+
+void ff_fft_lut_init(uint16_t *table, int off, int size, int *index)
+{
+    if (size < 16) {
+        table[*index] = off >> 2;
+        (*index)++;
+    }
+    else {
+        ff_fft_lut_init(table, off, size>>1, index);
+        ff_fft_lut_init(table, off+(size>>1), size>>2, index);
+        ff_fft_lut_init(table, off+3*(size>>2), size>>2, index);
+    }
+}
diff --git a/libavcodec/fmtconvert.c b/libavcodec/fmtconvert.c
index 372f2a3..951a2e5 100644
--- a/libavcodec/fmtconvert.c
+++ b/libavcodec/fmtconvert.c
@@ -30,10 +30,21 @@ static void int32_to_float_fmul_scalar_c(float *dst, const int *src, float mul,
         dst[i] = src[i] * mul;
 }
 
+static void int32_to_fixed_fmul_scalar_c(int16_t *dst, const int *src, int mul, int len) {
+    int i;
+    for(i=0; i<len; i++)
+    dst[i] = (src[i] * mul + 0x8000) >> 16;
+}
+
 static av_always_inline int float_to_int16_one(const float *src){
     return av_clip_int16(lrintf(*src));
 }
 
+static av_always_inline int fixed_to_int16_one(const int *src)
+{
+    return av_clip_int16_c_fixed(*src);
+}
+
 static void float_to_int16_c(int16_t *dst, const float *src, long len)
 {
     int i;
@@ -57,6 +68,35 @@ static void float_to_int16_interleave_c(int16_t *dst, const float **src,
     }
 }
 
+static void fixed_to_int16_interleave_c(int16_t *dst, const int **src,
+                                        long len, int channels)
+{
+    int i,j,c;
+    if(channels==2) {
+        for(i=0; i<len; i++) {
+            dst[2*i] = fixed_to_int16_one(src[0]+i);
+            dst[2*i+1] = fixed_to_int16_one(src[1]+i);
+        }
+    }
+    else {
+        if(channels==6) {
+            for(i=0; i<len; i++) {
+                dst[6*i] = fixed_to_int16_one(src[0]+i);
+                dst[6*i+1] = fixed_to_int16_one(src[1]+i);
+                dst[6*i+2] = fixed_to_int16_one(src[2]+i);
+                dst[6*i+3] = fixed_to_int16_one(src[3]+i);
+                dst[6*i+4] = fixed_to_int16_one(src[4]+i);
+                dst[6*i+5] = fixed_to_int16_one(src[5]+i);
+            }
+        }
+        else {
+            for(c=0; c<channels; c++)
+                for(i=0, j=c; i<len; i++, j+=channels)
+                    dst[j] = fixed_to_int16_one(src[c]+i);
+        }
+    }
+}
+
 void ff_float_interleave_c(float *dst, const float **src, unsigned int len,
                            int channels)
 {
@@ -76,9 +116,41 @@ void ff_float_interleave_c(float *dst, const float **src, unsigned int len,
     }
 }
 
+void ff_fixed_interleave_c(int *dst, const int **src, unsigned int len,
+                           int channels)
+{
+    int j, c;
+    unsigned int i;
+    if (channels == 6) {
+        for (i = 0; i < len; i++) {
+            dst[6*i]   = src[0][i];
+            dst[6*i+1] = src[1][i];
+            dst[6*i+2] = src[2][i];
+            dst[6*i+3] = src[3][i];
+            dst[6*i+4] = src[4][i];
+            dst[6*i+5] = src[5][i];
+        }
+    }
+    else if (channels == 2) {
+        for (i = 0; i < len; i++) {
+            dst[2*i]   = src[0][i];
+            dst[2*i+1] = src[1][i];
+        }
+    } else if (channels == 1 && len < INT_MAX / sizeof(int)) {
+        memcpy(dst, src[0], len * sizeof(int));
+    } else {
+        for (c = 0; c < channels; c++)
+            for (i = 0, j = c; i < len; i++, j += channels)
+                dst[j] = src[c][i];
+    }
+}
+
 av_cold void ff_fmt_convert_init(FmtConvertContext *c, AVCodecContext *avctx)
 {
     c->int32_to_float_fmul_scalar = int32_to_float_fmul_scalar_c;
+    c->int32_to_fixed_fmul_scalar = int32_to_fixed_fmul_scalar_c;
+    c->fixed_to_int16_interleave  = fixed_to_int16_interleave_c;
+    c->fixed_interleave           = ff_fixed_interleave_c;
     c->float_to_int16             = float_to_int16_c;
     c->float_to_int16_interleave  = float_to_int16_interleave_c;
     c->float_interleave           = ff_float_interleave_c;
diff --git a/libavcodec/fmtconvert.h b/libavcodec/fmtconvert.h
index ab2caa2..8bda1e7 100644
--- a/libavcodec/fmtconvert.h
+++ b/libavcodec/fmtconvert.h
@@ -38,6 +38,54 @@ typedef struct FmtConvertContext {
     void (*int32_to_float_fmul_scalar)(float *dst, const int *src, float mul, int len);
 
     /**
+     * Multiply a array of int32_t by a int32_t value and convert to int16_t.
+     * @param dst destination array of int16_t.
+     *            constraints: 16-byte aligned
+     * @param src source array of int32_t.
+     *            constraints: 16-byte aligned
+     * @param len number of elements in array.
+     *            constraints: multiple of 8
+     */
+    void (*int32_to_fixed_fmul_scalar)(int16_t *dst, const int *src, int mul, int len);
+    /**
+     * Convert an array of int32_t to an array of int16_t.
+     *
+     * @param dst destination array of int16_t.
+     *            constraints: 16-byte aligned
+     * @param src source array of int32_t.
+     *            constraints: 16-byte aligned
+     * @param len number of elements to convert.
+     *            constraints: multiple of 8
+     */
+    void (*fixed_to_int16)(int16_t *dst, const int *src, long len);
+    /**
+     * Convert multiple arrays of int32_t to an interleaved array of int16_t.
+     *
+     * @param dst destination array of interleaved int16_t.
+     *            constraints: 16-byte aligned
+     * @param src source array of int32_t arrays, one for each channel.
+     *            constraints: 16-byte aligned
+     * @param len number of elements to convert.
+     *            constraints: multiple of 8
+     * @param channels number of channels
+     */
+    void (*fixed_to_int16_interleave)(int16_t *dst, const int **src,
+                                      long len, int channels);
+    /**
+     * Convert multiple arrays of int32_t to an array of interleaved int32_t.
+     *
+     * @param dst destination array of interleaved int32_t.
+     *            constraints: 16-byte aligned
+     * @param src source array of int32_t arrays, one for each channel.
+     *            constraints: 16-byte aligned
+     * @param len number of elements to convert.
+     *            constraints: multiple of 8
+     * @param channels number of channels
+     */
+    void (*fixed_interleave)(int *dst, const int **src, unsigned int len,
+                             int channels);
+
+    /**
      * Convert an array of float to an array of int16_t.
      *
      * Convert floats from in the range [-32768.0,32767.0] to ints
@@ -87,6 +135,10 @@ typedef struct FmtConvertContext {
 void ff_float_interleave_c(float *dst, const float **src, unsigned int len,
                            int channels);
 
+void ff_fixed_interleave_c(int *dst, const int **src, unsigned int len,
+                           int channels);
+void fixed_interleave(int *dst, const int **src, unsigned int len, int channels);
+
 av_cold void ff_fmt_convert_init(FmtConvertContext *c, AVCodecContext *avctx);
 
 void ff_fmt_convert_init_arm(FmtConvertContext *c, AVCodecContext *avctx);
diff --git a/libavcodec/kbdwin.c b/libavcodec/kbdwin.c
index 2722312..7e90714 100644
--- a/libavcodec/kbdwin.c
+++ b/libavcodec/kbdwin.c
@@ -46,3 +46,33 @@ av_cold void ff_kbd_window_init(float *window, float alpha, int n)
    for (i = 0; i < n; i++)
        window[i] = sqrt(local_window[i] / sum);
 }
+
+av_cold void ff_kbd_window_init_fixed(int16_t *window, float alpha, int n)
+{
+    int i, j;
+    double sum = 0.0, bessel, tmp;
+    double local_window[FF_KBD_WINDOW_MAX];
+    double alpha2 = (alpha * M_PI / n) * (alpha * M_PI / n);
+
+    assert(n <= FF_KBD_WINDOW_MAX);
+
+    for (i = 0; i < n; i++) {
+        tmp = i * (n - i) * alpha2;
+        bessel = 1.0;
+        for (j = BESSEL_I0_ITER; j > 0; j--)
+            bessel = bessel * tmp / (j * j) + 1;
+        sum += bessel;
+        local_window[i] = sum;
+    }
+
+    sum++;
+    for (i = 0; i < n; i++)
+    {
+        int tmp;
+
+        tmp = (int)(32767*sqrt(local_window[i] / sum) + 0.5);
+        if (tmp > 32767)
+            tmp = 32767;
+        window[i] = (int16_t)tmp;
+    }
+}
diff --git a/libavcodec/kbdwin.h b/libavcodec/kbdwin.h
index 4b93975..fea8187 100644
--- a/libavcodec/kbdwin.h
+++ b/libavcodec/kbdwin.h
@@ -31,5 +31,5 @@
  * @param   n       size of half window, max FF_KBD_WINDOW_MAX
  */
 void ff_kbd_window_init(float *window, float alpha, int n);
-
+void ff_kbd_window_init_fixed(int16_t *window, float alpha, int n);
 #endif /* AVCODEC_KBDWIN_H */
diff --git a/libavutil/common.h b/libavutil/common.h
index 3e3baab..7637b64 100644
--- a/libavutil/common.h
+++ b/libavutil/common.h
@@ -164,6 +164,16 @@ static av_always_inline av_const int16_t av_clip_int16_c(int a)
 }
 
 /**
+ * Clip a signed integer value into the 0, 65536 range
+ * @param a value to clip
+ * @return clipped value
+ */
+static av_always_inline av_const int16_t av_clip_int16_c_fixed(int a)
+{
+    return (a > 0xefff ? 0xefff : a);
+}
+
+/**
  * Clip a signed 64-bit integer value into the -2147483648,2147483647 range.
  * @param a value to clip
  * @return clipped value
-- 
1.7.3.4



More information about the ffmpeg-devel mailing list