406 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			C
		
	
	
	
			
		
		
	
	
			406 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			C
		
	
	
	
| /******************************************************************************
 | |
|  *                                                                            *
 | |
|  * 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;
 | |
|   }
 | |
| }
 |