/* ** 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: bitenc.c Content: Bitstream encoder functions *******************************************************************************/ #include "bitenc.h" #include "bit_cnt.h" #include "dyn_bits.h" #include "qc_data.h" #include "interface.h" static const Word16 globalGainOffset = 100; static const Word16 icsReservedBit = 0; /***************************************************************************** * * function name: encodeSpectralData * description: encode spectral data * returns: spectral bits used * *****************************************************************************/ static Word32 encodeSpectralData(Word16 *sfbOffset, SECTION_DATA *sectionData, Word16 *quantSpectrum, HANDLE_BIT_BUF hBitStream) { Word16 i,sfb; Word16 dbgVal; SECTION_INFO* psectioninfo; dbgVal = GetBitsAvail(hBitStream); for(i=0; inoOfSections; i++) { psectioninfo = &(sectionData->sectionInfo[i]); /* huffencode spectral data for this section */ for(sfb=psectioninfo->sfbStart; sfbsfbStart+psectioninfo->sfbCnt; sfb++) { codeValues(quantSpectrum+sfbOffset[sfb], sfbOffset[sfb+1] - sfbOffset[sfb], psectioninfo->codeBook, hBitStream); } } return(GetBitsAvail(hBitStream)-dbgVal); } /***************************************************************************** * * function name:encodeGlobalGain * description: encodes Global Gain (common scale factor) * returns: none * *****************************************************************************/ static void encodeGlobalGain(Word16 globalGain, Word16 logNorm, Word16 scalefac, HANDLE_BIT_BUF hBitStream) { WriteBits(hBitStream, ((globalGain - scalefac) + globalGainOffset-(logNorm << 2)), 8); } /***************************************************************************** * * function name:encodeIcsInfo * description: encodes Ics Info * returns: none * *****************************************************************************/ static void encodeIcsInfo(Word16 blockType, Word16 windowShape, Word16 groupingMask, SECTION_DATA *sectionData, HANDLE_BIT_BUF hBitStream) { WriteBits(hBitStream,icsReservedBit,1); WriteBits(hBitStream,blockType,2); WriteBits(hBitStream,windowShape,1); switch(blockType){ case LONG_WINDOW: case START_WINDOW: case STOP_WINDOW: WriteBits(hBitStream,sectionData->maxSfbPerGroup,6); /* No predictor data present */ WriteBits(hBitStream, 0, 1); break; case SHORT_WINDOW: WriteBits(hBitStream,sectionData->maxSfbPerGroup,4); /* Write grouping bits */ WriteBits(hBitStream,groupingMask,TRANS_FAC-1); break; } } /***************************************************************************** * * function name: encodeSectionData * description: encode section data (common Huffman codebooks for adjacent * SFB's) * returns: none * *****************************************************************************/ static Word32 encodeSectionData(SECTION_DATA *sectionData, HANDLE_BIT_BUF hBitStream) { Word16 sectEscapeVal=0,sectLenBits=0; Word16 sectLen; Word16 i; Word16 dbgVal=GetBitsAvail(hBitStream); switch(sectionData->blockType) { case LONG_WINDOW: case START_WINDOW: case STOP_WINDOW: sectEscapeVal = SECT_ESC_VAL_LONG; sectLenBits = SECT_BITS_LONG; break; case SHORT_WINDOW: sectEscapeVal = SECT_ESC_VAL_SHORT; sectLenBits = SECT_BITS_SHORT; break; } for(i=0;inoOfSections;i++) { WriteBits(hBitStream,sectionData->sectionInfo[i].codeBook,4); sectLen = sectionData->sectionInfo[i].sfbCnt; while(sectLen >= sectEscapeVal) { WriteBits(hBitStream,sectEscapeVal,sectLenBits); sectLen = sectLen - sectEscapeVal; } WriteBits(hBitStream,sectLen,sectLenBits); } return(GetBitsAvail(hBitStream)-dbgVal); } /***************************************************************************** * * function name: encodeScaleFactorData * description: encode DPCM coded scale factors * returns: none * *****************************************************************************/ static Word32 encodeScaleFactorData(UWord16 *maxValueInSfb, SECTION_DATA *sectionData, Word16 *scalefac, HANDLE_BIT_BUF hBitStream) { Word16 i,j,lastValScf,deltaScf; Word16 dbgVal = GetBitsAvail(hBitStream); SECTION_INFO* psectioninfo; lastValScf=scalefac[sectionData->firstScf]; for(i=0;inoOfSections;i++){ psectioninfo = &(sectionData->sectionInfo[i]); if (psectioninfo->codeBook != CODE_BOOK_ZERO_NO){ for (j=psectioninfo->sfbStart; jsfbStart+psectioninfo->sfbCnt; j++){ if(maxValueInSfb[j] == 0) { deltaScf = 0; } else { deltaScf = lastValScf - scalefac[j]; lastValScf = scalefac[j]; } if(codeScalefactorDelta(deltaScf,hBitStream)){ return(1); } } } } return(GetBitsAvail(hBitStream)-dbgVal); } /***************************************************************************** * * function name:encodeMsInfo * description: encodes MS-Stereo Info * returns: none * *****************************************************************************/ static void encodeMSInfo(Word16 sfbCnt, Word16 grpSfb, Word16 maxSfb, Word16 msDigest, Word16 *jsFlags, HANDLE_BIT_BUF hBitStream) { Word16 sfb, sfbOff; switch(msDigest) { case MS_NONE: WriteBits(hBitStream,SI_MS_MASK_NONE,2); break; case MS_ALL: WriteBits(hBitStream,SI_MS_MASK_ALL,2); break; case MS_SOME: WriteBits(hBitStream,SI_MS_MASK_SOME,2); for(sfbOff = 0; sfbOff < sfbCnt; sfbOff+=grpSfb) { for(sfb=0; sfb 3 || tnsInfo.coef[i*TNS_MAX_ORDER_SHORT+k] < -4) { coefBits = 4; break; } } } else { coefBits = 2; for(k=0; k 1 || tnsInfo.coef[i*TNS_MAX_ORDER_SHORT+k] < -2) { coefBits = 3; break; } } } WriteBits(hBitStream, tnsInfo.coefRes[i] - coefBits, 1); /*coef_compres*/ for (k=0; kfirstScf], hBitStream); if(!commonWindow) { encodeIcsInfo(sectionData->blockType, windowShape, groupingMask, sectionData, hBitStream); } encodeSectionData(sectionData, hBitStream); encodeScaleFactorData(maxValueInSfb, sectionData, scf, hBitStream); encodePulseData(hBitStream); encodeTnsData(tnsInfo, sectionData->blockType, hBitStream); encodeGainControlData(hBitStream); encodeSpectralData(sfbOffset, sectionData, quantSpec, hBitStream); } /***************************************************************************** * * function name: writeSingleChannelElement * description: write single channel element to bitstream * returns: none * *****************************************************************************/ static Word16 writeSingleChannelElement(Word16 instanceTag, Word16 *sfbOffset, QC_OUT_CHANNEL* qcOutChannel, HANDLE_BIT_BUF hBitStream, TNS_INFO tnsInfo) { WriteBits(hBitStream,ID_SCE,3); WriteBits(hBitStream,instanceTag,4); writeIndividualChannelStream(0, qcOutChannel->mdctScale, qcOutChannel->windowShape, qcOutChannel->groupingMask, sfbOffset, qcOutChannel->scf, qcOutChannel->maxValueInSfb, qcOutChannel->globalGain, qcOutChannel->quantSpec, &(qcOutChannel->sectionData), hBitStream, tnsInfo ); return(0); } /***************************************************************************** * * function name: writeChannelPairElement * description: * returns: none * *****************************************************************************/ static Word16 writeChannelPairElement(Word16 instanceTag, Word16 msDigest, Word16 msFlags[MAX_GROUPED_SFB], Word16 *sfbOffset[2], QC_OUT_CHANNEL qcOutChannel[2], HANDLE_BIT_BUF hBitStream, TNS_INFO tnsInfo[2]) { WriteBits(hBitStream,ID_CPE,3); WriteBits(hBitStream,instanceTag,4); WriteBits(hBitStream,1,1); /* common window */ encodeIcsInfo(qcOutChannel[0].sectionData.blockType, qcOutChannel[0].windowShape, qcOutChannel[0].groupingMask, &(qcOutChannel[0].sectionData), hBitStream); encodeMSInfo(qcOutChannel[0].sectionData.sfbCnt, qcOutChannel[0].sectionData.sfbPerGroup, qcOutChannel[0].sectionData.maxSfbPerGroup, msDigest, msFlags, hBitStream); writeIndividualChannelStream(1, qcOutChannel[0].mdctScale, qcOutChannel[0].windowShape, qcOutChannel[0].groupingMask, sfbOffset[0], qcOutChannel[0].scf, qcOutChannel[0].maxValueInSfb, qcOutChannel[0].globalGain, qcOutChannel[0].quantSpec, &(qcOutChannel[0].sectionData), hBitStream, tnsInfo[0]); writeIndividualChannelStream(1, qcOutChannel[1].mdctScale, qcOutChannel[1].windowShape, qcOutChannel[1].groupingMask, sfbOffset[1], qcOutChannel[1].scf, qcOutChannel[1].maxValueInSfb, qcOutChannel[1].globalGain, qcOutChannel[1].quantSpec, &(qcOutChannel[1].sectionData), hBitStream, tnsInfo[1]); return(0); } /***************************************************************************** * * function name: writeFillElement * description: write fill elements to bitstream * returns: none * *****************************************************************************/ static void writeFillElement( const UWord8 *ancBytes, Word16 totFillBits, HANDLE_BIT_BUF hBitStream) { Word16 i; Word16 cnt,esc_count; /* Write fill Element(s): amount of a fill element can be 7+X*8 Bits, X element of [0..270] */ while(totFillBits >= (3+4)) { cnt = min(((totFillBits - (3+4)) >> 3), ((1<<4)-1)); WriteBits(hBitStream,ID_FIL,3); WriteBits(hBitStream,cnt,4); totFillBits = totFillBits - (3+4); if ((cnt == (1<<4)-1)) { esc_count = min( ((totFillBits >> 3) - ((1<<4)-1)), (1<<8)-1); WriteBits(hBitStream,esc_count,8); totFillBits = (totFillBits - 8); cnt = cnt + (esc_count - 1); } for(i=0;iqcElement.adtsUsed) /* write adts header*/ { WriteBits(hBitStream, 0xFFF, 12); /* 12 bit Syncword */ WriteBits(hBitStream, 1, 1); /* ID == 0 for MPEG4 AAC, 1 for MPEG2 AAC */ WriteBits(hBitStream, 0, 2); /* layer == 0 */ WriteBits(hBitStream, 1, 1); /* protection absent */ WriteBits(hBitStream, 1, 2); /* profile */ WriteBits(hBitStream, sampindex, 4); /* sampling rate */ WriteBits(hBitStream, 0, 1); /* private bit */ WriteBits(hBitStream, elInfo.nChannelsInEl, 3); /* ch. config (must be > 0) */ /* simply using numChannels only works for 6 channels or less, else a channel configuration should be written */ WriteBits(hBitStream, 0, 1); /* original/copy */ WriteBits(hBitStream, 0, 1); /* home */ /* Variable ADTS header */ WriteBits(hBitStream, 0, 1); /* copyr. id. bit */ WriteBits(hBitStream, 0, 1); /* copyr. id. start */ WriteBits(hBitStream, *globUsedBits >> 3, 13); WriteBits(hBitStream, 0x7FF, 11); /* buffer fullness (0x7FF for VBR) */ WriteBits(hBitStream, 0, 2); /* raw data blocks (0+1=1) */ } *globUsedBits=0; { Word16 *sfbOffset[2]; TNS_INFO tnsInfo[2]; elementUsedBits = 0; switch (elInfo.elType) { case ID_SCE: /* single channel */ sfbOffset[0] = psyOut->psyOutChannel[elInfo.ChannelIndex[0]].sfbOffsets; tnsInfo[0] = psyOut->psyOutChannel[elInfo.ChannelIndex[0]].tnsInfo; writeSingleChannelElement(elInfo.instanceTag, sfbOffset[0], &qcOut->qcChannel[elInfo.ChannelIndex[0]], hBitStream, tnsInfo[0]); break; case ID_CPE: /* channel pair */ { Word16 msDigest; Word16 *msFlags = psyOut->psyOutElement.toolsInfo.msMask; msDigest = psyOut->psyOutElement.toolsInfo.msDigest; sfbOffset[0] = psyOut->psyOutChannel[elInfo.ChannelIndex[0]].sfbOffsets; sfbOffset[1] = psyOut->psyOutChannel[elInfo.ChannelIndex[1]].sfbOffsets; tnsInfo[0]= psyOut->psyOutChannel[elInfo.ChannelIndex[0]].tnsInfo; tnsInfo[1]= psyOut->psyOutChannel[elInfo.ChannelIndex[1]].tnsInfo; writeChannelPairElement(elInfo.instanceTag, msDigest, msFlags, sfbOffset, &qcOut->qcChannel[elInfo.ChannelIndex[0]], hBitStream, tnsInfo); } break; default: return(1); } /* switch */ elementUsedBits = elementUsedBits - bitMarkUp; bitMarkUp = GetBitsAvail(hBitStream); frameBits = frameBits + elementUsedBits + bitMarkUp; } writeFillElement(NULL, qcOut->totFillBits, hBitStream); WriteBits(hBitStream,ID_END,3); /* byte alignement */ WriteBits(hBitStream,0, (8 - (hBitStream->cntBits & 7)) & 7); *globUsedBits = *globUsedBits- bitMarkUp; bitMarkUp = GetBitsAvail(hBitStream); *globUsedBits = *globUsedBits + bitMarkUp; frameBits = frameBits + *globUsedBits; if (frameBits != (qcOut->totStaticBitsUsed+qcOut->totDynBitsUsed + qcOut->totAncBitsUsed + qcOut->totFillBits + qcOut->alignBits)) { return(-1); } return(0); }