blob: e5d78aadc774f9f091b9588fe2c3099f529b44a8 [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: 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;
}