diff options
author | Dave Burke <daveburke@google.com> | 2012-04-17 09:51:45 -0700 |
---|---|---|
committer | Dave Burke <daveburke@google.com> | 2012-04-17 23:04:43 -0700 |
commit | 9bf37cc9712506b2483650c82d3c41152337ef7e (patch) | |
tree | 77db44e2bae06e3d144b255628be2b7a55c581d3 /libAACenc/src/bitenc.cpp | |
parent | a37315fe10ee143d6d0b28c19d41a476a23e63ea (diff) | |
download | ODR-AudioEnc-9bf37cc9712506b2483650c82d3c41152337ef7e.tar.gz ODR-AudioEnc-9bf37cc9712506b2483650c82d3c41152337ef7e.tar.bz2 ODR-AudioEnc-9bf37cc9712506b2483650c82d3c41152337ef7e.zip |
Fraunhofer AAC codec.
License boilerplate update to follow.
Change-Id: I2810460c11a58b6d148d84673cc031f3685e79b5
Diffstat (limited to 'libAACenc/src/bitenc.cpp')
-rw-r--r-- | libAACenc/src/bitenc.cpp | 1431 |
1 files changed, 1431 insertions, 0 deletions
diff --git a/libAACenc/src/bitenc.cpp b/libAACenc/src/bitenc.cpp new file mode 100644 index 0000000..d70f872 --- /dev/null +++ b/libAACenc/src/bitenc.cpp @@ -0,0 +1,1431 @@ + /******************************** MPEG Audio Encoder ************************** + + (C) Copyright Fraunhofer IIS (1999) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + + $Id$ + Initial author: M. Werner + contents/description: Bitstream encoder + +******************************************************************************/ + +#include "bitenc.h" +#include "bit_cnt.h" +#include "dyn_bits.h" +#include "qc_data.h" +#include "interface.h" +#include "aacEnc_ram.h" + + +#include "tpenc_lib.h" + +#include "FDK_tools_rom.h" /* needed for the bitstream syntax tables */ + +static const int globalGainOffset = 100; +static const int icsReservedBit = 0; +static const int noiseOffset = 90; + +/***************************************************************************** + + functionname: FDKaacEnc_encodeSpectralData + description: encode spectral data + returns: the number of written bits + input: + output: + +*****************************************************************************/ +static INT FDKaacEnc_encodeSpectralData(INT *sfbOffset, + SECTION_DATA *sectionData, + SHORT *quantSpectrum, + HANDLE_FDK_BITSTREAM hBitStream) +{ + INT i,sfb; + INT dbgVal = FDKgetValidBits(hBitStream); + + for(i=0;i<sectionData->noOfSections;i++) + { + if(sectionData->huffsection[i].codeBook != CODE_BOOK_PNS_NO) + { + /* huffencode spectral data for this huffsection */ + INT tmp = sectionData->huffsection[i].sfbStart+sectionData->huffsection[i].sfbCnt; + for(sfb=sectionData->huffsection[i].sfbStart; sfb<tmp; sfb++) + { + FDKaacEnc_codeValues(quantSpectrum+sfbOffset[sfb], + sfbOffset[sfb+1]-sfbOffset[sfb], + sectionData->huffsection[i].codeBook, + hBitStream); + } + } + } + return(FDKgetValidBits(hBitStream)-dbgVal); +} + +/***************************************************************************** + + functionname:FDKaacEnc_encodeGlobalGain + description: encodes Global Gain (common scale factor) + returns: the number of static bits + input: + output: + +*****************************************************************************/ +static INT FDKaacEnc_encodeGlobalGain(INT globalGain, + INT scalefac, + HANDLE_FDK_BITSTREAM hBitStream, + INT mdctScale) +{ + if (hBitStream != NULL) { + FDKwriteBits(hBitStream,globalGain - scalefac + globalGainOffset-4*(LOG_NORM_PCM-mdctScale),8); + } + return (8); +} + + +/***************************************************************************** + + functionname:FDKaacEnc_encodeIcsInfo + description: encodes Ics Info + returns: the number of static bits + input: + output: + +*****************************************************************************/ + +static INT FDKaacEnc_encodeIcsInfo(INT blockType, + INT windowShape, + INT groupingMask, + INT maxSfbPerGroup, + HANDLE_FDK_BITSTREAM hBitStream, + UINT syntaxFlags) +{ + INT statBits; + + if (blockType == SHORT_WINDOW) { + statBits = 8 + TRANS_FAC - 1; + } else { + if (syntaxFlags & AC_ELD) { + statBits = 6; + } else + { + statBits = (!(syntaxFlags & AC_SCALABLE)) ? 11 : 10; + } + } + + if (hBitStream != NULL) { + + if (!(syntaxFlags & AC_ELD)){ + FDKwriteBits(hBitStream,icsReservedBit,1); + FDKwriteBits(hBitStream,blockType,2); + FDKwriteBits(hBitStream, (windowShape == LOL_WINDOW) ? KBD_WINDOW : windowShape,1); + } + + switch(blockType){ + case LONG_WINDOW: + case START_WINDOW: + case STOP_WINDOW: + FDKwriteBits(hBitStream,maxSfbPerGroup,6); + + if (!(syntaxFlags & (AC_SCALABLE|AC_ELD)) ) { /* If not scalable syntax then ... */ + /* No predictor data present */ + FDKwriteBits(hBitStream, 0, 1); + } + break; + + case SHORT_WINDOW: + FDKwriteBits(hBitStream,maxSfbPerGroup,4); + + /* Write grouping bits */ + FDKwriteBits(hBitStream,groupingMask,TRANS_FAC-1); + break; + } + } + + return (statBits); +} + +/***************************************************************************** + + functionname: FDKaacEnc_encodeSectionData + description: encode section data (common Huffman codebooks for adjacent + SFB's) + returns: none + input: + output: + +*****************************************************************************/ +static INT FDKaacEnc_encodeSectionData(SECTION_DATA *sectionData, + HANDLE_FDK_BITSTREAM hBitStream, + UINT useVCB11) +{ + if (hBitStream != NULL) { + INT sectEscapeVal=0,sectLenBits=0; + INT sectLen; + INT i; + INT dbgVal=FDKgetValidBits(hBitStream); + INT sectCbBits = 4; + + 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++) + { + INT codeBook = sectionData->huffsection[i].codeBook; + + FDKwriteBits(hBitStream,codeBook,sectCbBits); + + { + sectLen = sectionData->huffsection[i].sfbCnt; + + while(sectLen >= sectEscapeVal) + { + FDKwriteBits(hBitStream,sectEscapeVal,sectLenBits); + sectLen-=sectEscapeVal; + } + FDKwriteBits(hBitStream,sectLen,sectLenBits); + } + } + return(FDKgetValidBits(hBitStream)-dbgVal); + } + return (0); +} + +/***************************************************************************** + + functionname: FDKaacEnc_encodeScaleFactorData + description: encode DPCM coded scale factors + returns: none + input: + output: + +*****************************************************************************/ +static INT FDKaacEnc_encodeScaleFactorData(UINT *maxValueInSfb, + SECTION_DATA *sectionData, + INT *scalefac, + HANDLE_FDK_BITSTREAM hBitStream, + INT *RESTRICT noiseNrg, + const INT *isScale, + INT globalGain) +{ + if (hBitStream != NULL) { + INT i,j,lastValScf,deltaScf; + INT deltaPns; + INT lastValPns = 0; + INT noisePCMFlag = TRUE; + INT lastValIs; + + INT dbgVal = FDKgetValidBits(hBitStream); + + lastValScf=scalefac[sectionData->firstScf]; + lastValPns = globalGain-scalefac[sectionData->firstScf]+globalGainOffset-4*LOG_NORM_PCM-noiseOffset; + lastValIs = 0; + + for(i=0; i<sectionData->noOfSections; i++){ + if (sectionData->huffsection[i].codeBook != CODE_BOOK_ZERO_NO) { + + if ((sectionData->huffsection[i].codeBook == CODE_BOOK_IS_OUT_OF_PHASE_NO) || + (sectionData->huffsection[i].codeBook == CODE_BOOK_IS_IN_PHASE_NO)) + { + INT sfbStart = sectionData->huffsection[i].sfbStart; + INT tmp = sfbStart + sectionData->huffsection[i].sfbCnt; + for(j=sfbStart; j<tmp; j++) { + INT deltaIs = isScale[j]-lastValIs; + lastValIs = isScale[j]; + if(FDKaacEnc_codeScalefactorDelta(deltaIs,hBitStream)) { + return(1); + } + } /* sfb */ + } + else if(sectionData->huffsection[i].codeBook == CODE_BOOK_PNS_NO) { + INT sfbStart = sectionData->huffsection[i].sfbStart; + INT tmp = sfbStart + sectionData->huffsection[i].sfbCnt; + for(j=sfbStart; j<tmp; j++) { + deltaPns = noiseNrg[j]-lastValPns; + lastValPns = noiseNrg[j]; + + if(noisePCMFlag){ + FDKwriteBits(hBitStream,deltaPns+(1<<(PNS_PCM_BITS-1)),PNS_PCM_BITS); + noisePCMFlag = FALSE; + } + else { + if(FDKaacEnc_codeScalefactorDelta(deltaPns,hBitStream)) { + return(1); + } + } + } /* sfb */ + } + else { + INT tmp = sectionData->huffsection[i].sfbStart+sectionData->huffsection[i].sfbCnt; + for(j=sectionData->huffsection[i].sfbStart; j<tmp; j++){ + /* + check if we can repeat the last value to save bits + */ + if(maxValueInSfb[j] == 0) + deltaScf = 0; + else{ + deltaScf = -(scalefac[j]-lastValScf); + lastValScf = scalefac[j]; + } + if(FDKaacEnc_codeScalefactorDelta(deltaScf,hBitStream)){ + return(1); + } + } /* sfb */ + } /* code scalefactor */ + } /* sectionData->huffsection[i].codeBook != CODE_BOOK_ZERO_NO */ + } /* section loop */ + + return(FDKgetValidBits(hBitStream)-dbgVal); + } /* if (hBitStream != NULL) */ + + return (0); +} + +/***************************************************************************** + + functionname:encodeMsInfo + description: encodes MS-Stereo Info + returns: the number of static bits + input: + output: + +*****************************************************************************/ +static INT FDKaacEnc_encodeMSInfo(INT sfbCnt, + INT grpSfb, + INT maxSfb, + INT msDigest, + INT *jsFlags, + HANDLE_FDK_BITSTREAM hBitStream) +{ + INT sfb, sfbOff, msBits = 0; + + if (hBitStream != NULL) + { + switch(msDigest) + { + case MS_NONE: + FDKwriteBits(hBitStream,SI_MS_MASK_NONE,2); + msBits += 2; + break; + + case MS_ALL: + FDKwriteBits(hBitStream,SI_MS_MASK_ALL,2); + msBits += 2; + break; + + case MS_SOME: + FDKwriteBits(hBitStream,SI_MS_MASK_SOME,2); + msBits += 2; + for(sfbOff = 0; sfbOff < sfbCnt; sfbOff+=grpSfb) + { + for(sfb=0; sfb<maxSfb; sfb++) + { + if(jsFlags[sfbOff+sfb] & MS_ON){ + FDKwriteBits(hBitStream,1,1); + } + else{ + FDKwriteBits(hBitStream,0,1); + } + msBits += 1; + } + } + break; + } + } + else { + msBits += 2; + if (msDigest == MS_SOME) { + for(sfbOff = 0; sfbOff < sfbCnt; sfbOff+=grpSfb) { + for(sfb=0; sfb<maxSfb; sfb++) { + msBits += 1; + } + } + } + } + return (msBits); +} + +/***************************************************************************** + + functionname: FDKaacEnc_encodeTnsDataPresent + description: encode TNS data (filter order, coeffs, ..) + returns: the number of static bits + input: + output: + +*****************************************************************************/ +static INT FDKaacEnc_encodeTnsDataPresent(TNS_INFO *tnsInfo, + INT blockType, + HANDLE_FDK_BITSTREAM hBitStream) +{ + if ( (hBitStream!=NULL) && (tnsInfo!=NULL) ) + { + INT i, tnsPresent = 0; + INT numOfWindows = (blockType==SHORT_WINDOW?TRANS_FAC:1); + + for (i=0; i<numOfWindows; i++) { + if (tnsInfo->numOfFilters[i]!=0) { + tnsPresent=1; + break; + } + } + + if (tnsPresent==0) { + FDKwriteBits(hBitStream,0,1); + } else { + FDKwriteBits(hBitStream,1,1); + } + } + return (1); +} + +/***************************************************************************** + + functionname: FDKaacEnc_encodeTnsData + description: encode TNS data (filter order, coeffs, ..) + returns: the number of static bits + input: + output: + +*****************************************************************************/ +static INT FDKaacEnc_encodeTnsData(TNS_INFO *tnsInfo, + INT blockType, + HANDLE_FDK_BITSTREAM hBitStream) +{ + INT tnsBits = 0; + + if (tnsInfo!=NULL) { + + INT i,j,k; + INT tnsPresent = 0; + INT coefBits; + INT numOfWindows=(blockType==SHORT_WINDOW?TRANS_FAC:1); + + for (i=0; i<numOfWindows; i++) { + if (tnsInfo->numOfFilters[i]!=0) { + tnsPresent=1; + } + } + + if (hBitStream != NULL) + { + if (tnsPresent==1) { /* there is data to be written*/ + for (i=0; i<numOfWindows; i++) { + FDKwriteBits(hBitStream,tnsInfo->numOfFilters[i],(blockType==SHORT_WINDOW?1:2)); + tnsBits += (blockType==SHORT_WINDOW?1:2); + if (tnsInfo->numOfFilters[i]) { + FDKwriteBits(hBitStream,(tnsInfo->coefRes[i]==4?1:0),1); + tnsBits += 1; + } + for (j=0; j<tnsInfo->numOfFilters[i]; j++) { + FDKwriteBits(hBitStream,tnsInfo->length[i][j],(blockType==SHORT_WINDOW?4:6)); + tnsBits += (blockType==SHORT_WINDOW?4:6); + FDK_ASSERT(tnsInfo->order[i][j] <= 12); + FDKwriteBits(hBitStream,tnsInfo->order[i][j],(blockType==SHORT_WINDOW?3:5)); + tnsBits += (blockType==SHORT_WINDOW?3:5); + if (tnsInfo->order[i][j]){ + FDKwriteBits(hBitStream,tnsInfo->direction[i][j],1); + tnsBits +=1; /*direction*/ + if(tnsInfo->coefRes[i] == 4) { + coefBits = 3; + for(k=0; k<tnsInfo->order[i][j]; k++) { + if (tnsInfo->coef[i][j][k]> 3 || + tnsInfo->coef[i][j][k]< -4) { + coefBits = 4; + break; + } + } + } else { + coefBits = 2; + for(k=0; k<tnsInfo->order[i][j]; k++) { + if ( tnsInfo->coef[i][j][k]> 1 + || tnsInfo->coef[i][j][k]< -2) { + coefBits = 3; + break; + } + } + } + FDKwriteBits(hBitStream,-(coefBits - tnsInfo->coefRes[i]),1); /*coef_compres*/ + tnsBits +=1; /*coef_compression */ + for (k=0; k<tnsInfo->order[i][j]; k++ ) { + static const INT rmask[] = {0,1,3,7,15}; + FDKwriteBits(hBitStream,tnsInfo->coef[i][j][k] & rmask[coefBits],coefBits); + tnsBits += coefBits; + } + } + } + } + } + } + else { + if (tnsPresent != 0) { + for (i=0; i<numOfWindows; i++) { + tnsBits += (blockType==SHORT_WINDOW?1:2); + if (tnsInfo->numOfFilters[i]) { + tnsBits += 1; + for (j=0; j<tnsInfo->numOfFilters[i]; j++) { + tnsBits += (blockType==SHORT_WINDOW?4:6); + tnsBits += (blockType==SHORT_WINDOW?3:5); + if (tnsInfo->order[i][j]) { + tnsBits +=1; /*direction*/ + tnsBits +=1; /*coef_compression */ + if (tnsInfo->coefRes[i] == 4) { + coefBits=3; + for (k=0; k<tnsInfo->order[i][j]; k++) { + if (tnsInfo->coef[i][j][k]> 3 || tnsInfo->coef[i][j][k]< -4) { + coefBits = 4; + break; + } + } + } + else { + coefBits = 2; + for (k=0; k<tnsInfo->order[i][j]; k++) { + if (tnsInfo->coef[i][j][k]> 1 || tnsInfo->coef[i][j][k]< -2) { + coefBits = 3; + break; + } + } + } + for (k=0; k<tnsInfo->order[i][j]; k++) { + tnsBits += coefBits; + } + } + } + } + } + } + } + } /* (tnsInfo!=NULL) */ + + return (tnsBits); +} + +/***************************************************************************** + + functionname: FDKaacEnc_encodeGainControlData + description: unsupported + returns: none + input: + output: + +*****************************************************************************/ +static INT FDKaacEnc_encodeGainControlData(HANDLE_FDK_BITSTREAM hBitStream) +{ + if (hBitStream != NULL) { + FDKwriteBits(hBitStream,0,1); + } + return (1); +} + +/***************************************************************************** + + functionname: FDKaacEnc_encodePulseData + description: not supported yet (dummy) + returns: none + input: + output: + +*****************************************************************************/ +static INT FDKaacEnc_encodePulseData(HANDLE_FDK_BITSTREAM hBitStream) +{ + if (hBitStream != NULL) { + FDKwriteBits(hBitStream,0,1); + } + return (1); +} + + +/***************************************************************************** + + functionname: FDKaacEnc_writeExtensionPayload + description: write extension payload to bitstream + returns: number of written bits + input: + output: + +*****************************************************************************/ +static INT FDKaacEnc_writeExtensionPayload( HANDLE_FDK_BITSTREAM hBitStream, + EXT_PAYLOAD_TYPE extPayloadType, + const UCHAR *extPayloadData, + INT extPayloadBits + ) +{ + #define EXT_TYPE_BITS ( 4 ) + #define DATA_EL_VERSION_BITS ( 4 ) + #define FILL_NIBBLE_BITS ( 4 ) + + INT extBitsUsed = 0; + + if (extPayloadBits >= EXT_TYPE_BITS) + { + UCHAR fillByte = 0x00; /* for EXT_FIL and EXT_FILL_DATA */ + + if (hBitStream != NULL) { + FDKwriteBits(hBitStream, extPayloadType, EXT_TYPE_BITS); + } + extBitsUsed += EXT_TYPE_BITS; + + switch (extPayloadType) { + case EXT_DYNAMIC_RANGE: + /* case EXT_SAC_DATA: */ + case EXT_SBR_DATA: + case EXT_SBR_DATA_CRC: + if (hBitStream != NULL) { + int i, writeBits = extPayloadBits; + for (i=0; writeBits >= 8; i++) { + FDKwriteBits(hBitStream, extPayloadData[i], 8); + writeBits -= 8; + } + if (writeBits > 0) { + FDKwriteBits(hBitStream, extPayloadData[i]>>(8-writeBits), writeBits); + } + } + extBitsUsed += extPayloadBits; + break; + + case EXT_DATA_ELEMENT: + { + INT dataElementLength = (extPayloadBits+7)>>3; + INT cnt = dataElementLength; + int loopCounter = 1; + + while (dataElementLength >= 255) { + loopCounter++; + dataElementLength -= 255; + } + + if (hBitStream != NULL) { + int i; + FDKwriteBits(hBitStream, 0x00, DATA_EL_VERSION_BITS); /* data_element_version = ANC_DATA */ + + for (i=1; i<loopCounter; i++) { + FDKwriteBits(hBitStream, 255, 8); + } + FDKwriteBits(hBitStream, dataElementLength, 8); + + for (i=0; i<cnt; i++) { + FDKwriteBits(hBitStream, extPayloadData[i], 8); + } + } + extBitsUsed += DATA_EL_VERSION_BITS + (loopCounter*8) + (cnt*8); + } + break; + + case EXT_FILL_DATA: + fillByte = 0xA5; + case EXT_FIL: + default: + if (hBitStream != NULL) { + int writeBits = extPayloadBits; + FDKwriteBits(hBitStream, 0x00, FILL_NIBBLE_BITS); + writeBits -= 8; /* acount for the extension type and the fill nibble */ + while (writeBits >= 8) { + FDKwriteBits(hBitStream, fillByte, 8); + writeBits -= 8; + } + } + extBitsUsed += FILL_NIBBLE_BITS + (extPayloadBits & ~0x7) - 8; + break; + } + } + + return (extBitsUsed); +} + + +/***************************************************************************** + + functionname: FDKaacEnc_writeDataStreamElement + description: write data stream elements like ancillary data ... + returns: the amount of used bits + input: + output: + +******************************************************************************/ +static INT FDKaacEnc_writeDataStreamElement( HANDLE_TRANSPORTENC hTpEnc, + INT elementInstanceTag, + INT dataPayloadBytes, + UCHAR *dataBuffer, + UINT alignAnchor ) +{ + #define DATA_BYTE_ALIGN_FLAG ( 0 ) + + #define EL_INSTANCE_TAG_BITS ( 4 ) + #define DATA_BYTE_ALIGN_FLAG_BITS ( 1 ) + #define DATA_LEN_COUNT_BITS ( 8 ) + #define DATA_LEN_ESC_COUNT_BITS ( 8 ) + + #define MAX_DATA_ALIGN_BITS ( 7 ) + #define MAX_DSE_DATA_BYTES ( 510 ) + + INT dseBitsUsed = 0; + + while (dataPayloadBytes > 0) + { + int esc_count = -1; + int cnt = 0; + INT crcReg = -1; + + dseBitsUsed += EL_ID_BITS + EL_INSTANCE_TAG_BITS + + DATA_BYTE_ALIGN_FLAG_BITS + DATA_LEN_COUNT_BITS; + + if (DATA_BYTE_ALIGN_FLAG) { + dseBitsUsed += MAX_DATA_ALIGN_BITS; + } + + cnt = fixMin(MAX_DSE_DATA_BYTES, dataPayloadBytes); + if ( cnt >= 255 ) { + esc_count = cnt - 255; + dseBitsUsed += DATA_LEN_ESC_COUNT_BITS; + } + + dataPayloadBytes -= cnt; + dseBitsUsed += cnt * 8; + + if (hTpEnc != NULL) { + HANDLE_FDK_BITSTREAM hBitStream = transportEnc_GetBitstream(hTpEnc); + int i; + + FDKwriteBits(hBitStream, ID_DSE, EL_ID_BITS); + + crcReg = transportEnc_CrcStartReg(hTpEnc, 0); + + FDKwriteBits(hBitStream, elementInstanceTag, EL_INSTANCE_TAG_BITS); + FDKwriteBits(hBitStream, DATA_BYTE_ALIGN_FLAG, DATA_BYTE_ALIGN_FLAG_BITS); + + /* write length field(s) */ + if ( esc_count >= 0 ) { + FDKwriteBits(hBitStream, 255, DATA_LEN_COUNT_BITS); + FDKwriteBits(hBitStream, esc_count, DATA_LEN_ESC_COUNT_BITS); + } else { + FDKwriteBits(hBitStream, cnt, DATA_LEN_COUNT_BITS); + } + + if (DATA_BYTE_ALIGN_FLAG) { + INT tmp = (INT)FDKgetValidBits(hBitStream); + FDKbyteAlign(hBitStream, alignAnchor); + /* count actual bits */ + dseBitsUsed += (INT)FDKgetValidBits(hBitStream) - tmp - MAX_DATA_ALIGN_BITS; + } + + /* write payload */ + for (i=0; i<cnt; i++) { + FDKwriteBits(hBitStream, dataBuffer[i], 8); + } + transportEnc_CrcEndReg(hTpEnc, crcReg); + } + } + + return (dseBitsUsed); +} + + +/***************************************************************************** + + functionname: FDKaacEnc_writeExtensionData + description: write extension payload to bitstream + returns: number of written bits + input: + output: + +*****************************************************************************/ +INT FDKaacEnc_writeExtensionData( HANDLE_TRANSPORTENC hTpEnc, + QC_OUT_EXTENSION *pExtension, + INT elInstanceTag, /* for DSE only */ + UINT alignAnchor, /* for DSE only */ + UINT syntaxFlags, + AUDIO_OBJECT_TYPE aot, + SCHAR epConfig + ) +{ + #define FILL_EL_COUNT_BITS ( 4 ) + #define FILL_EL_ESC_COUNT_BITS ( 8 ) + #define MAX_FILL_DATA_BYTES ( 269 ) + + HANDLE_FDK_BITSTREAM hBitStream = NULL; + INT payloadBits = pExtension->nPayloadBits; + INT extBitsUsed = 0; + + if (hTpEnc != NULL) { + hBitStream = transportEnc_GetBitstream(hTpEnc); + } + + if (syntaxFlags & (AC_SCALABLE|AC_ER)) + { + if ( syntaxFlags & AC_DRM ) + { /* CAUTION: The caller has to assure that fill + data is written before the SBR payload. */ + UCHAR *extPayloadData = pExtension->pPayload; + + switch (pExtension->type) + { + case EXT_SBR_DATA: + case EXT_SBR_DATA_CRC: + /* SBR payload is written in reverse */ + if (hBitStream != NULL) { + int i, writeBits = payloadBits; + + FDKpushFor(hBitStream, payloadBits-1); /* Does a cache sync internally */ + + for (i=0; writeBits >= 8; i++) { + FDKwriteBitsBwd(hBitStream, extPayloadData[i], 8); + writeBits -= 8; + } + if (writeBits > 0) { + FDKwriteBitsBwd(hBitStream, extPayloadData[i]>>(8-writeBits), writeBits); + } + + FDKsyncCacheBwd (hBitStream); + FDKpushFor (hBitStream, payloadBits+1); + } + extBitsUsed += payloadBits; + break; + + case EXT_FILL_DATA: + case EXT_FIL: + default: + if (hBitStream != NULL) { + int writeBits = payloadBits; + while (writeBits >= 8) { + FDKwriteBits(hBitStream, 0x00, 8); + writeBits -= 8; + } + FDKwriteBits(hBitStream, 0x00, writeBits); + } + extBitsUsed += payloadBits; + break; + } + } + else { + if ( (syntaxFlags & AC_ELD) && ((pExtension->type==EXT_SBR_DATA) || (pExtension->type==EXT_SBR_DATA_CRC)) ) { + + if (hBitStream != NULL) { + int i, writeBits = payloadBits; + UCHAR *extPayloadData = pExtension->pPayload; + + for (i=0; writeBits >= 8; i++) { + FDKwriteBits(hBitStream, extPayloadData[i], 8); + writeBits -= 8; + } + if (writeBits > 0) { + FDKwriteBits(hBitStream, extPayloadData[i]>>(8-writeBits), writeBits); + } + } + extBitsUsed += payloadBits; + } + else + { + /* ER or scalable syntax -> write extension en bloc */ + extBitsUsed += FDKaacEnc_writeExtensionPayload( hBitStream, + pExtension->type, + pExtension->pPayload, + payloadBits ); + } + } + } + else { + /* We have normal GA bitstream payload (AOT 2,5,29) so pack + the data into a fill elements or DSEs */ + + if ( pExtension->type == EXT_DATA_ELEMENT ) + { + extBitsUsed += FDKaacEnc_writeDataStreamElement( hTpEnc, + elInstanceTag, + pExtension->nPayloadBits>>3, + pExtension->pPayload, + alignAnchor ); + } + else { + while (payloadBits >= (EL_ID_BITS + FILL_EL_COUNT_BITS)) { + INT cnt, esc_count=-1, alignBits=7; + + if ( (pExtension->type == EXT_FILL_DATA) || (pExtension->type == EXT_FIL) ) + { + payloadBits -= EL_ID_BITS + FILL_EL_COUNT_BITS; + if (payloadBits >= 15*8) { + payloadBits -= FILL_EL_ESC_COUNT_BITS; + esc_count = 0; /* write esc_count even if cnt becomes smaller 15 */ + } + alignBits = 0; + } + + cnt = fixMin(MAX_FILL_DATA_BYTES, (payloadBits+alignBits)>>3); + + if (cnt >= 15) { + esc_count = cnt - 15 + 1; + } + + if (hBitStream != NULL) { + /* write bitstream */ + FDKwriteBits(hBitStream, ID_FIL, EL_ID_BITS); + if (esc_count >= 0) { + FDKwriteBits(hBitStream, 15, FILL_EL_COUNT_BITS); + FDKwriteBits(hBitStream, esc_count, FILL_EL_ESC_COUNT_BITS); + } else { + FDKwriteBits(hBitStream, cnt, FILL_EL_COUNT_BITS); + } + } + + extBitsUsed += EL_ID_BITS + FILL_EL_COUNT_BITS + ((esc_count>=0) ? FILL_EL_ESC_COUNT_BITS : 0); + + cnt = fixMin(cnt*8, payloadBits); /* convert back to bits */ + extBitsUsed += FDKaacEnc_writeExtensionPayload( hBitStream, + pExtension->type, + pExtension->pPayload, + cnt ); + payloadBits -= cnt; + } + } + } + + return (extBitsUsed); +} + + +/***************************************************************************** + + functionname: FDKaacEnc_ByteAlignment + description: + returns: + input: + output: + +*****************************************************************************/ +static void FDKaacEnc_ByteAlignment(HANDLE_FDK_BITSTREAM hBitStream, int alignBits) +{ + FDKwriteBits(hBitStream, 0, alignBits); +} + +AAC_ENCODER_ERROR FDKaacEnc_ChannelElementWrite( HANDLE_TRANSPORTENC hTpEnc, + ELEMENT_INFO *pElInfo, + QC_OUT_CHANNEL *qcOutChannel[(2)], + PSY_OUT_ELEMENT *psyOutElement, + PSY_OUT_CHANNEL *psyOutChannel[(2)], + UINT syntaxFlags, + AUDIO_OBJECT_TYPE aot, + SCHAR epConfig, + INT *pBitDemand, + UCHAR minCnt + ) +{ + AAC_ENCODER_ERROR error = AAC_ENC_OK; + HANDLE_FDK_BITSTREAM hBitStream = NULL; + INT bitDemand = 0; + const element_list_t *list; + int i, ch, decision_bit; + INT crcReg1 = -1, crcReg2 = -1; + UCHAR numberOfChannels; + + if (hTpEnc != NULL) { + /* Get bitstream handle */ + hBitStream = transportEnc_GetBitstream(hTpEnc); + } + + if ( (pElInfo->elType==ID_SCE) || (pElInfo->elType==ID_LFE) ) { + numberOfChannels = 1; + } else { + numberOfChannels = 2; + } + + /* Get channel element sequence table */ + list = getBitstreamElementList(aot, epConfig, numberOfChannels, 0); + if (list == NULL) { + error = AAC_ENC_UNSUPPORTED_AOT; + goto bail; + } + + if (!(syntaxFlags & (AC_SCALABLE|AC_ER))) { + if (hBitStream != NULL) { + FDKwriteBits(hBitStream, pElInfo->elType, EL_ID_BITS); + } + bitDemand += EL_ID_BITS; + } + + /* Iterate through sequence table */ + i = 0; + ch = 0; + decision_bit = 0; + do { + /* some tmp values */ + SECTION_DATA *pChSectionData = NULL; + INT *pChScf = NULL; + UINT *pChMaxValueInSfb = NULL; + TNS_INFO *pTnsInfo = NULL; + INT chGlobalGain = 0; + INT chBlockType = 0; + INT chMaxSfbPerGrp = 0; + INT chSfbPerGrp = 0; + INT chSfbCnt = 0; + INT chFirstScf = 0; + + if (minCnt==0) { + if ( qcOutChannel!=NULL ) { + pChSectionData = &(qcOutChannel[ch]->sectionData); + pChScf = qcOutChannel[ch]->scf; + chGlobalGain = qcOutChannel[ch]->globalGain; + pChMaxValueInSfb = qcOutChannel[ch]->maxValueInSfb; + chBlockType = pChSectionData->blockType; + chMaxSfbPerGrp = pChSectionData->maxSfbPerGroup; + chSfbPerGrp = pChSectionData->sfbPerGroup; + chSfbCnt = pChSectionData->sfbCnt; + chFirstScf = pChScf[pChSectionData->firstScf]; + } + else { + /* get values from PSY */ + chSfbCnt = psyOutChannel[ch]->sfbCnt; + chSfbPerGrp = psyOutChannel[ch]->sfbPerGroup; + chMaxSfbPerGrp = psyOutChannel[ch]->maxSfbPerGroup; + } + pTnsInfo = &psyOutChannel[ch]->tnsInfo; + } /* minCnt==0 */ + + if ( qcOutChannel==NULL ) { + chBlockType = psyOutChannel[ch]->lastWindowSequence; + } + + switch (list->id[i]) + { + case element_instance_tag: + /* Write element instance tag */ + if (hBitStream != NULL) { + FDKwriteBits(hBitStream, pElInfo->instanceTag, 4); + } + bitDemand += 4; + break; + + case common_window: + /* Write common window flag */ + decision_bit = psyOutElement->commonWindow; + if (hBitStream != NULL) { + FDKwriteBits(hBitStream, psyOutElement->commonWindow, 1); + } + bitDemand += 1; + break; + + case ics_info: + /* Write individual channel info */ + bitDemand += FDKaacEnc_encodeIcsInfo( chBlockType, + psyOutChannel[ch]->windowShape, + psyOutChannel[ch]->groupingMask, + chMaxSfbPerGrp, + hBitStream, + syntaxFlags); + break; + + case ltp_data_present: + /* Write LTP data present flag */ + if (hBitStream != NULL) { + FDKwriteBits(hBitStream, 0, 1); + } + bitDemand += 1; + break; + + case ltp_data: + /* Predictor data not supported. + Nothing to do here. */ + break; + + case ms: + /* Write MS info */ + bitDemand += FDKaacEnc_encodeMSInfo( chSfbCnt, + chSfbPerGrp, + chMaxSfbPerGrp, + (minCnt==0) ? psyOutElement->toolsInfo.msDigest : MS_NONE, + psyOutElement->toolsInfo.msMask, + hBitStream); + break; + + case global_gain: + bitDemand += FDKaacEnc_encodeGlobalGain( chGlobalGain, + chFirstScf, + hBitStream, + psyOutChannel[ch]->mdctScale ); + break; + + case section_data: + { + INT siBits = FDKaacEnc_encodeSectionData(pChSectionData, hBitStream, (syntaxFlags & AC_ER_VCB11)?1:0); + if (hBitStream != NULL) { + if (siBits != qcOutChannel[ch]->sectionData.sideInfoBits) { + error = AAC_ENC_WRITE_SEC_ERROR; + } + } + bitDemand += siBits; + } + break; + + case scale_factor_data: + { + INT sfDataBits = FDKaacEnc_encodeScaleFactorData( pChMaxValueInSfb, + pChSectionData, + pChScf, + hBitStream, + psyOutChannel[ch]->noiseNrg, + psyOutChannel[ch]->isScale, + chGlobalGain ); + if ( (hBitStream != NULL) + && (sfDataBits != (qcOutChannel[ch]->sectionData.scalefacBits + qcOutChannel[ch]->sectionData.noiseNrgBits)) ) { + error = AAC_ENC_WRITE_SCAL_ERROR; + } + bitDemand += sfDataBits; + } + break; + + case esc2_rvlc: + if (syntaxFlags & AC_ER_RVLC) { + /* write RVLC data into bitstream (error sens. cat. 2) */ + error = AAC_ENC_UNSUPPORTED_AOT; + } + break; + + case pulse: + /* Write pulse data */ + bitDemand += FDKaacEnc_encodePulseData(hBitStream); + break; + + case tns_data_present: + /* Write TNS data present flag */ + bitDemand += FDKaacEnc_encodeTnsDataPresent(pTnsInfo, + chBlockType, + hBitStream); + break; + case tns_data: + /* Write TNS data */ + bitDemand += FDKaacEnc_encodeTnsData(pTnsInfo, + chBlockType, + hBitStream); + break; + + case gain_control_data: + /* Nothing to do here */ + break; + + case gain_control_data_present: + bitDemand += FDKaacEnc_encodeGainControlData(hBitStream); + break; + + + case esc1_hcr: + if (syntaxFlags & AC_ER_HCR) + { + error = AAC_ENC_UNKNOWN; + } + break; + + case spectral_data: + if (hBitStream != NULL) + { + INT spectralBits = 0; + + spectralBits = FDKaacEnc_encodeSpectralData( psyOutChannel[ch]->sfbOffsets, + pChSectionData, + qcOutChannel[ch]->quantSpec, + hBitStream ); + + if (spectralBits != qcOutChannel[ch]->sectionData.huffmanBits) { + return AAC_ENC_WRITE_SPEC_ERROR; + } + bitDemand += spectralBits; + } + break; + + /* Non data cases */ + case adtscrc_start_reg1: + if (hTpEnc != NULL) { + crcReg1 = transportEnc_CrcStartReg(hTpEnc, 192); + } + break; + case adtscrc_start_reg2: + if (hTpEnc != NULL) { + crcReg2 = transportEnc_CrcStartReg(hTpEnc, 128); + } + break; + case adtscrc_end_reg1: + case drmcrc_end_reg: + if (hTpEnc != NULL) { + transportEnc_CrcEndReg(hTpEnc, crcReg1); + } + break; + case adtscrc_end_reg2: + if (hTpEnc != NULL) { + transportEnc_CrcEndReg(hTpEnc, crcReg2); + } + break; + case drmcrc_start_reg: + if (hTpEnc != NULL) { + crcReg1 = transportEnc_CrcStartReg(hTpEnc, 0); + } + break; + case next_channel: + ch = (ch + 1) % numberOfChannels; + break; + case link_sequence: + list = list->next[decision_bit]; + i=-1; + break; + + default: + error = AAC_ENC_UNKNOWN; + break; + } + + if (error != AAC_ENC_OK) { + return error; + } + + i++; + + } while (list->id[i] != end_of_sequence); + +bail: + if (pBitDemand != NULL) { + *pBitDemand = bitDemand; + } + + return error; +} + + +//----------------------------------------------------------------------------------------------- + +AAC_ENCODER_ERROR FDKaacEnc_WriteBitstream(HANDLE_TRANSPORTENC hTpEnc, + CHANNEL_MAPPING *channelMapping, + QC_OUT *qcOut, + PSY_OUT* psyOut, + QC_STATE *qcKernel, + AUDIO_OBJECT_TYPE aot, + UINT syntaxFlags, + SCHAR epConfig + ) +{ + HANDLE_FDK_BITSTREAM hBs = transportEnc_GetBitstream(hTpEnc); + AAC_ENCODER_ERROR ErrorStatus = AAC_ENC_OK; + int i, n, doByteAlign = 1; + INT bitMarkUp; + INT frameBits; + /* Get first bit of raw data block. + In case of ADTS+PCE, AU would start at PCE. + This is okay because PCE assures alignment. */ + UINT alignAnchor = FDKgetValidBits(hBs); + + frameBits = bitMarkUp = alignAnchor; + + if ( syntaxFlags & AC_DAB ) + { /* Write PAD data as first element for DAB+ */ + for (n = 0; n < qcOut->nExtensions; n++) { + if ( (qcOut->extension[n].type == EXT_DATA_ELEMENT) + && (qcOut->extension[n].nPayloadBits > 0) + && (qcOut->extension[n].pPayload != NULL) ) + { + FDKaacEnc_writeExtensionData( hTpEnc, + &qcOut->extension[n], + 0, + alignAnchor, + syntaxFlags, + aot, + epConfig ); + + qcOut->extension[n].nPayloadBits = 0; + } + } + } + + /* Channel element loop */ + for (i=0; i<channelMapping->nElements; i++) { + + ELEMENT_INFO elInfo = channelMapping->elInfo[i]; + INT elementUsedBits = 0; + + switch (elInfo.elType) + { + case ID_SCE: /* single channel */ + case ID_CPE: /* channel pair */ + case ID_LFE: /* low freq effects channel */ + { + if ( AAC_ENC_OK != (ErrorStatus = FDKaacEnc_ChannelElementWrite( hTpEnc, + &elInfo, + qcOut->qcElement[i]->qcOutChannel, + psyOut->psyOutElement[i], + psyOut->psyOutElement[i]->psyOutChannel, + syntaxFlags, /* syntaxFlags (ER tools ...) */ + aot, /* aot: AOT_AAC_LC, AOT_SBR, AOT_PS */ + epConfig, /* epConfig -1, 0, 1 */ + NULL, + 0 )) ) + { + return ErrorStatus; + } + + if ( !(syntaxFlags & AC_ER) ) + { + /* Write associated extension payload */ + for (n = 0; n < qcOut->qcElement[i]->nExtensions; n++) { + FDKaacEnc_writeExtensionData( hTpEnc, + &qcOut->qcElement[i]->extension[n], + 0, + alignAnchor, + syntaxFlags, + aot, + epConfig ); + } + } + } + break; + + /* In FDK, DSE signalling explicit done in elDSE. See channel_map.cpp */ + default: + return AAC_ENC_INVALID_ELEMENTINFO_TYPE; + + } /* switch */ + + if(elInfo.elType != ID_DSE) { + elementUsedBits -= bitMarkUp; + bitMarkUp = FDKgetValidBits(hBs); + elementUsedBits += bitMarkUp; + frameBits += elementUsedBits; + } + + } /* for (i=0; i<channelMapping.nElements; i++) */ + + if ( (syntaxFlags & AC_ER) && !(syntaxFlags & AC_DRM) ) + { + UCHAR channelElementExtensionWritten[(6)][(1)]; /* 0: extension not touched, 1: extension already written */ + + FDKmemclear(channelElementExtensionWritten, sizeof(channelElementExtensionWritten)); + + if ( syntaxFlags & AC_ELD ) { + + for (i=0; i<channelMapping->nElements; i++) { + for (n = 0; n < qcOut->qcElement[i]->nExtensions; n++) { + + if ( (qcOut->qcElement[i]->extension[n].type==EXT_SBR_DATA) + || (qcOut->qcElement[i]->extension[n].type==EXT_SBR_DATA_CRC) ) + { + /* Write sbr extension payload */ + FDKaacEnc_writeExtensionData( hTpEnc, + &qcOut->qcElement[i]->extension[n], + 0, + alignAnchor, + syntaxFlags, + aot, + epConfig ); + + channelElementExtensionWritten[i][n] = 1; + } /* SBR */ + } /* n */ + } /* i */ + } /* AC_ELD */ + + for (i=0; i<channelMapping->nElements; i++) { + for (n = 0; n < qcOut->qcElement[i]->nExtensions; n++) { + + if (channelElementExtensionWritten[i][n]==0) + { + /* Write all ramaining extension payloads in element */ + FDKaacEnc_writeExtensionData( hTpEnc, + &qcOut->qcElement[i]->extension[n], + 0, + alignAnchor, + syntaxFlags, + aot, + epConfig ); + } + } /* n */ + } /* i */ + } /* if AC_ER */ + + /* Extend global extension payload table with fill bits */ + if ( syntaxFlags & AC_DRM ) + { + /* Exception for Drm */ + for (n = 0; n < qcOut->nExtensions; n++) { + if ( (qcOut->extension[n].type == EXT_SBR_DATA) + || (qcOut->extension[n].type == EXT_SBR_DATA_CRC) ) { + /* SBR data must be the last extension! */ + FDKmemcpy(&qcOut->extension[qcOut->nExtensions], &qcOut->extension[n], sizeof(QC_OUT_EXTENSION)); + break; + } + } + /* Do byte alignment after AAC (+ MPS) payload. + Assure that MPS has been written as channel assigned extension payload! */ + if (((FDKgetValidBits(hBs)-alignAnchor+(UINT)qcOut->totFillBits)&0x7)!=(UINT)qcOut->alignBits) { + return AAC_ENC_WRITTEN_BITS_ERROR; + } + FDKaacEnc_ByteAlignment(hBs, qcOut->alignBits); + doByteAlign = 0; + + } /* AC_DRM */ + + /* Add fill data / stuffing bits */ + n = qcOut->nExtensions; + qcOut->extension[n].type = EXT_FILL_DATA; + qcOut->extension[n].nPayloadBits = qcOut->totFillBits; + qcOut->nExtensions++; + + /* Write global extension payload and fill data */ + for (n = 0; (n < qcOut->nExtensions) && (n < (2+2)); n++) + { + FDKaacEnc_writeExtensionData( hTpEnc, + &qcOut->extension[n], + 0, + alignAnchor, + syntaxFlags, + aot, + epConfig ); + + /* For EXT_FIL or EXT_FILL_DATA we could do an additional sanity check here */ + } + + if (!(syntaxFlags & (AC_SCALABLE|AC_ER))) { + FDKwriteBits(hBs, ID_END, EL_ID_BITS); + } + + if (doByteAlign) { + /* Assure byte alignment*/ + if (((alignAnchor-FDKgetValidBits(hBs))&0x7)!=(UINT)qcOut->alignBits) { + return AAC_ENC_WRITTEN_BITS_ERROR; + } + + FDKaacEnc_ByteAlignment(hBs, qcOut->alignBits); + } + + frameBits -= bitMarkUp; + frameBits += FDKgetValidBits(hBs); + + transportEnc_EndAccessUnit(hTpEnc, &frameBits); + + if (frameBits != qcOut->totalBits + qcKernel->globHdrBits){ + return AAC_ENC_WRITTEN_BITS_ERROR; + } + + return ErrorStatus; +} + |