From bd419b1ba8af83931b685304bb74677f20e43a2d Mon Sep 17 00:00:00 2001 From: Sandesh Venkatesh Date: Tue, 12 Nov 2024 17:36:01 +0530 Subject: [PATCH] Fix for 3GPP issue 992: Crash in ivas_dirac_dec_render_fx() in OMASA JBM decoding - 2 [x] link #992 [x] Exponent fix for extend_frm and shrink_frm --- lib_dec/jbm_pcmdsp_apa.c | 441 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 439 insertions(+), 2 deletions(-) diff --git a/lib_dec/jbm_pcmdsp_apa.c b/lib_dec/jbm_pcmdsp_apa.c index f8cce92ca..297221eb4 100644 --- a/lib_dec/jbm_pcmdsp_apa.c +++ b/lib_dec/jbm_pcmdsp_apa.c @@ -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; +} -- GitLab