view aacps.c @ 12483:0159a19bfff7 libavcodec

aacdec: Rework channel mapping compatibility hacks. For a PCE based configuration map the channels solely based on tags. For an indexed configuration map the channels solely based on position. This works with all known exotic samples including al17, elem_id0, bad_concat, and lfe_is_sce.
author alexc
date Fri, 10 Sep 2010 18:01:48 +0000
parents 8c657be75c11
children
line wrap: on
line source

/*
 * MPEG-4 Parametric Stereo decoding functions
 * Copyright (c) 2010 Alex Converse <alex.converse@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
 */

#include <stdint.h>
#include "libavutil/common.h"
#include "libavutil/mathematics.h"
#include "avcodec.h"
#include "get_bits.h"
#include "aacps.h"
#include "aacps_tablegen.h"
#include "aacpsdata.c"

#define PS_BASELINE 0  //< Operate in Baseline PS mode
                       //< Baseline implies 10 or 20 stereo bands,
                       //< mixing mode A, and no ipd/opd

#define numQMFSlots 32 //numTimeSlots * RATE

static const int8_t num_env_tab[2][4] = {
    { 0, 1, 2, 4, },
    { 1, 2, 3, 4, },
};

static const int8_t nr_iidicc_par_tab[] = {
    10, 20, 34, 10, 20, 34,
};

static const int8_t nr_iidopd_par_tab[] = {
     5, 11, 17,  5, 11, 17,
};

enum {
    huff_iid_df1,
    huff_iid_dt1,
    huff_iid_df0,
    huff_iid_dt0,
    huff_icc_df,
    huff_icc_dt,
    huff_ipd_df,
    huff_ipd_dt,
    huff_opd_df,
    huff_opd_dt,
};

static const int huff_iid[] = {
    huff_iid_df0,
    huff_iid_df1,
    huff_iid_dt0,
    huff_iid_dt1,
};

static VLC vlc_ps[10];

/**
 * Read Inter-channel Intensity Difference/Inter-Channel Coherence/
 * Inter-channel Phase Difference/Overall Phase Difference parameters from the
 * bitstream.
 *
 * @param avctx contains the current codec context
 * @param gb    pointer to the input bitstream
 * @param ps    pointer to the Parametric Stereo context
 * @param par   pointer to the parameter to be read
 * @param e     envelope to decode
 * @param dt    1: time delta-coded, 0: frequency delta-coded
 */
#define READ_PAR_DATA(PAR, OFFSET, MASK, ERR_CONDITION) \
static int read_ ## PAR ## _data(AVCodecContext *avctx, GetBitContext *gb, PSContext *ps, \
                        int8_t (*PAR)[PS_MAX_NR_IIDICC], int table_idx, int e, int dt) \
{ \
    int b, num = ps->nr_ ## PAR ## _par; \
    VLC_TYPE (*vlc_table)[2] = vlc_ps[table_idx].table; \
    if (dt) { \
        int e_prev = e ? e - 1 : ps->num_env_old - 1; \
        e_prev = FFMAX(e_prev, 0); \
        for (b = 0; b < num; b++) { \
            int val = PAR[e_prev][b] + get_vlc2(gb, vlc_table, 9, 3) - OFFSET; \
            if (MASK) val &= MASK; \
            PAR[e][b] = val; \
            if (ERR_CONDITION) \
                goto err; \
        } \
    } else { \
        int val = 0; \
        for (b = 0; b < num; b++) { \
            val += get_vlc2(gb, vlc_table, 9, 3) - OFFSET; \
            if (MASK) val &= MASK; \
            PAR[e][b] = val; \
            if (ERR_CONDITION) \
                goto err; \
        } \
    } \
    return 0; \
err: \
    av_log(avctx, AV_LOG_ERROR, "illegal "#PAR"\n"); \
    return -1; \
}

READ_PAR_DATA(iid,    huff_offset[table_idx],    0, FFABS(ps->iid_par[e][b]) > 7 + 8 * ps->iid_quant)
READ_PAR_DATA(icc,    huff_offset[table_idx],    0, ps->icc_par[e][b] > 7U)
READ_PAR_DATA(ipdopd,                      0, 0x07, 0)

static int ps_read_extension_data(GetBitContext *gb, PSContext *ps, int ps_extension_id)
{
    int e;
    int count = get_bits_count(gb);

    if (ps_extension_id)
        return 0;

    ps->enable_ipdopd = get_bits1(gb);
    if (ps->enable_ipdopd) {
        for (e = 0; e < ps->num_env; e++) {
            int dt = get_bits1(gb);
            read_ipdopd_data(NULL, gb, ps, ps->ipd_par, dt ? huff_ipd_dt : huff_ipd_df, e, dt);
            dt = get_bits1(gb);
            read_ipdopd_data(NULL, gb, ps, ps->opd_par, dt ? huff_opd_dt : huff_opd_df, e, dt);
        }
    }
    skip_bits1(gb);      //reserved_ps
    return get_bits_count(gb) - count;
}

static void ipdopd_reset(int8_t *opd_hist, int8_t *ipd_hist)
{
    int i;
    for (i = 0; i < PS_MAX_NR_IPDOPD; i++) {
        opd_hist[i] = 0;
        ipd_hist[i] = 0;
    }
}

int ff_ps_read_data(AVCodecContext *avctx, GetBitContext *gb_host, PSContext *ps, int bits_left)
{
    int e;
    int bit_count_start = get_bits_count(gb_host);
    int header;
    int bits_consumed;
    GetBitContext gbc = *gb_host, *gb = &gbc;

    header = get_bits1(gb);
    if (header) {     //enable_ps_header
        ps->enable_iid = get_bits1(gb);
        if (ps->enable_iid) {
            int iid_mode = get_bits(gb, 3);
            if (iid_mode > 5) {
                av_log(avctx, AV_LOG_ERROR, "iid_mode %d is reserved.\n",
                       iid_mode);
                goto err;
            }
            ps->nr_iid_par    = nr_iidicc_par_tab[iid_mode];
            ps->iid_quant     = iid_mode > 2;
            ps->nr_ipdopd_par = nr_iidopd_par_tab[iid_mode];
        }
        ps->enable_icc = get_bits1(gb);
        if (ps->enable_icc) {
            ps->icc_mode = get_bits(gb, 3);
            if (ps->icc_mode > 5) {
                av_log(avctx, AV_LOG_ERROR, "icc_mode %d is reserved.\n",
                       ps->icc_mode);
                goto err;
            }
            ps->nr_icc_par = nr_iidicc_par_tab[ps->icc_mode];
        }
        ps->enable_ext = get_bits1(gb);
    }

    ps->frame_class = get_bits1(gb);
    ps->num_env_old = ps->num_env;
    ps->num_env     = num_env_tab[ps->frame_class][get_bits(gb, 2)];

    ps->border_position[0] = -1;
    if (ps->frame_class) {
        for (e = 1; e <= ps->num_env; e++)
            ps->border_position[e] = get_bits(gb, 5);
    } else
        for (e = 1; e <= ps->num_env; e++)
            ps->border_position[e] = (e * numQMFSlots >> ff_log2_tab[ps->num_env]) - 1;

    if (ps->enable_iid) {
        for (e = 0; e < ps->num_env; e++) {
            int dt = get_bits1(gb);
            if (read_iid_data(avctx, gb, ps, ps->iid_par, huff_iid[2*dt+ps->iid_quant], e, dt))
                goto err;
        }
    } else
        memset(ps->iid_par, 0, sizeof(ps->iid_par));

    if (ps->enable_icc)
        for (e = 0; e < ps->num_env; e++) {
            int dt = get_bits1(gb);
            if (read_icc_data(avctx, gb, ps, ps->icc_par, dt ? huff_icc_dt : huff_icc_df, e, dt))
                goto err;
        }
    else
        memset(ps->icc_par, 0, sizeof(ps->icc_par));

    if (ps->enable_ext) {
        int cnt = get_bits(gb, 4);
        if (cnt == 15) {
            cnt += get_bits(gb, 8);
        }
        cnt *= 8;
        while (cnt > 7) {
            int ps_extension_id = get_bits(gb, 2);
            cnt -= 2 + ps_read_extension_data(gb, ps, ps_extension_id);
        }
        if (cnt < 0) {
            av_log(avctx, AV_LOG_ERROR, "ps extension overflow %d", cnt);
            goto err;
        }
        skip_bits(gb, cnt);
    }

    ps->enable_ipdopd &= !PS_BASELINE;

    //Fix up envelopes
    if (!ps->num_env || ps->border_position[ps->num_env] < numQMFSlots - 1) {
        //Create a fake envelope
        int source = ps->num_env ? ps->num_env - 1 : ps->num_env_old - 1;
        if (source >= 0 && source != ps->num_env) {
            if (ps->enable_iid) {
                memcpy(ps->iid_par+ps->num_env, ps->iid_par+source, sizeof(ps->iid_par[0]));
            }
            if (ps->enable_icc) {
                memcpy(ps->icc_par+ps->num_env, ps->icc_par+source, sizeof(ps->icc_par[0]));
            }
            if (ps->enable_ipdopd) {
                memcpy(ps->ipd_par+ps->num_env, ps->ipd_par+source, sizeof(ps->ipd_par[0]));
                memcpy(ps->opd_par+ps->num_env, ps->opd_par+source, sizeof(ps->opd_par[0]));
            }
        }
        ps->num_env++;
        ps->border_position[ps->num_env] = numQMFSlots - 1;
    }


    ps->is34bands_old = ps->is34bands;
    if (!PS_BASELINE && (ps->enable_iid || ps->enable_icc))
        ps->is34bands = (ps->enable_iid && ps->nr_iid_par == 34) ||
                        (ps->enable_icc && ps->nr_icc_par == 34);

    //Baseline
    if (!ps->enable_ipdopd) {
        memset(ps->ipd_par, 0, sizeof(ps->ipd_par));
        memset(ps->opd_par, 0, sizeof(ps->opd_par));
    }

    if (header)
        ps->start = 1;

    bits_consumed = get_bits_count(gb) - bit_count_start;
    if (bits_consumed <= bits_left) {
        skip_bits_long(gb_host, bits_consumed);
        return bits_consumed;
    }
    av_log(avctx, AV_LOG_ERROR, "Expected to read %d PS bits actually read %d.\n", bits_left, bits_consumed);
err:
    ps->start = 0;
    skip_bits_long(gb_host, bits_left);
    return bits_left;
}

/** Split one subband into 2 subsubbands with a symmetric real filter.
 * The filter must have its non-center even coefficients equal to zero. */
static void hybrid2_re(float (*in)[2], float (*out)[32][2], const float filter[7], int len, int reverse)
{
    int i, j;
    for (i = 0; i < len; i++, in++) {
        float re_in = filter[6] * in[6][0];          //real inphase
        float re_op = 0.0f;                          //real out of phase
        float im_in = filter[6] * in[6][1];          //imag inphase
        float im_op = 0.0f;                          //imag out of phase
        for (j = 0; j < 6; j += 2) {
            re_op += filter[j+1] * (in[j+1][0] + in[12-j-1][0]);
            im_op += filter[j+1] * (in[j+1][1] + in[12-j-1][1]);
        }
        out[ reverse][i][0] = re_in + re_op;
        out[ reverse][i][1] = im_in + im_op;
        out[!reverse][i][0] = re_in - re_op;
        out[!reverse][i][1] = im_in - im_op;
    }
}

/** Split one subband into 6 subsubbands with a complex filter */
static void hybrid6_cx(float (*in)[2], float (*out)[32][2], const float (*filter)[7][2], int len)
{
    int i, j, ssb;
    int N = 8;
    float temp[8][2];

    for (i = 0; i < len; i++, in++) {
        for (ssb = 0; ssb < N; ssb++) {
            float sum_re = filter[ssb][6][0] * in[6][0], sum_im = filter[ssb][6][0] * in[6][1];
            for (j = 0; j < 6; j++) {
                float in0_re = in[j][0];
                float in0_im = in[j][1];
                float in1_re = in[12-j][0];
                float in1_im = in[12-j][1];
                sum_re += filter[ssb][j][0] * (in0_re + in1_re) - filter[ssb][j][1] * (in0_im - in1_im);
                sum_im += filter[ssb][j][0] * (in0_im + in1_im) + filter[ssb][j][1] * (in0_re - in1_re);
            }
            temp[ssb][0] = sum_re;
            temp[ssb][1] = sum_im;
        }
        out[0][i][0] = temp[6][0];
        out[0][i][1] = temp[6][1];
        out[1][i][0] = temp[7][0];
        out[1][i][1] = temp[7][1];
        out[2][i][0] = temp[0][0];
        out[2][i][1] = temp[0][1];
        out[3][i][0] = temp[1][0];
        out[3][i][1] = temp[1][1];
        out[4][i][0] = temp[2][0] + temp[5][0];
        out[4][i][1] = temp[2][1] + temp[5][1];
        out[5][i][0] = temp[3][0] + temp[4][0];
        out[5][i][1] = temp[3][1] + temp[4][1];
    }
}

static void hybrid4_8_12_cx(float (*in)[2], float (*out)[32][2], const float (*filter)[7][2], int N, int len)
{
    int i, j, ssb;

    for (i = 0; i < len; i++, in++) {
        for (ssb = 0; ssb < N; ssb++) {
            float sum_re = filter[ssb][6][0] * in[6][0], sum_im = filter[ssb][6][0] * in[6][1];
            for (j = 0; j < 6; j++) {
                float in0_re = in[j][0];
                float in0_im = in[j][1];
                float in1_re = in[12-j][0];
                float in1_im = in[12-j][1];
                sum_re += filter[ssb][j][0] * (in0_re + in1_re) - filter[ssb][j][1] * (in0_im - in1_im);
                sum_im += filter[ssb][j][0] * (in0_im + in1_im) + filter[ssb][j][1] * (in0_re - in1_re);
            }
            out[ssb][i][0] = sum_re;
            out[ssb][i][1] = sum_im;
        }
    }
}

static void hybrid_analysis(float out[91][32][2], float in[5][44][2], float L[2][38][64], int is34, int len)
{
    int i, j;
    for (i = 0; i < 5; i++) {
        for (j = 0; j < 38; j++) {
            in[i][j+6][0] = L[0][j][i];
            in[i][j+6][1] = L[1][j][i];
        }
    }
    if (is34) {
        hybrid4_8_12_cx(in[0], out,    f34_0_12, 12, len);
        hybrid4_8_12_cx(in[1], out+12, f34_1_8,   8, len);
        hybrid4_8_12_cx(in[2], out+20, f34_2_4,   4, len);
        hybrid4_8_12_cx(in[3], out+24, f34_2_4,   4, len);
        hybrid4_8_12_cx(in[4], out+28, f34_2_4,   4, len);
        for (i = 0; i < 59; i++) {
            for (j = 0; j < len; j++) {
                out[i+32][j][0] = L[0][j][i+5];
                out[i+32][j][1] = L[1][j][i+5];
            }
        }
    } else {
        hybrid6_cx(in[0], out, f20_0_8, len);
        hybrid2_re(in[1], out+6, g1_Q2, len, 1);
        hybrid2_re(in[2], out+8, g1_Q2, len, 0);
        for (i = 0; i < 61; i++) {
            for (j = 0; j < len; j++) {
                out[i+10][j][0] = L[0][j][i+3];
                out[i+10][j][1] = L[1][j][i+3];
            }
        }
    }
    //update in_buf
    for (i = 0; i < 5; i++) {
        memcpy(in[i], in[i]+32, 6 * sizeof(in[i][0]));
    }
}

static void hybrid_synthesis(float out[2][38][64], float in[91][32][2], int is34, int len)
{
    int i, n;
    if (is34) {
        for (n = 0; n < len; n++) {
            memset(out[0][n], 0, 5*sizeof(out[0][n][0]));
            memset(out[1][n], 0, 5*sizeof(out[1][n][0]));
            for (i = 0; i < 12; i++) {
                out[0][n][0] += in[   i][n][0];
                out[1][n][0] += in[   i][n][1];
            }
            for (i = 0; i < 8; i++) {
                out[0][n][1] += in[12+i][n][0];
                out[1][n][1] += in[12+i][n][1];
            }
            for (i = 0; i < 4; i++) {
                out[0][n][2] += in[20+i][n][0];
                out[1][n][2] += in[20+i][n][1];
                out[0][n][3] += in[24+i][n][0];
                out[1][n][3] += in[24+i][n][1];
                out[0][n][4] += in[28+i][n][0];
                out[1][n][4] += in[28+i][n][1];
            }
        }
        for (i = 0; i < 59; i++) {
            for (n = 0; n < len; n++) {
                out[0][n][i+5] = in[i+32][n][0];
                out[1][n][i+5] = in[i+32][n][1];
            }
        }
    } else {
        for (n = 0; n < len; n++) {
            out[0][n][0] = in[0][n][0] + in[1][n][0] + in[2][n][0] +
                           in[3][n][0] + in[4][n][0] + in[5][n][0];
            out[1][n][0] = in[0][n][1] + in[1][n][1] + in[2][n][1] +
                           in[3][n][1] + in[4][n][1] + in[5][n][1];
            out[0][n][1] = in[6][n][0] + in[7][n][0];
            out[1][n][1] = in[6][n][1] + in[7][n][1];
            out[0][n][2] = in[8][n][0] + in[9][n][0];
            out[1][n][2] = in[8][n][1] + in[9][n][1];
        }
        for (i = 0; i < 61; i++) {
            for (n = 0; n < len; n++) {
                out[0][n][i+3] = in[i+10][n][0];
                out[1][n][i+3] = in[i+10][n][1];
            }
        }
    }
}

/// All-pass filter decay slope
#define DECAY_SLOPE      0.05f
/// Number of frequency bands that can be addressed by the parameter index, b(k)
static const int   NR_PAR_BANDS[]      = { 20, 34 };
/// Number of frequency bands that can be addressed by the sub subband index, k
static const int   NR_BANDS[]          = { 71, 91 };
/// Start frequency band for the all-pass filter decay slope
static const int   DECAY_CUTOFF[]      = { 10, 32 };
/// Number of all-pass filer bands
static const int   NR_ALLPASS_BANDS[]  = { 30, 50 };
/// First stereo band using the short one sample delay
static const int   SHORT_DELAY_BAND[]  = { 42, 62 };

/** Table 8.46 */
static void map_idx_10_to_20(int8_t *par_mapped, const int8_t *par, int full)
{
    int b;
    if (full)
        b = 9;
    else {
        b = 4;
        par_mapped[10] = 0;
    }
    for (; b >= 0; b--) {
        par_mapped[2*b+1] = par_mapped[2*b] = par[b];
    }
}

static void map_idx_34_to_20(int8_t *par_mapped, const int8_t *par, int full)
{
    par_mapped[ 0] = (2*par[ 0] +   par[ 1]) / 3;
    par_mapped[ 1] = (  par[ 1] + 2*par[ 2]) / 3;
    par_mapped[ 2] = (2*par[ 3] +   par[ 4]) / 3;
    par_mapped[ 3] = (  par[ 4] + 2*par[ 5]) / 3;
    par_mapped[ 4] = (  par[ 6] +   par[ 7]) / 2;
    par_mapped[ 5] = (  par[ 8] +   par[ 9]) / 2;
    par_mapped[ 6] =    par[10];
    par_mapped[ 7] =    par[11];
    par_mapped[ 8] = (  par[12] +   par[13]) / 2;
    par_mapped[ 9] = (  par[14] +   par[15]) / 2;
    par_mapped[10] =    par[16];
    if (full) {
        par_mapped[11] =    par[17];
        par_mapped[12] =    par[18];
        par_mapped[13] =    par[19];
        par_mapped[14] = (  par[20] +   par[21]) / 2;
        par_mapped[15] = (  par[22] +   par[23]) / 2;
        par_mapped[16] = (  par[24] +   par[25]) / 2;
        par_mapped[17] = (  par[26] +   par[27]) / 2;
        par_mapped[18] = (  par[28] +   par[29] +   par[30] +   par[31]) / 4;
        par_mapped[19] = (  par[32] +   par[33]) / 2;
    }
}

static void map_val_34_to_20(float par[PS_MAX_NR_IIDICC])
{
    par[ 0] = (2*par[ 0] +   par[ 1]) * 0.33333333f;
    par[ 1] = (  par[ 1] + 2*par[ 2]) * 0.33333333f;
    par[ 2] = (2*par[ 3] +   par[ 4]) * 0.33333333f;
    par[ 3] = (  par[ 4] + 2*par[ 5]) * 0.33333333f;
    par[ 4] = (  par[ 6] +   par[ 7]) * 0.5f;
    par[ 5] = (  par[ 8] +   par[ 9]) * 0.5f;
    par[ 6] =    par[10];
    par[ 7] =    par[11];
    par[ 8] = (  par[12] +   par[13]) * 0.5f;
    par[ 9] = (  par[14] +   par[15]) * 0.5f;
    par[10] =    par[16];
    par[11] =    par[17];
    par[12] =    par[18];
    par[13] =    par[19];
    par[14] = (  par[20] +   par[21]) * 0.5f;
    par[15] = (  par[22] +   par[23]) * 0.5f;
    par[16] = (  par[24] +   par[25]) * 0.5f;
    par[17] = (  par[26] +   par[27]) * 0.5f;
    par[18] = (  par[28] +   par[29] +   par[30] +   par[31]) * 0.25f;
    par[19] = (  par[32] +   par[33]) * 0.5f;
}

static void map_idx_10_to_34(int8_t *par_mapped, const int8_t *par, int full)
{
    if (full) {
        par_mapped[33] = par[9];
        par_mapped[32] = par[9];
        par_mapped[31] = par[9];
        par_mapped[30] = par[9];
        par_mapped[29] = par[9];
        par_mapped[28] = par[9];
        par_mapped[27] = par[8];
        par_mapped[26] = par[8];
        par_mapped[25] = par[8];
        par_mapped[24] = par[8];
        par_mapped[23] = par[7];
        par_mapped[22] = par[7];
        par_mapped[21] = par[7];
        par_mapped[20] = par[7];
        par_mapped[19] = par[6];
        par_mapped[18] = par[6];
        par_mapped[17] = par[5];
        par_mapped[16] = par[5];
    } else {
        par_mapped[16] =      0;
    }
    par_mapped[15] = par[4];
    par_mapped[14] = par[4];
    par_mapped[13] = par[4];
    par_mapped[12] = par[4];
    par_mapped[11] = par[3];
    par_mapped[10] = par[3];
    par_mapped[ 9] = par[2];
    par_mapped[ 8] = par[2];
    par_mapped[ 7] = par[2];
    par_mapped[ 6] = par[2];
    par_mapped[ 5] = par[1];
    par_mapped[ 4] = par[1];
    par_mapped[ 3] = par[1];
    par_mapped[ 2] = par[0];
    par_mapped[ 1] = par[0];
    par_mapped[ 0] = par[0];
}

static void map_idx_20_to_34(int8_t *par_mapped, const int8_t *par, int full)
{
    if (full) {
        par_mapped[33] =  par[19];
        par_mapped[32] =  par[19];
        par_mapped[31] =  par[18];
        par_mapped[30] =  par[18];
        par_mapped[29] =  par[18];
        par_mapped[28] =  par[18];
        par_mapped[27] =  par[17];
        par_mapped[26] =  par[17];
        par_mapped[25] =  par[16];
        par_mapped[24] =  par[16];
        par_mapped[23] =  par[15];
        par_mapped[22] =  par[15];
        par_mapped[21] =  par[14];
        par_mapped[20] =  par[14];
        par_mapped[19] =  par[13];
        par_mapped[18] =  par[12];
        par_mapped[17] =  par[11];
    }
    par_mapped[16] =  par[10];
    par_mapped[15] =  par[ 9];
    par_mapped[14] =  par[ 9];
    par_mapped[13] =  par[ 8];
    par_mapped[12] =  par[ 8];
    par_mapped[11] =  par[ 7];
    par_mapped[10] =  par[ 6];
    par_mapped[ 9] =  par[ 5];
    par_mapped[ 8] =  par[ 5];
    par_mapped[ 7] =  par[ 4];
    par_mapped[ 6] =  par[ 4];
    par_mapped[ 5] =  par[ 3];
    par_mapped[ 4] = (par[ 2] + par[ 3]) / 2;
    par_mapped[ 3] =  par[ 2];
    par_mapped[ 2] =  par[ 1];
    par_mapped[ 1] = (par[ 0] + par[ 1]) / 2;
    par_mapped[ 0] =  par[ 0];
}

static void map_val_20_to_34(float par[PS_MAX_NR_IIDICC])
{
    par[33] =  par[19];
    par[32] =  par[19];
    par[31] =  par[18];
    par[30] =  par[18];
    par[29] =  par[18];
    par[28] =  par[18];
    par[27] =  par[17];
    par[26] =  par[17];
    par[25] =  par[16];
    par[24] =  par[16];
    par[23] =  par[15];
    par[22] =  par[15];
    par[21] =  par[14];
    par[20] =  par[14];
    par[19] =  par[13];
    par[18] =  par[12];
    par[17] =  par[11];
    par[16] =  par[10];
    par[15] =  par[ 9];
    par[14] =  par[ 9];
    par[13] =  par[ 8];
    par[12] =  par[ 8];
    par[11] =  par[ 7];
    par[10] =  par[ 6];
    par[ 9] =  par[ 5];
    par[ 8] =  par[ 5];
    par[ 7] =  par[ 4];
    par[ 6] =  par[ 4];
    par[ 5] =  par[ 3];
    par[ 4] = (par[ 2] + par[ 3]) * 0.5f;
    par[ 3] =  par[ 2];
    par[ 2] =  par[ 1];
    par[ 1] = (par[ 0] + par[ 1]) * 0.5f;
    par[ 0] =  par[ 0];
}

static void decorrelation(PSContext *ps, float (*out)[32][2], const float (*s)[32][2], int is34)
{
    float power[34][PS_QMF_TIME_SLOTS] = {{0}};
    float transient_gain[34][PS_QMF_TIME_SLOTS];
    float *peak_decay_nrg = ps->peak_decay_nrg;
    float *power_smooth = ps->power_smooth;
    float *peak_decay_diff_smooth = ps->peak_decay_diff_smooth;
    float (*delay)[PS_QMF_TIME_SLOTS + PS_MAX_DELAY][2] = ps->delay;
    float (*ap_delay)[PS_AP_LINKS][PS_QMF_TIME_SLOTS + PS_MAX_AP_DELAY][2] = ps->ap_delay;
    const int8_t *k_to_i = is34 ? k_to_i_34 : k_to_i_20;
    const float peak_decay_factor = 0.76592833836465f;
    const float transient_impact  = 1.5f;
    const float a_smooth          = 0.25f; //< Smoothing coefficient
    int i, k, m, n;
    int n0 = 0, nL = 32;
    static const int link_delay[] = { 3, 4, 5 };
    static const float a[] = { 0.65143905753106f,
                               0.56471812200776f,
                               0.48954165955695f };

    if (is34 != ps->is34bands_old) {
        memset(ps->peak_decay_nrg,         0, sizeof(ps->peak_decay_nrg));
        memset(ps->power_smooth,           0, sizeof(ps->power_smooth));
        memset(ps->peak_decay_diff_smooth, 0, sizeof(ps->peak_decay_diff_smooth));
        memset(ps->delay,                  0, sizeof(ps->delay));
        memset(ps->ap_delay,               0, sizeof(ps->ap_delay));
    }

    for (n = n0; n < nL; n++) {
        for (k = 0; k < NR_BANDS[is34]; k++) {
            int i = k_to_i[k];
            power[i][n] += s[k][n][0] * s[k][n][0] + s[k][n][1] * s[k][n][1];
        }
    }

    //Transient detection
    for (i = 0; i < NR_PAR_BANDS[is34]; i++) {
        for (n = n0; n < nL; n++) {
            float decayed_peak = peak_decay_factor * peak_decay_nrg[i];
            float denom;
            peak_decay_nrg[i] = FFMAX(decayed_peak, power[i][n]);
            power_smooth[i] += a_smooth * (power[i][n] - power_smooth[i]);
            peak_decay_diff_smooth[i] += a_smooth * (peak_decay_nrg[i] - power[i][n] - peak_decay_diff_smooth[i]);
            denom = transient_impact * peak_decay_diff_smooth[i];
            transient_gain[i][n]   = (denom > power_smooth[i]) ?
                                         power_smooth[i] / denom : 1.0f;
        }
    }

    //Decorrelation and transient reduction
    //                         PS_AP_LINKS - 1
    //                               -----
    //                                | |  Q_fract_allpass[k][m]*z^-link_delay[m] - a[m]*g_decay_slope[k]
    //H[k][z] = z^-2 * phi_fract[k] * | | ----------------------------------------------------------------
    //                                | | 1 - a[m]*g_decay_slope[k]*Q_fract_allpass[k][m]*z^-link_delay[m]
    //                               m = 0
    //d[k][z] (out) = transient_gain_mapped[k][z] * H[k][z] * s[k][z]
    for (k = 0; k < NR_ALLPASS_BANDS[is34]; k++) {
        int b = k_to_i[k];
        float g_decay_slope = 1.f - DECAY_SLOPE * (k - DECAY_CUTOFF[is34]);
        float ag[PS_AP_LINKS];
        g_decay_slope = av_clipf(g_decay_slope, 0.f, 1.f);
        memcpy(delay[k], delay[k]+nL, PS_MAX_DELAY*sizeof(delay[k][0]));
        memcpy(delay[k]+PS_MAX_DELAY, s[k], numQMFSlots*sizeof(delay[k][0]));
        for (m = 0; m < PS_AP_LINKS; m++) {
            memcpy(ap_delay[k][m],   ap_delay[k][m]+numQMFSlots,           5*sizeof(ap_delay[k][m][0]));
            ag[m] = a[m] * g_decay_slope;
        }
        for (n = n0; n < nL; n++) {
            float in_re = delay[k][n+PS_MAX_DELAY-2][0] * phi_fract[is34][k][0] -
                          delay[k][n+PS_MAX_DELAY-2][1] * phi_fract[is34][k][1];
            float in_im = delay[k][n+PS_MAX_DELAY-2][0] * phi_fract[is34][k][1] +
                          delay[k][n+PS_MAX_DELAY-2][1] * phi_fract[is34][k][0];
            for (m = 0; m < PS_AP_LINKS; m++) {
                float a_re                = ag[m] * in_re;
                float a_im                = ag[m] * in_im;
                float link_delay_re       = ap_delay[k][m][n+5-link_delay[m]][0];
                float link_delay_im       = ap_delay[k][m][n+5-link_delay[m]][1];
                float fractional_delay_re = Q_fract_allpass[is34][k][m][0];
                float fractional_delay_im = Q_fract_allpass[is34][k][m][1];
                ap_delay[k][m][n+5][0] = in_re;
                ap_delay[k][m][n+5][1] = in_im;
                in_re = link_delay_re * fractional_delay_re - link_delay_im * fractional_delay_im - a_re;
                in_im = link_delay_re * fractional_delay_im + link_delay_im * fractional_delay_re - a_im;
                ap_delay[k][m][n+5][0] += ag[m] * in_re;
                ap_delay[k][m][n+5][1] += ag[m] * in_im;
            }
            out[k][n][0] = transient_gain[b][n] * in_re;
            out[k][n][1] = transient_gain[b][n] * in_im;
        }
    }
    for (; k < SHORT_DELAY_BAND[is34]; k++) {
        memcpy(delay[k], delay[k]+nL, PS_MAX_DELAY*sizeof(delay[k][0]));
        memcpy(delay[k]+PS_MAX_DELAY, s[k], numQMFSlots*sizeof(delay[k][0]));
        for (n = n0; n < nL; n++) {
            //H = delay 14
            out[k][n][0] = transient_gain[k_to_i[k]][n] * delay[k][n+PS_MAX_DELAY-14][0];
            out[k][n][1] = transient_gain[k_to_i[k]][n] * delay[k][n+PS_MAX_DELAY-14][1];
        }
    }
    for (; k < NR_BANDS[is34]; k++) {
        memcpy(delay[k], delay[k]+nL, PS_MAX_DELAY*sizeof(delay[k][0]));
        memcpy(delay[k]+PS_MAX_DELAY, s[k], numQMFSlots*sizeof(delay[k][0]));
        for (n = n0; n < nL; n++) {
            //H = delay 1
            out[k][n][0] = transient_gain[k_to_i[k]][n] * delay[k][n+PS_MAX_DELAY-1][0];
            out[k][n][1] = transient_gain[k_to_i[k]][n] * delay[k][n+PS_MAX_DELAY-1][1];
        }
    }
}

static void remap34(int8_t (**p_par_mapped)[PS_MAX_NR_IIDICC],
                    int8_t           (*par)[PS_MAX_NR_IIDICC],
                    int num_par, int num_env, int full)
{
    int8_t (*par_mapped)[PS_MAX_NR_IIDICC] = *p_par_mapped;
    int e;
    if (num_par == 20 || num_par == 11) {
        for (e = 0; e < num_env; e++) {
            map_idx_20_to_34(par_mapped[e], par[e], full);
        }
    } else if (num_par == 10 || num_par == 5) {
        for (e = 0; e < num_env; e++) {
            map_idx_10_to_34(par_mapped[e], par[e], full);
        }
    } else {
        *p_par_mapped = par;
    }
}

static void remap20(int8_t (**p_par_mapped)[PS_MAX_NR_IIDICC],
                    int8_t           (*par)[PS_MAX_NR_IIDICC],
                    int num_par, int num_env, int full)
{
    int8_t (*par_mapped)[PS_MAX_NR_IIDICC] = *p_par_mapped;
    int e;
    if (num_par == 34 || num_par == 17) {
        for (e = 0; e < num_env; e++) {
            map_idx_34_to_20(par_mapped[e], par[e], full);
        }
    } else if (num_par == 10 || num_par == 5) {
        for (e = 0; e < num_env; e++) {
            map_idx_10_to_20(par_mapped[e], par[e], full);
        }
    } else {
        *p_par_mapped = par;
    }
}

static void stereo_processing(PSContext *ps, float (*l)[32][2], float (*r)[32][2], int is34)
{
    int e, b, k, n;

    float (*H11)[PS_MAX_NUM_ENV+1][PS_MAX_NR_IIDICC] = ps->H11;
    float (*H12)[PS_MAX_NUM_ENV+1][PS_MAX_NR_IIDICC] = ps->H12;
    float (*H21)[PS_MAX_NUM_ENV+1][PS_MAX_NR_IIDICC] = ps->H21;
    float (*H22)[PS_MAX_NUM_ENV+1][PS_MAX_NR_IIDICC] = ps->H22;
    int8_t *opd_hist = ps->opd_hist;
    int8_t *ipd_hist = ps->ipd_hist;
    int8_t iid_mapped_buf[PS_MAX_NUM_ENV][PS_MAX_NR_IIDICC];
    int8_t icc_mapped_buf[PS_MAX_NUM_ENV][PS_MAX_NR_IIDICC];
    int8_t ipd_mapped_buf[PS_MAX_NUM_ENV][PS_MAX_NR_IIDICC];
    int8_t opd_mapped_buf[PS_MAX_NUM_ENV][PS_MAX_NR_IIDICC];
    int8_t (*iid_mapped)[PS_MAX_NR_IIDICC] = iid_mapped_buf;
    int8_t (*icc_mapped)[PS_MAX_NR_IIDICC] = icc_mapped_buf;
    int8_t (*ipd_mapped)[PS_MAX_NR_IIDICC] = ipd_mapped_buf;
    int8_t (*opd_mapped)[PS_MAX_NR_IIDICC] = opd_mapped_buf;
    const int8_t *k_to_i = is34 ? k_to_i_34 : k_to_i_20;
    const float (*H_LUT)[8][4] = (PS_BASELINE || ps->icc_mode < 3) ? HA : HB;

    //Remapping
    memcpy(H11[0][0], H11[0][ps->num_env_old], PS_MAX_NR_IIDICC*sizeof(H11[0][0][0]));
    memcpy(H11[1][0], H11[1][ps->num_env_old], PS_MAX_NR_IIDICC*sizeof(H11[1][0][0]));
    memcpy(H12[0][0], H12[0][ps->num_env_old], PS_MAX_NR_IIDICC*sizeof(H12[0][0][0]));
    memcpy(H12[1][0], H12[1][ps->num_env_old], PS_MAX_NR_IIDICC*sizeof(H12[1][0][0]));
    memcpy(H21[0][0], H21[0][ps->num_env_old], PS_MAX_NR_IIDICC*sizeof(H21[0][0][0]));
    memcpy(H21[1][0], H21[1][ps->num_env_old], PS_MAX_NR_IIDICC*sizeof(H21[1][0][0]));
    memcpy(H22[0][0], H22[0][ps->num_env_old], PS_MAX_NR_IIDICC*sizeof(H22[0][0][0]));
    memcpy(H22[1][0], H22[1][ps->num_env_old], PS_MAX_NR_IIDICC*sizeof(H22[1][0][0]));
    if (is34) {
        remap34(&iid_mapped, ps->iid_par, ps->nr_iid_par, ps->num_env, 1);
        remap34(&icc_mapped, ps->icc_par, ps->nr_icc_par, ps->num_env, 1);
        if (ps->enable_ipdopd) {
            remap34(&ipd_mapped, ps->ipd_par, ps->nr_ipdopd_par, ps->num_env, 0);
            remap34(&opd_mapped, ps->opd_par, ps->nr_ipdopd_par, ps->num_env, 0);
        }
        if (!ps->is34bands_old) {
            map_val_20_to_34(H11[0][0]);
            map_val_20_to_34(H11[1][0]);
            map_val_20_to_34(H12[0][0]);
            map_val_20_to_34(H12[1][0]);
            map_val_20_to_34(H21[0][0]);
            map_val_20_to_34(H21[1][0]);
            map_val_20_to_34(H22[0][0]);
            map_val_20_to_34(H22[1][0]);
            ipdopd_reset(ipd_hist, opd_hist);
        }
    } else {
        remap20(&iid_mapped, ps->iid_par, ps->nr_iid_par, ps->num_env, 1);
        remap20(&icc_mapped, ps->icc_par, ps->nr_icc_par, ps->num_env, 1);
        if (ps->enable_ipdopd) {
            remap20(&ipd_mapped, ps->ipd_par, ps->nr_ipdopd_par, ps->num_env, 0);
            remap20(&opd_mapped, ps->opd_par, ps->nr_ipdopd_par, ps->num_env, 0);
        }
        if (ps->is34bands_old) {
            map_val_34_to_20(H11[0][0]);
            map_val_34_to_20(H11[1][0]);
            map_val_34_to_20(H12[0][0]);
            map_val_34_to_20(H12[1][0]);
            map_val_34_to_20(H21[0][0]);
            map_val_34_to_20(H21[1][0]);
            map_val_34_to_20(H22[0][0]);
            map_val_34_to_20(H22[1][0]);
            ipdopd_reset(ipd_hist, opd_hist);
        }
    }

    //Mixing
    for (e = 0; e < ps->num_env; e++) {
        for (b = 0; b < NR_PAR_BANDS[is34]; b++) {
            float h11, h12, h21, h22;
            h11 = H_LUT[iid_mapped[e][b] + 7 + 23 * ps->iid_quant][icc_mapped[e][b]][0];
            h12 = H_LUT[iid_mapped[e][b] + 7 + 23 * ps->iid_quant][icc_mapped[e][b]][1];
            h21 = H_LUT[iid_mapped[e][b] + 7 + 23 * ps->iid_quant][icc_mapped[e][b]][2];
            h22 = H_LUT[iid_mapped[e][b] + 7 + 23 * ps->iid_quant][icc_mapped[e][b]][3];
            if (!PS_BASELINE && ps->enable_ipdopd && b < ps->nr_ipdopd_par) {
                //The spec say says to only run this smoother when enable_ipdopd
                //is set but the reference decoder appears to run it constantly
                float h11i, h12i, h21i, h22i;
                float ipd_adj_re, ipd_adj_im;
                int opd_idx = opd_hist[b] * 8 + opd_mapped[e][b];
                int ipd_idx = ipd_hist[b] * 8 + ipd_mapped[e][b];
                float opd_re = pd_re_smooth[opd_idx];
                float opd_im = pd_im_smooth[opd_idx];
                float ipd_re = pd_re_smooth[ipd_idx];
                float ipd_im = pd_im_smooth[ipd_idx];
                opd_hist[b] = opd_idx & 0x3F;
                ipd_hist[b] = ipd_idx & 0x3F;

                ipd_adj_re = opd_re*ipd_re + opd_im*ipd_im;
                ipd_adj_im = opd_im*ipd_re - opd_re*ipd_im;
                h11i = h11 * opd_im;
                h11  = h11 * opd_re;
                h12i = h12 * ipd_adj_im;
                h12  = h12 * ipd_adj_re;
                h21i = h21 * opd_im;
                h21  = h21 * opd_re;
                h22i = h22 * ipd_adj_im;
                h22  = h22 * ipd_adj_re;
                H11[1][e+1][b] = h11i;
                H12[1][e+1][b] = h12i;
                H21[1][e+1][b] = h21i;
                H22[1][e+1][b] = h22i;
            }
            H11[0][e+1][b] = h11;
            H12[0][e+1][b] = h12;
            H21[0][e+1][b] = h21;
            H22[0][e+1][b] = h22;
        }
        for (k = 0; k < NR_BANDS[is34]; k++) {
            float h11r, h12r, h21r, h22r;
            float h11i, h12i, h21i, h22i;
            float h11r_step, h12r_step, h21r_step, h22r_step;
            float h11i_step, h12i_step, h21i_step, h22i_step;
            int start = ps->border_position[e];
            int stop  = ps->border_position[e+1];
            float width = 1.f / (stop - start);
            b = k_to_i[k];
            h11r = H11[0][e][b];
            h12r = H12[0][e][b];
            h21r = H21[0][e][b];
            h22r = H22[0][e][b];
            if (!PS_BASELINE && ps->enable_ipdopd) {
            //Is this necessary? ps_04_new seems unchanged
            if ((is34 && k <= 13 && k >= 9) || (!is34 && k <= 1)) {
                h11i = -H11[1][e][b];
                h12i = -H12[1][e][b];
                h21i = -H21[1][e][b];
                h22i = -H22[1][e][b];
            } else {
                h11i = H11[1][e][b];
                h12i = H12[1][e][b];
                h21i = H21[1][e][b];
                h22i = H22[1][e][b];
            }
            }
            //Interpolation
            h11r_step = (H11[0][e+1][b] - h11r) * width;
            h12r_step = (H12[0][e+1][b] - h12r) * width;
            h21r_step = (H21[0][e+1][b] - h21r) * width;
            h22r_step = (H22[0][e+1][b] - h22r) * width;
            if (!PS_BASELINE && ps->enable_ipdopd) {
                h11i_step = (H11[1][e+1][b] - h11i) * width;
                h12i_step = (H12[1][e+1][b] - h12i) * width;
                h21i_step = (H21[1][e+1][b] - h21i) * width;
                h22i_step = (H22[1][e+1][b] - h22i) * width;
            }
            for (n = start + 1; n <= stop; n++) {
                //l is s, r is d
                float l_re = l[k][n][0];
                float l_im = l[k][n][1];
                float r_re = r[k][n][0];
                float r_im = r[k][n][1];
                h11r += h11r_step;
                h12r += h12r_step;
                h21r += h21r_step;
                h22r += h22r_step;
                if (!PS_BASELINE && ps->enable_ipdopd) {
                    h11i += h11i_step;
                    h12i += h12i_step;
                    h21i += h21i_step;
                    h22i += h22i_step;

                    l[k][n][0] = h11r*l_re + h21r*r_re - h11i*l_im - h21i*r_im;
                    l[k][n][1] = h11r*l_im + h21r*r_im + h11i*l_re + h21i*r_re;
                    r[k][n][0] = h12r*l_re + h22r*r_re - h12i*l_im - h22i*r_im;
                    r[k][n][1] = h12r*l_im + h22r*r_im + h12i*l_re + h22i*r_re;
                } else {
                    l[k][n][0] = h11r*l_re + h21r*r_re;
                    l[k][n][1] = h11r*l_im + h21r*r_im;
                    r[k][n][0] = h12r*l_re + h22r*r_re;
                    r[k][n][1] = h12r*l_im + h22r*r_im;
                }
            }
        }
    }
}

int ff_ps_apply(AVCodecContext *avctx, PSContext *ps, float L[2][38][64], float R[2][38][64], int top)
{
    float Lbuf[91][32][2];
    float Rbuf[91][32][2];
    const int len = 32;
    int is34 = ps->is34bands;

    top += NR_BANDS[is34] - 64;
    memset(ps->delay+top, 0, (NR_BANDS[is34] - top)*sizeof(ps->delay[0]));
    if (top < NR_ALLPASS_BANDS[is34])
        memset(ps->ap_delay + top, 0, (NR_ALLPASS_BANDS[is34] - top)*sizeof(ps->ap_delay[0]));

    hybrid_analysis(Lbuf, ps->in_buf, L, is34, len);
    decorrelation(ps, Rbuf, Lbuf, is34);
    stereo_processing(ps, Lbuf, Rbuf, is34);
    hybrid_synthesis(L, Lbuf, is34, len);
    hybrid_synthesis(R, Rbuf, is34, len);

    return 0;
}

#define PS_INIT_VLC_STATIC(num, size) \
    INIT_VLC_STATIC(&vlc_ps[num], 9, ps_tmp[num].table_size / ps_tmp[num].elem_size,    \
                    ps_tmp[num].ps_bits, 1, 1,                                          \
                    ps_tmp[num].ps_codes, ps_tmp[num].elem_size, ps_tmp[num].elem_size, \
                    size);

#define PS_VLC_ROW(name) \
    { name ## _codes, name ## _bits, sizeof(name ## _codes), sizeof(name ## _codes[0]) }

av_cold void ff_ps_init(void) {
    // Syntax initialization
    static const struct {
        const void *ps_codes, *ps_bits;
        const unsigned int table_size, elem_size;
    } ps_tmp[] = {
        PS_VLC_ROW(huff_iid_df1),
        PS_VLC_ROW(huff_iid_dt1),
        PS_VLC_ROW(huff_iid_df0),
        PS_VLC_ROW(huff_iid_dt0),
        PS_VLC_ROW(huff_icc_df),
        PS_VLC_ROW(huff_icc_dt),
        PS_VLC_ROW(huff_ipd_df),
        PS_VLC_ROW(huff_ipd_dt),
        PS_VLC_ROW(huff_opd_df),
        PS_VLC_ROW(huff_opd_dt),
    };

    PS_INIT_VLC_STATIC(0, 1544);
    PS_INIT_VLC_STATIC(1,  832);
    PS_INIT_VLC_STATIC(2, 1024);
    PS_INIT_VLC_STATIC(3, 1036);
    PS_INIT_VLC_STATIC(4,  544);
    PS_INIT_VLC_STATIC(5,  544);
    PS_INIT_VLC_STATIC(6,  512);
    PS_INIT_VLC_STATIC(7,  512);
    PS_INIT_VLC_STATIC(8,  512);
    PS_INIT_VLC_STATIC(9,  512);

    ps_tableinit();
}

av_cold void ff_ps_ctx_init(PSContext *ps)
{
}