| |
| /* ----------------------------------------------------------------------------------------------------------- |
| Software License for The Fraunhofer FDK AAC Codec Library for Android |
| |
| © Copyright 1995 - 2013 Fraunhofer-Gesellschaft zur Förderung der angewandten Forschung e.V. |
| All rights reserved. |
| |
| 1. INTRODUCTION |
| The Fraunhofer FDK AAC Codec Library for Android ("FDK AAC Codec") is software that implements |
| the MPEG Advanced Audio Coding ("AAC") encoding and decoding scheme for digital audio. |
| This FDK AAC Codec software is intended to be used on a wide variety of Android devices. |
| |
| AAC's HE-AAC and HE-AAC v2 versions are regarded as today's most efficient general perceptual |
| audio codecs. AAC-ELD is considered the best-performing full-bandwidth communications codec by |
| independent studies and is widely deployed. AAC has been standardized by ISO and IEC as part |
| of the MPEG specifications. |
| |
| Patent licenses for necessary patent claims for the FDK AAC Codec (including those of Fraunhofer) |
| may be obtained through Via Licensing (www.vialicensing.com) or through the respective patent owners |
| individually for the purpose of encoding or decoding bit streams in products that are compliant with |
| the ISO/IEC MPEG audio standards. Please note that most manufacturers of Android devices already license |
| these patent claims through Via Licensing or directly from the patent owners, and therefore FDK AAC Codec |
| software may already be covered under those patent licenses when it is used for those licensed purposes only. |
| |
| Commercially-licensed AAC software libraries, including floating-point versions with enhanced sound quality, |
| are also available from Fraunhofer. Users are encouraged to check the Fraunhofer website for additional |
| applications information and documentation. |
| |
| 2. COPYRIGHT LICENSE |
| |
| Redistribution and use in source and binary forms, with or without modification, are permitted without |
| payment of copyright license fees provided that you satisfy the following conditions: |
| |
| You must retain the complete text of this software license in redistributions of the FDK AAC Codec or |
| your modifications thereto in source code form. |
| |
| You must retain the complete text of this software license in the documentation and/or other materials |
| provided with redistributions of the FDK AAC Codec or your modifications thereto in binary form. |
| You must make available free of charge copies of the complete source code of the FDK AAC Codec and your |
| modifications thereto to recipients of copies in binary form. |
| |
| The name of Fraunhofer may not be used to endorse or promote products derived from this library without |
| prior written permission. |
| |
| You may not charge copyright license fees for anyone to use, copy or distribute the FDK AAC Codec |
| software or your modifications thereto. |
| |
| Your modified versions of the FDK AAC Codec must carry prominent notices stating that you changed the software |
| and the date of any change. For modified versions of the FDK AAC Codec, the term |
| "Fraunhofer FDK AAC Codec Library for Android" must be replaced by the term |
| "Third-Party Modified Version of the Fraunhofer FDK AAC Codec Library for Android." |
| |
| 3. NO PATENT LICENSE |
| |
| NO EXPRESS OR IMPLIED LICENSES TO ANY PATENT CLAIMS, including without limitation the patents of Fraunhofer, |
| ARE GRANTED BY THIS SOFTWARE LICENSE. Fraunhofer provides no warranty of patent non-infringement with |
| respect to this software. |
| |
| You may use this FDK AAC Codec software or modifications thereto only for purposes that are authorized |
| by appropriate patent licenses. |
| |
| 4. DISCLAIMER |
| |
| This FDK AAC Codec software is provided by Fraunhofer on behalf of the copyright holders and contributors |
| "AS IS" and WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, including but not limited to the implied warranties |
| of merchantability and fitness for a particular purpose. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR |
| CONTRIBUTORS BE LIABLE for any direct, indirect, incidental, special, exemplary, or consequential damages, |
| including but not limited to procurement of substitute goods or services; loss of use, data, or profits, |
| or business interruption, however caused and on any theory of liability, whether in contract, strict |
| liability, or tort (including negligence), arising in any way out of the use of this software, even if |
| advised of the possibility of such damage. |
| |
| 5. CONTACT INFORMATION |
| |
| Fraunhofer Institute for Integrated Circuits IIS |
| Attention: Audio and Multimedia Departments - FDK AAC LL |
| Am Wolfsmantel 33 |
| 91058 Erlangen, Germany |
| |
| www.iis.fraunhofer.de/amm |
| amm-info@iis.fraunhofer.de |
| ----------------------------------------------------------------------------------------------------------- */ |
| |
| /******************************** MPEG Audio Encoder ************************** |
| |
| 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; |
| |
| |
| /* 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[(8)][(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; |
| } |
| |