545 lines
15 KiB
C
545 lines
15 KiB
C
/*
|
|
** Copyright 2003-2010, VisualOn, Inc.
|
|
**
|
|
** 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.
|
|
*/
|
|
/*******************************************************************************
|
|
File: dyn_bits.c
|
|
|
|
Content: Noiseless coder module functions
|
|
|
|
*******************************************************************************/
|
|
|
|
#include "aac_rom.h"
|
|
#include "dyn_bits.h"
|
|
#include "bit_cnt.h"
|
|
#include "psy_const.h"
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* function name: buildBitLookUp
|
|
* description: count bits using all possible tables
|
|
*
|
|
*****************************************************************************/
|
|
static void
|
|
buildBitLookUp(const Word16 *quantSpectrum,
|
|
const Word16 maxSfb,
|
|
const Word16 *sfbOffset,
|
|
const UWord16 *sfbMax,
|
|
Word16 bitLookUp[MAX_SFB_LONG][CODE_BOOK_ESC_NDX + 1],
|
|
SECTION_INFO * sectionInfo)
|
|
{
|
|
Word32 i;
|
|
|
|
for (i=0; i<maxSfb; i++) {
|
|
Word16 sfbWidth, maxVal;
|
|
|
|
sectionInfo[i].sfbCnt = 1;
|
|
sectionInfo[i].sfbStart = i;
|
|
sectionInfo[i].sectionBits = INVALID_BITCOUNT;
|
|
sectionInfo[i].codeBook = -1;
|
|
sfbWidth = sfbOffset[i + 1] - sfbOffset[i];
|
|
maxVal = sfbMax[i];
|
|
bitCount(quantSpectrum + sfbOffset[i], sfbWidth, maxVal, bitLookUp[i]);
|
|
}
|
|
}
|
|
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* function name: findBestBook
|
|
* description: essential helper functions
|
|
*
|
|
*****************************************************************************/
|
|
static Word16
|
|
findBestBook(const Word16 *bc, Word16 *book)
|
|
{
|
|
Word32 minBits, j;
|
|
minBits = INVALID_BITCOUNT;
|
|
|
|
for (j=0; j<=CODE_BOOK_ESC_NDX; j++) {
|
|
|
|
if (bc[j] < minBits) {
|
|
minBits = bc[j];
|
|
*book = j;
|
|
}
|
|
}
|
|
return extract_l(minBits);
|
|
}
|
|
|
|
static Word16
|
|
findMinMergeBits(const Word16 *bc1, const Word16 *bc2)
|
|
{
|
|
Word32 minBits, j, sum;
|
|
minBits = INVALID_BITCOUNT;
|
|
|
|
for (j=0; j<=CODE_BOOK_ESC_NDX; j++) {
|
|
sum = bc1[j] + bc2[j];
|
|
if (sum < minBits) {
|
|
minBits = sum;
|
|
}
|
|
}
|
|
return extract_l(minBits);
|
|
}
|
|
|
|
static void
|
|
mergeBitLookUp(Word16 *bc1, const Word16 *bc2)
|
|
{
|
|
Word32 j;
|
|
|
|
for (j=0; j<=CODE_BOOK_ESC_NDX; j++) {
|
|
bc1[j] = min(bc1[j] + bc2[j], INVALID_BITCOUNT);
|
|
}
|
|
}
|
|
|
|
static Word16
|
|
findMaxMerge(const Word16 mergeGainLookUp[MAX_SFB_LONG],
|
|
const SECTION_INFO *sectionInfo,
|
|
const Word16 maxSfb, Word16 *maxNdx)
|
|
{
|
|
Word32 i, maxMergeGain;
|
|
maxMergeGain = 0;
|
|
|
|
for (i=0; i+sectionInfo[i].sfbCnt < maxSfb; i += sectionInfo[i].sfbCnt) {
|
|
|
|
if (mergeGainLookUp[i] > maxMergeGain) {
|
|
maxMergeGain = mergeGainLookUp[i];
|
|
*maxNdx = i;
|
|
}
|
|
}
|
|
return extract_l(maxMergeGain);
|
|
}
|
|
|
|
|
|
|
|
static Word16
|
|
CalcMergeGain(const SECTION_INFO *sectionInfo,
|
|
Word16 bitLookUp[MAX_SFB_LONG][CODE_BOOK_ESC_NDX + 1],
|
|
const Word16 *sideInfoTab,
|
|
const Word16 ndx1,
|
|
const Word16 ndx2)
|
|
{
|
|
Word32 SplitBits;
|
|
Word32 MergeBits;
|
|
Word32 MergeGain;
|
|
|
|
/*
|
|
Bit amount for splitted sections
|
|
*/
|
|
SplitBits = sectionInfo[ndx1].sectionBits + sectionInfo[ndx2].sectionBits;
|
|
|
|
MergeBits = sideInfoTab[sectionInfo[ndx1].sfbCnt + sectionInfo[ndx2].sfbCnt] +
|
|
findMinMergeBits(bitLookUp[ndx1], bitLookUp[ndx2]);
|
|
MergeGain = (SplitBits - MergeBits);
|
|
|
|
return extract_l(MergeGain);
|
|
}
|
|
|
|
/*
|
|
sectioning Stage 0:find minimum codbooks
|
|
*/
|
|
|
|
static void
|
|
gmStage0(SECTION_INFO * sectionInfo,
|
|
Word16 bitLookUp[MAX_SFB_LONG][CODE_BOOK_ESC_NDX + 1],
|
|
const Word16 maxSfb)
|
|
{
|
|
Word32 i;
|
|
|
|
for (i=0; i<maxSfb; i++) {
|
|
/* Side-Info bits will be calculated in Stage 1! */
|
|
|
|
if (sectionInfo[i].sectionBits == INVALID_BITCOUNT) {
|
|
sectionInfo[i].sectionBits = findBestBook(bitLookUp[i], &(sectionInfo[i].codeBook));
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
sectioning Stage 1:merge all connected regions with the same code book and
|
|
calculate side info
|
|
*/
|
|
|
|
static void
|
|
gmStage1(SECTION_INFO * sectionInfo,
|
|
Word16 bitLookUp[MAX_SFB_LONG][CODE_BOOK_ESC_NDX + 1],
|
|
const Word16 maxSfb,
|
|
const Word16 *sideInfoTab)
|
|
{
|
|
SECTION_INFO * sectionInfo_s;
|
|
SECTION_INFO * sectionInfo_e;
|
|
Word32 mergeStart, mergeEnd;
|
|
mergeStart = 0;
|
|
|
|
do {
|
|
|
|
sectionInfo_s = sectionInfo + mergeStart;
|
|
for (mergeEnd=mergeStart+1; mergeEnd<maxSfb; mergeEnd++) {
|
|
sectionInfo_e = sectionInfo + mergeEnd;
|
|
if (sectionInfo_s->codeBook != sectionInfo_e->codeBook)
|
|
break;
|
|
sectionInfo_s->sfbCnt += 1;
|
|
sectionInfo_s->sectionBits += sectionInfo_e->sectionBits;
|
|
|
|
mergeBitLookUp(bitLookUp[mergeStart], bitLookUp[mergeEnd]);
|
|
}
|
|
|
|
sectionInfo_s->sectionBits += sideInfoTab[sectionInfo_s->sfbCnt];
|
|
sectionInfo[mergeEnd - 1].sfbStart = sectionInfo_s->sfbStart; /* speed up prev search */
|
|
|
|
mergeStart = mergeEnd;
|
|
|
|
|
|
} while (mergeStart - maxSfb < 0);
|
|
}
|
|
|
|
/*
|
|
sectioning Stage 2:greedy merge algorithm, merge connected sections with
|
|
maximum bit gain until no more gain is possible
|
|
*/
|
|
static void
|
|
gmStage2(SECTION_INFO *sectionInfo,
|
|
Word16 mergeGainLookUp[MAX_SFB_LONG],
|
|
Word16 bitLookUp[MAX_SFB_LONG][CODE_BOOK_ESC_NDX + 1],
|
|
const Word16 maxSfb,
|
|
const Word16 *sideInfoTab)
|
|
{
|
|
Word16 i;
|
|
|
|
for (i=0; i+sectionInfo[i].sfbCnt<maxSfb; i+=sectionInfo[i].sfbCnt) {
|
|
mergeGainLookUp[i] = CalcMergeGain(sectionInfo,
|
|
bitLookUp,
|
|
sideInfoTab,
|
|
i,
|
|
(i + sectionInfo[i].sfbCnt));
|
|
}
|
|
|
|
while (TRUE) {
|
|
Word16 maxMergeGain, maxNdx = 0, maxNdxNext, maxNdxLast;
|
|
|
|
maxMergeGain = findMaxMerge(mergeGainLookUp, sectionInfo, maxSfb, &maxNdx);
|
|
|
|
|
|
if (maxMergeGain <= 0)
|
|
break;
|
|
|
|
|
|
maxNdxNext = maxNdx + sectionInfo[maxNdx].sfbCnt;
|
|
|
|
sectionInfo[maxNdx].sfbCnt = sectionInfo[maxNdx].sfbCnt + sectionInfo[maxNdxNext].sfbCnt;
|
|
sectionInfo[maxNdx].sectionBits = sectionInfo[maxNdx].sectionBits +
|
|
(sectionInfo[maxNdxNext].sectionBits - maxMergeGain);
|
|
|
|
|
|
mergeBitLookUp(bitLookUp[maxNdx], bitLookUp[maxNdxNext]);
|
|
|
|
|
|
if (maxNdx != 0) {
|
|
maxNdxLast = sectionInfo[maxNdx - 1].sfbStart;
|
|
mergeGainLookUp[maxNdxLast] = CalcMergeGain(sectionInfo,
|
|
bitLookUp,
|
|
sideInfoTab,
|
|
maxNdxLast,
|
|
maxNdx);
|
|
}
|
|
maxNdxNext = maxNdx + sectionInfo[maxNdx].sfbCnt;
|
|
|
|
sectionInfo[maxNdxNext - 1].sfbStart = sectionInfo[maxNdx].sfbStart;
|
|
|
|
|
|
if (maxNdxNext - maxSfb < 0) {
|
|
mergeGainLookUp[maxNdx] = CalcMergeGain(sectionInfo,
|
|
bitLookUp,
|
|
sideInfoTab,
|
|
maxNdx,
|
|
maxNdxNext);
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
count bits used by the noiseless coder
|
|
*/
|
|
static void
|
|
noiselessCounter(SECTION_DATA *sectionData,
|
|
Word16 mergeGainLookUp[MAX_SFB_LONG],
|
|
Word16 bitLookUp[MAX_SFB_LONG][CODE_BOOK_ESC_NDX + 1],
|
|
const Word16 *quantSpectrum,
|
|
const UWord16 *maxValueInSfb,
|
|
const Word16 *sfbOffset,
|
|
const Word32 blockType)
|
|
{
|
|
Word32 grpNdx, i;
|
|
const Word16 *sideInfoTab = NULL;
|
|
SECTION_INFO *sectionInfo;
|
|
|
|
/*
|
|
use appropriate side info table
|
|
*/
|
|
switch (blockType)
|
|
{
|
|
case LONG_WINDOW:
|
|
case START_WINDOW:
|
|
case STOP_WINDOW:
|
|
sideInfoTab = sideInfoTabLong;
|
|
break;
|
|
case SHORT_WINDOW:
|
|
sideInfoTab = sideInfoTabShort;
|
|
break;
|
|
}
|
|
|
|
|
|
sectionData->noOfSections = 0;
|
|
sectionData->huffmanBits = 0;
|
|
sectionData->sideInfoBits = 0;
|
|
|
|
|
|
if (sectionData->maxSfbPerGroup == 0)
|
|
return;
|
|
|
|
/*
|
|
loop trough groups
|
|
*/
|
|
for (grpNdx=0; grpNdx<sectionData->sfbCnt; grpNdx+=sectionData->sfbPerGroup) {
|
|
|
|
sectionInfo = sectionData->sectionInfo + sectionData->noOfSections;
|
|
|
|
buildBitLookUp(quantSpectrum,
|
|
sectionData->maxSfbPerGroup,
|
|
sfbOffset + grpNdx,
|
|
maxValueInSfb + grpNdx,
|
|
bitLookUp,
|
|
sectionInfo);
|
|
|
|
/*
|
|
0.Stage
|
|
*/
|
|
gmStage0(sectionInfo, bitLookUp, sectionData->maxSfbPerGroup);
|
|
|
|
/*
|
|
1.Stage
|
|
*/
|
|
gmStage1(sectionInfo, bitLookUp, sectionData->maxSfbPerGroup, sideInfoTab);
|
|
|
|
|
|
/*
|
|
2.Stage
|
|
*/
|
|
gmStage2(sectionInfo,
|
|
mergeGainLookUp,
|
|
bitLookUp,
|
|
sectionData->maxSfbPerGroup,
|
|
sideInfoTab);
|
|
|
|
|
|
/*
|
|
compress output, calculate total huff and side bits
|
|
*/
|
|
for (i=0; i<sectionData->maxSfbPerGroup; i+=sectionInfo[i].sfbCnt) {
|
|
findBestBook(bitLookUp[i], &(sectionInfo[i].codeBook));
|
|
sectionInfo[i].sfbStart = sectionInfo[i].sfbStart + grpNdx;
|
|
|
|
sectionData->huffmanBits = (sectionData->huffmanBits +
|
|
(sectionInfo[i].sectionBits - sideInfoTab[sectionInfo[i].sfbCnt]));
|
|
sectionData->sideInfoBits = (sectionData->sideInfoBits + sideInfoTab[sectionInfo[i].sfbCnt]);
|
|
sectionData->sectionInfo[sectionData->noOfSections] = sectionInfo[i];
|
|
sectionData->noOfSections = sectionData->noOfSections + 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* functionname: scfCount
|
|
* returns : ---
|
|
* description : count bits used by scalefactors.
|
|
*
|
|
********************************************************************************/
|
|
static void scfCount(const Word16 *scalefacGain,
|
|
const UWord16 *maxValueInSfb,
|
|
SECTION_DATA * sectionData)
|
|
|
|
{
|
|
SECTION_INFO *psectionInfo;
|
|
SECTION_INFO *psectionInfom;
|
|
|
|
/* counter */
|
|
Word32 i = 0; /* section counter */
|
|
Word32 j = 0; /* sfb counter */
|
|
Word32 k = 0; /* current section auxiliary counter */
|
|
Word32 m = 0; /* other section auxiliary counter */
|
|
Word32 n = 0; /* other sfb auxiliary counter */
|
|
|
|
/* further variables */
|
|
Word32 lastValScf = 0;
|
|
Word32 deltaScf = 0;
|
|
Flag found = 0;
|
|
Word32 scfSkipCounter = 0;
|
|
|
|
|
|
sectionData->scalefacBits = 0;
|
|
|
|
|
|
if (scalefacGain == NULL) {
|
|
return;
|
|
}
|
|
|
|
lastValScf = 0;
|
|
sectionData->firstScf = 0;
|
|
|
|
psectionInfo = sectionData->sectionInfo;
|
|
for (i=0; i<sectionData->noOfSections; i++) {
|
|
|
|
if (psectionInfo->codeBook != CODE_BOOK_ZERO_NO) {
|
|
sectionData->firstScf = psectionInfo->sfbStart;
|
|
lastValScf = scalefacGain[sectionData->firstScf];
|
|
break;
|
|
}
|
|
psectionInfo += 1;
|
|
}
|
|
|
|
psectionInfo = sectionData->sectionInfo;
|
|
for (i=0; i<sectionData->noOfSections; i++, psectionInfo += 1) {
|
|
|
|
if (psectionInfo->codeBook != CODE_BOOK_ZERO_NO
|
|
&& psectionInfo->codeBook != CODE_BOOK_PNS_NO) {
|
|
for (j = psectionInfo->sfbStart;
|
|
j < (psectionInfo->sfbStart + psectionInfo->sfbCnt); j++) {
|
|
/* check if we can repeat the last value to save bits */
|
|
|
|
if (maxValueInSfb[j] == 0) {
|
|
found = 0;
|
|
|
|
if (scfSkipCounter == 0) {
|
|
/* end of section */
|
|
|
|
if (j - ((psectionInfo->sfbStart + psectionInfo->sfbCnt) - 1) == 0) {
|
|
found = 0;
|
|
}
|
|
else {
|
|
for (k = j + 1; k < psectionInfo->sfbStart + psectionInfo->sfbCnt; k++) {
|
|
|
|
if (maxValueInSfb[k] != 0) {
|
|
int tmp = L_abs(scalefacGain[k] - lastValScf);
|
|
found = 1;
|
|
|
|
if ( tmp < CODE_BOOK_SCF_LAV) {
|
|
/* save bits */
|
|
deltaScf = 0;
|
|
}
|
|
else {
|
|
/* do not save bits */
|
|
deltaScf = lastValScf - scalefacGain[j];
|
|
lastValScf = scalefacGain[j];
|
|
scfSkipCounter = 0;
|
|
}
|
|
break;
|
|
}
|
|
/* count scalefactor skip */
|
|
scfSkipCounter = scfSkipCounter + 1;
|
|
}
|
|
}
|
|
|
|
psectionInfom = psectionInfo + 1;
|
|
/* search for the next maxValueInSfb[] != 0 in all other sections */
|
|
for (m = i + 1; (m < sectionData->noOfSections) && (found == 0); m++) {
|
|
|
|
if ((psectionInfom->codeBook != CODE_BOOK_ZERO_NO) &&
|
|
(psectionInfom->codeBook != CODE_BOOK_PNS_NO)) {
|
|
for (n = psectionInfom->sfbStart;
|
|
n < (psectionInfom->sfbStart + psectionInfom->sfbCnt); n++) {
|
|
|
|
if (maxValueInSfb[n] != 0) {
|
|
found = 1;
|
|
|
|
if ( (abs_s(scalefacGain[n] - lastValScf) < CODE_BOOK_SCF_LAV)) {
|
|
deltaScf = 0;
|
|
}
|
|
else {
|
|
deltaScf = (lastValScf - scalefacGain[j]);
|
|
lastValScf = scalefacGain[j];
|
|
scfSkipCounter = 0;
|
|
}
|
|
break;
|
|
}
|
|
/* count scalefactor skip */
|
|
scfSkipCounter = scfSkipCounter + 1;
|
|
}
|
|
}
|
|
|
|
psectionInfom += 1;
|
|
}
|
|
|
|
if (found == 0) {
|
|
deltaScf = 0;
|
|
scfSkipCounter = 0;
|
|
}
|
|
}
|
|
else {
|
|
deltaScf = 0;
|
|
scfSkipCounter = scfSkipCounter - 1;
|
|
}
|
|
}
|
|
else {
|
|
deltaScf = lastValScf - scalefacGain[j];
|
|
lastValScf = scalefacGain[j];
|
|
}
|
|
sectionData->scalefacBits += bitCountScalefactorDelta(deltaScf);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
typedef Word16 (*lookUpTable)[CODE_BOOK_ESC_NDX + 1];
|
|
|
|
|
|
Word16
|
|
dynBitCount(const Word16 *quantSpectrum,
|
|
const UWord16 *maxValueInSfb,
|
|
const Word16 *scalefac,
|
|
const Word16 blockType,
|
|
const Word16 sfbCnt,
|
|
const Word16 maxSfbPerGroup,
|
|
const Word16 sfbPerGroup,
|
|
const Word16 *sfbOffset,
|
|
SECTION_DATA *sectionData)
|
|
{
|
|
sectionData->blockType = blockType;
|
|
sectionData->sfbCnt = sfbCnt;
|
|
sectionData->sfbPerGroup = sfbPerGroup;
|
|
if(sfbPerGroup)
|
|
sectionData->noOfGroups = sfbCnt/sfbPerGroup;
|
|
else
|
|
sectionData->noOfGroups = 0x7fff;
|
|
sectionData->maxSfbPerGroup = maxSfbPerGroup;
|
|
|
|
noiselessCounter(sectionData,
|
|
sectionData->mergeGainLookUp,
|
|
(lookUpTable)sectionData->bitLookUp,
|
|
quantSpectrum,
|
|
maxValueInSfb,
|
|
sfbOffset,
|
|
blockType);
|
|
|
|
scfCount(scalefac,
|
|
maxValueInSfb,
|
|
sectionData);
|
|
|
|
|
|
return (sectionData->huffmanBits + sectionData->sideInfoBits +
|
|
sectionData->scalefacBits);
|
|
}
|
|
|