/****************************************************************************** * * * Copyright (C) 2018 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * ***************************************************************************** * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore */ #include #include "ixheaacd_type_def.h" #include "ixheaacd_sbr_common.h" #include "ixheaacd_constants.h" #include "ixheaacd_basic_ops32.h" #include "ixheaacd_basic_ops16.h" #include "ixheaacd_basic_ops40.h" #include "ixheaacd_basic_ops.h" #include "ixheaacd_bitbuffer.h" #include "ixheaacd_audioobjtypes.h" #include "ixheaacd_sbrdecsettings.h" #include "ixheaacd_memory_standards.h" #include "ixheaacd_error_codes.h" #include "ixheaacd_defines.h" #include "ixheaacd_aac_rom.h" #include "ixheaacd_pns.h" #include "ixheaacd_pulsedata.h" #include "ixheaacd_drc_data_struct.h" #include "ixheaacd_lt_predict.h" #include "ixheaacd_channelinfo.h" #include "ixheaacd_drc_dec.h" #include "ixheaacd_sbrdecoder.h" #include "ixheaacd_sbr_scale.h" #include "ixheaacd_lpp_tran.h" #include "ixheaacd_env_extr_part.h" #include "ixheaacd_sbr_rom.h" #include "ixheaacd_hybrid.h" #include "ixheaacd_ps_dec.h" #include "ixheaacd_ps_bitdec.h" #include "ixheaacd_pulsedata.h" #include "ixheaacd_pns.h" #include "ixheaacd_env_extr.h" #include "ixheaacd_common_rom.h" #include "ixheaacd_block.h" #include "ixheaacd_channel.h" #include "ixheaacd_audioobjtypes.h" #include "ixheaacd_latmdemux.h" #include "ixheaacd_aacdec.h" #include "ixheaacd_config.h" #include "ixheaacd_mps_polyphase.h" #include "ixheaacd_mps_dec.h" #include "ixheaacd_struct_def.h" #include "ixheaacd_headerdecode.h" #include "ixheaacd_multichannel.h" #include "ixheaacd_basic_op.h" WORD cblock_decode_huff_symbol(UWORD8 *ptr_read_next, WORD32 bit_pos, const UWORD16 *huff_ori, WORD16 *input, WORD32 *readword) { const UWORD16 *h; WORD tot_bits; { UWORD16 first_offset; WORD16 sign_ret_val; UWORD32 read_word1; read_word1 = *readword << bit_pos; h = (UWORD16 *)(huff_ori); first_offset = 7; h += (read_word1) >> (32 - first_offset); sign_ret_val = *h; tot_bits = 0; while (sign_ret_val > 0) { tot_bits += first_offset; bit_pos += first_offset; if ((bit_pos -= 8) >= 0) { *readword = (*readword << 8) | *ptr_read_next; ptr_read_next++; } else { bit_pos += 8; } read_word1 = (read_word1) << (first_offset); first_offset = (sign_ret_val >> 11); h += sign_ret_val & (0x07FF); h += (read_word1) >> (32 - first_offset); sign_ret_val = *h; } tot_bits += ((sign_ret_val & 0x7fff) >> 11); bit_pos += ((sign_ret_val & 0x7fff) >> 11); if ((bit_pos - 8) >= 0) { *readword = (*readword << 8) | *ptr_read_next; } *input = (sign_ret_val & (0x07FF)) - 60; } return tot_bits; } IA_ERRORCODE ixheaacd_dec_coupling_channel_element( ia_handle_bit_buf_struct bs, ia_aac_decoder_struct *aac_handle, WORD32 samp_rate_idx, ia_aac_dec_tables_struct *ptr_aac_tables, ixheaacd_misc_tables *common_tables_ptr, WORD *element_index_order, ia_enhaacplus_dec_ind_cc *ind_channel_info, WORD32 total_channels, WORD32 frame_size, WORD32 audio_object_type, ia_eld_specific_config_struct eld_specific_config, WORD32 ele_type) { WORD32 element_instance_tag; LOOPIDX c; WORD ind_sw_cce_flag, num_coupled_elements; WORD num_gain_element_lists = 0; WORD cc_domain; WORD gain_element_sign; WORD gain_element_scale; const UWORD16 *hcod_sf = ptr_aac_tables->pstr_huffmann_tables->huffman_code_book_scl; const UWORD32 *table_idx = ptr_aac_tables->pstr_huffmann_tables->huffman_code_book_scl_index; WORD16 index, length; IA_ERRORCODE error_status = IA_NO_ERROR; element_instance_tag = ixheaacd_read_bits_buf(bs, 4); element_index_order[0] = element_instance_tag; ind_sw_cce_flag = ixheaacd_read_bits_buf(bs, 1); num_coupled_elements = ixheaacd_read_bits_buf(bs, 3); for (c = 0; c < MAX_BS_ELEMENT; c++) ind_channel_info->elements_coupled[c] = -1; ind_channel_info->num_coupled_elements = num_coupled_elements; for (c = 0; c < (num_coupled_elements + 1); c++) { num_gain_element_lists++; ind_channel_info->cc_target_is_cpe[c] = ixheaacd_read_bits_buf(bs, 1); ind_channel_info->cc_target_tag_select[c] = ixheaacd_read_bits_buf(bs, 4); if (ind_channel_info->cc_target_is_cpe[c]) { ind_channel_info->cc_l[c] = ixheaacd_read_bits_buf(bs, 1); ind_channel_info->cc_r[c] = ixheaacd_read_bits_buf(bs, 1); if (ind_channel_info->cc_l[c] && ind_channel_info->cc_r[c]) num_gain_element_lists++; ind_channel_info->elements_coupled[c] = 1; } else ind_channel_info->elements_coupled[c] = 0; } if ((ind_sw_cce_flag == 0) && (num_gain_element_lists > MAX_BS_ELEMENT)) { return IA_FATAL_ERROR; } cc_domain = ixheaacd_read_bits_buf(bs, 1); gain_element_sign = ixheaacd_read_bits_buf(bs, 1); gain_element_scale = ixheaacd_read_bits_buf(bs, 2); aac_handle->pstr_aac_dec_ch_info[0]->str_ics_info.num_swb_window = 0; aac_handle->pstr_aac_dec_ch_info[0]->str_ics_info.sampling_rate_index = samp_rate_idx; aac_handle->pstr_aac_dec_ch_info[0]->common_window = 0; error_status = ixheaacd_individual_ch_stream( bs, aac_handle, 1, frame_size, total_channels, audio_object_type, eld_specific_config, ele_type); if (error_status) return error_status; ind_channel_info->cc_gain[0] = 1 << 29; for (c = 1; c < num_gain_element_lists; c++) { WORD cge; WORD common_gain_element_present[MAX_BS_ELEMENT]; WORD16 norm_value; if (ind_sw_cce_flag) cge = 1; else { common_gain_element_present[c] = ixheaacd_read_bits_buf(bs, 1); cge = common_gain_element_present[c]; return IA_ENHAACPLUS_DEC_EXE_FATAL_UNIMPLEMENTED_CCE; } if (cge) { UWORD8 *ptr_read_next = bs->ptr_read_next; WORD32 bit_pos = 7 - bs->bit_pos; WORD32 read_word = ixheaacd_aac_showbits_32(bs->ptr_read_next, bs->cnt_bits, NULL); UWORD32 read_word1; read_word1 = read_word << bit_pos; ixheaacd_huffman_decode(read_word1, &index, &length, hcod_sf, table_idx); bit_pos += length; ixheaacd_aac_read_byte(&ptr_read_next, &bit_pos, &read_word); while (bit_pos > 8) ixheaacd_aac_read_byte(&ptr_read_next, &bit_pos, &read_word); bs->ptr_read_next = ptr_read_next; bs->bit_pos = 7 - bit_pos; bs->cnt_bits -= length; norm_value = index - 60; if (norm_value == -1) ind_channel_info->cc_gain[c] = common_tables_ptr->cc_gain_scale[gain_element_scale]; else { int i; ind_channel_info->cc_gain[c] = common_tables_ptr->cc_gain_scale[gain_element_scale]; for (i = 0; i < (-norm_value) - 1; i++) { ind_channel_info->cc_gain[c] = ixheaacd_mul32_sh( ind_channel_info->cc_gain[c], common_tables_ptr->cc_gain_scale[gain_element_scale], 29); } } } else { return IA_ENHAACPLUS_DEC_EXE_FATAL_UNIMPLEMENTED_CCE; } } if (bs->cnt_bits < 0) { return IA_ENHAACPLUS_DEC_EXE_NONFATAL_INSUFFICIENT_INPUT_BYTES; } return error_status; } void ixheaacd_dec_couple_channel(WORD16 *p_time_data, WORD16 *out_samp_cc, WORD16 frame_size, WORD total_channels, WORD32 gain_cc) { WORD i; WORD16 out_cc; WORD16 *ptr_out_samp = &out_samp_cc[0]; for (i = frame_size - 1; i >= 0; i--) { out_cc = ixheaacd_round16(ixheaacd_shl32_sat( ixheaacd_mult32x16in32(gain_cc, *ptr_out_samp++), 3)); *p_time_data = ixheaacd_add16_sat(out_cc, *p_time_data); p_time_data += total_channels; } } void ixheaacd_dec_ind_coupling( ia_exhaacplus_dec_api_struct *p_obj_exhaacplus_dec, WORD16 *coup_ch_output, WORD16 frame_size, WORD total_channels, WORD16 *ptr_time_data) { WORD c, j, k; WORD l; WORD coupling_channel; WORD16 *out_samp_cc; ia_enhaacplus_dec_ind_cc *ind_channel_info; { coupling_channel = p_obj_exhaacplus_dec->aac_config.ui_coupling_channel; ind_channel_info = &p_obj_exhaacplus_dec->p_state_aac->ind_cc_info; out_samp_cc = coup_ch_output; j = 0; for (c = 0; c < ind_channel_info->num_coupled_elements + 1; c++) { for (l = 0; l < MAX_BS_ELEMENT; l++) { if (p_obj_exhaacplus_dec->aac_config.element_type[l] == ind_channel_info->elements_coupled[c] && p_obj_exhaacplus_dec->aac_config.element_instance_order[l] == ind_channel_info->cc_target_tag_select[c]) { break; } } if (l == MAX_BS_ELEMENT) { continue; } k = p_obj_exhaacplus_dec->aac_config.slot_element[l]; if (ind_channel_info->cc_target_is_cpe[c] == 0) { WORD16 *p_time_data = &ptr_time_data[k]; WORD32 gain_cc = ind_channel_info->cc_gain[j]; ixheaacd_dec_couple_channel(p_time_data, out_samp_cc, frame_size, total_channels, gain_cc); } if (ind_channel_info->cc_target_is_cpe[c] == 1) { if (ind_channel_info->cc_l[c] == 1) { WORD16 *p_time_data = &ptr_time_data[k]; WORD32 gain_cc = ind_channel_info->cc_gain[j]; ixheaacd_dec_couple_channel(p_time_data, out_samp_cc, frame_size, total_channels, gain_cc); } k = p_obj_exhaacplus_dec->aac_config.slot_element[l]; if (ind_channel_info->cc_r[c] == 1) { WORD16 *p_time_data = &ptr_time_data[k + 1]; WORD32 gain_cc = ind_channel_info->cc_gain[j + 1]; ixheaacd_dec_couple_channel(p_time_data, out_samp_cc, frame_size, total_channels, gain_cc); } } if (ind_channel_info->cc_target_is_cpe[c] == 1) { j += 2; } else { j += 1; } } } } void ixheaacd_dec_downmix_to_stereo( ia_exhaacplus_dec_api_struct *p_obj_exhaacplus_dec, WORD16 frame_size, WORD total_elements, WORD16 *ptr_time_data, WORD total_channels) { LOOPIDX i, j; WORD k = 0; if (5 == total_channels) k = 0; if (6 == total_channels) k = 1; if (7 == total_channels) k = 2; if (8 == total_channels) k = 3; for (j = 0; j < frame_size; j++) { WORD16 temp_l = 0, temp_r = 0; for (i = 0; i < total_elements; i++) { if (0 == p_obj_exhaacplus_dec->aac_config.element_type[i] || 3 == p_obj_exhaacplus_dec->aac_config.element_type[i]) { temp_l += (WORD16)( ixheaacd_mult32x16in32( p_obj_exhaacplus_dec->common_tables->down_mix_martix [k][0][p_obj_exhaacplus_dec->aac_config.slot_element[i]], ptr_time_data[j * total_channels + p_obj_exhaacplus_dec->aac_config .slot_element[i]]) >> 14); temp_r += (WORD16)( ixheaacd_mult32x16in32( p_obj_exhaacplus_dec->common_tables->down_mix_martix [k][1][p_obj_exhaacplus_dec->aac_config.slot_element[i]], ptr_time_data[j * total_channels + p_obj_exhaacplus_dec->aac_config .slot_element[i]]) >> 14); } if (1 == p_obj_exhaacplus_dec->aac_config.element_type[i]) { temp_l += (WORD16)( ixheaacd_mult32x16in32( p_obj_exhaacplus_dec->common_tables->down_mix_martix [k][0][p_obj_exhaacplus_dec->aac_config.slot_element[i]], ptr_time_data[j * total_channels + p_obj_exhaacplus_dec->aac_config .slot_element[i]]) >> 14); temp_r += (WORD16)( ixheaacd_mult32x16in32( p_obj_exhaacplus_dec->common_tables->down_mix_martix [k][1] [p_obj_exhaacplus_dec->aac_config.slot_element[i] + 1], ptr_time_data[j * total_channels + p_obj_exhaacplus_dec->aac_config.slot_element[i] + 1]) >> 14); } } ptr_time_data[2 * j] = temp_l; ptr_time_data[2 * j + 1] = temp_r; } }