diff --git a/encoder/iusace_enc_main.c b/encoder/iusace_enc_main.c index 503f9c9..b24e9c8 100644 --- a/encoder/iusace_enc_main.c +++ b/encoder/iusace_enc_main.c @@ -940,7 +940,7 @@ IA_ERRORCODE ixheaace_usac_encode(FLOAT32 **ptr_input, ixheaace_audio_specific_config_struct *pstr_asc, ia_bit_buf_struct *pstr_it_bit_buff, ixheaace_pstr_sbr_enc ptr_env_encoder, FLOAT32 **pp_drc_inp, - WORD32 *is_quant_spec_zero) { + WORD32 *is_quant_spec_zero, WORD32 *is_gain_limited) { IA_ERRORCODE err = IA_NO_ERROR; WORD32 i_ch, i, k; ia_usac_data_struct *ptr_usac_data = pstr_state; @@ -1293,7 +1293,7 @@ IA_ERRORCODE ixheaace_usac_encode(FLOAT32 **ptr_input, : ((ptr_usac_data->core_mode[ch_offset] == CORE_MODE_FD))) { err = iusace_fd_encode(pstr_sfb_prms, usac_independency_flg, ptr_usac_data, ptr_usac_config, pstr_it_bit_buff, nr_core_coder_channels, ch_offset, elem_idx, - &bits_written, is_quant_spec_zero); + &bits_written, is_quant_spec_zero, is_gain_limited); if (err) { return err; diff --git a/encoder/iusace_fd_enc.h b/encoder/iusace_fd_enc.h index 2fa8b8d..9f8b00d 100644 --- a/encoder/iusace_fd_enc.h +++ b/encoder/iusace_fd_enc.h @@ -24,4 +24,4 @@ IA_ERRORCODE iusace_fd_encode(ia_sfb_params_struct *pstr_sfb_prms, WORD32 usac_i ia_usac_encoder_config_struct *pstr_usac_config, ia_bit_buf_struct *pstr_it_bit_buff, WORD32 nr_core_coder_ch, WORD32 chn, WORD32 ele_id, WORD32 *bit_written, - WORD32 *is_quant_spec_zero); + WORD32 *is_quant_spec_zero, WORD32* is_gain_limited); diff --git a/encoder/iusace_main.h b/encoder/iusace_main.h index f869ccb..dcacb14 100644 --- a/encoder/iusace_main.h +++ b/encoder/iusace_main.h @@ -111,7 +111,8 @@ IA_ERRORCODE iusace_quantize_spec(ia_sfb_params_struct *pstr_sfb_prms, WORD32 usac_independancy_flag, WORD32 num_chans, ia_usac_data_struct *ptr_usac_data, ia_usac_encoder_config_struct *ptr_usac_config, WORD32 chn, - WORD32 ele_id, WORD32 *is_quant_spec_zero); + WORD32 ele_id, WORD32 *is_quant_spec_zero, + WORD32 *is_gain_limited); IA_ERRORCODE iusace_grouping(ia_sfb_params_struct *pstr_sfb_prms, WORD32 num_chans, ia_usac_data_struct *ptr_usac_data, diff --git a/encoder/ixheaace_aac_constants.h b/encoder/ixheaace_aac_constants.h index 40e779a..8c96a2f 100644 --- a/encoder/ixheaace_aac_constants.h +++ b/encoder/ixheaace_aac_constants.h @@ -118,4 +118,5 @@ typedef struct { #define MIN_NUM_CORE_CODER_CHANNELS (1) /*-------------------------- defines --------------------------------------*/ -#define BUFFERSIZE 1024 /* anc data */ \ No newline at end of file +#define BUFFERSIZE 1024 /* anc data */ +#define MAX_GAIN_INDEX (128) \ No newline at end of file diff --git a/encoder/ixheaace_api.c b/encoder/ixheaace_api.c index 67088a9..cde050a 100644 --- a/encoder/ixheaace_api.c +++ b/encoder/ixheaace_api.c @@ -2726,7 +2726,8 @@ static IA_ERRORCODE ia_enhaacplus_enc_execute(ixheaace_api_struct *pstr_api_stru &(pstr_api_struct->pstr_state->bit_stream), flag_last_element, write_program_config_element, i_num_coup_channels, i_channels_mask, ele_idx, total_fill_bits, total_channels, aot, pstr_api_struct->config->adts_flag, - num_bs_elements, &pstr_api_struct->pstr_state->is_quant_spec_zero); + num_bs_elements, &pstr_api_struct->pstr_state->is_quant_spec_zero, + &pstr_api_struct->pstr_state->is_gain_limited); if (error != IA_NO_ERROR) { return error; } @@ -3273,7 +3274,8 @@ static IA_ERRORCODE iusace_process(ixheaace_api_struct *pstr_api_struct) { &pstr_api_struct->pstr_state->str_usac_enc_data, &pstr_api_struct->pstr_state->audio_specific_config, pstr_it_bit_buff, pstr_sbr_encoder, pstr_api_struct->pstr_state->pp_drc_in_buf, - &pstr_api_struct->pstr_state->is_quant_spec_zero); + &pstr_api_struct->pstr_state->is_quant_spec_zero, + &pstr_api_struct->pstr_state->is_gain_limited); if (error) return error; padding_bits = 8 - (pstr_it_bit_buff->cnt_bits & 7); @@ -3610,6 +3612,7 @@ IA_ERRORCODE ixheaace_process(pVOID pstr_obj_ixheaace, pVOID pv_input, pVOID pv_ ixheaace_api_struct *pstr_api_struct = (ixheaace_api_struct *)pstr_obj_ixheaace; ixheaace_output_config *pstr_output_config = (ixheaace_output_config *)pv_output; pstr_api_struct->pstr_state->is_quant_spec_zero = 0; + pstr_api_struct->pstr_state->is_gain_limited = 0; if (!pstr_api_struct->usac_en) { for (ele_idx = 0; ele_idx < pstr_api_struct->config[0].num_bs_elements; ele_idx++) { error = ia_enhaacplus_enc_execute(pstr_api_struct, ele_idx); @@ -3617,11 +3620,17 @@ IA_ERRORCODE ixheaace_process(pVOID pstr_obj_ixheaace, pVOID pv_input, pVOID pv_ if ((error == IA_NO_ERROR) && (pstr_api_struct->pstr_state->is_quant_spec_zero)) { error = IA_EXHEAACE_EXE_NONFATAL_QUANTIZATION_SPECTRUM_ZERO; } + if ((error == IA_NO_ERROR) && (pstr_api_struct->pstr_state->is_gain_limited)) { + error = IA_EXHEAACE_EXE_NONFATAL_QUANTIZATION_INSUFFICIENT_BITRES; + } } else { error = iusace_process(pstr_api_struct); if ((error == IA_NO_ERROR) && (pstr_api_struct->pstr_state->is_quant_spec_zero)) { error = IA_EXHEAACE_EXE_NONFATAL_USAC_QUANTIZATION_SPECTRUM_ZERO; } + if ((error == IA_NO_ERROR) && (pstr_api_struct->pstr_state->is_gain_limited)) { + error = IA_EXHEAACE_EXE_NONFATAL_USAC_QUANTIZATION_INSUFFICIENT_BITRES; + } } pstr_output_config->i_out_bytes = pstr_api_struct->pstr_state->i_out_bytes; return error; diff --git a/encoder/ixheaace_api_defs.h b/encoder/ixheaace_api_defs.h index 99dbdba..3c2164d 100644 --- a/encoder/ixheaace_api_defs.h +++ b/encoder/ixheaace_api_defs.h @@ -44,4 +44,4 @@ IA_ERRORCODE ixheaace_usac_encode(FLOAT32 **ptr_input, ixheaace_audio_specific_config_struct *pstr_asc, ia_bit_buf_struct *pstr_it_bit_buff, ixheaace_pstr_sbr_enc ptr_env_encoder, FLOAT32 **ptr_drc_inp, - WORD32 *is_quant_spec_zero); + WORD32 *is_quant_spec_zero, WORD32 *is_gain_restricted); diff --git a/encoder/ixheaace_enc_main.c b/encoder/ixheaace_enc_main.c index 048f63f..1c25924 100644 --- a/encoder/ixheaace_enc_main.c +++ b/encoder/ixheaace_enc_main.c @@ -66,7 +66,7 @@ IA_ERRORCODE ia_enhaacplus_enc_aac_core_encode( VOID *ptr_bit_stream, FLAG flag_last_element, WORD32 *write_program_config_element, WORD32 i_num_coup_channels, WORD32 i_channels_mask, WORD32 ele_idx, WORD32 *total_fill_bits, WORD32 total_channels, WORD32 aot, WORD32 adts_flag, WORD32 num_bs_elements, - WORD32 *is_quant_spec_zero) { + WORD32 *is_quant_spec_zero, WORD32 *is_gain_limited) { IA_ERRORCODE err_code = IA_NO_ERROR; iexheaac_encoder_str *pstr_aac_encoder = pstr_aac_enc[ele_idx]; ixheaace_element_info *pstr_element_info = &pstr_aac_encoder->element_info; @@ -174,7 +174,8 @@ IA_ERRORCODE ia_enhaacplus_enc_aac_core_encode( pstr_aac_encoder->qc_out.qc_channel[pstr_element_info->channel_index[0]], &pstr_aac_encoder->qc_out.qc_element, MIN(anc_data_bytes_left, anc_data_bytes), pstr_aac_tabs, adts_flag, aot, stat_bits_flag, flag_last_element, frame_len_long, - pstr_aac_encoder->pstr_aac_scratch->shared_buffer5, is_quant_spec_zero); + pstr_aac_encoder->pstr_aac_scratch->shared_buffer5, is_quant_spec_zero, + is_gain_limited); if (err_code != IA_NO_ERROR) { return err_code; diff --git a/encoder/ixheaace_enc_main.h b/encoder/ixheaace_enc_main.h index e3c34ca..3dd377e 100644 --- a/encoder/ixheaace_enc_main.h +++ b/encoder/ixheaace_enc_main.h @@ -109,7 +109,7 @@ IA_ERRORCODE ia_enhaacplus_enc_aac_core_encode( VOID *ptr_bit_stream, FLAG flag_last_element, WORD32 *write_program_config_element, WORD32 i_num_coup_channels, WORD32 i_channels_mask, WORD32 ele_idx, WORD32 *total_fill_bits, WORD32 total_channels, WORD32 aot, WORD32 adts_flag, WORD32 num_bs_elements, - WORD32 *is_quant_spec_zero); + WORD32 *is_quant_spec_zero, WORD32 *is_gain_limited); VOID ia_enhaacplus_enc_set_shared_bufs(iaace_scratch *scr, WORD32 **shared_buf1, WORD32 **shared_buf2, WORD32 **shared_buf3, diff --git a/encoder/ixheaace_error_codes.h b/encoder/ixheaace_error_codes.h index c791c27..a0fe36f 100644 --- a/encoder/ixheaace_error_codes.h +++ b/encoder/ixheaace_error_codes.h @@ -142,12 +142,14 @@ typedef enum { // AAC Profiles IA_EXHEAACE_EXE_NONFATAL_QUANTIZATION_SPECTRUM_ZERO = 0x00001800, + IA_EXHEAACE_EXE_NONFATAL_QUANTIZATION_INSUFFICIENT_BITRES, // MPS IA_EXHEAACE_EXE_NONFATAL_MPS_ENCODE_ERROR = 0x00001900, IA_EXHEAACE_EXE_NONFATAL_MPS_INVALID_DATA_BANDS, // USAC IA_EXHEAACE_EXE_NONFATAL_USAC_QUANTIZATION_SPECTRUM_ZERO = 0x00001A00, + IA_EXHEAACE_EXE_NONFATAL_USAC_QUANTIZATION_INSUFFICIENT_BITRES, // DRC // ESBR diff --git a/encoder/ixheaace_fd_enc.c b/encoder/ixheaace_fd_enc.c index 5c55594..264460c 100644 --- a/encoder/ixheaace_fd_enc.c +++ b/encoder/ixheaace_fd_enc.c @@ -57,7 +57,7 @@ IA_ERRORCODE iusace_fd_encode(ia_sfb_params_struct *pstr_sfb_prms, WORD32 usac_i ia_usac_encoder_config_struct *pstr_usac_config, ia_bit_buf_struct *pstr_it_bit_buff, WORD32 nr_core_coder_ch, WORD32 chn, WORD32 ele_id, WORD32 *bit_written, - WORD32 *is_quant_spec_zero) { + WORD32 *is_quant_spec_zero, WORD32 *is_gain_limited) { iusace_scratch_mem *pstr_scratch = &pstr_usac_data->str_scratch; IA_ERRORCODE err_code = 0; WORD32 i_ch, idx = 0; @@ -96,7 +96,7 @@ IA_ERRORCODE iusace_fd_encode(ia_sfb_params_struct *pstr_sfb_prms, WORD32 usac_i err_code = iusace_quantize_spec(pstr_sfb_prms, usac_independancy_flag, nr_core_coder_ch, pstr_usac_data, pstr_usac_config, chn, ele_id, - is_quant_spec_zero); + is_quant_spec_zero, is_gain_limited); if (err_code) return err_code; for (i_ch = chn; i_ch < chn + nr_core_coder_ch; i_ch++) { diff --git a/encoder/ixheaace_fd_quant.c b/encoder/ixheaace_fd_quant.c index bcaf31d..69f0a9f 100644 --- a/encoder/ixheaace_fd_quant.c +++ b/encoder/ixheaace_fd_quant.c @@ -56,6 +56,7 @@ #include "iusace_block_switch_const.h" #include "iusace_rom.h" #include "ixheaace_cplx_pred.h" +#include "ixheaace_aac_constants.h" static WORD32 iusace_window_shape[5] = {WIN_SEL_1, WIN_SEL_0, WIN_SEL_0, WIN_SEL_1, WIN_SEL_0}; @@ -444,7 +445,8 @@ IA_ERRORCODE iusace_quantize_spec(ia_sfb_params_struct *pstr_sfb_prms, WORD32 usac_independancy_flag, WORD32 num_chans, ia_usac_data_struct *ptr_usac_data, ia_usac_encoder_config_struct *ptr_usac_config, WORD32 chn, - WORD32 ele_id, WORD32 *is_quant_spec_zero) { + WORD32 ele_id, WORD32 *is_quant_spec_zero, + WORD32 *is_gain_limited) { IA_ERRORCODE err_code; WORD32 i = 0, sfb; WORD32 j = 0; @@ -473,6 +475,7 @@ IA_ERRORCODE iusace_quantize_spec(ia_sfb_params_struct *pstr_sfb_prms, WORD32 *ptr_num_sfb = pstr_sfb_prms->num_sfb; WORD32 *ptr_num_window_groups = pstr_sfb_prms->num_window_groups; WORD32 bitres_bits, bitres_diff; + WORD32 gain; memset(num_scfs, 0, 2 * sizeof(num_scfs[0])); @@ -531,7 +534,7 @@ IA_ERRORCODE iusace_quantize_spec(ia_sfb_params_struct *pstr_sfb_prms, idx = 0; for (ch = chn; ch < chn + num_chans; ch++) { iterations = 0; - + gain = 0; for (kk = 0; kk < ptr_usac_config->ccfl; kk++) { ptr_exp_spec[kk] = (FLOAT32)pstr_psy_out[ch].ptr_spec_coeffs[kk]; ptr_mdct_spec_float[kk] = (FLOAT32)pstr_psy_out[ch].ptr_spec_coeffs[kk]; @@ -544,6 +547,7 @@ IA_ERRORCODE iusace_quantize_spec(ia_sfb_params_struct *pstr_sfb_prms, sfb_offs += pstr_psy_out[ch].sfb_per_group) { for (sfb = 0; sfb < pstr_psy_out[ch].max_sfb_per_grp; sfb++) { WORD32 scalefactor = pstr_qc_out->str_qc_out_chan[idx].scalefactor[sfb + sfb_offs]; + gain = MAX(gain, pstr_qc_out->str_qc_out_chan[idx].global_gain - scalefactor); iusace_quantize_lines( pstr_qc_out->str_qc_out_chan[idx].global_gain - scalefactor, pstr_psy_out[ch].sfb_offsets[sfb_offs + sfb + 1] - @@ -600,18 +604,26 @@ IA_ERRORCODE iusace_quantize_spec(ia_sfb_params_struct *pstr_sfb_prms, if (max_bits > max_ch_dyn_bits[idx]) { constraints_fulfilled = 0; } - if (!constraints_fulfilled) { - pstr_qc_out->str_qc_out_chan[idx].global_gain++; - } if (quant_spec_is_zero == 1) { constraints_fulfilled = 1; - /*Bit consuption is exceding bit reserviour, there is no scope left for bit consumption + /*Bit consuption is exceding bit reservoir, there is no scope left for bit consumption reduction, as spectrum is zero. Hence breaking the quantization loop. */ if (iterations > 0) { *is_quant_spec_zero = 1; max_bits = max_ch_dyn_bits[idx]; } } + if ((gain == MAX_GAIN_INDEX) && (constraints_fulfilled == 0)) { + /* Bit consuption is exceding bit reservoir, there is no scope left for bit consumption + reduction, as gain has reached the maximum value. Hence breaking the quantization + loop. */ + constraints_fulfilled = 1; + *is_gain_limited = 1; + max_bits = max_ch_dyn_bits[idx]; + } + if (!constraints_fulfilled) { + pstr_qc_out->str_qc_out_chan[idx].global_gain++; + } iterations++; } while (!constraints_fulfilled); diff --git a/encoder/ixheaace_qc_main_hp.c b/encoder/ixheaace_qc_main_hp.c index 1a039ea..0eae6e6 100644 --- a/encoder/ixheaace_qc_main_hp.c +++ b/encoder/ixheaace_qc_main_hp.c @@ -75,7 +75,7 @@ IA_ERRORCODE ia_enhaacplus_enc_qc_main( ixheaace_qc_out_element *pstr_qc_out_element, WORD32 ancillary_data_bytes, ixheaace_aac_tables *pstr_aac_tables, WORD32 adts_flag, WORD32 aot, WORD32 stat_bits_flag, WORD32 flag_last_element, WORD32 frame_len_long, WORD8 *ptr_scratch, - WORD32 *is_quant_spec_zero) { + WORD32 *is_quant_spec_zero, WORD32 *is_gain_limited) { IA_ERRORCODE err_code; WORD32 ch; WORD32 i = 0; @@ -90,6 +90,7 @@ IA_ERRORCODE ia_enhaacplus_enc_qc_main( ptr_scratch += sizeof(ixheaace_qc_stack); ia_adj_thr_elem_struct *pstr_adj_thr_elem = &pstr_qc_state->str_adj_thr.str_adj_thr_ele; + WORD32 gain; if (pstr_el_bits->bit_res_level < 0) { return IA_EXHEAACE_EXE_FATAL_INVALID_BIT_RES_LEVEL; @@ -143,6 +144,7 @@ IA_ERRORCODE ia_enhaacplus_enc_qc_main( are fulfilled */ WORD32 spec_idx, sfb_offs, sfb; iterations = 0; + gain = 0; for (spec_idx = 0; spec_idx < frame_len_long; spec_idx++) { ptr_stack->exp_spec[spec_idx] = (FLOAT32)psy_out_ch[ch].ptr_spec_coeffs[spec_idx]; ptr_stack->mdct_spec_float[spec_idx] = (FLOAT32)psy_out_ch[ch].ptr_spec_coeffs[spec_idx]; @@ -156,6 +158,7 @@ IA_ERRORCODE ia_enhaacplus_enc_qc_main( sfb_offs += psy_out_ch[ch].sfb_per_group) { for (sfb = 0; sfb < psy_out_ch[ch].max_sfb_per_grp; sfb++) { WORD32 scalefactor = pstr_qc_out_ch[ch].scalefactor[sfb + sfb_offs]; + gain = MAX(gain, pstr_qc_out_ch[ch].global_gain - scalefactor); iaace_quantize_lines( pstr_qc_out_ch[ch].global_gain - scalefactor, psy_out_ch[ch].sfb_offsets[sfb_offs + sfb + 1] - @@ -204,19 +207,26 @@ IA_ERRORCODE ia_enhaacplus_enc_qc_main( constraints_fulfilled = 0; } - if (!constraints_fulfilled) { - pstr_qc_out_ch[ch].global_gain++; - } - if (quant_spec_is_zero == 1) { constraints_fulfilled = 1; - /*Bit consuption is exceding bit reserviour, there is no scope left for bit consumption + /*Bit consuption is exceding bit reservoir, there is no scope left for bit consumption reduction, as spectrum is zero. Hence breaking the quantization loop. */ if (iterations > 0) { *is_quant_spec_zero = 1; ch_dyn_bits = max_ch_dyn_bits[ch]; } } + if ((gain == MAX_GAIN_INDEX) && (constraints_fulfilled == 0)) { + /* Bit consuption is exceding bit reservoir, there is no scope left for bit consumption + reduction, as gain has reached the maximum value. Hence breaking the quantization + loop. */ + constraints_fulfilled = 1; + *is_gain_limited = 1; + ch_dyn_bits = max_ch_dyn_bits[ch]; + } + if (!constraints_fulfilled) { + pstr_qc_out_ch[ch].global_gain++; + } iterations++; } while (!constraints_fulfilled); diff --git a/encoder/ixheaace_qc_util.h b/encoder/ixheaace_qc_util.h index 3c9b025..3886472 100644 --- a/encoder/ixheaace_qc_util.h +++ b/encoder/ixheaace_qc_util.h @@ -38,7 +38,7 @@ IA_ERRORCODE ia_enhaacplus_enc_qc_main( ixheaace_qc_out_element *pstr_qc_out_element, WORD32 ancillary_data_bytes, ixheaace_aac_tables *pstr_aac_tables, WORD32 adts_flag, WORD32 aot, WORD32 stat_bits_flag, WORD32 flag_last_element, WORD32 frame_len_long, WORD8 *ptr_scratch, - WORD32 *is_quant_spec_zero); + WORD32 *is_quant_spec_zero, WORD32 *is_gain_limited); VOID ia_enhaacplus_enc_update_bit_reservoir(ixheaace_qc_state *pstr_qc_kernel, ixheaace_qc_out *pstr_qc_out); diff --git a/encoder/ixheaace_struct_def.h b/encoder/ixheaace_struct_def.h index 23ad23d..4f0c3c7 100644 --- a/encoder/ixheaace_struct_def.h +++ b/encoder/ixheaace_struct_def.h @@ -105,6 +105,7 @@ typedef struct ixheaace_state_struct { ixheaace_mps_212_memory_struct *mps_pers_mem; ixheaace_mps_515_memory_struct *mps_515_pers_mem; WORD32 is_quant_spec_zero; + WORD32 is_gain_limited; } ixheaace_state_struct; typedef struct ixheaace_api_struct { diff --git a/test/encoder/ixheaace_error.c b/test/encoder/ixheaace_error.c index ababe4e..eccb2f7 100644 --- a/test/encoder/ixheaace_error.c +++ b/test/encoder/ixheaace_error.c @@ -119,13 +119,15 @@ pWORD8 ppb_ia_enhaacplus_enc_sbr_init_fatal[IA_MAX_ERROR_SUB_CODE] = { *****************************************************************************/ /* Non Fatal Errors */ pWORD8 ppb_ia_enhaacplus_enc_aac_exe_non_fatal[IA_MAX_ERROR_SUB_CODE] = { - (pWORD8) "Quantization zero spectrum detected"}; + (pWORD8) "Quantization zero spectrum detected", + (pWORD8) "Insufficient bit reservoir for non zero spectrum"}; pWORD8 ppb_ia_enhaacplus_enc_mps_exe_non_fatal[IA_MAX_ERROR_SUB_CODE] = { (pWORD8) "Encoding Failed", (pWORD8) "Invalid MPS data bands"}; pWORD8 ppb_ia_enhaacplus_enc_usac_exe_non_fatal[IA_MAX_ERROR_SUB_CODE] = { - (pWORD8) "Quantization zero spectrum detected"}; + (pWORD8) "Quantization zero spectrum detected", + (pWORD8) "Insufficient bit reservoir for non zero spectrum"}; pWORD8 ppb_ia_enhaacplus_enc_esbr_exe_non_fatal[IA_MAX_ERROR_SUB_CODE] = { (pWORD8) "Invalid bandwidth index encountered",