summaryrefslogtreecommitdiffstats
path: root/libAACenc/src/bitenc.cpp
diff options
context:
space:
mode:
authorDave Burke <daveburke@google.com>2012-04-17 09:51:45 -0700
committerDave Burke <daveburke@google.com>2012-04-17 23:04:43 -0700
commit9bf37cc9712506b2483650c82d3c41152337ef7e (patch)
tree77db44e2bae06e3d144b255628be2b7a55c581d3 /libAACenc/src/bitenc.cpp
parenta37315fe10ee143d6d0b28c19d41a476a23e63ea (diff)
downloadfdk-aac-9bf37cc9712506b2483650c82d3c41152337ef7e.tar.gz
fdk-aac-9bf37cc9712506b2483650c82d3c41152337ef7e.tar.bz2
fdk-aac-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.cpp1431
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;
+}
+