579 lines
17 KiB
C
579 lines
17 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: qc_main.c
|
|
|
|
Content: Quantizing & coding functions
|
|
|
|
*******************************************************************************/
|
|
|
|
#include "basic_op.h"
|
|
#include "oper_32b.h"
|
|
#include "qc_main.h"
|
|
#include "quantize.h"
|
|
#include "interface.h"
|
|
#include "adj_thr.h"
|
|
#include "sf_estim.h"
|
|
#include "stat_bits.h"
|
|
#include "bit_cnt.h"
|
|
#include "dyn_bits.h"
|
|
#include "channel_map.h"
|
|
#include "memalign.h"
|
|
|
|
#define UNUSED(x) (void)(x)
|
|
|
|
typedef enum{
|
|
FRAME_LEN_BYTES_MODULO = 1,
|
|
FRAME_LEN_BYTES_INT = 2
|
|
}FRAME_LEN_RESULT_MODE;
|
|
|
|
static const Word16 maxFillElemBits = 7 + 270*8;
|
|
|
|
/* forward declarations */
|
|
|
|
static Word16 calcMaxValueInSfb(Word16 sfbCnt,
|
|
Word16 maxSfbPerGroup,
|
|
Word16 sfbPerGroup,
|
|
Word16 sfbOffset[MAX_GROUPED_SFB],
|
|
Word16 quantSpectrum[FRAME_LEN_LONG],
|
|
UWord16 maxValue[MAX_GROUPED_SFB]);
|
|
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* function name: calcFrameLen
|
|
* description: estimate the frame length according the bitrates
|
|
*
|
|
*****************************************************************************/
|
|
static Word16 calcFrameLen(Word32 bitRate,
|
|
Word32 sampleRate,
|
|
FRAME_LEN_RESULT_MODE mode)
|
|
{
|
|
|
|
Word32 result;
|
|
Word32 quot;
|
|
|
|
result = (FRAME_LEN_LONG >> 3) * bitRate;
|
|
quot = result / sampleRate;
|
|
|
|
|
|
if (mode == FRAME_LEN_BYTES_MODULO) {
|
|
result -= quot * sampleRate;
|
|
}
|
|
else { /* FRAME_LEN_BYTES_INT */
|
|
result = quot;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* function name:framePadding
|
|
* description: Calculates if padding is needed for actual frame
|
|
* returns: paddingOn or not
|
|
*
|
|
*****************************************************************************/
|
|
static Word16 framePadding(Word32 bitRate,
|
|
Word32 sampleRate,
|
|
Word32 *paddingRest)
|
|
{
|
|
Word16 paddingOn;
|
|
Word16 difference;
|
|
|
|
paddingOn = 0;
|
|
|
|
difference = calcFrameLen( bitRate,
|
|
sampleRate,
|
|
FRAME_LEN_BYTES_MODULO );
|
|
*paddingRest = *paddingRest - difference;
|
|
|
|
|
|
if (*paddingRest <= 0 ) {
|
|
paddingOn = 1;
|
|
*paddingRest = *paddingRest + sampleRate;
|
|
}
|
|
|
|
return paddingOn;
|
|
}
|
|
|
|
|
|
/*********************************************************************************
|
|
*
|
|
* function name: QCOutNew
|
|
* description: init qcout parameter
|
|
* returns: 0 if success
|
|
*
|
|
**********************************************************************************/
|
|
|
|
Word16 QCOutNew(QC_OUT *hQC, Word16 nChannels, VO_MEM_OPERATOR *pMemOP)
|
|
{
|
|
Word32 i;
|
|
Word16 *quantSpec;
|
|
Word16 *scf;
|
|
UWord16 *maxValueInSfb;
|
|
|
|
quantSpec = (Word16 *)mem_malloc(pMemOP, nChannels * FRAME_LEN_LONG * sizeof(Word16), 32, VO_INDEX_ENC_AAC);
|
|
if(NULL == quantSpec)
|
|
return 1;
|
|
scf = (Word16 *)mem_malloc(pMemOP, nChannels * MAX_GROUPED_SFB * sizeof(Word16), 32, VO_INDEX_ENC_AAC);
|
|
if(NULL == scf)
|
|
{
|
|
return 1;
|
|
}
|
|
maxValueInSfb = (UWord16 *)mem_malloc(pMemOP, nChannels * MAX_GROUPED_SFB * sizeof(UWord16), 32, VO_INDEX_ENC_AAC);
|
|
if(NULL == maxValueInSfb)
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
for (i=0; i<nChannels; i++) {
|
|
hQC->qcChannel[i].quantSpec = quantSpec + i*FRAME_LEN_LONG;
|
|
|
|
hQC->qcChannel[i].maxValueInSfb = maxValueInSfb + i*MAX_GROUPED_SFB;
|
|
|
|
hQC->qcChannel[i].scf = scf + i*MAX_GROUPED_SFB;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*********************************************************************************
|
|
*
|
|
* function name: QCOutDelete
|
|
* description: unint qcout parameter
|
|
* returns: 0 if success
|
|
*
|
|
**********************************************************************************/
|
|
void QCOutDelete(QC_OUT* hQC, VO_MEM_OPERATOR *pMemOP)
|
|
{
|
|
Word32 i;
|
|
if(hQC)
|
|
{
|
|
if(hQC->qcChannel[0].quantSpec)
|
|
mem_free(pMemOP, hQC->qcChannel[0].quantSpec, VO_INDEX_ENC_AAC);
|
|
|
|
if(hQC->qcChannel[0].maxValueInSfb)
|
|
mem_free(pMemOP, hQC->qcChannel[0].maxValueInSfb, VO_INDEX_ENC_AAC);
|
|
|
|
if(hQC->qcChannel[0].scf)
|
|
mem_free(pMemOP, hQC->qcChannel[0].scf, VO_INDEX_ENC_AAC);
|
|
|
|
for (i=0; i<MAX_CHANNELS; i++) {
|
|
hQC->qcChannel[i].quantSpec = NULL;
|
|
|
|
hQC->qcChannel[i].maxValueInSfb = NULL;
|
|
|
|
hQC->qcChannel[i].scf = NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*********************************************************************************
|
|
*
|
|
* function name: QCNew
|
|
* description: set QC to zero
|
|
* returns: 0 if success
|
|
*
|
|
**********************************************************************************/
|
|
Word16 QCNew(QC_STATE *hQC, VO_MEM_OPERATOR *pMemOP)
|
|
{
|
|
pMemOP->Set(VO_INDEX_ENC_AAC, hQC,0,sizeof(QC_STATE));
|
|
|
|
return (0);
|
|
}
|
|
|
|
/*********************************************************************************
|
|
*
|
|
* function name: QCDelete
|
|
* description: unint qcout parameter
|
|
*
|
|
**********************************************************************************/
|
|
void QCDelete(QC_STATE *hQC, VO_MEM_OPERATOR *pMemOP)
|
|
{
|
|
UNUSED(hQC);
|
|
UNUSED(pMemOP);
|
|
}
|
|
|
|
/*********************************************************************************
|
|
*
|
|
* function name: QCInit
|
|
* description: init QD parameter
|
|
* returns: 0 if success
|
|
*
|
|
**********************************************************************************/
|
|
Word16 QCInit(QC_STATE *hQC,
|
|
struct QC_INIT *init)
|
|
{
|
|
hQC->nChannels = init->elInfo->nChannelsInEl;
|
|
hQC->maxBitsTot = init->maxBits;
|
|
hQC->bitResTot = sub(init->bitRes, init->averageBits);
|
|
hQC->averageBitsTot = init->averageBits;
|
|
hQC->maxBitFac = init->maxBitFac;
|
|
|
|
hQC->padding.paddingRest = init->padding.paddingRest;
|
|
|
|
hQC->globStatBits = 3; /* for ID_END */
|
|
|
|
/* channel elements init */
|
|
InitElementBits(&hQC->elementBits,
|
|
*init->elInfo,
|
|
init->bitrate,
|
|
init->averageBits,
|
|
hQC->globStatBits);
|
|
|
|
/* threshold parameter init */
|
|
AdjThrInit(&hQC->adjThr,
|
|
init->meanPe,
|
|
hQC->elementBits.chBitrate);
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*********************************************************************************
|
|
*
|
|
* function name: QCMain
|
|
* description: quantization and coding the spectrum
|
|
* returns: 0 if success
|
|
*
|
|
**********************************************************************************/
|
|
Word16 QCMain(QC_STATE* hQC,
|
|
ELEMENT_BITS* elBits,
|
|
ATS_ELEMENT* adjThrStateElement,
|
|
PSY_OUT_CHANNEL psyOutChannel[MAX_CHANNELS], /* may be modified in-place */
|
|
PSY_OUT_ELEMENT* psyOutElement,
|
|
QC_OUT_CHANNEL qcOutChannel[MAX_CHANNELS], /* out */
|
|
QC_OUT_ELEMENT* qcOutElement,
|
|
Word16 nChannels,
|
|
Word16 ancillaryDataBytes)
|
|
{
|
|
Word16 maxChDynBits[MAX_CHANNELS];
|
|
Word16 chBitDistribution[MAX_CHANNELS];
|
|
Word32 ch;
|
|
|
|
if (elBits->bitResLevel < 0) {
|
|
return -1;
|
|
}
|
|
|
|
if (elBits->bitResLevel > elBits->maxBitResBits) {
|
|
return -1;
|
|
}
|
|
|
|
qcOutElement->staticBitsUsed = countStaticBitdemand(psyOutChannel,
|
|
psyOutElement,
|
|
nChannels,
|
|
qcOutElement->adtsUsed);
|
|
|
|
|
|
if (ancillaryDataBytes) {
|
|
qcOutElement->ancBitsUsed = 7 + (ancillaryDataBytes << 3);
|
|
|
|
if (ancillaryDataBytes >= 15)
|
|
qcOutElement->ancBitsUsed = qcOutElement->ancBitsUsed + 8;
|
|
}
|
|
else {
|
|
qcOutElement->ancBitsUsed = 0;
|
|
}
|
|
|
|
CalcFormFactor(hQC->logSfbFormFactor, hQC->sfbNRelevantLines, hQC->logSfbEnergy, psyOutChannel, nChannels);
|
|
|
|
/*adjust thresholds for the desired bitrate */
|
|
AdjustThresholds(&hQC->adjThr,
|
|
adjThrStateElement,
|
|
psyOutChannel,
|
|
psyOutElement,
|
|
chBitDistribution,
|
|
hQC->logSfbEnergy,
|
|
hQC->sfbNRelevantLines,
|
|
qcOutElement,
|
|
elBits,
|
|
nChannels,
|
|
hQC->maxBitFac);
|
|
|
|
/*estimate scale factors */
|
|
EstimateScaleFactors(psyOutChannel,
|
|
qcOutChannel,
|
|
hQC->logSfbEnergy,
|
|
hQC->logSfbFormFactor,
|
|
hQC->sfbNRelevantLines,
|
|
nChannels);
|
|
|
|
/* condition to prevent empty bitreservoir */
|
|
for (ch = 0; ch < nChannels; ch++) {
|
|
Word32 maxDynBits;
|
|
maxDynBits = elBits->averageBits + elBits->bitResLevel - 7; /* -7 bec. of align bits */
|
|
maxDynBits = maxDynBits - qcOutElement->staticBitsUsed + qcOutElement->ancBitsUsed;
|
|
maxChDynBits[ch] = extract_l(chBitDistribution[ch] * maxDynBits / 1000);
|
|
}
|
|
|
|
qcOutElement->dynBitsUsed = 0;
|
|
for (ch = 0; ch < nChannels; ch++) {
|
|
Word32 chDynBits;
|
|
Flag constraintsFulfilled;
|
|
Word32 iter;
|
|
iter = 0;
|
|
do {
|
|
constraintsFulfilled = 1;
|
|
|
|
QuantizeSpectrum(psyOutChannel[ch].sfbCnt,
|
|
psyOutChannel[ch].maxSfbPerGroup,
|
|
psyOutChannel[ch].sfbPerGroup,
|
|
psyOutChannel[ch].sfbOffsets,
|
|
psyOutChannel[ch].mdctSpectrum,
|
|
qcOutChannel[ch].globalGain,
|
|
qcOutChannel[ch].scf,
|
|
qcOutChannel[ch].quantSpec);
|
|
|
|
if (calcMaxValueInSfb(psyOutChannel[ch].sfbCnt,
|
|
psyOutChannel[ch].maxSfbPerGroup,
|
|
psyOutChannel[ch].sfbPerGroup,
|
|
psyOutChannel[ch].sfbOffsets,
|
|
qcOutChannel[ch].quantSpec,
|
|
qcOutChannel[ch].maxValueInSfb) > MAX_QUANT) {
|
|
constraintsFulfilled = 0;
|
|
}
|
|
|
|
chDynBits = dynBitCount(qcOutChannel[ch].quantSpec,
|
|
qcOutChannel[ch].maxValueInSfb,
|
|
qcOutChannel[ch].scf,
|
|
psyOutChannel[ch].windowSequence,
|
|
psyOutChannel[ch].sfbCnt,
|
|
psyOutChannel[ch].maxSfbPerGroup,
|
|
psyOutChannel[ch].sfbPerGroup,
|
|
psyOutChannel[ch].sfbOffsets,
|
|
&qcOutChannel[ch].sectionData);
|
|
|
|
if (chDynBits >= maxChDynBits[ch]) {
|
|
constraintsFulfilled = 0;
|
|
}
|
|
|
|
if (!constraintsFulfilled) {
|
|
qcOutChannel[ch].globalGain = qcOutChannel[ch].globalGain + 1;
|
|
}
|
|
|
|
iter = iter + 1;
|
|
|
|
} while(!constraintsFulfilled);
|
|
|
|
qcOutElement->dynBitsUsed = qcOutElement->dynBitsUsed + chDynBits;
|
|
|
|
qcOutChannel[ch].mdctScale = psyOutChannel[ch].mdctScale;
|
|
qcOutChannel[ch].groupingMask = psyOutChannel[ch].groupingMask;
|
|
qcOutChannel[ch].windowShape = psyOutChannel[ch].windowShape;
|
|
}
|
|
|
|
/* save dynBitsUsed for correction of bits2pe relation */
|
|
AdjThrUpdate(adjThrStateElement, qcOutElement->dynBitsUsed);
|
|
|
|
{
|
|
Word16 bitResSpace = elBits->maxBitResBits - elBits->bitResLevel;
|
|
Word16 deltaBitRes = elBits->averageBits -
|
|
(qcOutElement->staticBitsUsed +
|
|
qcOutElement->dynBitsUsed + qcOutElement->ancBitsUsed);
|
|
|
|
qcOutElement->fillBits = max(0, (deltaBitRes - bitResSpace));
|
|
}
|
|
|
|
return 0; /* OK */
|
|
}
|
|
|
|
|
|
/*********************************************************************************
|
|
*
|
|
* function name: calcMaxValueInSfb
|
|
* description: search the max Spectrum in one sfb
|
|
*
|
|
**********************************************************************************/
|
|
static Word16 calcMaxValueInSfb(Word16 sfbCnt,
|
|
Word16 maxSfbPerGroup,
|
|
Word16 sfbPerGroup,
|
|
Word16 sfbOffset[MAX_GROUPED_SFB],
|
|
Word16 quantSpectrum[FRAME_LEN_LONG],
|
|
UWord16 maxValue[MAX_GROUPED_SFB])
|
|
{
|
|
Word16 sfbOffs, sfb;
|
|
Word16 maxValueAll;
|
|
|
|
maxValueAll = 0;
|
|
|
|
for(sfbOffs=0;sfbOffs<sfbCnt;sfbOffs+=sfbPerGroup) {
|
|
for (sfb = 0; sfb < maxSfbPerGroup; sfb++) {
|
|
Word16 line;
|
|
Word16 maxThisSfb;
|
|
maxThisSfb = 0;
|
|
|
|
for (line = sfbOffset[sfbOffs+sfb]; line < sfbOffset[sfbOffs+sfb+1]; line++) {
|
|
Word16 absVal;
|
|
absVal = abs_s(quantSpectrum[line]);
|
|
maxThisSfb = max(maxThisSfb, absVal);
|
|
}
|
|
|
|
maxValue[sfbOffs+sfb] = maxThisSfb;
|
|
maxValueAll = max(maxValueAll, maxThisSfb);
|
|
}
|
|
}
|
|
return maxValueAll;
|
|
}
|
|
|
|
|
|
/*********************************************************************************
|
|
*
|
|
* function name: updateBitres
|
|
* description: update bitreservoir
|
|
*
|
|
**********************************************************************************/
|
|
void updateBitres(QC_STATE* qcKernel,
|
|
QC_OUT* qcOut)
|
|
|
|
{
|
|
ELEMENT_BITS *elBits;
|
|
|
|
qcKernel->bitResTot = 0;
|
|
|
|
elBits = &qcKernel->elementBits;
|
|
|
|
|
|
if (elBits->averageBits > 0) {
|
|
/* constant bitrate */
|
|
Word16 bitsUsed;
|
|
bitsUsed = (qcOut->qcElement.staticBitsUsed + qcOut->qcElement.dynBitsUsed) +
|
|
(qcOut->qcElement.ancBitsUsed + qcOut->qcElement.fillBits);
|
|
elBits->bitResLevel = elBits->bitResLevel + (elBits->averageBits - bitsUsed);
|
|
qcKernel->bitResTot = qcKernel->bitResTot + elBits->bitResLevel;
|
|
}
|
|
else {
|
|
/* variable bitrate */
|
|
elBits->bitResLevel = elBits->maxBits;
|
|
qcKernel->bitResTot = qcKernel->maxBitsTot;
|
|
}
|
|
}
|
|
|
|
/*********************************************************************************
|
|
*
|
|
* function name: FinalizeBitConsumption
|
|
* description: count bits used
|
|
*
|
|
**********************************************************************************/
|
|
Word16 FinalizeBitConsumption(QC_STATE *qcKernel,
|
|
QC_OUT* qcOut)
|
|
{
|
|
Word32 nFullFillElem;
|
|
Word32 totFillBits;
|
|
Word16 diffBits;
|
|
Word16 bitsUsed;
|
|
|
|
totFillBits = 0;
|
|
|
|
qcOut->totStaticBitsUsed = qcKernel->globStatBits;
|
|
qcOut->totStaticBitsUsed += qcOut->qcElement.staticBitsUsed;
|
|
qcOut->totDynBitsUsed = qcOut->qcElement.dynBitsUsed;
|
|
qcOut->totAncBitsUsed = qcOut->qcElement.ancBitsUsed;
|
|
qcOut->totFillBits = qcOut->qcElement.fillBits;
|
|
|
|
if (qcOut->qcElement.fillBits) {
|
|
totFillBits += qcOut->qcElement.fillBits;
|
|
}
|
|
|
|
nFullFillElem = (max((qcOut->totFillBits - 1), 0) / maxFillElemBits) * maxFillElemBits;
|
|
|
|
qcOut->totFillBits = qcOut->totFillBits - nFullFillElem;
|
|
|
|
/* check fill elements */
|
|
|
|
if (qcOut->totFillBits > 0) {
|
|
/* minimum Fillelement contains 7 (TAG + byte cnt) bits */
|
|
qcOut->totFillBits = max(7, qcOut->totFillBits);
|
|
/* fill element size equals n*8 + 7 */
|
|
qcOut->totFillBits = qcOut->totFillBits + ((8 - ((qcOut->totFillBits - 7) & 0x0007)) & 0x0007);
|
|
}
|
|
|
|
qcOut->totFillBits = qcOut->totFillBits + nFullFillElem;
|
|
|
|
/* now distribute extra fillbits and alignbits over channel elements */
|
|
qcOut->alignBits = 7 - ((qcOut->totDynBitsUsed + qcOut->totStaticBitsUsed +
|
|
qcOut->totAncBitsUsed + qcOut->totFillBits - 1) & 0x0007);
|
|
|
|
|
|
if ( (qcOut->alignBits + qcOut->totFillBits - totFillBits == 8) &&
|
|
(qcOut->totFillBits > 8))
|
|
qcOut->totFillBits = qcOut->totFillBits - 8;
|
|
|
|
|
|
diffBits = qcOut->alignBits + qcOut->totFillBits - totFillBits;
|
|
|
|
if(diffBits>=0) {
|
|
qcOut->qcElement.fillBits += diffBits;
|
|
}
|
|
|
|
bitsUsed = qcOut->totDynBitsUsed + qcOut->totStaticBitsUsed + qcOut->totAncBitsUsed;
|
|
bitsUsed = bitsUsed + qcOut->totFillBits + qcOut->alignBits;
|
|
|
|
if (bitsUsed > qcKernel->maxBitsTot) {
|
|
return -1;
|
|
}
|
|
return bitsUsed;
|
|
}
|
|
|
|
|
|
/*********************************************************************************
|
|
*
|
|
* function name: AdjustBitrate
|
|
* description: adjusts framelength via padding on a frame to frame basis,
|
|
* to achieve a bitrate that demands a non byte aligned
|
|
* framelength
|
|
* return: errorcode
|
|
*
|
|
**********************************************************************************/
|
|
Word16 AdjustBitrate(QC_STATE *hQC,
|
|
Word32 bitRate, /* total bitrate */
|
|
Word32 sampleRate) /* output sampling rate */
|
|
{
|
|
Word16 paddingOn;
|
|
Word16 frameLen;
|
|
Word16 codeBits;
|
|
Word16 codeBitsLast;
|
|
|
|
/* Do we need a extra padding byte? */
|
|
paddingOn = framePadding(bitRate,
|
|
sampleRate,
|
|
&hQC->padding.paddingRest);
|
|
|
|
/* frame length */
|
|
frameLen = paddingOn + calcFrameLen(bitRate,
|
|
sampleRate,
|
|
FRAME_LEN_BYTES_INT);
|
|
|
|
frameLen = frameLen << 3;
|
|
codeBitsLast = hQC->averageBitsTot - hQC->globStatBits;
|
|
codeBits = frameLen - hQC->globStatBits;
|
|
|
|
/* calculate bits for every channel element */
|
|
if (codeBits != codeBitsLast) {
|
|
Word16 totalBits = 0;
|
|
|
|
hQC->elementBits.averageBits = (hQC->elementBits.relativeBits * codeBits) >> 16; /* relativeBits was scaled down by 2 */
|
|
totalBits += hQC->elementBits.averageBits;
|
|
|
|
hQC->elementBits.averageBits = hQC->elementBits.averageBits + (codeBits - totalBits);
|
|
}
|
|
|
|
hQC->averageBitsTot = frameLen;
|
|
|
|
return 0;
|
|
}
|