/* ** 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; iqcChannel[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; iqcChannel[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;sfbOffsbitResTot = 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; }