Commit 3944b583 authored by Sandesh Venkatesh's avatar Sandesh Venkatesh
Browse files

Merge branch '3gpp_issue_992_fix_2' into 'main'

Fix for 3GPP issue 992: Crash in ivas_dirac_dec_render_fx() in OMASA JBM decoding - 2 [allow regression]

See merge request !768
parents 83a229c7 bd419b1b
Loading
Loading
Loading
Loading
+439 −2
Original line number Diff line number Diff line
@@ -151,8 +151,12 @@ static bool copy_frm_fx( apa_state_t *ps, const Word16 frm_in[], Word16 frm_out[

static bool shrink_frm_fx( apa_state_t *ps, const Word16 frm_in[], UWord16 maxScaling, Word16 frm_out[], UWord16 *l_frm_out );

static bool shrink_frm_ivas_fx( apa_state_t *ps, const Word16 frm_in[], UWord16 maxScaling, Word16 frm_out[], Word16 Q_frm_in, UWord16 *l_frm_out );

static bool extend_frm_fx( apa_state_t *ps, const Word16 frm_in[], Word16 frm_out[], UWord16 *l_frm_out );

static bool extend_frm_ivas_fx( apa_state_t *ps, const Word16 frm_in[], Word16 frm_out[], Word16 Q_frm_in, UWord16 *l_frm_out );

/*---------------------------------------------------------------------*
 * Public functions
 *---------------------------------------------------------------------*/
@@ -991,12 +995,12 @@ UWord8 apa_exec_ivas_fx(
        /* shrink */
        ELSE IF( LT_32( ps->scale, 100 ) )
        {
            shrink_frm_fx( ps, frm_in, maxScaling, a_tmp, &l_frm_out );
            shrink_frm_ivas_fx( ps, frm_in, maxScaling, a_tmp, Q_a_out, &l_frm_out );
        }
        /* extend */
        ELSE
        {
            extend_frm_fx( ps, frm_in, a_tmp, &l_frm_out );
            extend_frm_ivas_fx( ps, frm_in, a_tmp, Q_a_out, &l_frm_out );
        }
        /* control the amount/frequency of scaling */
        IF( NE_32( l_frm_out, ps->l_frm ) )
@@ -1721,6 +1725,180 @@ static bool shrink_frm_fx(
    return 0;
}

static bool shrink_frm_ivas_fx(
    apa_state_t *ps,
    const Word16 frm_in_fx[], // Qx
    UWord16 maxScaling,
    Word16 frm_out_fx[], // Qx
    Word16 Q_frm_in,
    UWord16 *l_frm_out )
{
    bool findSynchResult = 0;
    move16();
    Word16 xtract, l_rem, s_start, s_end;
    UWord16 i;
    UWord16 over;
    Word16 energy_fx = 0;
    Word32 quality_fx = 0;
    UWord16 l_frm;
    UWord16 l_seg;
    move16();
    move32();

    l_frm = ps->l_frm;
    move16();
    l_seg = ps->l_seg;
    move16();

    /* only 2nd input frame is used */
    frm_in_fx += l_frm;

    /* set search range */
    // s_start = ( ps->p_min / ps->num_channels ) * ps->num_channels;
    Word16 tmp, tmp_e;
    tmp = BASOP_Util_Divide3232_Scale( ps->p_min, ps->num_channels, &tmp_e );
    tmp = shr( tmp, sub( 15, tmp_e ) );
    s_start = i_mult( tmp, extract_l( ps->num_channels ) );
    s_end = add( s_start, extract_l( ps->l_search ) );
    IF( GE_32( L_add( s_end, l_seg ), l_frm ) )
    {
        s_end = extract_l( L_sub( l_frm, l_seg ) );
    }

    /* calculate overlap position */
    IF( isSilence_fx( frm_in_fx, l_seg, 10 ) )
    {
        /* maximum scaling */
        energy_fx = -65 * ( 1 << 8 ); // Q8
        move16();
        quality_fx = 5 << Q16; // Q16
        move32();
        IF( ps->evs_compat_mode == false )
        {

            xtract = maxScaling;
            move16();
            /* take samples already in the renderer buf into account */
            xtract = add( xtract, extract_l( ps->l_r_buf ) );
            /* snap to renderer time slot borders */
            xtract = sub( xtract, extract_l( L_sub( ps->l_ts, ( L_add( L_sub( l_frm, xtract ), ps->l_r_buf ) ) % ps->l_ts ) ) );
            WHILE( xtract < 0 )
            {
                xtract = add( xtract, extract_l( ps->l_ts ) );
            }
            WHILE( GT_32( xtract, sub( s_end, extract_l( ps->num_channels ) ) ) )
            {
                /* exceeded the possible shrinking, go back one renderer ts*/
                xtract = sub( xtract, extract_l( ps->l_ts ) );
            }
        }
        ELSE IF( maxScaling != 0U && GT_16( s_end, add( extract_l( maxScaling ), 1 ) ) )
        {
            xtract = maxScaling;
            move16();
        }
        ELSE
        {
            /* set to last valid element (i.e. element[len - 1] but note for stereo last element is last pair of samples) */
            xtract = sub( s_end, extract_l( ps->num_channels ) );
        }
    }
    ELSE
    {
        /* find synch */
        scaleSignal16( frm_in_fx, ps->frmInScaled, l_frm, ps->signalScaleForCorrelation );
        ps->signalScaleForCorrelation = sub( ps->signalScaleForCorrelation, Q_frm_in );
        move16();
        findSynchResult = find_synch_fx( ps, ps->frmInScaled, l_frm, s_start, (UWord16) ( sub( s_end, s_start ) ), 0, l_seg, 0, &energy_fx, &quality_fx, &xtract );
        ps->signalScaleForCorrelation = add( ps->signalScaleForCorrelation, Q_frm_in );
        move16();
    }

    /* assert synch_pos is cleanly divisible by number of channels */
    assert( xtract % ps->num_channels == 0 );

    /* set frame overlappable - reset if necessary */
    over = 1;
    move16();

    /* test whether frame has sufficient quality */
    IF( LT_32( quality_fx, L_add( L_sub( ps->targetQuality_fx,
                                         L_mult0( ps->bad_frame_count, 6554 /*0.1 (Q16)*/ ) ),
                                  L_mult0( ps->good_frame_count, 13107 /*0.2 (Q16)*/ ) ) ) )
    {
        /* not sufficient */
        over = 0;
        move16();
        IF( LT_32( ps->bad_frame_count, ps->qualityred ) )
        {
            ps->bad_frame_count = u_extract_l( UL_addNsD( ps->bad_frame_count, 1 ) );
            move16();
        }
        IF( GT_32( ps->good_frame_count, 0 ) )
        {
            ps->good_frame_count = u_extract_l( UL_subNsD( ps->good_frame_count, 1 ) );
            move16();
        }
    }
    ELSE
    {
        /* sufficient quality */
        IF( ps->bad_frame_count > 0 )
        {
            ps->bad_frame_count = u_extract_l( UL_subNsD( ps->bad_frame_count, 1 ) );
            move16();
        }
        IF( LT_32( ps->good_frame_count, ps->qualityrise ) )
        {
            ps->good_frame_count = u_extract_l( UL_addNsD( ps->good_frame_count, 1 ) );
            move16();
        }
    }

    /* Calculate output data */
    test();
    IF( over && xtract )
    {
        IF( findSynchResult == 1 )
        {
            return 1;
        }
        IF( EQ_16( ps->evs_compat_mode, true ) )
        {
            // overlapAddEvs_fx( frm_in_fx, frm_in_fx + xtract, frm_out_fx, l_seg, ps->num_channels, ps->win_fx + ps->l_halfwin_fx, ps->win_fx );
            overlapAdd( frm_in_fx, frm_in_fx + xtract, frm_out_fx, l_seg, ps->num_channels, ps->win_fx + ps->l_halfwin, ps->win_fx, ps->win_incrementor );
        }
        ELSE
        {
            overlapAdd( frm_in_fx, frm_in_fx + xtract, frm_out_fx, l_seg, ps->num_channels, ps->win_fx + ps->l_halfwin, ps->win_fx, ps->win_incrementor );
        }
    }
    ELSE
    {
        xtract = 0;
        move16();
        FOR( i = 0; i < l_seg; i++ )
        {
            frm_out_fx[i] = frm_in_fx[i];
            move16();
        }
    }

    /* append remaining samples */
    l_rem = extract_l( L_sub( L_sub( l_frm, xtract ), l_seg ) );
    FOR( i = 0; i < l_rem; i++ )
    {
        frm_out_fx[l_seg + i] = frm_in_fx[l_frm - l_rem + i];
        move16();
    }

    /* set output length */
    *l_frm_out = u_extract_l( UL_addNsD( l_seg, l_rem ) );
    move16();

    return 0;
}

/*
********************************************************************************
*
@@ -1994,3 +2172,262 @@ static bool extend_frm_fx(
    move16();
    return 0;
}


static bool extend_frm_ivas_fx(
    apa_state_t *ps,
    const Word16 frm_in_fx[], // Qx
    Word16 frm_out_fx[],      // Qx
    Word16 Q_frm_in,
    UWord16 *l_frm_out )
{
    bool findSynchResult = 0;
    move16();
    UWord16 l_frm_out_target;
    UWord16 n, i;
    Word16 N;
    Word16 s[MAXN + 2], s_max, s_min;
    Word16 xtract[MAXN + 2], sync_start, s_end;
    UWord16 over[MAXN + 2];
    Word16 l_rem;
    Word16 s_start = 0;
    move16();
    Word16 energy_fx;
    Word32 quality_fx = 0;
    move32();
    UWord16 l_frm, l_seg;
    const Word16 *fadeOut_fx, *fadeIn_fx;
    Word16 *out_fx;

    l_frm = ps->l_frm;
    l_seg = ps->l_seg;
    move16();
    move16();
    /* number of segments/iterations */
    l_frm_out_target = (UWord16) ( L_add( l_frm, L_shr( l_frm, 1 ) ) );
    //(l_frm_out_target/l_seg -1 )
    Word16 tmp, tmp_e;
    tmp = BASOP_Util_Divide3232_Scale( l_frm_out_target, l_seg, &tmp_e );
    tmp = shr( tmp, sub( 15, tmp_e ) );
    N = sub( ( tmp ), 1 );
    if ( LT_16( N, 1 ) )
    {
        N = 1;
        move16();
    }
    IF( GT_16( N, MAXN ) )
    {
        return 1;
    }
    /* calculate equally spaced search regions */
    /* s[n] are given relative to 2nd frame and point to the start of */
    /* the search region. The first segment (n=1) will not be moved. */
    /* Hence, the iterations will start with n=2. */
    s_min = extract_l( L_negate( L_add( ps->l_search, ps->p_min ) ) );
    /* (make sure not to exceed array dimension) */
    IF( L_add( l_frm, s_min ) < 0 )
    {
        s_min = extract_l( L_negate( l_frm ) );
    }
    s_max = extract_l( L_sub( L_sub( l_frm, L_shl( l_seg, 1 ) ), ps->l_search ) );
    if ( s_max < s_min )
    {
        N = 1;
        move16();
    }
    /* for just one segment start at s_min */
    if ( N == 1 )
    {
        s[2] = s_min;
        move16();
    }
    /* else, spread linear in between s_min and s_max */
    /* (including s_min and s_max) */
    ELSE
    {
        FOR( n = 2; n <= ( N + 1 ); n++ )
        {
            // s[n] = s_min + ( ( s_max - s_min ) * ( n - 2 ) ) / ( N - 1 );
            Word16 tmp2, tmp2_e;
            tmp2 = sub( s_max, s_min );
            tmp2 = i_mult( tmp2, extract_l( L_sub( n, 2 ) ) );
            tmp2 = BASOP_Util_Divide1616_Scale( tmp2, sub( N, 1 ), &tmp2_e );
            tmp2 = shr( tmp2, sub( 15, tmp2_e ) );
            s[n] = add( s_min, tmp2 );
            move16();
        }
    }

    /*
     *  Planning Phase
     */

    xtract[1] = extract_l( L_negate( l_seg ) ); /* make sync_start=0 in 1st iteration */
    move16();
    n = 2;
    move16();
    /* define synch segment (to be correlated with search region) */
    sync_start = extract_l( L_add( xtract[n - 1], l_seg ) );
    over[n] = 1; /* will be reset if overlap is not required */
    move16();
    /* check end of search region: should be at least p_min */
    /* samples on the left of synch_start */
    IF( LT_32( L_add( s[n], ps->l_search ), L_sub( sync_start, ( ps->p_min ) ) ) )
    {
        s_start = s[n];
        move16();
        s_end = extract_l( L_add( s_start, ps->l_search ) );
    }
    ELSE
    {
        /* shrink search region to enforce minimum shift */
        s_end = extract_l( L_sub( sync_start, ( ps->p_min ) ) );
        IF( LT_16( extract_l( L_add( s[n], ps->l_search ) ), sync_start ) )
        {
            s_start = s[n]; /* just do it with normal start position */
            move16();
        }
        ELSE IF( EQ_32( n, L_add( N, 1 ) ) ) /* move search region left for last segment */
        {
            s_start = extract_l( L_sub( s_end, L_sub( ps->l_search, ps->p_min ) ) );
        }
        ELSE
        {
            over[n] = 0; /* don't search/overlap (just copy down) */
            move16();
        }
    }

    IF( over[n] )
    {
        /* calculate overlap position */
        IF( isSilence_fx( frm_in_fx, l_seg, 10 ) )
        {
            /* maximum scaling */
            energy_fx = -65 * ( 1 << 8 ); // Q8
            move16();
            quality_fx = 5 << 16; // Q16
            move32();
            xtract[n] = extract_l( L_add( s_start, ps->num_channels ) );
            move16();
            IF( ps->evs_compat_mode == false )
            {
                /* take renderer buffer samples into accout */
                xtract[n] = extract_l( L_add( xtract[n], ps->l_r_buf ) );
                /* snap to next renderer time slot border to resynchronize */
                // xtract[n] -= ( ( N - 1 ) * l_seg - xtract[n] + ps->l_r_buf ) % ps->l_ts;
                Word16 tmp3;
                tmp3 = extract_l( L_add( L_sub( W_extract_l( W_mult0_32_32( L_sub( N, 1 ), l_seg ) ), xtract[n] ), ps->l_r_buf ) );
                xtract[n] = sub( xtract[n], tmp3 % ps->l_ts );
                move16();
                move16();
            }
        }
        ELSE
        {
            Word16 *frmInScaled;
            frmInScaled = ps->frmInScaled;
            assert( sizeof( ps->frmInScaled ) / sizeof( ps->frmInScaled[0] ) >= 2 * (size_t) l_frm );
            scaleSignal16( frm_in_fx, frmInScaled, shl( l_frm, 1 ), ps->signalScaleForCorrelation );
            ps->signalScaleForCorrelation = sub( ps->signalScaleForCorrelation, Q_frm_in );
            findSynchResult = find_synch_fx( ps, frmInScaled, extract_l( L_shl( l_frm, 1 ) ), s_start, sub( s_end, s_start ), sync_start, l_seg, l_frm, &energy_fx, &quality_fx, &xtract[n] );
            ps->signalScaleForCorrelation = add( ps->signalScaleForCorrelation, Q_frm_in );
        }
        /* assert synch_pos is cleanly divisible by number of channels */
        assert( xtract[n] % ps->num_channels == 0 );

        /* test for sufficient quality */
        IF( LT_32( quality_fx, L_add( L_sub( ps->targetQuality_fx,
                                             L_mult0( ps->bad_frame_count, 6554 /*.1f in Q16*/ ) ),
                                      L_mult0( ps->good_frame_count, 13107 /*.1f in Q16*/ ) ) ) )
        {
            /* not sufficient */
            over[n] = 0;
            move16();
            xtract[n] = sync_start;
            move16();
            IF( LT_32( ps->bad_frame_count, ps->qualityred ) )
            {
                ps->bad_frame_count = u_extract_l( UL_addNsD( ps->bad_frame_count, 1 ) );
                move16();
            }
            IF( GT_32( ps->good_frame_count, 0 ) )
            {
                ps->good_frame_count = u_extract_l( UL_subNsD( ps->good_frame_count, 1 ) );
                move16();
            }
        }
        ELSE
        {
            /* sufficient quality */
            IF( GT_32( ps->bad_frame_count, 0 ) )
            {
                ps->bad_frame_count = u_extract_l( UL_subNsD( ps->bad_frame_count, 1 ) );
                move16();
            }
            IF( LT_32( ps->good_frame_count, ps->qualityrise ) )
            {
                ps->good_frame_count = u_extract_l( UL_addNsD( ps->good_frame_count, 1 ) );
                move16();
            }
        }
        IF( findSynchResult )
        {
            return 1;
        }
    }
    ELSE
    {
        xtract[n] = sync_start;
        move16();
    }


    /* Calculate output data */
    FOR( n = 2; n <= N; n++ )
    {
        test();
        IF( over[n] && NE_16( extract_l( L_add( xtract[n - 1], l_seg ) ), xtract[n] ) )
        {
            /* mix 2nd half of previous segment with 1st half of current segment */
            fadeOut_fx = frm_in_fx + l_frm + xtract[n - 1] + l_seg;
            fadeIn_fx = frm_in_fx + l_frm + xtract[n];
            out_fx = frm_out_fx + ( n - 2 ) * l_seg;
            IF( EQ_16( ps->evs_compat_mode, true ) )
            {
                // overlapAddEvs_fx( fadeOut_fx, fadeIn_fx, out_fx, l_seg, ps->num_channels, ps->win_fx + ps->l_halfwin_fx, ps->win_fx );
                overlapAdd( fadeOut_fx, fadeIn_fx, out_fx, l_seg, ps->num_channels, ps->win_fx + ps->l_halfwin, ps->win_fx, ps->win_incrementor );
            }
            ELSE
            {
                overlapAdd( fadeOut_fx, fadeIn_fx, out_fx, l_seg, ps->num_channels, ps->win_fx + ps->l_halfwin, ps->win_fx, ps->win_incrementor );
            }
        }
        ELSE
        {
            /* just copy down 1st half of current segment (= 2nd half of previous segment) */
            Word16 *frm_out_ptr;
            const Word16 *frm_in_ptr;
            frm_out_ptr = &( frm_out_fx[( n - 2 ) * l_seg] );
            frm_in_ptr = &( frm_in_fx[l_frm + xtract[n]] );
            FOR( i = 0; i < l_seg; i++ )
            {
                frm_out_ptr[i] = frm_in_ptr[i];
                move16();
            }
        }
    }

    /* append remaining samples */
    l_rem = l_frm - ( xtract[N] + l_seg );
    FOR( i = 0; i < l_rem; i++ )
    {
        frm_out_fx[( N - 1 ) * l_seg + i] = frm_in_fx[2 * l_frm - l_rem + i];
        move16();
    }

    /* set output length */
    *l_frm_out = (UWord16) ( W_mult0_32_32( L_sub( N, 1 ), L_add( l_seg, l_rem ) ) );
    move16();
    return 0;
}