blob: 4d763d00bf6c2d81d7e148a0d385eba152b00846 [file] [log] [blame]
/*
** 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);
}