mirror of
https://gitlab.com/ecodis/exhale.git
synced 2025-06-05 21:59:32 +02:00
add source code
This commit is contained in:
559
src/lib/bitStreamWriter.cpp
Normal file
559
src/lib/bitStreamWriter.cpp
Normal file
@ -0,0 +1,559 @@
|
||||
/* bitStreamWriter.cpp - source file for class with basic bit-stream writing capability
|
||||
* written by C. R. Helmrich, last modified in 2019 - see License.htm for legal notices
|
||||
*
|
||||
* The copyright in this software is being made available under a Modified BSD-Style License
|
||||
* and comes with ABSOLUTELY NO WARRANTY. This software may be subject to other third-
|
||||
* party rights, including patent rights. No such rights are granted under this License.
|
||||
*
|
||||
* Copyright (c) 2018-2020 Christian R. Helmrich, project ecodis. All rights reserved.
|
||||
*/
|
||||
|
||||
#include "exhaleLibPch.h"
|
||||
#include "bitStreamWriter.h"
|
||||
|
||||
// private helper functions
|
||||
void BitStreamWriter::writeByteAlignment () // write '0' bits until stream is byte-aligned
|
||||
{
|
||||
if (m_auBitStream.heldBitCount > 0)
|
||||
{
|
||||
m_auBitStream.stream.push_back (m_auBitStream.heldBitChunk);
|
||||
m_auBitStream.heldBitChunk = 0;
|
||||
m_auBitStream.heldBitCount = 0;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned BitStreamWriter::writeChannelWiseIcsInfo (const IcsInfo& icsInfo) // ics_info()
|
||||
{
|
||||
#if RESTRICT_TO_AAC
|
||||
m_auBitStream.write ((unsigned) icsInfo.windowSequence, 2);
|
||||
#else
|
||||
m_auBitStream.write (unsigned (icsInfo.windowSequence == STOP_START ? LONG_START : icsInfo.windowSequence), 2);
|
||||
#endif
|
||||
m_auBitStream.write ((unsigned) icsInfo.windowShape, 1);
|
||||
if (icsInfo.windowSequence == EIGHT_SHORT)
|
||||
{
|
||||
m_auBitStream.write (icsInfo.maxSfb, 4);
|
||||
m_auBitStream.write (icsInfo.windowGrouping, 7); // scale_factor_grouping
|
||||
|
||||
return 14;
|
||||
}
|
||||
m_auBitStream.write (icsInfo.maxSfb, 6);
|
||||
|
||||
return 9;
|
||||
}
|
||||
|
||||
unsigned BitStreamWriter::writeChannelWiseTnsData (const TnsData& tnsData, const bool eightShorts)
|
||||
{
|
||||
const unsigned numWindows = (eightShorts ? 8 : 1);
|
||||
const unsigned offsetBits = (eightShorts ? 1 : 2);
|
||||
unsigned bitCount = 0, i;
|
||||
|
||||
for (unsigned w = 0; w < numWindows; w++)
|
||||
{
|
||||
bitCount += offsetBits;
|
||||
if (w != tnsData.filteredWindow)
|
||||
{
|
||||
m_auBitStream.write (0/*n_filt[w] = 0*/, offsetBits);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_auBitStream.write (tnsData.numFilters, offsetBits);
|
||||
if (tnsData.numFilters > 0)
|
||||
{
|
||||
m_auBitStream.write (tnsData.coeffResLow ? 0 : 1, 1); // coef_res[w]
|
||||
bitCount++;
|
||||
for (unsigned f = 0; f < tnsData.numFilters; f++)
|
||||
{
|
||||
const unsigned order = tnsData.filterOrder[f];
|
||||
|
||||
m_auBitStream.write (tnsData.filterLength[f], 2 + offsetBits * 2);
|
||||
m_auBitStream.write (order, 2 + offsetBits);
|
||||
bitCount += 4 + offsetBits * 3;
|
||||
if (order > 0)
|
||||
{
|
||||
const int8_t* coeff = tnsData.coeff[f];
|
||||
unsigned coefBits = (tnsData.coeffResLow ? 3 : 4);
|
||||
char coefMaxValue = (tnsData.coeffResLow ? 2 : 4);
|
||||
bool dontCompress = false;
|
||||
|
||||
m_auBitStream.write (tnsData.filterDownward[f] ? 1 : 0, 1);
|
||||
for (i = 0; i < order; i++) // get coef_compress, then write coef
|
||||
{
|
||||
dontCompress |= ((coeff[i] < -coefMaxValue) || (coeff[i] >= coefMaxValue));
|
||||
}
|
||||
m_auBitStream.write (dontCompress ? 0 : 1, 1);
|
||||
coefMaxValue <<= 1;
|
||||
if (dontCompress) coefMaxValue <<= 1; else coefBits--;
|
||||
for (i = 0; i < order; i++)
|
||||
{
|
||||
m_auBitStream.write (unsigned (coeff[i] < 0 ? coefMaxValue + coeff[i] : coeff[i]), coefBits);
|
||||
}
|
||||
bitCount += 2 + order * coefBits;
|
||||
}
|
||||
}
|
||||
} // if (n_filt[w])
|
||||
}
|
||||
} // for w
|
||||
|
||||
return bitCount;
|
||||
}
|
||||
|
||||
unsigned BitStreamWriter::writeFDChannelStream (const CoreCoderData& elData, EntropyCoder& entrCoder, const unsigned ch,
|
||||
const int32_t* const mdctSignal, const uint8_t* const mdctQuantMag,
|
||||
#if !RESTRICT_TO_AAC
|
||||
const bool timeWarping, const bool noiseFilling,
|
||||
#endif
|
||||
const bool indepFlag /*= false*/)
|
||||
{
|
||||
const IcsInfo& icsInfo = elData.icsInfoCurr[ch];
|
||||
const TnsData& tnsData = elData.tnsData[ch];
|
||||
const SfbGroupData& grp = elData.groupingData[ch];
|
||||
const unsigned maxSfb = grp.sfbsPerGroup;
|
||||
const bool eightShorts = icsInfo.windowSequence == EIGHT_SHORT;
|
||||
uint8_t* const sf = (uint8_t* const) grp.scaleFactors;
|
||||
uint8_t sfIdxPred = CLIP_UCHAR (sf[0] > SCHAR_MAX ? 0 : sf[0] + (eightShorts ? 68 : 80));
|
||||
unsigned bitCount = 8, g, b, i;
|
||||
|
||||
m_auBitStream.write (sfIdxPred, 8); // adjusted global_gain
|
||||
#if !RESTRICT_TO_AAC
|
||||
if (noiseFilling)
|
||||
{
|
||||
m_auBitStream.write (elData.specFillData[ch], 8); // noise level | offset
|
||||
bitCount += 8;
|
||||
}
|
||||
#endif
|
||||
if (!elData.commonWindow)
|
||||
{
|
||||
bitCount += writeChannelWiseIcsInfo (icsInfo); // ics_info
|
||||
}
|
||||
#if !RESTRICT_TO_AAC
|
||||
if (timeWarping) // && (!common_tw)
|
||||
{
|
||||
m_auBitStream.write (0, 1); // enforce tw_data_present = 0
|
||||
bitCount++;
|
||||
}
|
||||
#endif
|
||||
sfIdxPred = sf[0]; // scale factors
|
||||
for (g = 0; g < grp.numWindowGroups; g++)
|
||||
{
|
||||
uint8_t* const gSf = &sf[m_numSwbShort * g];
|
||||
|
||||
for (b = 0; b < maxSfb; b++)
|
||||
{
|
||||
uint8_t sfIdx = gSf[b];
|
||||
|
||||
if ((g + 1 < grp.numWindowGroups) && (b + 1 == maxSfb) && ((unsigned) sfIdx + INDEX_OFFSET < sf[m_numSwbShort * (g + 1)]))
|
||||
{
|
||||
// ugly, avoidable if each gr. had its own global_gain
|
||||
gSf[b] = sfIdx = sf[m_numSwbShort * (g + 1)] - INDEX_OFFSET;
|
||||
}
|
||||
if ((g > 0) || (b > 0))
|
||||
{
|
||||
int sfIdxDpcm = (int) sfIdx - sfIdxPred;
|
||||
unsigned sfBits;
|
||||
|
||||
if (sfIdxDpcm > INDEX_OFFSET) // just as sanity checks
|
||||
{
|
||||
sfIdxDpcm = INDEX_OFFSET;
|
||||
sfIdxPred += INDEX_OFFSET;
|
||||
}
|
||||
else if (sfIdxDpcm < -INDEX_OFFSET) // highly unlikely
|
||||
{
|
||||
sfIdxDpcm = -INDEX_OFFSET;
|
||||
sfIdxPred -= INDEX_OFFSET;
|
||||
}
|
||||
else // scale factor range OK
|
||||
{
|
||||
sfIdxPred = sfIdx;
|
||||
}
|
||||
sfBits = entrCoder.indexGetBitCount (sfIdxDpcm);
|
||||
m_auBitStream.write (entrCoder.indexGetHuffCode (sfIdxDpcm), sfBits);
|
||||
bitCount += sfBits;
|
||||
}
|
||||
}
|
||||
} // for g
|
||||
|
||||
if (!elData.commonTnsData && (tnsData.numFilters > 0))
|
||||
{
|
||||
bitCount += writeChannelWiseTnsData (tnsData, eightShorts);
|
||||
}
|
||||
|
||||
bitCount += (indepFlag ? 1 : 2); // arith_reset_flag, fac_data_present bits
|
||||
|
||||
if (maxSfb == 0) // zeroed spectrum
|
||||
{
|
||||
entrCoder.initWindowCoding (!eightShorts /*reset*/, eightShorts);
|
||||
|
||||
if (!indepFlag) m_auBitStream.write (1, 1); // force reset
|
||||
}
|
||||
else // not zeroed, nasty since SFB ungrouping may be needed
|
||||
{
|
||||
const uint16_t* grpOff = grp.sfbOffsets;
|
||||
uint8_t grpLen = grp.windowGroupLength[0];
|
||||
uint8_t grpWin = 0;
|
||||
uint8_t swbSize[MAX_NUM_SWB_SHORT];
|
||||
const uint8_t* winMag = (grpLen > 1 ? m_uCharBuffer : mdctQuantMag);
|
||||
const uint16_t lg = (grpLen > 1 ? grpOff[maxSfb] / grpLen : grpOff[maxSfb]);
|
||||
|
||||
if (eightShorts || (grpLen > 1)) // ungroup the SFB widths
|
||||
{
|
||||
for (b = 0, i = oneTwentyEightOver[grpLen]; b < maxSfb; b++)
|
||||
{
|
||||
swbSize[b] = ((grpOff[b+1] - grpOff[b]) * i) >> 7; // sfbWidth/grpLen
|
||||
}
|
||||
}
|
||||
g = 0;
|
||||
for (int w = 0; w < (eightShorts ? 8 : 1); w++, grpWin++) // window loop
|
||||
{
|
||||
if (grpWin >= grpLen) // next g
|
||||
{
|
||||
grpOff += m_numSwbShort;
|
||||
grpLen = grp.windowGroupLength[++g];
|
||||
grpWin = 0;
|
||||
winMag = (grpLen > 1 ? m_uCharBuffer : &mdctQuantMag[grpOff[0]]);
|
||||
}
|
||||
if (eightShorts && (grpLen > 1))
|
||||
{
|
||||
for (b = i = 0; b < maxSfb; b++) // ungroup magnitudes
|
||||
{
|
||||
memcpy (&m_uCharBuffer[i], &mdctQuantMag[grpOff[b] + grpWin * swbSize[b]], swbSize[b] * sizeof (uint8_t));
|
||||
i += swbSize[b];
|
||||
}
|
||||
}
|
||||
entrCoder.initWindowCoding (indepFlag && (w == 0), eightShorts);
|
||||
|
||||
if (!indepFlag && (w == 0)) // optimize arith_reset_flag
|
||||
{
|
||||
if ((b = entrCoder.arithGetResetBit (winMag, 0, lg)) != 0)
|
||||
{
|
||||
entrCoder.arithResetMemory ();
|
||||
entrCoder.arithSetCodState (USHRT_MAX << 16);
|
||||
entrCoder.arithSetCtxState (0);
|
||||
}
|
||||
m_auBitStream.write (b, 1); // write adapted reset bit
|
||||
}
|
||||
bitCount += entrCoder.arithCodeSigMagn (winMag, 0, lg, true, &m_auBitStream);
|
||||
|
||||
if (eightShorts && (grpLen > 1))
|
||||
{
|
||||
for (b = i = 0; b < maxSfb; b++) // ungroup coef signs
|
||||
{
|
||||
const int32_t* const swbSig = &mdctSignal[grpOff[b] + grpWin * swbSize[b]];
|
||||
|
||||
for (unsigned j = 0; j < swbSize[b]; j++, i++)
|
||||
{
|
||||
if (winMag[i] != 0)
|
||||
{
|
||||
m_auBitStream.write (swbSig[j] < 0 ? 0 : 1, 1); // - = 0, + = 1
|
||||
bitCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else // not grouped long window
|
||||
{
|
||||
const int32_t* const winSig = &mdctSignal[grpOff[0]];
|
||||
|
||||
for (i = 0; i < lg; i++)
|
||||
{
|
||||
if (winMag[i] != 0)
|
||||
{
|
||||
m_auBitStream.write (winSig[i] < 0 ? 0 : 1, 1); // -1 = 0, +1 = 1
|
||||
bitCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
} // for w
|
||||
} // if (maxSfb == 0)
|
||||
|
||||
m_auBitStream.write (0, 1); // fac_data_present, no fac_data
|
||||
|
||||
return bitCount;
|
||||
}
|
||||
|
||||
unsigned BitStreamWriter::writeStereoCoreToolInfo (const CoreCoderData& elData,
|
||||
#if !RESTRICT_TO_AAC
|
||||
const bool timeWarping,
|
||||
#endif
|
||||
const bool indepFlag /*= false*/)
|
||||
{
|
||||
const IcsInfo& icsInfo0 = elData.icsInfoCurr[0];
|
||||
const IcsInfo& icsInfo1 = elData.icsInfoCurr[1];
|
||||
const TnsData& tnsData0 = elData.tnsData[0];
|
||||
const TnsData& tnsData1 = elData.tnsData[1];
|
||||
unsigned bitCount = 2, g, b;
|
||||
|
||||
m_auBitStream.write (elData.tnsActive ? 1 : 0, 1); // tns_active
|
||||
m_auBitStream.write (elData.commonWindow ? 1 : 0, 1);
|
||||
if (elData.commonWindow)
|
||||
{
|
||||
const unsigned maxSfbSte = __max (icsInfo0.maxSfb, icsInfo1.maxSfb);
|
||||
const unsigned sfb1Bits = icsInfo1.windowSequence == EIGHT_SHORT ? 4 : 6;
|
||||
|
||||
bitCount += writeChannelWiseIcsInfo (icsInfo0); // ics_info()
|
||||
m_auBitStream.write (elData.commonMaxSfb ? 1 : 0, 1);
|
||||
if (!elData.commonMaxSfb)
|
||||
{
|
||||
m_auBitStream.write (icsInfo1.maxSfb, sfb1Bits); // max_sfb1
|
||||
bitCount += sfb1Bits;
|
||||
}
|
||||
m_auBitStream.write (__min (3, elData.stereoMode), 2); // ms_mask_present
|
||||
bitCount += 3;
|
||||
if (elData.stereoMode == 1) // write SFB-wise ms_used[][] flag
|
||||
{
|
||||
for (g = 0; g < elData.groupingData[0].numWindowGroups; g++)
|
||||
{
|
||||
const char* const gMsUsed = &elData.stereoData[m_numSwbShort * g];
|
||||
|
||||
for (b = 0; b < maxSfbSte; b++)
|
||||
{
|
||||
m_auBitStream.write (gMsUsed[b] > 0 ? 1 : 0, 1);
|
||||
}
|
||||
}
|
||||
bitCount += maxSfbSte * g;
|
||||
}
|
||||
#if !RESTRICT_TO_AAC
|
||||
else if (elData.stereoMode >= 3) // SFB-wise cplx_pred_data()
|
||||
{
|
||||
m_auBitStream.write (elData.stereoMode - 3, 1); // _pred_all
|
||||
if (elData.stereoMode == 3)
|
||||
{
|
||||
for (g = 0; g < elData.groupingData[0].numWindowGroups; g++)
|
||||
{
|
||||
const char* const gCplxPredUsed = &elData.stereoData[m_numSwbShort * g];
|
||||
|
||||
for (b = 0; b < maxSfbSte; b += SFB_PER_PRED_BAND)
|
||||
{
|
||||
m_auBitStream.write (gCplxPredUsed[b] > 0 ? 1 : 0, 1);
|
||||
}
|
||||
}
|
||||
bitCount += ((maxSfbSte + 1) / SFB_PER_PRED_BAND) * g;
|
||||
}
|
||||
// pred_dir and complex_coef. TODO: rest of cplx_pred_data()
|
||||
m_auBitStream.write (elData.stereoConfig & 3, 2);
|
||||
bitCount += 3;
|
||||
}
|
||||
#endif
|
||||
} // common_window
|
||||
#if !RESTRICT_TO_AAC
|
||||
if (timeWarping)
|
||||
{
|
||||
m_auBitStream.write (0, 1); // common_tw not needed in xHE-AAC
|
||||
bitCount++;
|
||||
} // tw_mdct
|
||||
#endif
|
||||
if (elData.tnsActive)
|
||||
{
|
||||
if (elData.commonWindow)
|
||||
{
|
||||
m_auBitStream.write (elData.commonTnsData ? 1 : 0, 1);
|
||||
bitCount++;
|
||||
}
|
||||
m_auBitStream.write (elData.tnsOnLeftRight ? 1 : 0, 1);
|
||||
bitCount++;
|
||||
if (elData.commonTnsData)
|
||||
{
|
||||
bitCount += writeChannelWiseTnsData (tnsData0, icsInfo0.windowSequence == EIGHT_SHORT);
|
||||
}
|
||||
else // tns_present_both and tns_data_present[1]
|
||||
{
|
||||
const bool tnsPresentBoth = (tnsData0.numFilters > 0) && (tnsData1.numFilters > 0);
|
||||
|
||||
m_auBitStream.write (tnsPresentBoth ? 1 : 0, 1);
|
||||
bitCount++;
|
||||
if (!tnsPresentBoth)
|
||||
{
|
||||
m_auBitStream.write (tnsData1.numFilters > 0 ? 1 : 0, 1);
|
||||
bitCount++;
|
||||
}
|
||||
}
|
||||
} // tns_active
|
||||
|
||||
return bitCount;
|
||||
}
|
||||
|
||||
// public functions
|
||||
unsigned BitStreamWriter::createAudioConfig (const char samplingFrequencyIndex, const bool shortFrameLength,
|
||||
const uint8_t chConfigurationIndex, const uint8_t numElements,
|
||||
const ELEM_TYPE* const elementType, const bool configExtensionPresent,
|
||||
#if !RESTRICT_TO_AAC
|
||||
const bool* const tw_mdct /*N/A*/, const bool* const noiseFilling,
|
||||
#endif
|
||||
unsigned char* const audioConfig)
|
||||
{
|
||||
unsigned bitCount = 37;
|
||||
|
||||
if ((elementType == nullptr) || (audioConfig == nullptr) || (chConfigurationIndex >= USAC_MAX_NUM_ELCONFIGS) ||
|
||||
#if !RESTRICT_TO_AAC
|
||||
(noiseFilling == nullptr) || (tw_mdct == nullptr) ||
|
||||
#endif
|
||||
(numElements == 0) || (numElements > USAC_MAX_NUM_ELEMENTS) || (samplingFrequencyIndex < 0) || (samplingFrequencyIndex >= 0x1F))
|
||||
{
|
||||
return 0; // invalid arguments error
|
||||
}
|
||||
|
||||
m_auBitStream.reset ();
|
||||
// --- AudioSpecificConfig(): https://wiki.multimedia.cx/index.php/MPEG-4_Audio/
|
||||
m_auBitStream.write (0x7CA, 11); // audio object type (AOT) 32 (esc) + 10 = 42
|
||||
if (samplingFrequencyIndex < AAC_NUM_SAMPLE_RATES)
|
||||
{
|
||||
m_auBitStream.write (samplingFrequencyIndex, 4);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_auBitStream.write (0xF, 4); // esc
|
||||
m_auBitStream.write (toSamplingRate (samplingFrequencyIndex), 24);
|
||||
bitCount += 24;
|
||||
}
|
||||
// for multichannel audio, refer to channel mapping of AotSpecificConfig below
|
||||
m_auBitStream.write (chConfigurationIndex > 2 ? 0 : chConfigurationIndex, 4);
|
||||
|
||||
// --- AotSpecificConfig(): UsacConfig()
|
||||
m_auBitStream.write (samplingFrequencyIndex, 5); // usacSamplingFrequencyIndex
|
||||
m_auBitStream.write (shortFrameLength ? 0 : 1, 3); // coreSbrFrameLengthIndex
|
||||
m_auBitStream.write (chConfigurationIndex, 5); // channelConfigurationIndex
|
||||
m_auBitStream.write (numElements - 1, 4); // numElements in UsacDecoderConfig
|
||||
|
||||
for (unsigned el = 0; el < numElements; el++) // el element loop
|
||||
{
|
||||
m_auBitStream.write ((unsigned) elementType[el], 2); // usacElementType[el]
|
||||
bitCount += 2;
|
||||
if (elementType[el] < ID_USAC_LFE) // SCE, CPE: UsacCoreConfig
|
||||
{
|
||||
#if RESTRICT_TO_AAC
|
||||
m_auBitStream.write (0, 2); // time warping and noise filling not allowed
|
||||
#else
|
||||
m_auBitStream.write ((tw_mdct[el] ? 2 : 0) | (noiseFilling[el] ? 1 : 0), 2);
|
||||
#endif
|
||||
bitCount += 2;
|
||||
}
|
||||
} // for el
|
||||
|
||||
m_auBitStream.write (configExtensionPresent ? 1 : 0, 1); // usacConfigExten...
|
||||
if (configExtensionPresent) // 23003-4: loudnessInfo
|
||||
{
|
||||
m_auBitStream.write (0, 2); // numConfigExtensions
|
||||
m_auBitStream.write (ID_EXT_LOUDNESS_INFO, 4);
|
||||
m_auBitStream.write (8, 4); // usacConfigExtLength
|
||||
|
||||
m_auBitStream.write (1, 12);// loudnessInfoCount=1
|
||||
m_auBitStream.write (1, 14); // peakLevelPresent=1
|
||||
m_auBitStream.write (0, 12); // bsSamplePeakLevel
|
||||
m_auBitStream.write (1, 5); // measurementCount=1
|
||||
|
||||
m_auBitStream.write (1, 4); // methodDefinition=1
|
||||
m_auBitStream.write (0, 8); // methodValue storage
|
||||
m_auBitStream.write (0, 4); // measurementSystem=0
|
||||
m_auBitStream.write (3, 2); // reliability=3, good
|
||||
|
||||
m_auBitStream.write (0, 1); // ...SetExtPresent=0
|
||||
bitCount += 72;
|
||||
}
|
||||
|
||||
bitCount += (8 - m_auBitStream.heldBitCount) & 7;
|
||||
writeByteAlignment (); // flush bytes
|
||||
|
||||
memcpy (audioConfig, &m_auBitStream.stream.front (), __min (16, bitCount >> 3));
|
||||
|
||||
return (bitCount >> 3); // byte count
|
||||
}
|
||||
|
||||
unsigned BitStreamWriter::createAudioFrame (CoreCoderData** const elementData, EntropyCoder* const entropyCoder,
|
||||
int32_t** const mdctSignals, uint8_t** const mdctQuantMag,
|
||||
const bool usacIndependencyFlag, const uint8_t numElements,
|
||||
const uint8_t numSwbShort, uint8_t* const tempBuffer,
|
||||
#if !RESTRICT_TO_AAC
|
||||
const bool* const tw_mdct /*N/A*/, const bool* const noiseFilling,
|
||||
#endif
|
||||
unsigned char* const accessUnit, const unsigned nSamplesInFrame /*= 1024*/)
|
||||
{
|
||||
unsigned bitCount = 1, ci = 0;
|
||||
|
||||
if ((elementData == nullptr) || (entropyCoder == nullptr) || (tempBuffer == nullptr) ||
|
||||
(mdctSignals == nullptr) || (mdctQuantMag == nullptr) || (accessUnit == nullptr) || (nSamplesInFrame > 2048) ||
|
||||
#if !RESTRICT_TO_AAC
|
||||
(noiseFilling == nullptr) || (tw_mdct == nullptr) ||
|
||||
#endif
|
||||
(numElements == 0) || (numElements > USAC_MAX_NUM_ELEMENTS) || (numSwbShort < MIN_NUM_SWB_SHORT) || (numSwbShort > MAX_NUM_SWB_SHORT))
|
||||
{
|
||||
return 0; // invalid arguments error
|
||||
}
|
||||
|
||||
m_auBitStream.reset ();
|
||||
m_frameLength = nSamplesInFrame;
|
||||
m_numSwbShort = numSwbShort;
|
||||
m_uCharBuffer = tempBuffer;
|
||||
m_auBitStream.write (usacIndependencyFlag ? 1 : 0, 1);
|
||||
|
||||
for (unsigned el = 0; el < numElements; el++) // el element loop
|
||||
{
|
||||
const CoreCoderData* const elData = elementData[el];
|
||||
|
||||
if (elData == nullptr)
|
||||
{
|
||||
return 0; // internal memory error
|
||||
}
|
||||
switch (elData->elementType) // write out UsacCoreCoderData()
|
||||
{
|
||||
case ID_USAC_SCE: // UsacSingleChannelElement()
|
||||
{
|
||||
m_auBitStream.write (CORE_MODE_FD, 1);
|
||||
m_auBitStream.write (elData->tnsActive ? 1 : 0, 1); // tns_data_present
|
||||
bitCount += 2;
|
||||
bitCount += writeFDChannelStream (*elData, entropyCoder[ci], 0,
|
||||
mdctSignals[ci], mdctQuantMag[ci],
|
||||
#if !RESTRICT_TO_AAC
|
||||
tw_mdct[el], noiseFilling[el],
|
||||
#endif
|
||||
usacIndependencyFlag);
|
||||
ci++;
|
||||
break;
|
||||
}
|
||||
case ID_USAC_CPE: // UsacChannelPairElement()
|
||||
{
|
||||
m_auBitStream.write (CORE_MODE_FD, 1); // L
|
||||
m_auBitStream.write (CORE_MODE_FD, 1); // R
|
||||
bitCount += 2;
|
||||
bitCount += writeStereoCoreToolInfo (*elData,
|
||||
#if !RESTRICT_TO_AAC
|
||||
tw_mdct[el],
|
||||
#endif
|
||||
usacIndependencyFlag);
|
||||
bitCount += writeFDChannelStream (*elData, entropyCoder[ci], 0, // L
|
||||
mdctSignals[ci], mdctQuantMag[ci],
|
||||
#if !RESTRICT_TO_AAC
|
||||
tw_mdct[el], noiseFilling[el],
|
||||
#endif
|
||||
usacIndependencyFlag);
|
||||
ci++;
|
||||
bitCount += writeFDChannelStream (*elData, entropyCoder[ci], 1, // R
|
||||
mdctSignals[ci], mdctQuantMag[ci],
|
||||
#if !RESTRICT_TO_AAC
|
||||
tw_mdct[el], noiseFilling[el],
|
||||
#endif
|
||||
usacIndependencyFlag);
|
||||
ci++;
|
||||
break;
|
||||
}
|
||||
case ID_USAC_LFE: // UsacLfeElement()
|
||||
{
|
||||
bitCount += writeFDChannelStream (*elData, entropyCoder[ci], 0,
|
||||
mdctSignals[ci], mdctQuantMag[ci],
|
||||
#if !RESTRICT_TO_AAC
|
||||
false, false,
|
||||
#endif
|
||||
usacIndependencyFlag);
|
||||
ci++;
|
||||
break;
|
||||
}
|
||||
default: break;
|
||||
}
|
||||
} // for el
|
||||
|
||||
bitCount += (8 - m_auBitStream.heldBitCount) & 7;
|
||||
writeByteAlignment (); // flush bytes
|
||||
|
||||
memcpy (accessUnit, &m_auBitStream.stream.front (), __min (768 * ci, bitCount >> 3));
|
||||
|
||||
return (bitCount >> 3); // byte count
|
||||
}
|
Reference in New Issue
Block a user