You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
379 lines
11 KiB
379 lines
11 KiB
/****************************************************************************** |
|
* |
|
* Copyright (C) 2014 The Android Open Source Project |
|
* Copyright 2003 - 2004 Open Interface North America, Inc. All rights |
|
* reserved. |
|
* |
|
* 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. |
|
* |
|
******************************************************************************/ |
|
|
|
/******************************************************************************* |
|
$Revision: #1 $ |
|
******************************************************************************/ |
|
|
|
/** |
|
@file |
|
|
|
The functions in this file relate to the allocation of available bits to |
|
subbands within the SBC/eSBC frame, along with support functions for computing |
|
frame length and bitrate. |
|
|
|
@ingroup codec_internal |
|
*/ |
|
|
|
/** |
|
@addtogroup codec_internal |
|
@{ |
|
*/ |
|
|
|
#include <oi_codec_sbc_private.h> |
|
#include "oi_utils.h" |
|
|
|
uint32_t OI_SBC_MaxBitpool(OI_CODEC_SBC_FRAME_INFO* frame) { |
|
switch (frame->mode) { |
|
case SBC_MONO: |
|
case SBC_DUAL_CHANNEL: |
|
return 16 * frame->nrof_subbands; |
|
case SBC_STEREO: |
|
case SBC_JOINT_STEREO: |
|
return 32 * frame->nrof_subbands; |
|
} |
|
|
|
ERROR(("Invalid frame mode %d", frame->mode)); |
|
OI_ASSERT(false); |
|
return 0; /* Should never be reached */ |
|
} |
|
|
|
PRIVATE uint16_t internal_CalculateFramelen(OI_CODEC_SBC_FRAME_INFO* frame) { |
|
uint16_t nbits = frame->nrof_blocks * frame->bitpool; |
|
uint16_t nrof_subbands = frame->nrof_subbands; |
|
uint16_t result = nbits; |
|
|
|
if (frame->mode == SBC_JOINT_STEREO) { |
|
result += nrof_subbands + (8 * nrof_subbands); |
|
} else { |
|
if (frame->mode == SBC_DUAL_CHANNEL) { |
|
result += nbits; |
|
} |
|
if (frame->mode == SBC_MONO) { |
|
result += 4 * nrof_subbands; |
|
} else { |
|
result += 8 * nrof_subbands; |
|
} |
|
} |
|
return SBC_HEADER_LEN + (result + 7) / 8; |
|
} |
|
|
|
PRIVATE uint32_t internal_CalculateBitrate(OI_CODEC_SBC_FRAME_INFO* frame) { |
|
OI_UINT blocksbands; |
|
blocksbands = frame->nrof_subbands * frame->nrof_blocks; |
|
|
|
return DIVIDE(8 * internal_CalculateFramelen(frame) * frame->frequency, |
|
blocksbands); |
|
} |
|
|
|
INLINE uint16_t OI_SBC_CalculateFrameAndHeaderlen( |
|
OI_CODEC_SBC_FRAME_INFO* frame, OI_UINT* headerLen_) { |
|
OI_UINT headerLen = |
|
SBC_HEADER_LEN + frame->nrof_subbands * frame->nrof_channels / 2; |
|
|
|
if (frame->mode == SBC_JOINT_STEREO) { |
|
headerLen++; |
|
} |
|
|
|
*headerLen_ = headerLen; |
|
return internal_CalculateFramelen(frame); |
|
} |
|
|
|
#define MIN(x, y) ((x) < (y) ? (x) : (y)) |
|
|
|
/* |
|
* Computes the bit need for each sample and as also returns a counts of bit |
|
* needs that are greater than one. This count is used in the first phase of bit |
|
* allocation. |
|
* |
|
* We also compute a preferred bitpool value that this is the minimum bitpool |
|
* needed to guarantee lossless representation of the audio data. The preferred |
|
* bitpool may be larger than the bits actually required but the only input we |
|
* have are the scale factors. For example, it takes 2 bits to represent values |
|
* in the range -1 .. +1 but the scale factor is 0. To guarantee lossless |
|
* representation we add 2 to each scale factor and sum them to come up with the |
|
* preferred bitpool. This is not ideal because 0 requires 0 bits but we |
|
* currently have no way of knowing this. |
|
* |
|
* @param bitneed Array to return bitneeds for each subband |
|
* |
|
* @param ch Channel 0 or 1 |
|
* |
|
* @param preferredBitpool Returns the number of reserved bits |
|
* |
|
* @return The SBC bit need |
|
* |
|
*/ |
|
OI_UINT computeBitneed(OI_CODEC_SBC_COMMON_CONTEXT* common, uint8_t* bitneeds, |
|
OI_UINT ch, OI_UINT* preferredBitpool) { |
|
static const int8_t offset4[4][4] = { |
|
{-1, 0, 0, 0}, {-2, 0, 0, 1}, {-2, 0, 0, 1}, {-2, 0, 0, 1}}; |
|
|
|
static const int8_t offset8[4][8] = {{-2, 0, 0, 0, 0, 0, 0, 1}, |
|
{-3, 0, 0, 0, 0, 0, 1, 2}, |
|
{-4, 0, 0, 0, 0, 0, 1, 2}, |
|
{-4, 0, 0, 0, 0, 0, 1, 2}}; |
|
|
|
const OI_UINT nrof_subbands = common->frameInfo.nrof_subbands; |
|
OI_UINT sb; |
|
int8_t* scale_factor = &common->scale_factor[ch ? nrof_subbands : 0]; |
|
OI_UINT bitcount = 0; |
|
uint8_t maxBits = 0; |
|
uint8_t prefBits = 0; |
|
|
|
if (common->frameInfo.alloc == SBC_SNR) { |
|
for (sb = 0; sb < nrof_subbands; sb++) { |
|
OI_INT bits = scale_factor[sb]; |
|
if (bits > maxBits) { |
|
maxBits = bits; |
|
} |
|
bitneeds[sb] = bits; |
|
if (bitneeds[sb] > 1) { |
|
bitcount += bits; |
|
} |
|
prefBits += 2 + bits; |
|
} |
|
} else { |
|
const int8_t* offset; |
|
if (nrof_subbands == 4) { |
|
offset = offset4[common->frameInfo.freqIndex]; |
|
} else { |
|
offset = offset8[common->frameInfo.freqIndex]; |
|
} |
|
for (sb = 0; sb < nrof_subbands; sb++) { |
|
OI_INT bits = scale_factor[sb]; |
|
if (bits > maxBits) { |
|
maxBits = bits; |
|
} |
|
prefBits += 2 + bits; |
|
if (bits) { |
|
bits -= offset[sb]; |
|
if (bits > 0) { |
|
bits /= 2; |
|
} |
|
bits += 5; |
|
} |
|
bitneeds[sb] = bits; |
|
if (bitneeds[sb] > 1) { |
|
bitcount += bits; |
|
} |
|
} |
|
} |
|
common->maxBitneed = OI_MAX(maxBits, common->maxBitneed); |
|
*preferredBitpool += prefBits; |
|
return bitcount; |
|
} |
|
|
|
/* |
|
* Explanation of the adjustToFitBitpool inner loop. |
|
* |
|
* The inner loop computes the effect of adjusting the bit allocation up or |
|
* down. Allocations must be 0 or in the range 2..16. This is accomplished by |
|
* the following code: |
|
* |
|
* for (s = bands - 1; s >= 0; --s) { |
|
* OI_INT bits = bitadjust + bitneeds[s]; |
|
* bits = bits < 2 ? 0 : bits; |
|
* bits = bits > 16 ? 16 : bits; |
|
* count += bits; |
|
* } |
|
* |
|
* This loop can be optimized to perform 4 operations at a time as follows: |
|
* |
|
* Adjustment is computed as a 7 bit signed value and added to the bitneed. |
|
* |
|
* Negative allocations are zeroed by masking. (n & 0x40) >> 6 puts the |
|
* sign bit into bit 0, adding this to 0x7F give us a mask of 0x80 |
|
* for -ve values and 0x7F for +ve values. |
|
* |
|
* n &= 0x7F + (n & 0x40) >> 6) |
|
* |
|
* Allocations greater than 16 are truncated to 16. Adjusted allocations are in |
|
* the range 0..31 so we know that bit 4 indicates values >= 16. We use this bit |
|
* to create a mask that zeroes bits 0 .. 3 if bit 4 is set. |
|
* |
|
* n &= (15 + (n >> 4)) |
|
* |
|
* Allocations of 1 are disallowed. Add and shift creates a mask that |
|
* eliminates the illegal value |
|
* |
|
* n &= ((n + 14) >> 4) | 0x1E |
|
* |
|
* These operations can be performed in 8 bits without overflowing so we can |
|
* operate on 4 values at once. |
|
*/ |
|
|
|
/* |
|
* Encoder/Decoder |
|
* |
|
* Computes adjustment +/- of bitneeds to fill bitpool and returns overall |
|
* adjustment and excess bits. |
|
* |
|
* @param bitpool The bitpool we have to work within |
|
* |
|
* @param bitneeds An array of bit needs (more acturately allocation |
|
* prioritities) for each subband across all blocks in the SBC |
|
* frame |
|
* |
|
* @param subbands The number of subbands over which the adkustment is |
|
* calculated. For mono and dual mode this is 4 or 8, for |
|
* stereo or joint stereo this is 8 or 16. |
|
* |
|
* @param bitcount A starting point for the adjustment |
|
* |
|
* @param excess Returns the excess bits after the adjustment |
|
* |
|
* @return The adjustment. |
|
*/ |
|
OI_INT adjustToFitBitpool(const OI_UINT bitpool, uint32_t* bitneeds, |
|
const OI_UINT subbands, OI_UINT bitcount, |
|
OI_UINT* excess) { |
|
OI_INT maxBitadjust = 0; |
|
OI_INT bitadjust = (bitcount > bitpool) ? -8 : 8; |
|
OI_INT chop = 8; |
|
|
|
/* |
|
* This is essentially a binary search for the optimal adjustment value. |
|
*/ |
|
while ((bitcount != bitpool) && chop) { |
|
uint32_t total = 0; |
|
OI_UINT count; |
|
uint32_t adjust4; |
|
OI_INT i; |
|
|
|
adjust4 = bitadjust & 0x7F; |
|
adjust4 |= (adjust4 << 8); |
|
adjust4 |= (adjust4 << 16); |
|
|
|
for (i = (subbands / 4 - 1); i >= 0; --i) { |
|
uint32_t mask; |
|
uint32_t n = bitneeds[i] + adjust4; |
|
mask = 0x7F7F7F7F + ((n & 0x40404040) >> 6); |
|
n &= mask; |
|
mask = 0x0F0F0F0F + ((n & 0x10101010) >> 4); |
|
n &= mask; |
|
mask = (((n + 0x0E0E0E0E) >> 4) | 0x1E1E1E1E); |
|
n &= mask; |
|
total += n; |
|
} |
|
|
|
count = (total & 0xFFFF) + (total >> 16); |
|
count = (count & 0xFF) + (count >> 8); |
|
|
|
chop >>= 1; |
|
if (count > bitpool) { |
|
bitadjust -= chop; |
|
} else { |
|
maxBitadjust = bitadjust; |
|
bitcount = count; |
|
bitadjust += chop; |
|
} |
|
} |
|
|
|
*excess = bitpool - bitcount; |
|
|
|
return maxBitadjust; |
|
} |
|
|
|
/* |
|
* The bit allocator trys to avoid single bit allocations except as a last |
|
* resort. So in the case where a bitneed of 1 was passed over during the |
|
* adsjustment phase 2 bits are now allocated. |
|
*/ |
|
INLINE OI_INT allocAdjustedBits(uint8_t* dest, OI_INT bits, OI_INT excess) { |
|
if (bits < 16) { |
|
if (bits > 1) { |
|
if (excess) { |
|
++bits; |
|
--excess; |
|
} |
|
} else if ((bits == 1) && (excess > 1)) { |
|
bits = 2; |
|
excess -= 2; |
|
} else { |
|
bits = 0; |
|
} |
|
} else { |
|
bits = 16; |
|
} |
|
*dest = (uint8_t)bits; |
|
return excess; |
|
} |
|
|
|
/* |
|
* Excess bits not allocated by allocaAdjustedBits are allocated round-robin. |
|
*/ |
|
INLINE OI_INT allocExcessBits(uint8_t* dest, OI_INT excess) { |
|
if (*dest < 16) { |
|
*dest += 1; |
|
return excess - 1; |
|
} else { |
|
return excess; |
|
} |
|
} |
|
|
|
void oneChannelBitAllocation(OI_CODEC_SBC_COMMON_CONTEXT* common, |
|
BITNEED_UNION1* bitneeds, OI_UINT ch, |
|
OI_UINT bitcount) { |
|
const uint8_t nrof_subbands = common->frameInfo.nrof_subbands; |
|
OI_UINT excess; |
|
OI_UINT sb; |
|
OI_INT bitadjust; |
|
uint8_t RESTRICT* allocBits; |
|
|
|
{ |
|
OI_UINT ex; |
|
bitadjust = adjustToFitBitpool(common->frameInfo.bitpool, bitneeds->uint32, |
|
nrof_subbands, bitcount, &ex); |
|
/* We want the compiler to put excess into a register */ |
|
excess = ex; |
|
} |
|
|
|
/* |
|
* Allocate adjusted bits |
|
*/ |
|
allocBits = &common->bits.uint8[ch ? nrof_subbands : 0]; |
|
|
|
sb = 0; |
|
while (sb < nrof_subbands) { |
|
excess = allocAdjustedBits(&allocBits[sb], bitneeds->uint8[sb] + bitadjust, |
|
excess); |
|
++sb; |
|
} |
|
sb = 0; |
|
while (excess) { |
|
excess = allocExcessBits(&allocBits[sb], excess); |
|
++sb; |
|
} |
|
} |
|
|
|
void monoBitAllocation(OI_CODEC_SBC_COMMON_CONTEXT* common) { |
|
BITNEED_UNION1 bitneeds; |
|
OI_UINT bitcount; |
|
OI_UINT bitpoolPreference = 0; |
|
|
|
bitcount = computeBitneed(common, bitneeds.uint8, 0, &bitpoolPreference); |
|
|
|
oneChannelBitAllocation(common, &bitneeds, 0, bitcount); |
|
} |
|
|
|
/** |
|
@} |
|
*/
|
|
|