| /****************************************************************************** |
| * * |
| * 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 <string.h> |
| |
| #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; |
| } |
| } |