#include "./aacframe.h" #include "./aaccodebook.h" #include "../adts/adtsframe.h" #include "../mp4/mp4ids.h" #include "../exceptions.h" #include #include #include using namespace std; using namespace CppUtilities; /*! * \file aacframe.cpp * \remarks The AAC parser is still WIP. It does not work yet and its API/ABI may change even in patch releases. */ namespace TagParser { /// \cond const std::uint8_t maxPredictionSfb[16] = { 33, 33, 38, 40, 40, 40, 41, 41, 37, 37, 37, 34, 64, 64, 64, 64 }; const uint8_t swb512WindowCount[] = { 0, 0, 0, 36, 36, 37, 31, 31, 0, 0, 0, 0 }; const std::uint8_t swb480WindowCount[] = { 0, 0, 0, 35, 35, 37, 30, 30, 0, 0, 0, 0 }; const std::uint8_t swb960WindowCount[] = { 40, 40, 45, 49, 49, 49, 46, 46, 42, 42, 42, 40 }; const std::uint8_t swb1024WindowCount[] = { 41, 41, 47, 49, 49, 51, 47, 47, 43, 43, 43, 40 }; const std::uint8_t swb128WindowCount[] = { 12, 12, 12, 14, 14, 14, 15, 15, 15, 15, 15, 15 }; const std::uint16_t swbOffset1024_96[] = { 0, 4, 8, 12, 16, 20, 24, 28, 32, 36, 40, 44, 48, 52, 56, 64, 72, 80, 88, 96, 108, 120, 132, 144, 156, 172, 188, 212, 240, 276, 320, 384, 448, 512, 576, 640, 704, 768, 832, 896, 960, 1024 }; const std::uint16_t swbOffset128_96[] = { 0, 4, 8, 12, 16, 20, 24, 32, 40, 48, 64, 92, 128 }; const std::uint16_t swbOffset1024_64[] = { 0, 4, 8, 12, 16, 20, 24, 28, 32, 36, 40, 44, 48, 52, 56, 64, 72, 80, 88, 100, 112, 124, 140, 156, 172, 192, 216, 240, 268, 304, 344, 384, 424, 464, 504, 544, 584, 624, 664, 704, 744, 784, 824, 864, 904, 944, 984, 1024 }; const std::uint16_t swbOffset128_64[] = { 0, 4, 8, 12, 16, 20, 24, 32, 40, 48, 64, 92, 128 }; const std::uint16_t swbOffset1024_48[] = { 0, 4, 8, 12, 16, 20, 24, 28, 32, 36, 40, 48, 56, 64, 72, 80, 88, 96, 108, 120, 132, 144, 160, 176, 196, 216, 240, 264, 292, 320, 352, 384, 416, 448, 480, 512, 544, 576, 608, 640, 672, 704, 736, 768, 800, 832, 864, 896, 928, 1024 }; const std::uint16_t swbOffset512_48[] = { 0, 4, 8, 12, 16, 20, 24, 28, 32, 36, 40, 44, 48, 52, 56, 60, 68, 76, 84, 92, 100, 112, 124, 136, 148, 164, 184, 208, 236, 268, 300, 332, 364, 396, 428, 460, 512 }; const std::uint16_t swbOffset480_48[] = { 0, 4, 8, 12, 16, 20, 24, 28, 32, 36, 40, 44, 48, 52, 56, 64, 72, 80, 88, 96, 108, 120, 132, 144, 156, 172, 188, 212, 240, 272, 304, 336, 368, 400, 432, 480 }; const std::uint16_t swbOffset128_48[] = { 0, 4, 8, 12, 16, 20, 28, 36, 44, 56, 68, 80, 96, 112, 128 }; const std::uint16_t swbOffset1024_32[] = { 0, 4, 8, 12, 16, 20, 24, 28, 32, 36, 40, 48, 56, 64, 72, 80, 88, 96, 108, 120, 132, 144, 160, 176, 196, 216, 240, 264, 292, 320, 352, 384, 416, 448, 480, 512, 544, 576, 608, 640, 672, 704, 736, 768, 800, 832, 864, 896, 928, 960, 992, 1024 }; const std::uint16_t swbOffset512_32[] = { 0, 4, 8, 12, 16, 20, 24, 28, 32, 36, 40, 44, 48, 52, 56, 64, 72, 80, 88, 96, 108, 120, 132, 144, 160, 176, 192, 212, 236, 260, 288, 320, 352, 384, 416, 448, 480, 512 }; const std::uint16_t swbOffset480_32[] = { 0, 4, 8, 12, 16, 20, 24, 28, 32, 36, 40, 44, 48, 52, 56, 60, 64, 72, 80, 88, 96, 104, 112, 124, 136, 148, 164, 180, 200, 224, 256, 288, 320, 352, 384, 416, 448, 480 }; const std::uint16_t swbOffset1024_24[] = { 0, 4, 8, 12, 16, 20, 24, 28, 32, 36, 40, 44, 52, 60, 68, 76, 84, 92, 100, 108, 116, 124, 136, 148, 160, 172, 188, 204, 220, 240, 260, 284, 308, 336, 364, 396, 432, 468, 508, 552, 600, 652, 704, 768, 832, 896, 960, 1024 }; const std::uint16_t swbOffset512_24[] = { 0, 4, 8, 12, 16, 20, 24, 28, 32, 36, 40, 44, 52, 60, 68, 80, 92, 104, 120, 140, 164, 192, 224, 256, 288, 320, 352, 384, 416, 448, 480, 512 }; const std::uint16_t swbOffset480_24[] = { 0, 4, 8, 12, 16, 20, 24, 28, 32, 36, 40, 44, 52, 60, 68, 80, 92, 104, 120, 140, 164, 192, 224, 256, 288, 320, 352, 384, 416, 448, 480 }; const std::uint16_t swbOffset128_24[] = { 0, 4, 8, 12, 16, 20, 24, 28, 36, 44, 52, 64, 76, 92, 108, 128 }; const std::uint16_t swbOffset1024_16[] = { 0, 8, 16, 24, 32, 40, 48, 56, 64, 72, 80, 88, 100, 112, 124, 136, 148, 160, 172, 184, 196, 212, 228, 244, 260, 280, 300, 320, 344, 368, 396, 424, 456, 492, 532, 572, 616, 664, 716, 772, 832, 896, 960, 1024 }; const std::uint16_t swbOffset128_16[] = { 0, 4, 8, 12, 16, 20, 24, 28, 32, 40, 48, 60, 72, 88, 108, 128 }; const std::uint16_t swbOffset1024_8[] = { 0, 12, 24, 36, 48, 60, 72, 84, 96, 108, 120, 132, 144, 156, 172, 188, 204, 220, 236, 252, 268, 288, 308, 328, 348, 372, 396, 420, 448, 476, 508, 544, 580, 620, 664, 712, 764, 820, 880, 944, 1024 }; const std::uint16_t swbOffset128_8[] = { 0, 4, 8, 12, 16, 20, 24, 28, 36, 44, 52, 60, 72, 88, 108, 128 }; static const std::uint16_t *const swbOffset1024Window[] = { swbOffset1024_96, /* 96000 */ swbOffset1024_96, /* 88200 */ swbOffset1024_64, /* 64000 */ swbOffset1024_48, /* 48000 */ swbOffset1024_48, /* 44100 */ swbOffset1024_32, /* 32000 */ swbOffset1024_24, /* 24000 */ swbOffset1024_24, /* 22050 */ swbOffset1024_16, /* 16000 */ swbOffset1024_16, /* 12000 */ swbOffset1024_16, /* 11025 */ swbOffset1024_8, /* 8000 */ }; static const std::uint16_t *const swbOffset512Window[] = { nullptr, /* 96000 */ nullptr, /* 88200 */ nullptr, /* 64000 */ swbOffset512_48, /* 48000 */ swbOffset512_48, /* 44100 */ swbOffset512_32, /* 32000 */ swbOffset512_24, /* 24000 */ swbOffset512_24, /* 22050 */ nullptr, /* 16000 */ nullptr, /* 12000 */ nullptr, /* 11025 */ nullptr, /* 8000 */ }; static const std::uint16_t *const swbOffset480Window[] = { nullptr, /* 96000 */ nullptr, /* 88200 */ nullptr, /* 64000 */ swbOffset480_48, /* 48000 */ swbOffset480_48, /* 44100 */ swbOffset480_32, /* 32000 */ swbOffset480_24, /* 24000 */ swbOffset480_24, /* 22050 */ nullptr, /* 16000 */ nullptr, /* 12000 */ nullptr, /* 11025 */ nullptr, /* 8000 */ }; static const std::uint16_t *const swbOffset128Window[] = { swbOffset128_96, /* 96000 */ swbOffset128_96, /* 88200 */ swbOffset128_64, /* 64000 */ swbOffset128_48, /* 48000 */ swbOffset128_48, /* 44100 */ swbOffset128_48, /* 32000 */ swbOffset128_24, /* 24000 */ swbOffset128_24, /* 22050 */ swbOffset128_16, /* 16000 */ swbOffset128_16, /* 12000 */ swbOffset128_16, /* 11025 */ swbOffset128_8 /* 8000 */ }; /*! * \brief Constructs a new LTP info object. */ AacLtpInfo::AacLtpInfo() : lastBand(0) , dataPresent(0) , lag(0) , lagUpdate(0) , coef(0) , longUsed{ 0 } , shortUsed{ 0 } , shortLagPresent{ 0 } , shortLag{ 0 } { } /*! * \brief Constructs a new predictor info object. */ AacPredictorInfo::AacPredictorInfo() : maxSfb(0) , reset(0) , resetGroupNumber(0) , predictionUsed{ 0 } { } /*! * \brief Constructs a new pulse info object. */ AacPulseInfo::AacPulseInfo() : count(0) , startSfb(0) , offset{ 0 } , amp{ 0 } { } /*! * \brief Constructs a new TNS info object. */ AacTnsInfo::AacTnsInfo() : filt{ 0 } , coefRes{ 0 } , length{ { 0 } } , order{ { 0 } } , direction{ { 0 } } , coefCompress{ { 0 } } , coef{ { { 0 } } } { } /*! * \brief Constructs a new SSR info object. */ AacSsrInfo::AacSsrInfo() : maxBand(0) , adjustNum{ { 0 } } , alevcode{ { { 0 } } } , aloccode{ { { 0 } } } { } /*! * \brief Constructs a new DRC info object. */ AacDrcInfo::AacDrcInfo() : present(0) , bandCount(0) , pceInstanceTag(0) , excludedChannelsPresent(0) , bandTop{ 0 } , progRefLevel(0) , dynamicRangeSign{ 0 } , dynamicRangeControl{ 0 } , excludeMask{ 0 } , additionalExcludedChannels{ 0 } { } /*! * \brief Constructs a new PS info object. */ AacPsInfo::AacPsInfo() { } /*! * \brief Constructs a new DRM-PS info object. */ AacDrmPsInfo::AacDrmPsInfo() { } /*! * \brief Constructs a new SBR info object. */ AacSbrInfo::AacSbrInfo(std::uint8_t sbrElementType, std::uint16_t samplingFrequency, std::uint16_t frameLength, bool isDrm) : aacElementId(sbrElementType) , samplingFrequency(samplingFrequency) , maxAacLine(0) , rate(0) , justSeeked(0) , ret(0) , ampRes{ 0 } , k0(0) , kx(0) , m(0) , nMaster(0) , nHigh(0) , nLow(0) , nq(0) , nl{ 0 } , n{ 0 } , fMaster{ 0 } , fTableRes{ { 0 } } , fTableNoise{ 0 } , fTableLim{ { 0 } } , fGroup{ { 0 } } , ng{ 0 } , tableMapKToG{ 0 } , absBordLead{ 0 } , absBordTrail{ 0 } , relLeadCount{ 0 } , relTrailCount{ 0 } , le{ 0 } , lePrev{ 0 } , lq{ 0 } , te{ { 0 } } , tq{ { 0 } } , f{ { 0 } } , fPrev{ 0 } , //*G_temp_prev{{0}}, //*Q_temp_prev{{0}}, //GQ_ringbuf_index{0}, e{ { { 0 } } } , ePrev{ { 0 } } , //E_orig{{{0}}}, //E_curr{{{0}}}, q{ { { 0 } } } , //Q_div{{{0}}}, //Q_div2{{{0}}}, qPrev{ { 0 } } , la{ 0 } , laPrev{ 0 } , bsInvfMode{ { 0 } } , bsInvfModePrev{ { 0 } } , //bwArray{{0}}, //bwArray_prev{{0}}, noPatches(0) , patchNoSubbands{ 0 } , patchStartSubband{ 0 } , bsAddHarmonic{ { 0 } } , bsAddHarmonicPrev{ { 0 } } , indexNoisePrev{ 0 } , psiIsPrev{ 0 } , bsStartFreqPrev(numeric_limits::max()) , bsStopFreqPrev(0) , bsXoverBandPrev(0) , bsFreqScalePrev(0) , bsAlterScalePrev(0) , bsNoiseBandsPrev(0) , prevEnvIsShort{ -1, -1 } , kxPrev(0) , bsco(0) , bscoPrev(0) , mPrev(0) , frameLength(frameLength) , reset(1) , frame(0) , headerCount(0) , idAac(0) , //qmfa_info *qmfa{0}, //qmfs_info *qmfs{0}, //qmf_t Xsbr{{{0}}}, isDrmSbr(isDrm) , //drm_ps_info *drm_ps; timeSlotsRateCount(aacSbrRate * (frameLength == 960 ? aacNoTimeSlots960 : aacNoTimeSlots)) , timeSlotsCount(frameLength == 960 ? aacNoTimeSlots960 : aacNoTimeSlots) , tHfGen(8) , tHfAdj(2) , psUsed(0) , psResetFlag(0) , bsHeaderFlag(0) , bsCrcFlag(0) , bsSbrCrcBits(0) , bsProtocolVersion(0) , bsAmpRes(1) , bsStartFreq(5) , bsStopFreq(0) , bsXoverBand(0) , bsFreqScale(2) , bsAlterScale(1) , bsNoiseBands(2) , bsLimiterBands(2) , bsLimiterGains(2) , bsInterpolFreq(1) , bsSmoothingMode(1) , bsSamplerateMode(1) , bsAddHarmonicFlag{ 0 } , bsAddHarmonicFlagPrev{ 0 } , bsExtendedData(0) , bsExtensionId(0) , bsExtensionData(0) , bsCoupling(0) , bsFrameClass{ 0 } , bsRelBord{ { 0 } } , bsRelBord0{ { 0 } } , bsRelBord1{ { 0 } } , bsPointer{ 0 } , bsAbsBord0{ 0 } , bsAbsBord1{ 0 } , bsRelCount0{ 0 } , bsRelCount1{ 0 } , bsDfEnv{ { 0 } } , bsDfNoise{ { 0 } } { throw NotImplementedException(); // TODO /* switch (sbrElementType) { using namespace AacSyntaxElementTypes; case ChannelPairElement: break; default:; } */ } /*! * \brief Constructs a new program config object. */ AacProgramConfig::AacProgramConfig() : elementInstanceTag(0) , objectType(0) , samplingFrequencyIndex(0) , frontChannelElementCount(0) , sideChannelElementCount(0) , backChannelElementCount(0) , lfeChannelElementCount(0) , assocDataElementCount(0) , validCcElementCount(0) , monoMixdownPresent(0) , monoMixdownElementNumber(0) , stereoMixdownPresent(0) , stereoMixdownElementNumber(0) , matrixMixdownIdxPresent(0) , pseudoSurroundEnable(0) , matrixMixdownIdx(0) , frontElementIsCpe{ 0 } , frontElementTagSelect{ 0 } , sideElementIsCpe{ 0 } , sideElementTagSelect{ 0 } , backElementIsCpe{ 0 } , backElementTagSelect{ 0 } , lfeElementTagSelect{ 0 } , assocDataElementTagSelect{ 0 } , ccElementIsIndSw{ 0 } , validCcElementTagSelect{ 0 } , channels(0) , commentFieldBytes(0) , commentFieldData{ 0 } , frontChannelCount(0) , sideChannelCount(0) , backChannelCount(0) , lfeChannelCount(0) , sceChannel{ 0 } , cpeChannel{ 0 } { } /*! * \brief Constructs a new ICS info object. */ AacIcsInfo::AacIcsInfo() : maxSfb(0) , swbCount(0) , windowGroupCount(0) , windowCount(0) , windowSequence(0) , windowGroupLengths{ 0 } , windowShape(0) , scaleFactorGrouping(0) , sectionSfbOffset{ { 0 } } , swbOffset{ 0 } , maxSwbOffset(0) , sectionCb{ { 0 } } , sectionStart{ { 0 } } , sectionEnd{ { 0 } } , sfbCb{ { 0 } } , sectionsPerGroup{ 0 } , globalGain(0) , scaleFactors{ { 0 } } , midSideCodingMaskPresent(0) , midSideCodingUsed{ { 0 } } , noiseUsed(0) , isUsed(0) , pulseDataPresent(0) , tnsDataPresent(0) , gainControlPresent(0) , predictorDataPresent(0) , reorderedSpectralDataLength(0) , longestCodewordLength(0) , sfConcealment(0) , revGlobalGain(0) , rvlcSfLength(0) , dpcmNoiseNrg(0) , sfEscapesPresent(0) , rvlcEscapesLength(0) , dpcmNoiseLastPos(0) { } /*! * \class TagParser::AacFrameElementParser * \brief The AacFrameElementParser class parses AAC frame elements. * \remarks * - Only reads reads the basic syntax yet; does not reconstruct samples. * - This class is not well tested yet. */ /*! * \brief Parses "Long Term Prediction" info. */ void AacFrameElementParser::parseLtpInfo(const AacIcsInfo &ics, AacLtpInfo <p) { ltp.lag = 0; if (m_mpeg4AudioObjectId == Mpeg4AudioObjectIds::ErAacLd) { if ((ltp.lagUpdate = m_reader.readBit())) { ltp.lag = m_reader.readBits(10); } } else { ltp.lag = m_reader.readBits(11); } if (ltp.lag > (m_frameLength << 1)) { throw InvalidDataException(); } ltp.coef = m_reader.readBits(3); switch (ics.windowSequence) { case AacIcsSequenceTypes::EightShortSequence: for (std::uint8_t w = 0; w < ics.windowCount; ++w) { if ((ltp.shortUsed[w] = m_reader.readBit())) { if ((ltp.shortLagPresent[w] = m_reader.readBit())) { ltp.shortLag[w] = m_reader.readBits(4); } } } break; default: ltp.lastBand = std::min(ics.maxSfb, aacMaxLtpSfb); for (std::uint8_t sfb = 0; sfb < ltp.lastBand; ++sfb) { ltp.longUsed[sfb] = m_reader.readBit(); } } } /*! * \brief Parses "individual channel stream" info. */ void AacFrameElementParser::parseIcsInfo(AacIcsInfo &ics) { using namespace AacIcsSequenceTypes; if (m_reader.readBit()) { // isc reserved bit (must be 0) throw InvalidDataException(); } ics.windowSequence = m_reader.readBits(2); ics.windowShape = m_reader.readBit(); if (m_mpeg4AudioObjectId == Mpeg4AudioObjectIds::ErAacLd && ics.windowSequence != OnlyLongSequence) { throw InvalidDataException(); // no block switching in LD } if (ics.windowSequence == EightShortSequence) { ics.maxSfb = m_reader.readBits(4); ics.scaleFactorGrouping = m_reader.readBits(7); } else { ics.maxSfb = m_reader.readBits(6); } calculateWindowGroupingInfo(ics); if (ics.windowSequence != EightShortSequence) { if ((ics.predictorDataPresent = m_reader.readBit())) { switch (m_mpeg4AudioObjectId) { case Mpeg4AudioObjectIds::AacMain: // MPEG-2 style AAC predictor if ((ics.predictor.reset = m_reader.readBit())) { ics.predictor.resetGroupNumber = m_reader.readBits(5); ics.predictor.maxSfb = ics.maxSfb; } if (ics.predictor.maxSfb > maxPredictionSfb[m_mpeg4SamplingFrequencyIndex]) { ics.predictor.maxSfb = maxPredictionSfb[m_mpeg4SamplingFrequencyIndex]; } for (std::uint8_t sfb = 0; sfb < ics.predictor.maxSfb; ++sfb) { ics.predictor.predictionUsed[sfb] = m_reader.readBit(); } break; default: // "Long Term Prediction" if (m_mpeg4AudioObjectId < Mpeg4AudioObjectIds::ErAacLc) { if ((ics.ltp1.dataPresent = m_reader.readBit())) { parseLtpInfo(ics, ics.ltp1); } if (m_commonWindow) { if ((ics.ltp2.dataPresent = m_reader.readBit())) { parseLtpInfo(ics, ics.ltp2); } } } if (!m_commonWindow && (m_mpeg4AudioObjectId >= Mpeg4AudioObjectIds::ErAacLc)) { if ((ics.ltp1.dataPresent = m_reader.readBit())) { parseLtpInfo(ics, ics.ltp1); } } } } } } /*! * \brief Parses section data. */ void AacFrameElementParser::parseSectionData(AacIcsInfo &ics) { const std::uint8_t sectionBits = ics.windowSequence == AacIcsSequenceTypes::EightShortSequence ? 3 : 5; const std::uint8_t sectionEscValue = static_cast((1 << sectionBits) - 1); for (std::uint8_t groupIndex = 0, sectionIndex = 0; groupIndex < ics.windowGroupCount; ++groupIndex, sectionIndex = 0) { for (std::uint8_t i = 0, sectionLength, sectionLengthIncrease; i < ics.maxSfb; i += sectionLength, ++sectionIndex) { ics.sectionCb[groupIndex][sectionIndex] = m_reader.readBits(m_aacSectionDataResilienceFlag ? 5 : 4); sectionLength = 0; sectionLengthIncrease = (!m_aacSectionDataResilienceFlag && (ics.sectionCb[groupIndex][sectionIndex] < 16 || ics.sectionCb[groupIndex][sectionIndex] > 32) && ics.sectionCb[groupIndex][sectionIndex] != 11) ? m_reader.readBits(sectionBits) : 1; while (sectionLengthIncrease == sectionEscValue) { sectionLength += sectionLengthIncrease; sectionLengthIncrease = m_reader.readBits(sectionBits); } sectionLength += sectionLengthIncrease; ics.sectionStart[groupIndex][sectionIndex] = i; ics.sectionEnd[groupIndex][sectionIndex] = i + sectionLength; if (ics.windowSequence == AacIcsSequenceTypes::EightShortSequence) { if (i + sectionLength > 8 * 15) { throw InvalidDataException(); } else if (sectionIndex >= 8 * 15) { throw InvalidDataException(); } } else { if (i + sectionLength > aacMaxSfb) { throw InvalidDataException(); } else if (sectionIndex >= aacMaxSfb) { throw InvalidDataException(); } } for (std::uint8_t sfb = i; sfb < i + sectionLength; ++sfb) { ics.sfbCb[groupIndex][sfb] = ics.sectionCb[groupIndex][sectionIndex]; } } ics.sectionsPerGroup[groupIndex] = sectionIndex; } } /*! * \brief Decodes scale factor data (called by parseScaleFactorData()). */ void AacFrameElementParser::decodeScaleFactorData(AacIcsInfo &ics) { std::int16_t tmp; std::uint8_t noisePcmFlag = 1; std::int16_t scaleFactor = ics.globalGain; std::int16_t isPosition = 0; std::int16_t noiseEnergy = ics.globalGain - 90; using namespace AacScaleFactorTypes; for (std::uint8_t group = 0; group < ics.windowGroupCount; ++group) { for (std::uint8_t sfb = 0; sfb < ics.maxSfb; ++sfb) { switch (ics.sfbCb[group][sfb]) { case ZeroHcb: // zero book ics.scaleFactors[group][sfb] = 0; break; case IntensityHcb: // intensity books case IntensityHcb2: ics.scaleFactors[group][sfb] = static_cast(isPosition += (parseHuffmanScaleFactor() - 60)); break; case NoiseHcb: // noise books if (noisePcmFlag) { noisePcmFlag = 0; tmp = m_reader.readBits(9); } else { tmp = parseHuffmanScaleFactor() - 60; } ics.scaleFactors[group][sfb] = static_cast(noiseEnergy += tmp); break; default: // spectral books scaleFactor += parseHuffmanScaleFactor() - 60; if (scaleFactor < 0 || scaleFactor > 255) { throw InvalidDataException(); } else { ics.scaleFactors[group][sfb] = 0; } } } } } /*! * \brief Decodes RVLC scale factor data. */ void AacFrameElementParser::decodeRvlcScaleFactorData(AacIcsInfo &ics) { if (ics.rvlcSfLength) { m_reader.skipBits(ics.rvlcSfLength); } if (ics.sfEscapesPresent) { m_reader.skipBits(ics.rvlcEscapesLength); } // TODO: decode RVLC scale factors and escapes } /*! * \brief Parses scale factor data. */ void AacFrameElementParser::parseScaleFactorData(AacIcsInfo &ics) { if (!m_aacScalefactorDataResilienceFlag) { decodeScaleFactorData(ics); } else { decodeRvlcScaleFactorData(ics); } } /*! * \brief Parses pulse data. */ void AacFrameElementParser::parsePulseData(AacIcsInfo &ics) { AacPulseInfo &p = ics.pulse; p.count = m_reader.readBits(2); p.startSfb = m_reader.readBits(6); if (p.startSfb > ics.swbCount) { throw InvalidDataException(); } for (std::uint8_t i = 0; i <= p.count; ++i) { p.offset[i] = m_reader.readBits(5); p.amp[i] = m_reader.readBits(4); } } /*! * \brief Parses TNS data. */ void AacFrameElementParser::parseTnsData(AacIcsInfo &ics) { std::uint8_t filtBits, lengthBits, orderBits, startCoefBits, coefBits; if (ics.windowSequence == AacIcsSequenceTypes::EightShortSequence) { filtBits = 1; lengthBits = 4; orderBits = 3; } else { filtBits = 2; lengthBits = 6; orderBits = 5; } for (std::uint8_t window = 0; window < ics.windowCount; ++window) { if ((ics.tns.filt[window] = m_reader.readBits(filtBits))) { startCoefBits = (ics.tns.coefRes[window] = m_reader.readBit()) ? 4 : 3; } for (std::uint8_t filt = 0; filt < ics.tns.filt[window]; ++filt) { ics.tns.length[window][filt] = m_reader.readBits(lengthBits); if ((ics.tns.order[window][filt] = m_reader.readBits(orderBits))) { ics.tns.direction[window][filt] = m_reader.readBit(); ics.tns.coefCompress[window][filt] = m_reader.readBit(); coefBits = startCoefBits - ics.tns.coefCompress[window][filt]; for (std::uint8_t i = 0; i < ics.tns.order[window][filt]; ++i) { ics.tns.coef[window][filt][i] = m_reader.readBits(coefBits); } } } } } /*! * \brief Parses gain control data. */ void AacFrameElementParser::parseGainControlData(AacIcsInfo &ics) { AacSsrInfo &ssr = ics.ssr; ssr.maxBand = m_reader.readBits(2); switch (ics.windowSequence) { using namespace AacIcsSequenceTypes; case OnlyLongSequence: for (std::uint8_t bd = 1; bd <= ssr.maxBand; ++bd) { for (std::uint8_t wd = 0; wd < 1; ++wd) { ssr.adjustNum[bd][wd] = m_reader.readBits(3); for (std::uint8_t ad = 0; ad < ssr.adjustNum[bd][wd]; ++ad) { ssr.alevcode[bd][wd][ad] = m_reader.readBits(4); ssr.aloccode[bd][wd][ad] = m_reader.readBits(5); } } } break; case LongStartSequence: for (std::uint8_t bd = 1; bd <= ssr.maxBand; ++bd) { for (std::uint8_t wd = 0; wd < 2; ++wd) { ssr.adjustNum[bd][wd] = m_reader.readBits(3); for (std::uint8_t ad = 0; ad < ssr.adjustNum[bd][wd]; ++ad) { ssr.alevcode[bd][wd][ad] = m_reader.readBits(4); ssr.aloccode[bd][wd][ad] = m_reader.readBits(wd ? 2 : 4); } } } break; case EightShortSequence: for (std::uint8_t bd = 1; bd <= ssr.maxBand; ++bd) { for (std::uint8_t wd = 0; wd < 8; ++wd) { ssr.adjustNum[bd][wd] = m_reader.readBits(3); for (std::uint8_t ad = 0; ad < ssr.adjustNum[bd][wd]; ++ad) { ssr.alevcode[bd][wd][ad] = m_reader.readBits(4); ssr.aloccode[bd][wd][ad] = m_reader.readBits(2); } } } break; case LongStopSequence: for (std::uint8_t bd = 1; bd <= ssr.maxBand; ++bd) { for (std::uint8_t wd = 0; wd < 2; ++wd) { ssr.adjustNum[bd][wd] = m_reader.readBits(3); for (std::uint8_t ad = 0; ad < ssr.adjustNum[bd][wd]; ++ad) { ssr.alevcode[bd][wd][ad] = m_reader.readBits(4); ssr.aloccode[bd][wd][ad] = m_reader.readBits(wd ? 5 : 4); } } } break; } } /*! * \brief Parses spectral data. */ void AacFrameElementParser::parseSpectralData(AacIcsInfo &ics, std::int16_t *specData) { //byte groups = 0; //uint16 nshort = m_frameLength / 8; for (std::uint8_t group = 0; group < ics.windowGroupCount; ++group) { //byte p = groups * nshort; for (std::uint8_t section = 0; section < ics.sectionsPerGroup[group]; ++section) { using namespace AacScaleFactorTypes; std::uint8_t sectionCb = ics.sectionCb[group][section]; std::uint16_t increment = (sectionCb >= FirstPairHcb) ? 2 : 4; switch (sectionCb) { case ZeroHcb: case NoiseHcb: case IntensityHcb: case IntensityHcb2: //p += (ics.sectionSfbOffset[group][ics.sectionEnd[group][section]] - ics.sectionSfbOffset[group][ics.sectionStart[group][section]]); break; default: for (std::uint16_t k = ics.sectionSfbOffset[group][ics.sectionStart[group][section]]; k < ics.sectionSfbOffset[group][ics.sectionEnd[group][section]]; k += increment) { parseHuffmanSpectralData(sectionCb, specData); //p += increment; } } } //groups += ics.windowGroupLengths[group]; } } /*! * \brief Parses "side info". */ void AacFrameElementParser::parseSideInfo(AacIcsInfo &ics, bool scaleFlag) { ics.globalGain = m_reader.readBits(8); if (!m_commonWindow && !scaleFlag) { parseIcsInfo(ics); } parseSectionData(ics); parseScaleFactorData(ics); if (!scaleFlag) { if ((ics.pulseDataPresent = m_reader.readBit())) { parsePulseData(ics); } if ((ics.tnsDataPresent = m_reader.readBit())) { parseTnsData(ics); } if ((ics.gainControlPresent = m_reader.readBit())) { if (m_mpeg4AudioObjectId != Mpeg4AudioObjectIds::AacSsr) { throw InvalidDataException(); } else { parseGainControlData(ics); } } } if (m_aacScalefactorDataResilienceFlag) { decodeRvlcScaleFactorData(ics); } } std::uint8_t AacFrameElementParser::parseExcludedChannels() { for (std::uint8_t i = 0; i < 7; ++i) { m_drc.excludeMask[i] = m_reader.readBit(); } std::uint8_t size = 0; for (; (m_drc.additionalExcludedChannels[size] = m_reader.readBit()); ++size) { for (std::uint8_t i = 0; i < 7; ++i) { m_drc.excludeMask[i] = m_reader.readBit(); } } return size + 1; } std::uint8_t AacFrameElementParser::parseDynamicRange() { std::uint8_t size = 1; m_drc.bandCount = 1; if (m_reader.readBit()) { // excluded channels present m_drc.pceInstanceTag = m_reader.readBits(4); m_reader.skipBits(4); // skip reserved bits ++size; } if ((m_drc.excludedChannelsPresent = m_reader.readBit())) { size += parseExcludedChannels(); } if (m_reader.readBit()) { // has bands data m_drc.bandCount += m_reader.readBits(4); m_reader.skipBits(4); // skip reserved bits ++size; for (std::uint8_t i = 0; i < m_drc.bandCount; ++i, ++size) { m_drc.bandTop[i] = m_reader.readBits(8); } } if (m_reader.readBit()) { // has prog ref level m_drc.progRefLevel = m_reader.readBits(7); m_reader.skipBits(1); // skip reserved bit ++size; } for (std::uint8_t i = 0; i < m_drc.bandCount; ++i) { m_drc.dynamicRangeSign[i] = m_reader.readBit(); m_drc.dynamicRangeControl[i] = m_reader.readBits(7); ++size; } return size; } std::int16_t AacFrameElementParser::sbrHuffmanDec(SbrHuffTab table) { std::uint8_t bit; std::int16_t index = 0; while (index >= 0) { bit = m_reader.readBit(); index = table[index][bit]; } return index + 64; } void AacFrameElementParser::parseSbrGrid(std::shared_ptr &sbr, std::uint8_t channel) { std::uint8_t tmp, bsEnvCount; //byte bsRelCount0, bsRelCount1; switch ((sbr->bsFrameClass[channel] = m_reader.readBits(2))) { using namespace BsFrameClasses; case FixFix: tmp = m_reader.readBits(2); sbr->absBordLead[channel] = 0; sbr->absBordTrail[channel] = sbr->timeSlotsCount; sbr->relLeadCount[channel] = (bsEnvCount = min(static_cast(1 << tmp), 5)) - 1; sbr->relTrailCount[channel] = 0; tmp = m_reader.readBit(); for (std::uint8_t env = 0; env < bsEnvCount; ++env) { sbr->f[channel][env] = tmp; } break; case FixVar: sbr->absBordLead[channel] = 0; sbr->absBordTrail[channel] = m_reader.readBits(2) + sbr->timeSlotsCount; sbr->relLeadCount[channel] = 0; sbr->relTrailCount[channel] = bsEnvCount = m_reader.readBits(2); for (std::uint8_t rel = 0; rel < bsEnvCount; ++rel) { sbr->bsRelBord[channel][rel] = 2 * m_reader.readBits(2) + 2; } sbr->bsPointer[channel] = m_reader.readBits(static_cast(sbrLog2(static_cast(bsEnvCount + 2)))); for (std::uint8_t env = 0; env <= bsEnvCount; ++env) { sbr->f[channel][bsEnvCount - env] = m_reader.readBit(); } break; case VarFix: sbr->absBordLead[channel] = m_reader.readBits(2); sbr->absBordTrail[channel] = sbr->timeSlotsCount; sbr->relLeadCount[channel] = bsEnvCount = m_reader.readBits(2); sbr->relTrailCount[channel] = 0; for (std::uint8_t rel = 0; rel < bsEnvCount; ++rel) { sbr->bsRelBord[channel][rel] = 2 * m_reader.readBits(2) + 2; } sbr->bsPointer[channel] = m_reader.readBits(static_cast(sbrLog2(static_cast(bsEnvCount + 2)))); for (std::uint8_t env = 0; env < bsEnvCount; ++env) { sbr->f[channel][env] = m_reader.readBit(); } break; case VarVar: sbr->absBordLead[channel] = m_reader.readBits(2); sbr->absBordTrail[channel] = m_reader.readBits(2) + sbr->timeSlotsCount; //bsRelCount0 = m_reader.readBits(2); //bsRelCount1 = m_reader.readBits(2); m_reader.skipBits(4); bsEnvCount = min(5, sbr->bsRelCount0[channel] + sbr->bsRelCount1[channel] + 1); for (std::uint8_t rel = 0; rel < sbr->bsRelCount0[channel]; ++rel) { sbr->bsRelBord0[channel][rel] = 2 * m_reader.readBits(2) + 2; } for (std::uint8_t rel = 0; rel < sbr->bsRelCount1[channel]; ++rel) { sbr->bsRelBord1[channel][rel] = 2 * m_reader.readBits(2) + 2; } sbr->bsPointer[channel] = m_reader.readBits( static_cast(sbrLog2(static_cast(sbr->bsRelCount0[channel] + sbr->bsRelCount1[channel] + 2)))); for (std::uint8_t env = 0; env < bsEnvCount; ++env) { sbr->f[channel][env] = m_reader.readBit(); } sbr->relLeadCount[channel] = sbr->bsRelCount0[channel]; sbr->relTrailCount[channel] = sbr->bsRelCount1[channel]; break; default:; } if ((sbr->le[channel] = min(bsEnvCount, sbr->bsFrameClass[channel] == BsFrameClasses::VarVar ? 5 : 4)) <= 0) { throw InvalidDataException(); } sbr->lq[channel] = sbr->le[channel] > 1 ? 2 : 1; // TODO: envelope time border vector, noise floor time border vector } void AacFrameElementParser::parseSbrDtdf(std::shared_ptr &sbr, std::uint8_t channel) { for (std::uint8_t i = 0; i < sbr->le[channel]; ++i) { sbr->bsDfEnv[channel][i] = m_reader.readBit(); } for (std::uint8_t i = 0; i < sbr->lq[channel]; ++i) { sbr->bsDfNoise[channel][i] = m_reader.readBit(); } } void AacFrameElementParser::parseInvfMode(std::shared_ptr &sbr, std::uint8_t channel) { for (std::uint8_t i = 0; i < sbr->nq; ++i) { sbr->bsInvfMode[channel][i] = m_reader.readBits(2); } } void AacFrameElementParser::parseSbrEnvelope(std::shared_ptr &sbr, std::uint8_t channel) { std::int8_t delta; //SbrHuffTab tHuff; SbrHuffTab fHuff; if ((sbr->le[channel] == 1) && (sbr->bsFrameClass[channel] == BsFrameClasses::FixFix)) { sbr->ampRes[channel] = 0; } else { sbr->ampRes[channel] = sbr->bsAmpRes; } if ((sbr->bsCoupling) && (channel == 1)) { delta = 1; if (sbr->ampRes[channel]) { //tHuff = tHuffmanEnvBal30dB; fHuff = fHuffmanEnvBal30dB; } else { //tHuff = tHuffmanEnvBal15dB; fHuff = fHuffmanEnvBal15dB; } } else { delta = 0; if (sbr->ampRes[channel]) { //tHuff = tHuffmanEnv30dB; fHuff = fHuffmanEnv30dB; } else { //tHuff = tHuffmanEnv15dB; fHuff = fHuffmanEnv15dB; } } for (std::uint8_t env = 0; env < sbr->le[channel]; ++env) { if (sbr->bsDfEnv[channel][env] == 0) { if ((sbr->bsCoupling == 1) && (channel == 1)) { if (sbr->ampRes[channel]) { sbr->e[channel][0][env] = static_cast(m_reader.readBits(5) << delta); } else { sbr->e[channel][0][env] = static_cast(m_reader.readBits(6) << delta); } } else { if (sbr->ampRes[channel]) { sbr->e[channel][0][env] = static_cast(m_reader.readBits(6) << delta); } else { sbr->e[channel][0][env] = static_cast(m_reader.readBits(7) << delta); } } for (std::uint8_t band = 1; band < sbr->n[sbr->f[channel][env]]; ++band) { sbr->e[channel][band][env] = static_cast(sbrHuffmanDec(fHuff) << delta); } } else { for (std::uint8_t band = 0; band < sbr->n[sbr->f[channel][env]]; ++band) { sbr->e[channel][band][env] = static_cast(sbrHuffmanDec(fHuff) << delta); } } } // TODO: extract envelope data } void AacFrameElementParser::parseSbrNoise(std::shared_ptr &sbr, std::uint8_t channel) { std::int8_t delta; //SbrHuffTab tHuff; SbrHuffTab fHuff; if ((sbr->bsCoupling == 1) && (channel == 1)) { delta = 1; //tHuff = tHuffmanNoiseBal30dB; fHuff = fHuffmanEnvBal30dB; } else { delta = 1; //tHuff = tHuffmanNoise30dB; fHuff = fHuffmanEnv30dB; } for (std::uint8_t noise = 0; noise < sbr->lq[channel]; ++noise) { if (sbr->bsDfNoise[channel][noise] == 0) { if ((sbr->bsCoupling == 1) && (channel == 1)) { sbr->q[channel][0][noise] = m_reader.readBits(5) << delta; } else { sbr->q[channel][0][noise] = m_reader.readBits(5) << delta; } for (std::uint8_t band = 1; band < sbr->nq; ++band) { sbr->q[channel][band][noise] = sbrHuffmanDec(fHuff) << delta; } } else { for (std::uint8_t band = 0; band < sbr->nq; ++band) { sbr->q[channel][band][noise] = sbrHuffmanDec(fHuff) << delta; } } } // TODO: extract noise floor data } void AacFrameElementParser::parseSbrSinusoidalCoding(std::shared_ptr &sbr, std::uint8_t channel) { for (std::uint8_t i = 0; i < sbr->nHigh; ++i) { sbr->bsAddHarmonic[channel][i] = m_reader.readBit(); } } std::uint16_t AacFrameElementParser::parseSbrExtension(std::shared_ptr &sbr, std::uint8_t extensionId, std::uint8_t) { std::uint8_t header; std::uint16_t res; switch (extensionId) { using namespace AacSbrExtensionIds; case Ps: if (sbr->psResetFlag) { sbr->ps->headerRead = 0; } res = parsePsData(sbr->ps, header); if (sbr->psUsed == 0 && header == 1) { sbr->psUsed = 1; } if (header == 1) { sbr->psResetFlag = 0; } return res; case DrmParametricStereo: sbr->psUsed = 1; return parseDrmPsData(sbr->drmPs); default: sbr->bsExtendedData = m_reader.readBits(6); return 6; } } std::uint16_t AacFrameElementParser::parsePsData(std::shared_ptr &ps, std::uint8_t &header) { if (m_reader.readBit()) { header = 1; ps->headerRead = 1; ps->use34HybridBands = 0; if ((ps->enableIID = m_reader.readBit())) { ps->iidMode = m_reader.readBits(3); } } throw NotImplementedException(); // TODO } std::uint16_t AacFrameElementParser::parseDrmPsData(std::shared_ptr &drmPs) { VAR_UNUSED(drmPs) throw NotImplementedException(); // TODO } void AacFrameElementParser::parseSbrSingleChannelElement(std::shared_ptr &sbr) { if (m_reader.readBit()) { // bs data extra m_reader.skipBits(4); // skip bs reserved } if (sbr->isDrmSbr) { m_reader.skipBits(1); // bs coupling } parseSbrGrid(sbr, 0); parseSbrDtdf(sbr, 0); parseInvfMode(sbr, 0); parseSbrEnvelope(sbr, 0); parseSbrNoise(sbr, 0); // TODO: envelope noise dequantisation if ((sbr->bsAddHarmonicFlag[0] = m_reader.readBit())) { parseSbrSinusoidalCoding(sbr, 0); } if ((sbr->bsExtendedData = m_reader.readBit())) { std::uint16_t cnt = m_reader.readBits(4); if (cnt == 0xF) { cnt += m_reader.readBits(8); } std::uint16_t bitsLeft = 8 * cnt; while (bitsLeft > 7) { sbr->bsExtensionId = m_reader.readBits(2); std::uint16_t tmpBitCount = 2 + parseSbrExtension(sbr, sbr->bsExtensionId, static_cast(bitsLeft)); if (tmpBitCount > bitsLeft) { throw InvalidDataException(); } else { bitsLeft -= tmpBitCount; } } if (bitsLeft) { // read remaining bits m_reader.skipBits(bitsLeft); } } } void AacFrameElementParser::parseSbrChannelPairElement(std::shared_ptr &sbr) { if (m_reader.readBit()) { // bs data extra m_reader.skipBits(8); // skip bs reserved } if ((sbr->bsCoupling = m_reader.readBit())) { parseSbrGrid(sbr, 0); // copy data from left to right sbr->bsFrameClass[1] = sbr->bsFrameClass[0]; sbr->le[1] = sbr->le[0]; sbr->lq[1] = sbr->lq[0]; sbr->bsPointer[1] = sbr->bsPointer[0]; for (std::uint8_t n = 0; n < sbr->le[0]; ++n) { sbr->te[1][n] = sbr->te[0][n]; sbr->f[1][n] = sbr->f[0][n]; } for (std::uint8_t n = 0; n < sbr->lq[0]; ++n) { sbr->tq[1][n] = sbr->tq[0][n]; } parseSbrDtdf(sbr, 0); parseSbrDtdf(sbr, 1); parseInvfMode(sbr, 0); for (std::uint8_t n = 0; n < sbr->nq; ++n) { sbr->bsInvfMode[1][n] = sbr->bsInvfMode[0][n]; } parseSbrEnvelope(sbr, 0); parseSbrNoise(sbr, 0); parseSbrEnvelope(sbr, 1); parseSbrNoise(sbr, 1); } else { parseSbrGrid(sbr, 0); parseSbrGrid(sbr, 1); parseSbrDtdf(sbr, 0); parseSbrDtdf(sbr, 1); parseInvfMode(sbr, 0); parseInvfMode(sbr, 1); parseSbrEnvelope(sbr, 0); parseSbrEnvelope(sbr, 1); parseSbrNoise(sbr, 0); parseSbrNoise(sbr, 1); } if ((sbr->bsAddHarmonicFlag[0] = m_reader.readBit())) { parseSbrSinusoidalCoding(sbr, 0); } if ((sbr->bsAddHarmonicFlag[1] = m_reader.readBit())) { parseSbrSinusoidalCoding(sbr, 1); } // TODO: envelope noise dequantisation (for both channels) if (sbr->bsCoupling) { // TODO: unmap envelope noise } if ((sbr->bsExtendedData = m_reader.readBit())) { std::uint16_t cnt = m_reader.readBits(4); if (cnt == 0xF) { cnt += m_reader.readBits(8); } std::uint16_t bitsLeft = 8 * cnt; while (bitsLeft > 7) { sbr->bsExtensionId = m_reader.readBits(2); std::uint16_t tmpBitCount = 2 + parseSbrExtension(sbr, sbr->bsExtensionId, static_cast(bitsLeft)); if (tmpBitCount > bitsLeft) { throw InvalidDataException(); } else { bitsLeft -= tmpBitCount; } } if (bitsLeft) { // read remaining bits m_reader.skipBits(bitsLeft); } } } shared_ptr AacFrameElementParser::makeSbrInfo(std::uint8_t sbrElement, bool isDrm) { if (m_mpeg4ExtensionSamplingFrequencyIndex >= sizeof(mpeg4SamplingFrequencyTable) && m_mpeg4SamplingFrequencyIndex >= sizeof(mpeg4SamplingFrequencyTable)) { throw InvalidDataException(); // sampling frequency index is invalid } return make_shared(m_elementId[sbrElement], m_mpeg4ExtensionSamplingFrequencyIndex < sizeof(mpeg4SamplingFrequencyTable) ? mpeg4SamplingFrequencyTable[m_mpeg4ExtensionSamplingFrequencyIndex] : mpeg4SamplingFrequencyTable[m_mpeg4SamplingFrequencyIndex] * 2, m_frameLength, isDrm); } void AacFrameElementParser::parseSbrExtensionData(std::uint8_t sbrElement, std::uint16_t count, bool crcFlag) { VAR_UNUSED(count); //uint16 alignBitCount = 0; std::shared_ptr &sbr = m_sbrElements[sbrElement]; if (m_psResetFlag) { sbr->psResetFlag = m_psResetFlag; } if (!sbr->isDrmSbr) { if (crcFlag) { sbr->bsSbrCrcBits = m_reader.readBits(10); } } //auto startFrequ = sbr->bsStartFreq; //auto samplerateMode = sbr->bsSamplerateMode; //auto stopFrequ = sbr->bsStopFreq; //auto frequScale = sbr->bsFreqScale; //auto alterScale = sbr->bsAlterScale; //auto xoverBand = sbr->bsXoverBand; if ((sbr->bsHeaderFlag = m_reader.readBit())) { sbr->bsStartFreq = m_reader.readBits(4); sbr->bsStopFreq = m_reader.readBits(4); sbr->bsXoverBand = m_reader.readBits(3); m_reader.skipBits(2); std::uint8_t bsExtraHeader1 = m_reader.readBit(); std::uint8_t bsExtraHeader2 = m_reader.readBit(); if (bsExtraHeader1) { sbr->bsFreqScale = m_reader.readBits(2); sbr->bsAlterScale = m_reader.readBit(); sbr->bsNoiseBands = m_reader.readBits(2); } else { sbr->bsFreqScale = 2; sbr->bsAlterScale = 1; sbr->bsNoiseBands = 2; } if (bsExtraHeader2) { sbr->bsLimiterBands = m_reader.readBits(2); sbr->bsLimiterGains = m_reader.readBits(2); sbr->bsInterpolFreq = m_reader.readBit(); sbr->bsSmoothingMode = m_reader.readBit(); } else { sbr->bsLimiterBands = 2; sbr->bsLimiterGains = 2; sbr->bsInterpolFreq = 1; sbr->bsSmoothingMode = 1; } } if (sbr->headerCount) { if (sbr->reset || (sbr->bsHeaderFlag && sbr->justSeeked)) { // TODO: calc SBR tables; restore old values on error } sbr->rate = sbr->bsSamplerateMode ? 2 : 1; switch (sbr->aacElementId) { using namespace AacSyntaxElementTypes; case SingleChannelElement: parseSbrSingleChannelElement(sbr); break; case ChannelPairElement: parseSbrChannelPairElement(sbr); break; } } } std::uint8_t AacFrameElementParser::parseHuffmanScaleFactor() { std::uint16_t offset = 0; while (aacHcbSf[offset][1]) { offset += aacHcbSf[offset][m_reader.readBit()]; if (offset > 240) { throw InvalidDataException(); } } return aacHcbSf[offset][0]; } void AacFrameElementParser::parseHuffmanSpectralData(std::uint8_t cb, std::int16_t *sp) { switch (cb) { case 1: case 2: // 2-step method for data quadruples huffman2StepQuad(cb, sp); break; case 3: // binary search for data quadruples huffmanBinaryQuadSign(cb, sp); break; case 4: // binary search for data paris huffmanBinaryPair(cb, sp); break; case 5: // 2-step method for data pairs huffman2StepPair(cb, sp); break; case 6: // 2-step method for data pairs huffman2StepPair(cb, sp); break; case 7: case 9: // binary search for data pairs huffmanBinaryPairSign(cb, sp); break; case 8: case 10: // 2-step method for data pairs huffman2StepPairSign(cb, sp); break; case 11: try { huffman2StepPairSign(11, sp); } catch (const InvalidDataException &) { sp[0] = huffmanGetEscape(sp[0]); sp[1] = huffmanGetEscape(sp[1]); throw; } sp[0] = huffmanGetEscape(sp[0]); sp[1] = huffmanGetEscape(sp[1]); break; case 12: try { huffman2StepPair(11, sp); } catch (const InvalidDataException &) { sp[0] = huffmanCodebook(0); sp[1] = huffmanCodebook(1); throw; } sp[0] = huffmanCodebook(0); sp[1] = huffmanCodebook(1); break; case 16: case 17: case 18: case 19: case 20: case 21: case 22: case 23: case 24: case 25: case 26: case 27: case 28: case 29: case 30: case 31: try { huffman2StepPairSign(11, sp); } catch (const InvalidDataException &) { sp[0] = huffmanGetEscape(sp[0]); sp[1] = huffmanGetEscape(sp[1]); vcb11CheckLav(cb, sp); throw; } sp[0] = huffmanGetEscape(sp[0]); sp[1] = huffmanGetEscape(sp[1]); vcb11CheckLav(cb, sp); break; default: throw InvalidDataException(); // non existend codebook number } } void AacFrameElementParser::huffmanSignBits(std::int16_t *sp, std::uint8_t len) { for (std::int16_t *end = sp + len; sp < end; ++sp) { if (*sp) { if (m_reader.readBit()) { *sp = -(*sp); } } } } void AacFrameElementParser::huffman2StepQuad(std::uint8_t cb, std::int16_t *sp) { std::uint32_t cw = m_reader.showBits(aacHcbN[cb]); std::uint16_t offset = aacHcbTable[cb][cw].offset; uint8_t extraBits = aacHcbTable[cb][cw].extraBits; if (extraBits) { m_reader.skipBits(aacHcbN[cb]); offset += m_reader.showBits(extraBits); m_reader.skipBits(aacHcb2QuadTable[cb][offset].bits - aacHcbN[cb]); } else { m_reader.skipBits(aacHcb2QuadTable[cb][offset].bits); } if (offset > aacHcb2QuadTableSize[cb]) { throw InvalidDataException(); } sp[0] = aacHcb2QuadTable[cb][offset].x; sp[1] = aacHcb2QuadTable[cb][offset].y; sp[2] = aacHcb2QuadTable[cb][offset].v; sp[3] = aacHcb2QuadTable[cb][offset].w; } void AacFrameElementParser::huffmanBinaryQuadSign(std::uint8_t cb, std::int16_t *sp) { try { huffman2StepQuad(cb, sp); } catch (const InvalidDataException &) { huffmanSignBits(sp, 4); throw; } huffmanSignBits(sp, 4); } void AacFrameElementParser::huffmanBinaryPair(std::uint8_t cb, std::int16_t *sp) { std::uint16_t offset = 0; while (!aacHcbBinTable[cb][offset].isLeaf) { offset += aacHcbBinTable[cb][offset].data[m_reader.readBit()]; } if (offset > aacHcbBinTableSize[cb]) { throw InvalidDataException(); } sp[0] = aacHcbBinTable[cb][offset].data[0]; sp[1] = aacHcbBinTable[cb][offset].data[1]; } void AacFrameElementParser::huffman2StepPair(std::uint8_t cb, std::int16_t *sp) { std::uint32_t cw = m_reader.showBits(aacHcbN[cb]); std::uint16_t offset = aacHcbTable[cb][cw].offset; uint8_t extraBits = aacHcbTable[cb][cw].extraBits; if (extraBits) { m_reader.skipBits(aacHcbN[cb]); offset += m_reader.showBits(extraBits); m_reader.skipBits(aacHcb2PairTable[cb][offset].bits - aacHcbN[cb]); } else { m_reader.skipBits(aacHcb2PairTable[cb][offset].bits); } if (offset > aacHcb2PairTableSize[cb]) { throw InvalidDataException(); } sp[0] = aacHcb2PairTable[cb][offset].x; sp[1] = aacHcb2PairTable[cb][offset].y; } void AacFrameElementParser::huffmanBinaryPairSign(std::uint8_t cb, std::int16_t *sp) { try { huffmanBinaryPair(cb, sp); } catch (const InvalidDataException &) { huffmanSignBits(sp, 2); throw; } huffmanSignBits(sp, 2); } void AacFrameElementParser::huffman2StepPairSign(std::uint8_t cb, std::int16_t *sp) { try { huffman2StepPair(cb, sp); } catch (const InvalidDataException &) { huffmanSignBits(sp, 2); throw; } huffmanSignBits(sp, 2); } std::int16_t AacFrameElementParser::huffmanGetEscape(std::int16_t sp) { std::uint8_t neg; if (sp < 0) { if (sp != -16) return sp; neg = 1; } else { if (sp != 16) return sp; neg = 0; } std::uint8_t size; for (size = 4; m_reader.readBit(); ++size) { } const std::int16_t off = m_reader.readBits(size); return static_cast(neg ? -(off | (1 << size)) : (off | (1 << size))); } void AacFrameElementParser::vcb11CheckLav(std::uint8_t cb, std::int16_t *sp) { static const uint16_t vcb11LavTab[] = { 16, 31, 47, 63, 95, 127, 159, 191, 223, 255, 319, 383, 511, 767, 1023, 2047 }; std::uint16_t max = 0; if (cb < 16 || cb > 31) return; max = vcb11LavTab[cb - 16]; if ((abs(sp[0]) > max) || (abs(sp[1]) > max)) { sp[0] = 0; sp[1] = 0; } } /*! * \brief Calculates "window grouping info". */ void AacFrameElementParser::calculateWindowGroupingInfo(AacIcsInfo &ics) { using namespace AacIcsSequenceTypes; switch (ics.windowSequence) { case OnlyLongSequence: case LongStartSequence: case LongStopSequence: ics.windowCount = ics.windowGroupCount = ics.windowGroupLengths[0] = 1; if (m_mpeg4AudioObjectId == Mpeg4AudioObjectIds::ErAacLd) { if (m_frameLength == 512) { ics.swbCount = swb512WindowCount[m_mpeg4SamplingFrequencyIndex]; } else { // if 480 ics.swbCount = swb480WindowCount[m_mpeg4SamplingFrequencyIndex]; } } else { if (m_frameLength == 1024) { ics.swbCount = swb1024WindowCount[m_mpeg4SamplingFrequencyIndex]; } else { ics.swbCount = swb960WindowCount[m_mpeg4SamplingFrequencyIndex]; } } if (ics.maxSfb > ics.swbCount) { throw InvalidDataException(); } if (m_mpeg4AudioObjectId == Mpeg4AudioObjectIds::ErAacLd) { if (m_frameLength == 512) { for (std::uint8_t i = 0; i <= ics.swbCount; ++i) { ics.sectionSfbOffset[0][i] = swbOffset512Window[m_mpeg4SamplingFrequencyIndex][i]; ics.swbOffset[i] = swbOffset512Window[m_mpeg4SamplingFrequencyIndex][i]; } } else { for (std::uint8_t i = 0; i <= ics.swbCount; ++i) { ics.sectionSfbOffset[0][i] = swbOffset480Window[m_mpeg4SamplingFrequencyIndex][i]; ics.swbOffset[i] = swbOffset480Window[m_mpeg4SamplingFrequencyIndex][i]; } } } else { for (std::uint8_t i = 0; i <= ics.swbCount; ++i) { ics.sectionSfbOffset[0][i] = swbOffset1024Window[m_mpeg4SamplingFrequencyIndex][i]; ics.swbOffset[i] = swbOffset1024Window[m_mpeg4SamplingFrequencyIndex][i]; } } ics.sectionSfbOffset[0][ics.swbCount] = ics.swbOffset[ics.swbCount] = ics.maxSwbOffset = m_frameLength; break; case EightShortSequence: ics.windowCount = 8; ics.windowGroupCount = ics.windowGroupLengths[0] = 1; ics.swbCount = swb128WindowCount[m_mpeg4SamplingFrequencyIndex]; if (ics.maxSfb > ics.swbCount) { throw InvalidDataException(); } for (std::uint8_t i = 0; i < ics.swbCount; ++i) { ics.swbOffset[i] = swbOffset128Window[m_mpeg4SamplingFrequencyIndex][i]; } ics.swbOffset[ics.swbCount] = ics.maxSwbOffset = m_frameLength / 8; for (std::uint8_t i = 0; i < ics.windowCount - 1; ++i) { if (!(ics.scaleFactorGrouping & (1 << (6 - i)))) { ics.windowGroupLengths[ics.windowGroupCount] = 1; ++ics.windowGroupCount; } else { ++(ics.windowGroupLengths[ics.windowGroupCount - 1]); } } for (std::uint8_t g = 0; g < ics.windowGroupCount; ++g) { std::uint8_t sectionSfb = 0; std::uint16_t offset = 0, width; for (std::uint8_t i = 0; i < ics.swbCount; ++i) { if (i + 1 == ics.swbCount) { width = (m_frameLength / 8) - swbOffset128Window[m_mpeg4SamplingFrequencyIndex][i]; } else { width = swbOffset128Window[m_mpeg4SamplingFrequencyIndex][i + 1] - swbOffset128Window[m_mpeg4SamplingFrequencyIndex][i]; } width *= ics.windowGroupLengths[g]; ics.sectionSfbOffset[g][sectionSfb++] = offset; offset += width; } ics.sectionSfbOffset[g][sectionSfb] = offset; } break; default: throw InvalidDataException(); } } /*! * \brief Parses "individual channel stream" (basic audio unit). */ void AacFrameElementParser::parseIndividualChannelStream(AacIcsInfo &ics, std::int16_t *specData, bool scaleFlag) { parseSideInfo(ics, scaleFlag); if (m_mpeg4AudioObjectId >= Mpeg4AudioObjectIds::ErAacLc) { if (ics.tnsDataPresent) { parseTnsData(ics); } } if (m_mpeg4AudioObjectId == Mpeg4AudioObjectIds::ErParametric) { // DRM stuff? // TODO: check CRC throw NotImplementedException(); } if (m_aacSpectralDataResilienceFlag) { // TODO: parseReorderedSpectralData(ic); throw NotImplementedException(); } else { parseSpectralData(ics, specData); } if (ics.pulseDataPresent) { if (ics.windowSequence == AacIcsSequenceTypes::EightShortSequence) { throw InvalidDataException(); // pulse coding not allowed for short blocks } else { // TODO: reconstruct pulse coding //decodePulseData(ic); } } } /*! * \brief Parses "single channel element". */ void AacFrameElementParser::parseSingleChannelElement() { if (m_elementCount + 1 > aacMaxSyntaxElements) { throw NotImplementedException(); // can not parse frame with more than aacMaxSyntaxElements syntax elements } // TODO: check whether limit of channels is exceeded std::int16_t specData[1024] = { 0 }; m_elementId[m_elementCount] = AacSyntaxElementTypes::SingleChannelElement; m_elementInstanceTag[m_elementCount] = m_reader.readBits(4); //m_channel = channel; //m_pairedChannel = -1; parseIndividualChannelStream(m_ics1, specData); if (m_ics1.isUsed) { throw InvalidDataException(); // IS not allowed in single channel } // check wheter next bitstream element is a fill element (for SBR decoding) if (m_reader.showBits(3) == AacSyntaxElementTypes::FillElement) { parseFillElement(m_elementCount); } // TODO: reconstruct single channel element // TODO: map output channels position to internal data channels m_channelCount += m_elementChannelCount[m_elementCount]; ++m_elementCount; } /*! * \brief Parses "channel pair element". */ void AacFrameElementParser::parseChannelPairElement() { if (m_elementCount + 2 > aacMaxSyntaxElements) { throw NotImplementedException(); // can not parse frame with more than aacMaxSyntaxElements syntax elements } // TODO: check whether limit of channels is exceeded m_elementId[m_elementCount] = AacSyntaxElementTypes::ChannelPairElement; m_elementChannelCount[m_elementCount] = 2; // number of output channels in CPE is always 2 std::int16_t specData1[1024] = { 0 }; std::int16_t specData2[1024] = { 0 }; //m_channel = channels; //m_pairedChannel = channels + 1; m_elementInstanceTag[m_elementCount] = m_reader.readBits(4); if ((m_commonWindow = m_reader.readBit())) { // both channels have common ics data parseIcsInfo(m_ics1); if ((m_ics1.midSideCodingMaskPresent = m_reader.readBits(2) == 1)) { // ms mask present for (std::uint8_t g = 0; g < m_ics1.windowGroupCount; ++g) { for (std::uint8_t sfb = 0; sfb < m_ics1.maxSfb; ++sfb) { m_ics1.midSideCodingUsed[g][sfb] = m_reader.readBit(); } } //m_reader.skipBits(m_ics1.windowGroupCount * m_ics1.maxSfb); } if (m_mpeg4AudioObjectId >= Mpeg4AudioObjectIds::ErAacLc && m_ics1.predictorDataPresent) { if ((m_ics1.ltp1.dataPresent = m_reader.readBit())) { parseLtpInfo(m_ics1, m_ics1.ltp1); } } m_ics2 = m_ics1; } else { m_ics1.midSideCodingMaskPresent = false; } parseIndividualChannelStream(m_ics1, specData1); if (m_commonWindow && m_mpeg4AudioObjectId >= Mpeg4AudioObjectIds::ErAacLc && m_ics1.predictorDataPresent) { if ((m_ics1.ltp2.dataPresent = m_reader.readBit())) { parseLtpInfo(m_ics1, m_ics1.ltp2); } } parseIndividualChannelStream(m_ics2, specData2); // check if next bitstream element is a fill element (for SBR decoding) if (m_reader.showBits(3) == AacSyntaxElementTypes::FillElement) { parseFillElement(m_elementCount); } // TODO: reconstruct channel pair // TODO: map output channels position to internal data channels m_channelCount += 2; ++m_elementCount; } /*! * \brief Parses/skips "channel coupling element". */ void AacFrameElementParser::parseCouplingChannelElement() { m_reader.skipBits(4); // element instance tag std::uint8_t swCceFlag = m_reader.readBit(); std::uint8_t coupledElementCount = m_reader.readBits(3); std::uint8_t gainElementLists = 0; for (std::uint8_t c = 0; c < coupledElementCount; ++c) { ++gainElementLists; std::uint8_t ccTargetIsCpe = m_reader.readBit(); //byte ccTargetTagSelect = m_reader.readBits(4); m_reader.skipBits(4); // cc target tag select if (ccTargetIsCpe) { // cc left and right if (m_reader.readBit() & m_reader.readBit()) { ++gainElementLists; } } } m_reader.skipBits(4); // 1 bit cc domain, 1 bit gain element sign, 2 bits gain element scale AacIcsInfo ics; std::int16_t specData[1024]; parseIndividualChannelStream(ics, specData); for (std::uint8_t c = 1; c < gainElementLists; ++c) { if (swCceFlag || m_reader.readBit()) { parseHuffmanScaleFactor(); } else { for (std::uint8_t group = 0; group < ics.windowCount; ++group) { for (std::uint8_t sfb = 0; sfb < ics.maxSfb; ++sfb) { if (ics.sfbCb[group][sfb] != AacScaleFactorTypes::ZeroHcb) { parseHuffmanScaleFactor(); } } } } } } /*! * \brief Parses "low frequency element". */ void AacFrameElementParser::parseLowFrequencyElement() { parseSingleChannelElement(); } /*! * \brief Parses/skips "data stream element". */ void AacFrameElementParser::parseDataStreamElement() { std::uint8_t byteAligned = m_reader.readBit(); std::uint16_t count = m_reader.readBits(8); if (count == 0xFF) { count += m_reader.readBits(8); } if (byteAligned) { m_reader.align(); } m_reader.skipBits(count * 8); } /*! * \brief Parses "program config element". */ void AacFrameElementParser::parseProgramConfigElement() { m_pce.elementInstanceTag = m_reader.readBits(4); m_pce.objectType = m_reader.readBits(2); m_pce.samplingFrequencyIndex = m_reader.readBits(4); m_pce.frontChannelElementCount = m_reader.readBits(4); m_pce.sideChannelElementCount = m_reader.readBits(4); m_pce.backChannelElementCount = m_reader.readBits(4); m_pce.lfeChannelElementCount = m_reader.readBits(2); m_pce.assocDataElementCount = m_reader.readBits(3); m_pce.validCcElementCount = m_reader.readBits(4); if ((m_pce.monoMixdownPresent = m_reader.readBit())) { m_pce.monoMixdownElementNumber = m_reader.readBits(4); } if ((m_pce.stereoMixdownPresent = m_reader.readBit())) { m_pce.stereoMixdownElementNumber = m_reader.readBits(4); } if ((m_pce.matrixMixdownIdxPresent = m_reader.readBit())) { m_pce.matrixMixdownIdx = m_reader.readBits(2); m_pce.pseudoSurroundEnable = m_reader.readBit(); } std::uint8_t i; for (i = 0; i < m_pce.frontChannelElementCount; ++i) { m_pce.frontElementIsCpe[i] = m_reader.readBit(); m_pce.frontElementTagSelect[i] = m_reader.readBits(4); if (m_pce.frontElementIsCpe[i]) { // channel coupling element m_pce.cpeChannel[m_pce.frontElementTagSelect[i]] = m_pce.channels; m_pce.frontChannelCount += 2; m_pce.channels += 2; } else { // single channel element m_pce.sceChannel[m_pce.frontElementTagSelect[i]] = m_pce.channels; ++m_pce.frontChannelCount; ++m_pce.channels; } } for (i = 0; i < m_pce.sideChannelElementCount; ++i) { m_pce.sideElementIsCpe[i] = m_reader.readBit(); m_pce.sideElementTagSelect[i] = m_reader.readBits(4); if (m_pce.sideElementIsCpe[i]) { // channel coupling element m_pce.cpeChannel[m_pce.sideElementTagSelect[i]] = m_pce.channels; m_pce.sideChannelCount += 2; m_pce.channels += 2; } else { // single channel element m_pce.sceChannel[m_pce.sideElementTagSelect[i]] = m_pce.channels; ++m_pce.sideChannelCount; ++m_pce.channels; } } for (i = 0; i < m_pce.backChannelElementCount; ++i) { m_pce.backElementIsCpe[i] = m_reader.readBit(); m_pce.backElementTagSelect[i] = m_reader.readBits(4); if (m_pce.backElementIsCpe[i]) { // channel coupling element m_pce.cpeChannel[m_pce.backElementTagSelect[i]] = m_pce.channels; m_pce.backChannelCount += 2; m_pce.channels += 2; } else { // single channel element m_pce.sceChannel[m_pce.backElementTagSelect[i]] = m_pce.channels; ++m_pce.backChannelCount; ++m_pce.channels; } } for (i = 0; i < m_pce.lfeChannelElementCount; ++i) { m_pce.lfeElementTagSelect[i] = m_reader.readBits(4); m_pce.sceChannel[m_pce.lfeElementTagSelect[i]] = m_pce.channels; ++m_pce.lfeChannelCount; ++m_pce.channels; } for (i = 0; i < m_pce.assocDataElementCount; ++i) { m_pce.assocDataElementTagSelect[i] = m_reader.readBits(4); } for (i = 0; i < m_pce.validCcElementCount; ++i) { m_pce.ccElementIsIndSw[i] = m_reader.readBit(); m_pce.validCcElementTagSelect[i] = m_reader.readBits(4); } m_reader.align(); m_pce.commentFieldBytes = m_reader.readBits(8); for (i = 0; i < m_pce.commentFieldBytes; ++i) { m_pce.commentFieldData[i] = m_reader.readBits(8); } m_pce.commentFieldData[i] = 0; if (m_pce.channels > aacMaxChannels) { throw NotImplementedException(); // supported channel maximum exceeded } } /*! * \brief Parses "fill element". */ void AacFrameElementParser::parseFillElement(std::uint8_t sbrElement) { std::uint16_t count = m_reader.readBits(4); bool crcFlag = 0; if (count == 0xF) { count += m_reader.readBits(8); } while (count > 0) { continueWhile: switch (m_reader.readBits(4)) { // extension type using namespace AacExtensionTypes; case DynamicRange: count -= parseDynamicRange(); break; case SbrDataCrc: crcFlag = true; case SbrData: if (sbrElement == aacInvalidSbrElement) { throw InvalidDataException(); } else { // ensure SBR element exists if (!m_sbrElements[sbrElement]) { m_sbrElements[sbrElement] = makeSbrInfo(sbrElement); } parseSbrExtensionData(sbrElement, count, crcFlag); // set global flags m_sbrPresentFlag = 1; if (m_sbrElements[sbrElement]->ps) { m_psUsed[sbrElement] = 1; m_psUsedGlobal = 1; } } count = 0; break; case FillData: m_reader.skipBits(4 + 8 * (count - 1)); count = 0; break; case DataElement: // data element version if (m_reader.readBits(4) == 0) { // ANC data std::uint8_t dataElementLength = 0, loopCounter = 0; std::uint16_t dataElementLengthPart; do { dataElementLengthPart = m_reader.readBits(8); dataElementLength += dataElementLengthPart; ++loopCounter; } while (dataElementLengthPart == 0xFF); for (std::uint16_t i = 0; i < dataElementLength; ++i) { m_reader.skipBits(8); // data element byte count -= dataElementLength + loopCounter + 1; goto continueWhile; // FIXME: loop will run at most once } } m_reader.skipBits(8 * (count - 1)); count = 0; break; case Fill: case SacData: default: m_reader.skipBits(4 + 8 * (count - 1)); count = 0; } } } /*! * \brief Parses a raw data block. * * Reads the element type first and then calls the appropriate method for the element type. */ void AacFrameElementParser::parseRawDataBlock() { if (m_mpeg4AudioObjectId < Mpeg4AudioObjectIds::ErAacLc) { for (;;) { switch (m_reader.readBits(3)) { // parse element type using namespace AacSyntaxElementTypes; case SingleChannelElement: parseSingleChannelElement(); break; case ChannelPairElement: parseChannelPairElement(); break; case ChannelCouplingElement: parseCouplingChannelElement(); break; case LowFrequencyElement: parseLowFrequencyElement(); break; case DataStreamElement: parseDataStreamElement(); break; case ProgramConfigElement: parseProgramConfigElement(); break; case FillElement: parseFillElement(); break; case EndOfFrame: goto endOfBlock; default:; } } } else { // error resilience switch (m_mpeg4ChannelConfig) { using namespace Mpeg4ChannelConfigs; using namespace AacSyntaxElementTypes; case FrontCenter: parseSingleChannelElement(); break; case FrontLeftFrontRight: parseChannelPairElement(); break; case FrontCenterFrontLeftFrontRight: parseSingleChannelElement(); parseChannelPairElement(); break; case FrontCenterFrontLeftFrontRightBackCenter: parseSingleChannelElement(); parseChannelPairElement(); parseSingleChannelElement(); break; case FrontCenterFrontLeftFrontRightBackLeftBackRight: parseSingleChannelElement(); parseChannelPairElement(); parseChannelPairElement(); break; case FrontCenterFrontLeftFrontRightBackLeftBackRightLFEChannel: parseSingleChannelElement(); parseChannelPairElement(); parseChannelPairElement(); parseSingleChannelElement(); break; case FrontCenterFrontLeftFrontRightSideLeftSideRightBackLeftBackRightLFEChannel: parseSingleChannelElement(); parseChannelPairElement(); parseChannelPairElement(); parseChannelPairElement(); parseSingleChannelElement(); break; } } endOfBlock:; } /*! * \brief Parses the frame data from the specified \a stream at the current position. */ void AacFrameElementParser::parse(const AdtsFrame &adtsFrame, std::istream &stream, std::size_t dataSize) { auto data = make_unique(dataSize); stream.read(data.get(), dataSize); parse(adtsFrame, data, dataSize); } /*! * \brief Parses the specified frame \a data. */ void AacFrameElementParser::parse(const AdtsFrame &adtsFrame, std::unique_ptr &data, std::size_t dataSize) { m_reader.reset(data.get(), dataSize); m_mpeg4AudioObjectId = adtsFrame.mpeg4AudioObjectId(); m_mpeg4SamplingFrequencyIndex = adtsFrame.mpeg4SamplingFrequencyIndex(); parseRawDataBlock(); } /// \endcond } // namespace TagParser