345 lines
11 KiB
C
345 lines
11 KiB
C
/******************************************************************************
|
|
* *
|
|
* Copyright (C) 2023 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 "ixheaac_type_def.h"
|
|
#include "ixheaac_constants.h"
|
|
#include "ixheaace_psy_const.h"
|
|
#include "ixheaace_tns.h"
|
|
#include "ixheaace_tns_params.h"
|
|
#include "ixheaace_rom.h"
|
|
#include "ixheaace_common_rom.h"
|
|
#include "ixheaace_bitbuffer.h"
|
|
#include "ixheaace_aac_constants.h"
|
|
#include "ixheaace_write_adts_adif.h"
|
|
|
|
#include "ixheaac_basic_ops32.h"
|
|
#include "ixheaac_basic_ops16.h"
|
|
#include "ixheaac_basic_ops40.h"
|
|
#include "ixheaac_basic_ops.h"
|
|
#include "ixheaace_common_utils.h"
|
|
|
|
static VOID ia_enhaacplus_enc_putbit(ixheaace_bitstream_params *pstr_bitstream, UWORD32 data,
|
|
WORD32 num_bit) {
|
|
WORD32 num, max_num, curr_num;
|
|
WORD32 num_used, idx;
|
|
unsigned long bits;
|
|
WORD32 current_bitstream_bit;
|
|
UWORD8 *bitstream_data;
|
|
|
|
if (num_bit == 0) return;
|
|
|
|
current_bitstream_bit = pstr_bitstream->current_bit;
|
|
bitstream_data = pstr_bitstream->data;
|
|
|
|
/*
|
|
Functionality of Writing bits to the bitstream is split into 3 stages.
|
|
*/
|
|
|
|
/*
|
|
Stage #1: Write remainder bits to the partially filled byte
|
|
*/
|
|
|
|
num = 0;
|
|
num_used = current_bitstream_bit & 7;
|
|
max_num = BYTE_NUMBIT - num_used;
|
|
curr_num = MIN(num_bit, max_num);
|
|
bits = data >> (num_bit - curr_num);
|
|
|
|
idx = (current_bitstream_bit >> 3);
|
|
|
|
if (num_used == 0) bitstream_data[idx] = 0;
|
|
|
|
bitstream_data[idx] |= (bits & ((1 << curr_num) - 1)) << (max_num - curr_num);
|
|
current_bitstream_bit += curr_num;
|
|
num += curr_num;
|
|
|
|
/*
|
|
Stage #2:
|
|
At this point, (num + num_used), will be a multiple of 8
|
|
Now the bytes can be written directly to bitstream_data[], as long
|
|
as (num + 8) < num_bit
|
|
*/
|
|
|
|
while ((num + 8) < num_bit) {
|
|
num += 8;
|
|
current_bitstream_bit += 8;
|
|
bits = data >> (num_bit - num);
|
|
bitstream_data[++idx] = (UWORD8)bits;
|
|
}
|
|
|
|
/*
|
|
Stage #3: Write remainder bits from the data
|
|
*/
|
|
if (num < num_bit) {
|
|
curr_num = num_bit - num;
|
|
num_used = current_bitstream_bit & 7;
|
|
max_num = BYTE_NUMBIT - num_used;
|
|
idx = current_bitstream_bit >> 3;
|
|
if (num_used == 0) bitstream_data[idx] = 0;
|
|
bitstream_data[idx] |= (data & ((1 << curr_num) - 1)) << (max_num - curr_num);
|
|
current_bitstream_bit += curr_num;
|
|
}
|
|
|
|
pstr_bitstream->current_bit = current_bitstream_bit;
|
|
pstr_bitstream->num_bit = current_bitstream_bit;
|
|
}
|
|
|
|
static WORD16 ia_enhaacplus_enc_get_sample_rate_index(WORD32 sample_rate) {
|
|
if (92017 <= sample_rate) {
|
|
return 0;
|
|
}
|
|
if (75132 <= sample_rate) {
|
|
return 1;
|
|
}
|
|
if (55426 <= sample_rate) {
|
|
return 2;
|
|
}
|
|
if (46009 <= sample_rate) {
|
|
return 3;
|
|
}
|
|
if (37566 <= sample_rate) {
|
|
return 4;
|
|
}
|
|
if (27713 <= sample_rate) {
|
|
return 5;
|
|
}
|
|
if (23004 <= sample_rate) {
|
|
return 6;
|
|
}
|
|
if (18783 <= sample_rate) {
|
|
return 7;
|
|
}
|
|
if (13856 <= sample_rate) {
|
|
return 8;
|
|
}
|
|
if (11502 <= sample_rate) {
|
|
return 9;
|
|
}
|
|
if (9391 <= sample_rate) {
|
|
return 10;
|
|
}
|
|
return 11;
|
|
}
|
|
|
|
WORD32 ia_enhaacplus_enc_write_pce(WORD32 samp_rate, WORD32 ch_mask, WORD32 num_core_coder_chans,
|
|
ixheaace_bit_buf_handle pstr_bit_stream_handle) {
|
|
UWORD32 object_type = 0;
|
|
UWORD8 buffer[200];
|
|
ixheaace_bitstream_params bitstream_temp;
|
|
ixheaace_bitstream_params *pstr_bitstream = &bitstream_temp;
|
|
WORD32 write_flag = 1;
|
|
WORD32 start_bits = pstr_bit_stream_handle->cnt_bits, end_bits;
|
|
pstr_bitstream->data = buffer;
|
|
pstr_bitstream->num_bit = 8;
|
|
pstr_bitstream->current_bit = 0;
|
|
|
|
object_type = 01;
|
|
|
|
if (write_flag) {
|
|
WORD32 i;
|
|
WORD32 num_front_chan_ele, num_side_chan_ele, num_back_chan_ele, num_lfe_chan_ele;
|
|
|
|
/* element instance tag can be anything... writing 0 */
|
|
ixheaace_write_bits(pstr_bit_stream_handle, 0x00, 4);
|
|
|
|
/* object type --> LC / LTP / any other */
|
|
ixheaace_write_bits(pstr_bit_stream_handle, object_type, 2);
|
|
|
|
/* sampling freq index */
|
|
ixheaace_write_bits(pstr_bit_stream_handle,
|
|
ia_enhaacplus_enc_get_sample_rate_index(samp_rate), 4);
|
|
|
|
/* num_front_channel_elements --> only this present for mono / stereo */
|
|
num_front_chan_ele = 0;
|
|
|
|
if (ch_mask & 0x3) {
|
|
num_front_chan_ele++; /*Front Left and Right Present*/
|
|
}
|
|
if (ch_mask & 0x4) {
|
|
num_front_chan_ele++; /*Front Center Present*/
|
|
}
|
|
ixheaace_write_bits(pstr_bit_stream_handle, num_front_chan_ele, 4);
|
|
|
|
/* num_side_channel_elements 4 */
|
|
num_side_chan_ele = 0;
|
|
|
|
if (ch_mask & 0xC0) {
|
|
num_side_chan_ele++; /*Back Left and Right Present*/
|
|
}
|
|
ixheaace_write_bits(pstr_bit_stream_handle, num_side_chan_ele, 4);
|
|
|
|
/* num_back_channel_elements 4 */
|
|
num_back_chan_ele = 0;
|
|
|
|
if (ch_mask & 0x30) {
|
|
num_back_chan_ele++; /*Back Left and Right of center Present*/
|
|
}
|
|
ixheaace_write_bits(pstr_bit_stream_handle, num_back_chan_ele, 4);
|
|
|
|
/* num_lfe_channel_elements 2 */
|
|
num_lfe_chan_ele = 0;
|
|
|
|
if (ch_mask & 0x8) {
|
|
num_lfe_chan_ele++; /*LFE channel Present*/
|
|
}
|
|
ixheaace_write_bits(pstr_bit_stream_handle, num_lfe_chan_ele, 2);
|
|
|
|
/* num_assoc_data_elements 3 */
|
|
ixheaace_write_bits(pstr_bit_stream_handle, 0x00, 3);
|
|
|
|
/* num_valid_cc_elements 4 */
|
|
ixheaace_write_bits(pstr_bit_stream_handle, num_core_coder_chans, 4);
|
|
|
|
/* mono mix down is zero */
|
|
ixheaace_write_bits(pstr_bit_stream_handle, 0x00, 1);
|
|
|
|
/* mono_mixdown_element_number 4 if mono_mixdown_present == 1 */
|
|
|
|
/* stereo_mixdown_present is zero */
|
|
ixheaace_write_bits(pstr_bit_stream_handle, 0x00, 1);
|
|
|
|
/* stereo_mixdown_element_number 4 if stereo_mixdown_present == 1 */
|
|
|
|
/* matrix_mixdown_idx_present is zero */
|
|
ixheaace_write_bits(pstr_bit_stream_handle, 0x00, 1);
|
|
|
|
{
|
|
/* stereo --> 1 mono --> 0 */
|
|
if (ch_mask & 0x4) {
|
|
ixheaace_write_bits(pstr_bit_stream_handle, 0x00, 1);
|
|
/* element tag select */
|
|
ixheaace_write_bits(pstr_bit_stream_handle, 0x00, 4);
|
|
}
|
|
if (ch_mask & 0x3) {
|
|
if ((ch_mask & 0x3) == 0x3) {
|
|
/* stereo channel */
|
|
ixheaace_write_bits(pstr_bit_stream_handle, 0x01, 1);
|
|
} else {
|
|
/* mono channel */
|
|
ixheaace_write_bits(pstr_bit_stream_handle, 0x00, 1);
|
|
}
|
|
|
|
/* element tag select */
|
|
ixheaace_write_bits(pstr_bit_stream_handle, 0x00, 4);
|
|
}
|
|
}
|
|
|
|
for (i = 0; i < num_side_chan_ele; i++) {
|
|
if ((ch_mask & 0xC0) == 0xC0) {
|
|
/* stereo channel */
|
|
ixheaace_write_bits(pstr_bit_stream_handle, 0x01, 1);
|
|
} else {
|
|
/* mono channel */
|
|
ixheaace_write_bits(pstr_bit_stream_handle, 0x00, 1);
|
|
}
|
|
|
|
/* element tag select */
|
|
ixheaace_write_bits(pstr_bit_stream_handle, 0x02, 4);
|
|
}
|
|
|
|
for (i = 0; i < num_back_chan_ele; i++) {
|
|
if ((ch_mask & 0x30) == 0x30) {
|
|
/* stereo channel */
|
|
ixheaace_write_bits(pstr_bit_stream_handle, 0x01, 1);
|
|
} else {
|
|
/* mono channel */
|
|
ixheaace_write_bits(pstr_bit_stream_handle, 0x00, 1);
|
|
}
|
|
|
|
/* element tag select */
|
|
ixheaace_write_bits(pstr_bit_stream_handle, 0x01, 4);
|
|
}
|
|
|
|
for (i = 0; i < num_lfe_chan_ele; i++) {
|
|
/* element tag select */
|
|
ixheaace_write_bits(pstr_bit_stream_handle, 0x00, 4);
|
|
}
|
|
|
|
/* loop for independent coupling elements */
|
|
for (i = 0; i < num_core_coder_chans; i++) {
|
|
/* It is independent coupling channel */
|
|
ixheaace_write_bits(pstr_bit_stream_handle, 0x01, 1);
|
|
|
|
/* element tag select */
|
|
ixheaace_write_bits(pstr_bit_stream_handle, num_core_coder_chans - i - 1, 4);
|
|
}
|
|
|
|
/* byte align the stream */
|
|
ixheaace_write_bits(pstr_bit_stream_handle, 0,
|
|
(UWORD8)((8 - (pstr_bit_stream_handle->cnt_bits % 8)) % 8));
|
|
/* comment field types --> do not quite know what this is */
|
|
ixheaace_write_bits(pstr_bit_stream_handle, 0x00, 8);
|
|
}
|
|
|
|
end_bits = pstr_bit_stream_handle->cnt_bits;
|
|
|
|
return (end_bits - start_bits);
|
|
}
|
|
|
|
WORD32 ia_enhaacplus_enc_write_ADTS_header(pUWORD8 buffer, WORD32 bytes_used, WORD32 samp_rate,
|
|
WORD32 num_ch) {
|
|
WORD32 bits = 56;
|
|
UWORD32 object_type = 0;
|
|
ixheaace_bitstream_params bitstream_temp;
|
|
ixheaace_bitstream_params *pstr_bitstream = &bitstream_temp;
|
|
WORD32 write_flag = 1;
|
|
pstr_bitstream->data = buffer;
|
|
pstr_bitstream->num_bit = 8;
|
|
|
|
pstr_bitstream->current_bit = 0;
|
|
;
|
|
object_type = 01;
|
|
|
|
if (write_flag) {
|
|
/* Fixed ADTS header */
|
|
ia_enhaacplus_enc_putbit(pstr_bitstream, 0xFFFF, 12); /* 12 bit Syncword */
|
|
ia_enhaacplus_enc_putbit(pstr_bitstream, 0 /*aacStateStruct->aacConfigSturct.mpegVersion*/,
|
|
1); /* ID == 0 for MPEG4 AAC, 1 for MPEG2 AAC */
|
|
ia_enhaacplus_enc_putbit(pstr_bitstream, 0, 2); /* layer == 0 */
|
|
ia_enhaacplus_enc_putbit(pstr_bitstream, 1, 1); /* protection absent */
|
|
ia_enhaacplus_enc_putbit(pstr_bitstream, object_type, 2); /* profile */
|
|
ia_enhaacplus_enc_putbit(
|
|
pstr_bitstream,
|
|
ia_enhaacplus_enc_get_sample_rate_index(samp_rate) /*aacStateStruct->sampleRateIdx*/,
|
|
4); /* sampling rate */
|
|
ia_enhaacplus_enc_putbit(pstr_bitstream, 0, 1); /* private bit */
|
|
ia_enhaacplus_enc_putbit(pstr_bitstream, num_ch /*aacStateStruct->aacConfigSturct.ch*/,
|
|
3); /* ch. aacConfigSturct (must be > 0) */
|
|
/* simply using num_channels only works for
|
|
6 channels or less, else a channel
|
|
configuration should be written */
|
|
ia_enhaacplus_enc_putbit(pstr_bitstream, 0, 1); /* original/copy */
|
|
ia_enhaacplus_enc_putbit(pstr_bitstream, 0, 1); /* home */
|
|
|
|
/* Variable ADTS header */
|
|
ia_enhaacplus_enc_putbit(pstr_bitstream, 0, 1); /* copyr. id. bit */
|
|
ia_enhaacplus_enc_putbit(pstr_bitstream, 0, 1); /* copyr. id. start */
|
|
ia_enhaacplus_enc_putbit(pstr_bitstream, /*aacStateStruct->*/ bytes_used + 7, 13);
|
|
ia_enhaacplus_enc_putbit(pstr_bitstream, 0x7FF, 11); /* buffer fullness (0x7FF for VBR) */
|
|
|
|
ia_enhaacplus_enc_putbit(pstr_bitstream, 0, 2); /* raw data blocks (0+1=1) */
|
|
}
|
|
|
|
/*
|
|
* MPEG2 says byte_aligment() here, but ADTS always is multiple of 8 bits
|
|
* MPEG4 has no byte_alignment() here
|
|
*/
|
|
return bits / 8;
|
|
}
|