diff options
author | Matthias P. Braendli <matthias.braendli@mpb.li> | 2019-11-11 11:38:02 +0100 |
---|---|---|
committer | Matthias P. Braendli <matthias.braendli@mpb.li> | 2019-11-11 11:38:02 +0100 |
commit | 0e5af65c467b2423a0b857ae3ad98c91acc1e190 (patch) | |
tree | d07f69550d8886271e44fe79c4dcfb299cafbd38 /fdk-aac/libAACenc/src/bitenc.cpp | |
parent | efe406d9724f959c8bc2a31802559ca6d41fd897 (diff) | |
download | ODR-AudioEnc-0e5af65c467b2423a0b857ae3ad98c91acc1e190.tar.gz ODR-AudioEnc-0e5af65c467b2423a0b857ae3ad98c91acc1e190.tar.bz2 ODR-AudioEnc-0e5af65c467b2423a0b857ae3ad98c91acc1e190.zip |
Include patched FDK-AAC in the repository
The initial idea was to get the DAB+ patch into upstream, but since
that follows the android source releases, there is no place for a custom
DAB+ patch there.
So instead of having to maintain a patched fdk-aac that has to have the
same .so version as the distribution package on which it is installed,
we prefer having a separate fdk-aac-dab library to avoid collision.
At that point, there's no reason to keep fdk-aac in a separate
repository, as odr-audioenc is the only tool that needs DAB+ encoding
support. Including it here simplifies installation, and makes it
consistent with toolame-dab, also shipped in this repository.
DAB+ decoding support (needed by ODR-SourceCompanion, dablin, etisnoop,
welle.io and others) can be done using upstream FDK-AAC.
Diffstat (limited to 'fdk-aac/libAACenc/src/bitenc.cpp')
-rw-r--r-- | fdk-aac/libAACenc/src/bitenc.cpp | 1362 |
1 files changed, 1362 insertions, 0 deletions
diff --git a/fdk-aac/libAACenc/src/bitenc.cpp b/fdk-aac/libAACenc/src/bitenc.cpp new file mode 100644 index 0000000..512d596 --- /dev/null +++ b/fdk-aac/libAACenc/src/bitenc.cpp @@ -0,0 +1,1362 @@ +/* ----------------------------------------------------------------------------- +Software License for The Fraunhofer FDK AAC Codec Library for Android + +© Copyright 1995 - 2018 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 +----------------------------------------------------------------------------- */ + +/**************************** AAC encoder library ****************************** + + Author(s): M. Werner + + Description: Bitstream encoder + +*******************************************************************************/ + +#include <stdio.h> +#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_SAC_DATA: */ + case EXT_LDSAC_DATA: + if (hBitStream != NULL) { + FDKwriteBits(hBitStream, *extPayloadData++, 4); /* nibble */ + } + extBitsUsed += 4; + FDK_FALLTHROUGH; + case EXT_DYNAMIC_RANGE: + 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++, 8); + writeBits -= 8; + } + if (writeBits > 0) { + FDKwriteBits(hBitStream, (*extPayloadData) >> (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; + FDK_FALLTHROUGH; + 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_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, 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; + + + /* Write DSEs first in case of DAB */ + for (n = 0; (n < qcOut->nExtensions) && (n < (2+2)); n++) { + if ( (syntaxFlags & AC_DAB) && + (qcOut->extension[n].type == EXT_DATA_ELEMENT) ) { + 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 */ + } + + /* 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 */ + n = qcOut->nExtensions; + + /* Add fill data / stuffing bits */ + n = qcOut->nExtensions; + +// if (!(syntaxFlags & AC_DAB)) { + qcOut->extension[n].type = EXT_FILL_DATA; + qcOut->extension[n].nPayloadBits = qcOut->totFillBits; + qcOut->nExtensions++; +// } else { +// doByteAlign = 0; +// } + if (syntaxFlags & AC_DAB) + doByteAlign = 0; + + /* Write global extension payload and fill data */ + for (n = 0; (n < qcOut->nExtensions) && (n < (2+2)); n++) + { + if ( !(syntaxFlags & AC_DAB) || + ( (syntaxFlags & AC_DAB) && + (qcOut->extension[n].type != EXT_DATA_ELEMENT) + ) + ) { + 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 | AC_DAB))) { + FDKwriteBits(hBs, ID_END, EL_ID_BITS); + } + + if (doByteAlign) { + /* Assure byte alignment*/ + if (((FDKgetValidBits(hBs) - alignAnchor + qcOut->alignBits) & 0x7) != 0) { + 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){ + fprintf(stderr, "frameBits != qcOut->totalBits + qcKernel->globHdrBits: %d != %d + %d", frameBits, qcOut->totalBits, qcKernel->globHdrBits); + return AAC_ENC_WRITTEN_BITS_ERROR; + } + + //fprintf(stderr, "ErrorStatus=%d", ErrorStatus); + return ErrorStatus; +} |