[FFmpeg-devel] [PATCH] MPEG-4 Parametric Stereo decoder

Alex Converse alex.converse
Thu Jun 3 04:28:32 CEST 2010


On Mon, May 31, 2010 at 6:42 PM, Michael Niedermayer <michaelni at gmx.at> wrote:
>
> On Thu, May 20, 2010 at 01:51:41PM -0400, Alex Converse wrote:
> > Yes there are some places where it can be further optimized but I'm
> > losing motivation on this quickly so perhaps some review will respark
> > my interest.
>
> [...]
> > +static int iid_data(AVCodecContext *avctx, GetBitContext *gb, PSContext *ps, int e, int dt)
> > +{
> > + ? ?int b;
> > + ? ?int table_idx = huff_iid[2*dt+ps->iid_quant];
> > + ? ?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 < ps->nr_iid_par; b++) {
> > + ? ? ? ? ? ?ps->iid_par[e][b] = ps->iid_par[e_prev][b] +
> > + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?get_vlc2(gb, vlc_table, 9, 3) -
> > + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?huff_offset[table_idx];
> > + ? ? ? ? ? ?if (FFABS(ps->iid_par[e][b]) > 7 + 8 * ps->iid_quant) {
> > + ? ? ? ? ? ? ? ?av_log(avctx, AV_LOG_ERROR, "illegal iid\n");
> > + ? ? ? ? ? ? ? ?return -1;
> > + ? ? ? ? ? ?}
> > + ? ? ? ?}
> > + ? ?} else {
> > + ? ? ? ?int prev = 0;
> > + ? ? ? ?for (b = 0; b < ps->nr_iid_par; b++) {
> > + ? ? ? ? ? ?prev += get_vlc2(gb, vlc_table, 9, 3) -
> > + ? ? ? ? ? ? ? ? ? ?huff_offset[table_idx];
> > + ? ? ? ? ? ?ps->iid_par[e][b] = prev;
> > + ? ? ? ? ? ?if (FFABS(ps->iid_par[e][b]) > 7 + 8 * ps->iid_quant) {
> > + ? ? ? ? ? ? ? ?av_log(avctx, AV_LOG_ERROR, "illegal iid\n");
> > + ? ? ? ? ? ? ? ?return -1;
> > + ? ? ? ? ? ?}
> > + ? ? ? ?}
> > + ? ?}
> > + ? ?return 0;
> > +}
> > +
>
> > +static int icc_data(AVCodecContext *avctx, GetBitContext *gb, PSContext *ps, int e, int dt)
>
> this should have some doxy that explains what icc is and explains what
> e and dt are
>

icc was documented in the header the *_data() functions are now doxyed

>
> > +{
> > + ? ?int b;
> > + ? ?int table_idx = dt ? huff_icc_dt : huff_icc_df;
> > + ? ?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 < ps->nr_icc_par; b++) {
> > + ? ? ? ? ? ?ps->icc_par[e][b] = ps->icc_par[e_prev][b] + get_vlc2(gb, vlc_table, 9, 3) - huff_offset[table_idx];
> > + ? ? ? ? ? ?if (ps->icc_par[e][b] > 7U) {
> > + ? ? ? ? ? ? ? ?av_log(avctx, AV_LOG_ERROR, "illegal icc\n");
> > + ? ? ? ? ? ? ? ?return -1;
> > + ? ? ? ? ? ?}
> > + ? ? ? ?}
> > + ? ?} else {
> > + ? ? ? ?int prev = 0;
> > + ? ? ? ?for (b = 0; b < ps->nr_icc_par; b++) {
> > + ? ? ? ? ? ?prev += get_vlc2(gb, vlc_table, 9, 3) - huff_offset[table_idx];
> > + ? ? ? ? ? ?ps->icc_par[e][b] = prev;
> > + ? ? ? ? ? ?if (ps->icc_par[e][b] > 7U) {
> > + ? ? ? ? ? ? ? ?av_log(avctx, AV_LOG_ERROR, "illegal icc\n");
> > + ? ? ? ? ? ? ? ?return -1;
> > + ? ? ? ? ? ?}
> > + ? ? ? ?}
> > + ? ?}
>
> this could be simplified to:
> for (b = 0; b < ps->nr_icc_par; b++) {
> ? ?ps->icc_par[e][b]= prev[b] + get_vlc2(gb, vlc_table, 9, 3) - huff_offset[table_idx];
> ? ?if (ps->icc_par[e][b] > 7U) {
> ? ? ? ?av_log(avctx, AV_LOG_ERROR, "illegal icc\n");
> ? ? ? ?return -1;
> ? ?}
> }
> and this possibly applies to other functions as well
>

Are you talking about the if case the else case or both combined?
why is prev dereferenced two levels but not par?
Am I missing something here?


> > + ? ?return 0;
> > +}
> > +
> > +static void ipd_data(GetBitContext *gb, PSContext *ps, int e, int dt)
> > +{
> > + ? ?int b;
> > + ? ?int table_idx = dt ? huff_ipd_dt : huff_ipd_df;
> > + ? ?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 < ps->nr_ipdopd_par; b++) {
> > + ? ? ? ? ? ?ps->ipd_par[e][b] = (ps->ipd_par[e_prev][b] + get_vlc2(gb, vlc_table, 9, 1)) & 0x07;
> > + ? ? ? ?}
> > + ? ?} else {
> > + ? ? ? ?int prev = 0;
> > + ? ? ? ?for (b = 0; b < ps->nr_ipdopd_par; b++) {
> > + ? ? ? ? ? ?prev += get_vlc2(gb, vlc_table, 9, 3);
> > + ? ? ? ? ? ?prev &= 0x07;
> > + ? ? ? ? ? ?ps->ipd_par[e][b] = prev;
> > + ? ? ? ?}
> > + ? ?}
> > +}
> > +
> > +static void opd_data(GetBitContext *gb, PSContext *ps, int e, int dt)
> > +{
> > + ? ?int b;
> > + ? ?int table_idx = dt ? huff_opd_dt : huff_opd_df;
> > + ? ?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 < ps->nr_ipdopd_par; b++) {
> > + ? ? ? ? ? ?ps->opd_par[e][b] = (ps->opd_par[e_prev][b] + get_vlc2(gb, vlc_table, 9, 1)) & 0x07;
> > + ? ? ? ?}
> > + ? ?} else {
> > + ? ? ? ?int prev = 0;
> > + ? ? ? ?for (b = 0; b < ps->nr_ipdopd_par; b++) {
> > + ? ? ? ? ? ?prev += get_vlc2(gb, vlc_table, 9, 3);
> > + ? ? ? ? ? ?prev &= 0x07;
> > + ? ? ? ? ? ?ps->opd_par[e][b] = prev;
> > + ? ? ? ?}
> > + ? ?}
> > +}
>
> all these functions look like they do pretty much the same, maybe this can be
> done with just a single function?
>

I thought about it but they all have different valid ranges, unless
you just mean merging ipd/opd which both have the same circular range.

>
> [...]
> > +int ff_ps_data(AVCodecContext *avctx, GetBitContext *gb, PSContext *ps)
> > +{
> > + ? ?int e;
> > + ? ?int bit_count_start = get_bits_count(gb);
> > + ? ?int header;
> > +
> > + ? ?header = get_bits1(gb);
> > + ? ?if (header) { ? ? //enable_ps_header
> > + ? ? ? ?ps->enable_iid = get_bits1(gb);
> > + ? ? ? ?if (ps->enable_iid) {
> > + ? ? ? ? ? ?ps->iid_mode = get_bits(gb, 3);
> > + ? ? ? ? ? ?if (ps->iid_mode > 5) {
> > + ? ? ? ? ? ? ? ?av_log(avctx, AV_LOG_ERROR, "iid_mode %d is reserved.\n",
> > + ? ? ? ? ? ? ? ? ? ? ? ps->iid_mode);
> > + ? ? ? ? ? ? ? ?return -1;
> > + ? ? ? ? ? ?}
> > + ? ? ? ? ? ?ps->nr_iid_par ? ?= nr_iidicc_par_tab[ps->iid_mode];
> > + ? ? ? ? ? ?ps->iid_quant ? ? = ps->iid_mode > 2;
> > + ? ? ? ? ? ?ps->nr_ipdopd_par = nr_iidopd_par_tab[ps->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);
> > + ? ? ? ? ? ? ? ?return -1;
> > + ? ? ? ? ? ?}
> > + ? ? ? ? ? ?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 / ps->num_env - 1;
> > +
>
> > + ? ?if (ps->enable_iid)
> > + ? ? ? ?for (e = 0; e < ps->num_env; e++) {
> > + ? ? ? ? ? ?int dt = get_bits1(gb);
> > + ? ? ? ? ? ?if (iid_data(avctx, gb, ps, e, dt))
> > + ? ? ? ? ? ? ? ?return -1;
> > + ? ? ? ?}
> > + ? ?else
>
> i think that woudld benrfit from a {}
>

Fixed

>
> > + ? ? ? ?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 (icc_data(avctx, gb, ps, e, dt))
> > + ? ? ? ? ? ? ? ?return -1;
> > + ? ? ? ?}
> > + ? ?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_extension(gb, ps, ps_extension_id);
> > + ? ? ? ?}
> > + ? ? ? ?if (cnt < 0) {
> > + ? ? ? ? ? ?av_log(avctx, AV_LOG_ERROR, "ps extension overflow %d", cnt);
> > + ? ? ? ? ? ?return -1;
> > + ? ? ? ?}
> > + ? ? ? ?skip_bits(gb, cnt);
> > + ? ?}
> > +
> > + ? ?ps->enable_ipdopd &= !PS_BASELINE;
> > +
> > + ? ?//Fix up envelopes
> > + ? ?if (!ps->num_env) {
> > + ? ? ? ?ps->num_env = 1;
> > + ? ? ? ?ps->border_position[1] = 31;
> > + ? ? ? ?if (ps->enable_iid && ps->num_env_old > 1) {
> > + ? ? ? ? ? ?memcpy(ps->iid_par, ps->iid_par+ps->num_env_old-1, sizeof(ps->iid_par[0]));
> > + ? ? ? ?}
> > + ? ? ? ?if (ps->enable_icc && ps->num_env_old > 1) {
> > + ? ? ? ? ? ?memcpy(ps->icc_par, ps->icc_par+ps->num_env_old-1, sizeof(ps->icc_par[0]));
> > + ? ? ? ?}
> > + ? ? ? ?if (ps->enable_ipdopd && ps->num_env_old > 1) {
> > + ? ? ? ? ? ?memcpy(ps->ipd_par, ps->ipd_par+ps->num_env_old-1, sizeof(ps->ipd_par[0]));
> > + ? ? ? ? ? ?memcpy(ps->opd_par, ps->opd_par+ps->num_env_old-1, sizeof(ps->opd_par[0]));
> > + ? ? ? ?}
> > + ? ?} else if (ps->border_position[ps->num_env] < numQMFSlots - 1) {
> > + ? ? ? ?//Create a fake envelope
> > + ? ? ? ?if (ps->enable_iid && ps->num_env_old > 1) {
> > + ? ? ? ? ? ?memcpy(ps->iid_par+ps->num_env, ps->iid_par+ps->num_env-1, sizeof(ps->iid_par[0]));
> > + ? ? ? ?}
> > + ? ? ? ?if (ps->enable_icc && ps->num_env_old > 1) {
> > + ? ? ? ? ? ?memcpy(ps->icc_par+ps->num_env, ps->icc_par+ps->num_env-1, sizeof(ps->icc_par[0]));
> > + ? ? ? ?}
> > + ? ? ? ?if (ps->enable_ipdopd) {
>
> this if() differes from the others, intended or bug?
>

bug... fixed

>
> > + ? ? ? ? ? ?memcpy(ps->ipd_par+ps->num_env, ps->ipd_par+ps->num_env-1, sizeof(ps->ipd_par[0]));
> > + ? ? ? ? ? ?memcpy(ps->opd_par+ps->num_env, ps->opd_par+ps->num_env-1, sizeof(ps->opd_par[0]));
> > + ? ? ? ?}
> > + ? ? ? ?ps->num_env++;
> > + ? ? ? ?ps->border_position[ps->num_env] = numQMFSlots - 1;
> > + ? ?}
>
> also it appears this could maybe be factoreized toward someting like:
>
> ? ?if (ps->enable_iid && ps->num_env_old > 1) {
> ? ? ? ?memcpy(ps->iid_par+ps->num_env, ps->iid_par+X, sizeof(ps->iid_par[0]));
> ? ?}
> ? ?if (ps->enable_icc && ps->num_env_old > 1) {
> ? ? ? ?memcpy(ps->icc_par+ps->num_env, ps->icc_par+X, sizeof(ps->icc_par[0]));
> ? ?}
> ? ?if (ps->enable_ipdopd && ps->num_env_old > 1) {
> ? ? ? ?memcpy(ps->ipd_par+ps->num_env, ps->ipd_par+X, sizeof(ps->ipd_par[0]));
> ? ? ? ?memcpy(ps->opd_par+ps->num_env, ps->opd_par+X, sizeof(ps->opd_par[0]));
> ? ?}
> ? ?ps->num_env++;
>

see Vitor's review

>
> [...]
> > +
> > +/** Split one subband into 2 subsubbands with a real filter */
> > +static av_noinline 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++) {
> > + ? ? ? ?float re_in = filter[6] * in[6+i][0]; ? ? ? ?//real inphase
>
> 0.5 * in[6+i][0]

If we are going to start inlining values here are we better off using
the g1_Q2 symbol directly in this function rather than making it a
parameter?

>
>
> > + ? ? ? ?float re_op = 0.0f; ? ? ? ? ? ? ? ? ? ? ? ? ?//real out of phase
> > + ? ? ? ?float im_in = filter[6] * in[6+i][1]; ? ? ? ?//imag inphase
> > + ? ? ? ?float im_op = 0.0f; ? ? ? ? ? ? ? ? ? ? ? ? ?//imag out of phase
> > + ? ? ? ?for (j = 0; j < 6; j += 2) {
>
> > + ? ? ? ? ? ?re_in += filter[j ?] * (in[i+j ?][0] + in[12-j ?+i][0]);
> > + ? ? ? ? ? ?im_in += filter[j ?] * (in[i+j ?][1] + in[12-j ?+i][1]);
>
> these are always 0 * i think
>

Yes the even indices are zero, see above question

>
> > + ? ? ? ? ? ?re_op += filter[j+1] * (in[i+j+1][0] + in[12-j-1+i][0]);
> > + ? ? ? ? ? ?im_op += filter[j+1] * (in[i+j+1][1] + in[12-j-1+i][1]);
> > + ? ? ? ?}
> > + ? ? ? ?out[ ?reverse][i][0] = re_in + re_op;
> > + ? ? ? ?out[ ?reverse][i][1] = im_in + im_op;
> > + ? ? ? ?out[1-reverse][i][0] = re_in - re_op;
> > + ? ? ? ?out[1-reverse][i][1] = im_in - im_op;
> > + ? ?}
> > +}
> > +
>
> > +/** Split one subband into 6 subsubbands with a complex filter */
>
> what kind of filter?
> is this a standard filter of some kind, dct? mdct? based
>

They are (obviously) bandpass filters. They are translated from the
same prototype LPF. I don't know where they are derived from, I have
some CT papers I can check.

>
> > +static av_noinline 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++) {
> > + ? ? ? ?for (ssb = 0; ssb < N; ssb++) {
> > + ? ? ? ? ? ?float sum_re = filter[ssb][6][0] * in[i+6][0], sum_im = filter[ssb][6][0] * in[i+6][1];
> > + ? ? ? ? ? ?for (j = 0; j < 6; j++) {
> > + ? ? ? ? ? ? ? ?float in0_re = in[i+j][0];
> > + ? ? ? ? ? ? ? ?float in0_im = in[i+j][1];
> > + ? ? ? ? ? ? ? ?float in1_re = in[i+12-j][0];
> > + ? ? ? ? ? ? ? ?float in1_im = in[i+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);
>
> the filter values with even j look optimizeable (0.0 or 2 equal values or such)
>

All of f20_0_8 ire different permuttions/signs of the same coefs. This
should somehow be exploitable

> similar things are true for the remaining filter
>

The relationships get more complex in this case.

>
> > + ? ? ? ? ? ?}
> > + ? ? ? ? ? ?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 av_noinline 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++) {
> > + ? ? ? ?for (ssb = 0; ssb < N; ssb++) {
> > + ? ? ? ? ? ?float sum_re = filter[ssb][6][0] * in[i+6][0], sum_im = filter[ssb][6][0] * in[i+6][1];
> > + ? ? ? ? ? ?for (j = 0; j < 6; j++) {
> > + ? ? ? ? ? ? ? ?float in0_re = in[i+j][0];
> > + ? ? ? ? ? ? ? ?float in0_im = in[i+j][1];
> > + ? ? ? ? ? ? ? ?float in1_re = in[i+12-j][0];
> > + ? ? ? ? ? ? ? ?float in1_im = in[i+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 av_noinline void hybrid_analysis(float out[91][32][2], float in[64][44][2], int is34, int len)
> > +{
> > + ? ?int 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++) {
> > + ? ? ? ? ? ?memcpy(out[32 + i], in[5 + i]+6, len * sizeof(in[0][0]));
> > + ? ? ? ?}
> > + ? ?} 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++) {
> > + ? ? ? ? ? ?memcpy(out[10 + i], in[3 + i]+6, len * sizeof(in[0][0]));
> > + ? ? ? ?}
>
> is all that memcpy unavoidable?
>

It may be avoidable with a float(**)x[2] instead of a float(*)[][2].
FFmpeg seems to avoid the former.

I was also thinking it may be prudent to merge transpose_in() with
hybrid_analysis() which would make the point moot, no?

>
> [...]
> > +#define MAP_GENERIC_34_TO_20(out, in, full) \
> > + ? ?out[ 0] = (2*in[ 0] + ? in[ 1]) / 3; ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? \
> > + ? ?out[ 1] = ( ?in[ 1] + 2*in[ 2]) / 3; ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? \
> > + ? ?out[ 2] = (2*in[ 3] + ? in[ 4]) / 3; ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? \
> > + ? ?out[ 3] = ( ?in[ 4] + 2*in[ 5]) / 3; ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? \
> > + ? ?out[ 4] = ( ?in[ 6] + ? in[ 7]) / 2; ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? \
>
> for the idx (int8) case the /2 and /3 could be done by LUT
> for float, multiply by inverse seems better
>

see below

>
> > + ? ?out[ 5] = ( ?in[ 8] + ? in[ 9]) / 2; ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? \
> > + ? ?out[ 6] = ? ?in[10]; ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? \
> > + ? ?out[ 7] = ? ?in[11]; ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? \
> > + ? ?out[ 8] = ( ?in[12] + ? in[13]) / 2; ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? \
> > + ? ?out[ 9] = ( ?in[14] + ? in[15]) / 2; ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? \
> > + ? ?out[10] = ? ?in[16]; ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? \
> > + ? ?if (full) { ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?\
> > + ? ?out[11] = ? ?in[17]; ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? \
> > + ? ?out[12] = ? ?in[18]; ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? \
> > + ? ?out[13] = ? ?in[19]; ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? \
> > + ? ?out[14] = ( ?in[20] + ? in[21]) / 2; ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? \
> > + ? ?out[15] = ( ?in[22] + ? in[23]) / 2; ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? \
> > + ? ?out[16] = ( ?in[24] + ? in[25]) / 2; ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? \
> > + ? ?out[17] = ( ?in[26] + ? in[27]) / 2; ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? \
> > + ? ?out[18] = ( ?in[28] + ? in[29] + ? in[30] + ? in[31]) / 4; ? ? ? ? \
> > + ? ?out[19] = ( ?in[32] + ? in[33]) / 2; ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? \
> > + ? ?}
>
> the indention looks a bit confusing
>

This was rewritten after vitor's review

>
> [...]
> > +static av_noinline void decorrelation(PSContext *ps, float (*out)[32][2], const float (*s)[32][2], int is34)
> > +{
> > + ? ?float power[34][PS_QMF_TIME_SLOTS];
> > + ? ?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));
> > + ? ?}
> > +
> > + ? ?memset(power, 0, sizeof(power));
> > + ? ?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];
>
> > + ? ? ? ? ? ?peak_decay_nrg[i] = (decayed_peak < power[i][n]) ? power[i][n] : decayed_peak;
>
> FFMAX
>

fixed

>
> > + ? ? ? ? ? ?power_smooth[i] = a_smooth * power[i][n] + (1.0f - a_smooth) * power_smooth[i];
>
> 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]) +
> > + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? (1.0f - a_smooth) * peak_decay_diff_smooth[i];
>
> something similar
>
>
> > + ? ? ? ? ? ?transient_gain[i][n] ? = (transient_impact * peak_decay_diff_smooth[i] > power_smooth[i]) ?
> > + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? power_smooth[i] / (transient_impact * peak_decay_diff_smooth[i]) : 1.0f;
>
> maybe clearer with a temporaray variable

fixed

> X = transient_impact * peak_decay_diff_smooth[i]
> transient_gain[i][n] ? = ?X > power_smooth[i] ? power_smooth[i] / X : 1.0f; // FFMIN(power_smooth[i] / X, 1);
>
>
> > +//av_log(NULL, AV_LOG_ERROR, "transient_gain[%2d][%2d] %f %f %f\n", i, n, transient_gain[i][n], peak_decay_diff_smooth[i], power_smooth[i]);
> > + ? ? ? ?}
> > + ? ?}
> > +
> > + ? ?//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]);
> > + ? ? ? ?g_decay_slope = FFMIN(g_decay_slope, 1.f);
> > + ? ? ? ?g_decay_slope = FFMAX(g_decay_slope, 0.f);
>
> av_clipf

fixed

> > + ? ? ? ?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]));
> > + ? ? ? ?}
> > + ? ? ? ?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 ag ? ? ? ? ? ? ? ? ?= a[m] * g_decay_slope;
>
> it appears that this ag[3] can be calculated outside of the loops

fixed

> > + ? ? ? ? ? ? ? ?float a_re ? ? ? ? ? ? ? ?= ag * in_re;
> > + ? ? ? ? ? ? ? ?float a_im ? ? ? ? ? ? ? ?= ag * 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 * in_re;
> > + ? ? ? ? ? ? ? ?ap_delay[k][m][n+5][1] += ag * 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];
> > + ? ? ? ?}
>
> can the compiler factor transient_gain[k_to_i[k]] and delay[k] out
> or does it keep these dereferences in the loop?
>

I was going to wait until any major refactoring was done before
figuring out how all this stuff lands

>
> > + ? ?}
> > + ? ?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 av_noinline 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;
> > + ? ?float (*opd_smooth)[2][2] = ps->opd_smooth;
> > + ? ?float (*ipd_smooth)[2][2] = ps->ipd_smooth;
> > + ? ?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_IPDOPD];
> > + ? ?int8_t opd_mapped_buf[PS_MAX_NUM_ENV][PS_MAX_NR_IPDOPD];
> > + ? ?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_IPDOPD] = ipd_mapped_buf;
> > + ? ?int8_t (*opd_mapped)[PS_MAX_NR_IPDOPD] = 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;
> > + ? ?static const float ipdopd_sin[] = { 0, M_SQRT1_2, 1, ?M_SQRT1_2, ?0, -M_SQRT1_2, -1, -M_SQRT1_2 };
> > + ? ?static const float ipdopd_cos[] = { 1, M_SQRT1_2, 0, -M_SQRT1_2, -1, -M_SQRT1_2, ?0, ?M_SQRT1_2 };
> > +
> > + ? ?//Remapping
> > + ? ?for (b = 0; b < PS_MAX_NR_IIDICC; b++) {
> > + ? ? ? ?H11[0][0][b] = H11[0][ps->num_env_old][b];
> > + ? ? ? ?H12[0][0][b] = H12[0][ps->num_env_old][b];
> > + ? ? ? ?H21[0][0][b] = H21[0][ps->num_env_old][b];
> > + ? ? ? ?H22[0][0][b] = H22[0][ps->num_env_old][b];
> > + ? ? ? ?H11[1][0][b] = H11[1][ps->num_env_old][b];
> > + ? ? ? ?H12[1][0][b] = H12[1][ps->num_env_old][b];
> > + ? ? ? ?H21[1][0][b] = H21[1][ps->num_env_old][b];
> > + ? ? ? ?H22[1][0][b] = H22[1][ps->num_env_old][b];
> > + ? ?}
> > + ? ?if (is34) {
> > + ? ? ? ?for (e = 0; e < ps->num_env; e++) {
>
> > + ? ? ? ? ? ?if (ps->nr_icc_par == 20)
> > + ? ? ? ? ? ? ? ?map_idx_20_to_34(icc_mapped[e], ps->icc_par[e], 1);
> > + ? ? ? ? ? ?else if (ps->nr_icc_par == 10) {
> > + ? ? ? ? ? ? ? ?map_idx_10_to_20(icc_mapped[e], ps->icc_par[e], 1);
> > + ? ? ? ? ? ? ? ?map_idx_20_to_34(icc_mapped[e], icc_mapped[e], 1);
> > + ? ? ? ? ? ?} else
> > + ? ? ? ? ? ? ? ?icc_mapped = ps->icc_par;
>
> > + ? ? ? ? ? ?if (ps->nr_iid_par == 20)
> > + ? ? ? ? ? ? ? ?map_idx_20_to_34(iid_mapped[e], ps->iid_par[e], 1);
> > + ? ? ? ? ? ?else if (ps->nr_iid_par == 10) {
> > + ? ? ? ? ? ? ? ?map_idx_10_to_20(iid_mapped[e], ps->iid_par[e], 1);
> > + ? ? ? ? ? ? ? ?map_idx_20_to_34(iid_mapped[e], iid_mapped[e], 1);
> > + ? ? ? ? ? ?} else
> > + ? ? ? ? ? ? ? ?iid_mapped = ps->iid_par;
>
> duplicate
> and maybe the map* functions should be marked as no_inline to avoid bloating
> this up imensely

mapping has been rewritten

> > + ? ? ? ? ? ?if (ps->enable_ipdopd) {
> > + ? ? ? ? ? ? ? ?if (ps->nr_ipdopd_par == 11) {
> > + ? ? ? ? ? ? ? ? ? ?map_idx_20_to_34(ipd_mapped[e], ps->ipd_par[e], 0);
> > + ? ? ? ? ? ? ? ? ? ?map_idx_20_to_34(opd_mapped[e], ps->opd_par[e], 0);
> > + ? ? ? ? ? ? ? ?} else if (ps->nr_ipdopd_par == 5) {
>
> > + ? ? ? ? ? ? ? ? ? ?map_idx_10_to_20(ipd_mapped[e], ps->ipd_par[e], 0);
> > + ? ? ? ? ? ? ? ? ? ?map_idx_20_to_34(ipd_mapped[e], ipd_mapped[e], 0);
>
> these 2 could be combined and optimized

fixed

> > + ? ? ? ? ? ? ? ? ? ?map_idx_10_to_20(opd_mapped[e], ps->opd_par[e], 0);
> > + ? ? ? ? ? ? ? ? ? ?map_idx_20_to_34(opd_mapped[e], opd_mapped[e], 0);
> > + ? ? ? ? ? ? ? ?} else {
> > + ? ? ? ? ? ? ? ? ? ?ipd_mapped = ps->ipd_par;
> > + ? ? ? ? ? ? ? ? ? ?opd_mapped = ps->opd_par;
> > + ? ? ? ? ? ? ? ?}
> > + ? ? ? ? ? ?}
> > + ? ? ? ?}
> > + ? ? ? ?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(ps->ipd_smooth, ps->opd_smooth);
> > + ? ? ? ?}
> > + ? ?} else {
> > + ? ? ? ?for (e = 0; e < ps->num_env; e++) {
> > + ? ? ? ? ? ?if (ps->nr_icc_par == 34)
> > + ? ? ? ? ? ? ? ?map_idx_34_to_20(icc_mapped[e], ps->icc_par[e], 1);
> > + ? ? ? ? ? ?else if (ps->nr_icc_par == 10)
> > + ? ? ? ? ? ? ? ?map_idx_10_to_20(icc_mapped[e], ps->icc_par[e], 1);
> > + ? ? ? ? ? ?else
> > + ? ? ? ? ? ? ? ?icc_mapped = ps->icc_par;
> > + ? ? ? ? ? ?if (ps->nr_iid_par == 34)
> > + ? ? ? ? ? ? ? ?map_idx_34_to_20(iid_mapped[e], ps->iid_par[e], 1);
> > + ? ? ? ? ? ?else if (ps->nr_iid_par == 10)
> > + ? ? ? ? ? ? ? ?map_idx_10_to_20(iid_mapped[e], ps->iid_par[e], 1);
> > + ? ? ? ? ? ?else
> > + ? ? ? ? ? ? ? ?iid_mapped = ps->iid_par;
> > + ? ? ? ? ? ?if (ps->enable_ipdopd) {
> > + ? ? ? ? ? ? ? ?if (ps->nr_ipdopd_par == 17) {
> > + ? ? ? ? ? ? ? ? ? ?map_idx_34_to_20(ipd_mapped[e], ps->ipd_par[e], 0);
> > + ? ? ? ? ? ? ? ? ? ?map_idx_34_to_20(opd_mapped[e], ps->opd_par[e], 0);
> > + ? ? ? ? ? ? ? ?} else if (ps->nr_ipdopd_par == 5) {
> > + ? ? ? ? ? ? ? ? ? ?map_idx_10_to_20(ipd_mapped[e], ps->ipd_par[e], 0);
> > + ? ? ? ? ? ? ? ? ? ?map_idx_10_to_20(opd_mapped[e], ps->opd_par[e], 0);
> > + ? ? ? ? ? ? ? ?} else {
> > + ? ? ? ? ? ? ? ? ? ?ipd_mapped = ps->ipd_par;
> > + ? ? ? ? ? ? ? ? ? ?opd_mapped = ps->opd_par;
> > + ? ? ? ? ? ? ? ?}
> > + ? ? ? ? ? ?}
> > + ? ? ? ?}
> > + ? ? ? ?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(ps->ipd_smooth, ps->opd_smooth);
> > + ? ? ? ?}
> > + ? ?}
> > +
>
> > + ? ?//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 opd_mag, ipd_mag, ipd_adj_re, ipd_adj_im;
> > + ? ? ? ? ? ? ? ?float opd_re = ipdopd_cos[ps->opd_par[e][b]];
> > + ? ? ? ? ? ? ? ?float opd_im = ipdopd_sin[ps->opd_par[e][b]];
> > + ? ? ? ? ? ? ? ?float ipd_re = ipdopd_cos[ps->ipd_par[e][b]];
> > + ? ? ? ? ? ? ? ?float ipd_im = ipdopd_sin[ps->ipd_par[e][b]];
> > + ? ? ? ? ? ? ? ?float opd_im_smooth = 0.25f * opd_smooth[b][0][1] + 0.5f * opd_smooth[b][1][1] + opd_im;
> > + ? ? ? ? ? ? ? ?float opd_re_smooth = 0.25f * opd_smooth[b][0][0] + 0.5f * opd_smooth[b][1][0] + opd_re;
> > + ? ? ? ? ? ? ? ?float ipd_im_smooth = 0.25f * ipd_smooth[b][0][1] + 0.5f * ipd_smooth[b][1][1] + ipd_im;
> > + ? ? ? ? ? ? ? ?float ipd_re_smooth = 0.25f * ipd_smooth[b][0][0] + 0.5f * ipd_smooth[b][1][0] + ipd_re;
> > + ? ? ? ? ? ? ? ?opd_smooth[b][0][0] = opd_smooth[b][1][0];
> > + ? ? ? ? ? ? ? ?opd_smooth[b][0][1] = opd_smooth[b][1][1];
> > + ? ? ? ? ? ? ? ?opd_smooth[b][1][0] = opd_re;
> > + ? ? ? ? ? ? ? ?opd_smooth[b][1][1] = opd_im;
> > + ? ? ? ? ? ? ? ?ipd_smooth[b][0][0] = ipd_smooth[b][1][0];
> > + ? ? ? ? ? ? ? ?ipd_smooth[b][0][1] = ipd_smooth[b][1][1];
> > + ? ? ? ? ? ? ? ?ipd_smooth[b][1][0] = ipd_re;
> > + ? ? ? ? ? ? ? ?ipd_smooth[b][1][1] = ipd_im;
> > + ? ? ? ? ? ? ? ?opd_mag = 1 / sqrt(opd_im_smooth * opd_im_smooth + opd_re_smooth * opd_re_smooth);
> > + ? ? ? ? ? ? ? ?ipd_mag = 1 / sqrt(ipd_im_smooth * ipd_im_smooth + ipd_re_smooth * ipd_re_smooth);
> > + ? ? ? ? ? ? ? ?opd_re = opd_re_smooth * opd_mag;
> > + ? ? ? ? ? ? ? ?opd_im = opd_im_smooth * opd_mag;
> > + ? ? ? ? ? ? ? ?ipd_re = ipd_re_smooth * ipd_mag;
> > + ? ? ? ? ? ? ? ?ipd_im = ipd_im_smooth * ipd_mag;
>
> if i decyphered this nonsense correctly then
> ?pd_re/im values here can have 512 distinct values
> thus a LUT that is indexed by 3 ps->o/ipd_par[e][b] values could be used
>

Quantized ipd/opd take the the vales of 0-7 so smoothed values
normalized to unit vectors would be 8x8x8x2 floats 1024 values total
(512 real and 512 imaginary). Do you think an LUT is worth it here? It
would eliminate the invsqrt.

>
> [...]
> --
> Michael ? ? GnuPG fingerprint: 9FF2128B147EF6730BADF133611EC787040B0FAB
>

--Alex



More information about the ffmpeg-devel mailing list