| /* |
| ** 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" |
| |
| #define UNUSED(x) (void)(x) |
| |
| 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; i<sectionData->noOfSections; i++) { |
| psectioninfo = &(sectionData->sectionInfo[i]); |
| /* |
| huffencode spectral data for this section |
| */ |
| for(sfb=psectioninfo->sfbStart; |
| sfb<psectioninfo->sfbStart+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;i<sectionData->noOfSections;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;i<sectionData->noOfSections;i++){ |
| psectioninfo = &(sectionData->sectionInfo[i]); |
| if (psectioninfo->codeBook != CODE_BOOK_ZERO_NO){ |
| for (j=psectioninfo->sfbStart; |
| j<psectioninfo->sfbStart+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<maxSfb; sfb++) { |
| |
| if(jsFlags[sfbOff+sfb] & MS_ON) { |
| WriteBits(hBitStream,1,1); |
| } |
| else{ |
| WriteBits(hBitStream,0,1); |
| } |
| } |
| } |
| break; |
| } |
| |
| } |
| |
| /***************************************************************************** |
| * |
| * function name: encodeTnsData |
| * description: encode TNS data (filter order, coeffs, ..) |
| * returns: none |
| * |
| *****************************************************************************/ |
| static void encodeTnsData(TNS_INFO tnsInfo, |
| Word16 blockType, |
| HANDLE_BIT_BUF hBitStream) { |
| Word16 i,k; |
| Flag tnsPresent; |
| Word16 numOfWindows; |
| Word16 coefBits; |
| Flag isShort; |
| |
| |
| if (blockType==2) { |
| isShort = 1; |
| numOfWindows = TRANS_FAC; |
| } |
| else { |
| isShort = 0; |
| numOfWindows = 1; |
| } |
| |
| tnsPresent=0; |
| for (i=0; i<numOfWindows; i++) { |
| |
| if (tnsInfo.tnsActive[i]) { |
| tnsPresent=1; |
| } |
| } |
| |
| if (tnsPresent==0) { |
| WriteBits(hBitStream,0,1); |
| } |
| else{ /* there is data to be written*/ |
| WriteBits(hBitStream,1,1); /*data_present */ |
| for (i=0; i<numOfWindows; i++) { |
| |
| WriteBits(hBitStream,tnsInfo.tnsActive[i],(isShort?1:2)); |
| |
| if (tnsInfo.tnsActive[i]) { |
| |
| WriteBits(hBitStream,((tnsInfo.coefRes[i] - 4)==0?1:0),1); |
| |
| WriteBits(hBitStream,tnsInfo.length[i],(isShort?4:6)); |
| |
| WriteBits(hBitStream,tnsInfo.order[i],(isShort?3:5)); |
| |
| if (tnsInfo.order[i]){ |
| WriteBits(hBitStream, FILTER_DIRECTION, 1); |
| |
| if(tnsInfo.coefRes[i] == 4) { |
| coefBits = 3; |
| for(k=0; k<tnsInfo.order[i]; k++) { |
| |
| if (tnsInfo.coef[i*TNS_MAX_ORDER_SHORT+k] > 3 || |
| tnsInfo.coef[i*TNS_MAX_ORDER_SHORT+k] < -4) { |
| coefBits = 4; |
| break; |
| } |
| } |
| } |
| else { |
| coefBits = 2; |
| for(k=0; k<tnsInfo.order[i]; k++) { |
| |
| if (tnsInfo.coef[i*TNS_MAX_ORDER_SHORT+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; k<tnsInfo.order[i]; k++ ) { |
| static const Word16 rmask[] = {0,1,3,7,15}; |
| |
| WriteBits(hBitStream,tnsInfo.coef[i*TNS_MAX_ORDER_SHORT+k] & rmask[coefBits],coefBits); |
| } |
| } |
| } |
| } |
| } |
| |
| } |
| |
| /***************************************************************************** |
| * |
| * function name: encodeGainControlData |
| * description: unsupported |
| * returns: none |
| * |
| *****************************************************************************/ |
| static void encodeGainControlData(HANDLE_BIT_BUF hBitStream) |
| { |
| WriteBits(hBitStream,0,1); |
| } |
| |
| /***************************************************************************** |
| * |
| * function name: encodePulseData |
| * description: not supported yet (dummy) |
| * returns: none |
| * |
| *****************************************************************************/ |
| static void encodePulseData(HANDLE_BIT_BUF hBitStream) |
| { |
| WriteBits(hBitStream,0,1); |
| } |
| |
| |
| /***************************************************************************** |
| * |
| * function name: WriteIndividualChannelStream |
| * description: management of write process of individual channel stream |
| * returns: none |
| * |
| *****************************************************************************/ |
| static void |
| writeIndividualChannelStream(Flag commonWindow, |
| Word16 mdctScale, |
| Word16 windowShape, |
| Word16 groupingMask, |
| Word16 *sfbOffset, |
| Word16 scf[], |
| UWord16 *maxValueInSfb, |
| Word16 globalGain, |
| Word16 quantSpec[], |
| SECTION_DATA *sectionData, |
| HANDLE_BIT_BUF hBitStream, |
| TNS_INFO tnsInfo) |
| { |
| Word16 logNorm; |
| |
| logNorm = LOG_NORM_PCM - (mdctScale + 1); |
| |
| encodeGlobalGain(globalGain, logNorm,scf[sectionData->firstScf], 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;i<cnt;i++) { |
| |
| if(ancBytes) |
| WriteBits(hBitStream, *ancBytes++,8); |
| else |
| WriteBits(hBitStream,0,8); |
| totFillBits = totFillBits - 8; |
| } |
| } |
| } |
| |
| /***************************************************************************** |
| * |
| * function name: WriteBitStream |
| * description: main function of write bitsteam process |
| * returns: 0 if success |
| * |
| *****************************************************************************/ |
| Word16 WriteBitstream (HANDLE_BIT_BUF hBitStream, |
| ELEMENT_INFO elInfo, |
| QC_OUT *qcOut, |
| PSY_OUT *psyOut, |
| Word16 *globUsedBits, |
| const UWord8 *ancBytes, |
| Word16 sampindex |
| ) /* returns error code */ |
| { |
| Word16 bitMarkUp; |
| Word16 elementUsedBits; |
| Word16 frameBits=0; |
| |
| UNUSED(ancBytes); |
| |
| /* struct bitbuffer bsWriteCopy; */ |
| bitMarkUp = GetBitsAvail(hBitStream); |
| if(qcOut->qcElement.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); |
| } |