aboutsummaryrefslogtreecommitdiffstats
path: root/fdk-aac/libMpegTPDec/src/tpdec_latm.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'fdk-aac/libMpegTPDec/src/tpdec_latm.cpp')
-rw-r--r--fdk-aac/libMpegTPDec/src/tpdec_latm.cpp676
1 files changed, 676 insertions, 0 deletions
diff --git a/fdk-aac/libMpegTPDec/src/tpdec_latm.cpp b/fdk-aac/libMpegTPDec/src/tpdec_latm.cpp
new file mode 100644
index 0000000..2edf055
--- /dev/null
+++ b/fdk-aac/libMpegTPDec/src/tpdec_latm.cpp
@@ -0,0 +1,676 @@
+/* -----------------------------------------------------------------------------
+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
+----------------------------------------------------------------------------- */
+
+/******************* MPEG transport format decoder library *********************
+
+ Author(s): Daniel Homm
+
+ Description:
+
+*******************************************************************************/
+
+#include "tpdec_latm.h"
+
+#include "FDK_bitstream.h"
+
+#define TPDEC_TRACKINDEX(p, l) (1 * (p) + (l))
+
+static UINT CLatmDemux_GetValue(HANDLE_FDK_BITSTREAM bs) {
+ UCHAR bytesForValue = 0, tmp = 0;
+ int value = 0;
+
+ bytesForValue = (UCHAR)FDKreadBits(bs, 2);
+
+ for (UINT i = 0; i <= bytesForValue; i++) {
+ value <<= 8;
+ tmp = (UCHAR)FDKreadBits(bs, 8);
+ value += tmp;
+ }
+
+ return value;
+}
+
+static TRANSPORTDEC_ERROR CLatmDemux_ReadAudioMuxElement(
+ HANDLE_FDK_BITSTREAM bs, CLatmDemux *pLatmDemux, int m_muxConfigPresent,
+ CSTpCallBacks *pTpDecCallbacks, CSAudioSpecificConfig *pAsc,
+ int *pfConfigFound) {
+ TRANSPORTDEC_ERROR ErrorStatus = TRANSPORTDEC_OK;
+
+ if (m_muxConfigPresent) {
+ pLatmDemux->m_useSameStreamMux = FDKreadBits(bs, 1);
+
+ if (!pLatmDemux->m_useSameStreamMux) {
+ int i;
+ UCHAR configChanged = 0;
+ UCHAR configMode = 0;
+
+ FDK_BITSTREAM bsAnchor;
+
+ FDK_BITSTREAM bsAnchorDummyParse;
+
+ if (!pLatmDemux->applyAsc) {
+ bsAnchorDummyParse = *bs;
+ pLatmDemux->newCfgHasAudioPreRoll = 0;
+ /* do dummy-parsing of ASC to determine if there is an audioPreRoll */
+ configMode |= AC_CM_DET_CFG_CHANGE;
+ if (TRANSPORTDEC_OK !=
+ (ErrorStatus = CLatmDemux_ReadStreamMuxConfig(
+ bs, pLatmDemux, pTpDecCallbacks, pAsc, pfConfigFound,
+ configMode, configChanged))) {
+ goto bail;
+ }
+
+ /* Allow flushing only when audioPreroll functionality is enabled in
+ * current and new config otherwise the new config can be applied
+ * immediately. */
+ if (pAsc->m_sc.m_usacConfig.element[0]
+ .extElement.usacExtElementHasAudioPreRoll &&
+ pLatmDemux->newCfgHasAudioPreRoll) {
+ pLatmDemux->newCfgHasAudioPreRoll = 0;
+ /* with audioPreRoll we must flush before applying new cfg */
+ pLatmDemux->applyAsc = 0;
+ } else {
+ *bs = bsAnchorDummyParse;
+ pLatmDemux->applyAsc = 1; /* apply new config immediate */
+ }
+ }
+
+ if (pLatmDemux->applyAsc) {
+ for (i = 0; i < 2; i++) {
+ configMode = 0;
+
+ if (i == 0) {
+ configMode |= AC_CM_DET_CFG_CHANGE;
+ bsAnchor = *bs;
+ } else {
+ configMode |= AC_CM_ALLOC_MEM;
+ *bs = bsAnchor;
+ }
+
+ if (TRANSPORTDEC_OK !=
+ (ErrorStatus = CLatmDemux_ReadStreamMuxConfig(
+ bs, pLatmDemux, pTpDecCallbacks, pAsc, pfConfigFound,
+ configMode, configChanged))) {
+ goto bail;
+ }
+
+ if (ErrorStatus == TRANSPORTDEC_OK) {
+ if ((i == 0) && (pAsc->AacConfigChanged || pAsc->SbrConfigChanged ||
+ pAsc->SacConfigChanged)) {
+ int errC;
+
+ configChanged = 1;
+ errC = pTpDecCallbacks->cbFreeMem(pTpDecCallbacks->cbFreeMemData,
+ pAsc);
+ if (errC != 0) {
+ ErrorStatus = TRANSPORTDEC_PARSE_ERROR;
+ goto bail;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /* If there was no configuration read, its not possible to parse
+ * PayloadLengthInfo below. */
+ if (!*pfConfigFound) {
+ ErrorStatus = TRANSPORTDEC_SYNC_ERROR;
+ goto bail;
+ }
+
+ if (pLatmDemux->m_AudioMuxVersionA == 0) {
+ /* Do only once per call, because parsing and decoding is done in-line. */
+ if (TRANSPORTDEC_OK !=
+ (ErrorStatus = CLatmDemux_ReadPayloadLengthInfo(bs, pLatmDemux))) {
+ *pfConfigFound = 0;
+ goto bail;
+ }
+ } else {
+ /* audioMuxVersionA > 0 is reserved for future extensions */
+ ErrorStatus = TRANSPORTDEC_UNSUPPORTED_FORMAT;
+ *pfConfigFound = 0;
+ goto bail;
+ }
+
+bail:
+ if (ErrorStatus != TRANSPORTDEC_OK) {
+ pLatmDemux->applyAsc = 1;
+ }
+
+ return (ErrorStatus);
+}
+
+TRANSPORTDEC_ERROR CLatmDemux_Read(HANDLE_FDK_BITSTREAM bs,
+ CLatmDemux *pLatmDemux, TRANSPORT_TYPE tt,
+ CSTpCallBacks *pTpDecCallbacks,
+ CSAudioSpecificConfig *pAsc,
+ int *pfConfigFound,
+ const INT ignoreBufferFullness) {
+ UINT cntBits;
+ UINT cmpBufferFullness;
+ UINT audioMuxLengthBytesLast = 0;
+ TRANSPORTDEC_ERROR ErrorStatus = TRANSPORTDEC_OK;
+
+ cntBits = FDKgetValidBits(bs);
+
+ if ((INT)cntBits < MIN_LATM_HEADERLENGTH) {
+ return TRANSPORTDEC_NOT_ENOUGH_BITS;
+ }
+
+ if (TRANSPORTDEC_OK != (ErrorStatus = CLatmDemux_ReadAudioMuxElement(
+ bs, pLatmDemux, (tt != TT_MP4_LATM_MCP0),
+ pTpDecCallbacks, pAsc, pfConfigFound)))
+ return (ErrorStatus);
+
+ if (!ignoreBufferFullness) {
+ cmpBufferFullness =
+ 24 + audioMuxLengthBytesLast * 8 +
+ pLatmDemux->m_linfo[0][0].m_bufferFullness *
+ pAsc[TPDEC_TRACKINDEX(0, 0)].m_channelConfiguration * 32;
+
+ /* evaluate buffer fullness */
+
+ if (pLatmDemux->m_linfo[0][0].m_bufferFullness != 0xFF) {
+ if (!pLatmDemux->BufferFullnessAchieved) {
+ if (cntBits < cmpBufferFullness) {
+ /* condition for start of decoding is not fulfilled */
+
+ /* the current frame will not be decoded */
+ return TRANSPORTDEC_NOT_ENOUGH_BITS;
+ } else {
+ pLatmDemux->BufferFullnessAchieved = 1;
+ }
+ }
+ }
+ }
+
+ return (ErrorStatus);
+}
+
+TRANSPORTDEC_ERROR CLatmDemux_ReadStreamMuxConfig(
+ HANDLE_FDK_BITSTREAM bs, CLatmDemux *pLatmDemux,
+ CSTpCallBacks *pTpDecCallbacks, CSAudioSpecificConfig *pAsc,
+ int *pfConfigFound, UCHAR configMode, UCHAR configChanged) {
+ CSAudioSpecificConfig ascDummy; /* the actual config is needed for flushing,
+ after that new config can be parsed */
+ CSAudioSpecificConfig *pAscDummy;
+ pAscDummy = &ascDummy;
+ pLatmDemux->usacExplicitCfgChanged = 0;
+ LATM_LAYER_INFO *p_linfo = NULL;
+ TRANSPORTDEC_ERROR ErrorStatus = TRANSPORTDEC_OK;
+ UCHAR updateConfig[1 * 1] = {0};
+
+ pLatmDemux->m_AudioMuxVersion = FDKreadBits(bs, 1);
+
+ if (pLatmDemux->m_AudioMuxVersion == 0) {
+ pLatmDemux->m_AudioMuxVersionA = 0;
+ } else {
+ pLatmDemux->m_AudioMuxVersionA = FDKreadBits(bs, 1);
+ }
+
+ if (pLatmDemux->m_AudioMuxVersionA == 0) {
+ if (pLatmDemux->m_AudioMuxVersion == 1) {
+ pLatmDemux->m_taraBufferFullness = CLatmDemux_GetValue(bs);
+ }
+ pLatmDemux->m_allStreamsSameTimeFraming = FDKreadBits(bs, 1);
+ pLatmDemux->m_noSubFrames = FDKreadBits(bs, 6) + 1;
+ pLatmDemux->m_numProgram = FDKreadBits(bs, 4) + 1;
+
+ if (pLatmDemux->m_numProgram > LATM_MAX_PROG) {
+ ErrorStatus = TRANSPORTDEC_UNSUPPORTED_FORMAT;
+ goto bail;
+ }
+
+ int idCnt = 0;
+ for (UINT prog = 0; prog < pLatmDemux->m_numProgram; prog++) {
+ pLatmDemux->m_numLayer[prog] = FDKreadBits(bs, 3) + 1;
+ if (pLatmDemux->m_numLayer[prog] > LATM_MAX_LAYER) {
+ ErrorStatus = TRANSPORTDEC_UNSUPPORTED_FORMAT;
+ goto bail;
+ }
+
+ for (UINT lay = 0; lay < pLatmDemux->m_numLayer[prog]; lay++) {
+ int useSameConfig;
+ p_linfo = &pLatmDemux->m_linfo[prog][lay];
+
+ p_linfo->m_streamID = idCnt++;
+ p_linfo->m_frameLengthInBits = 0;
+
+ if ((prog == 0) && (lay == 0)) {
+ useSameConfig = 0;
+ } else {
+ useSameConfig = FDKreadBits(bs, 1);
+ }
+
+ if (useSameConfig) {
+ if (lay > 0) {
+ FDKmemcpy(&pAsc[TPDEC_TRACKINDEX(prog, lay)],
+ &pAsc[TPDEC_TRACKINDEX(prog, lay - 1)],
+ sizeof(CSAudioSpecificConfig));
+ } else {
+ ErrorStatus = TRANSPORTDEC_PARSE_ERROR;
+ goto bail;
+ }
+ } else {
+ UINT usacConfigLengthPrev = 0;
+ UCHAR usacConfigPrev[TP_USAC_MAX_CONFIG_LEN];
+
+ if (!(pLatmDemux->applyAsc) &&
+ (pAsc[TPDEC_TRACKINDEX(prog, lay)].m_aot == AOT_USAC)) {
+ usacConfigLengthPrev =
+ (UINT)(pAsc[TPDEC_TRACKINDEX(prog, lay)]
+ .m_sc.m_usacConfig.UsacConfigBits +
+ 7) >>
+ 3; /* store previous USAC config length */
+ if (usacConfigLengthPrev > TP_USAC_MAX_CONFIG_LEN) {
+ ErrorStatus = TRANSPORTDEC_PARSE_ERROR;
+ goto bail;
+ }
+ FDKmemclear(usacConfigPrev, TP_USAC_MAX_CONFIG_LEN);
+ FDKmemcpy(
+ usacConfigPrev,
+ &pAsc[TPDEC_TRACKINDEX(prog, lay)].m_sc.m_usacConfig.UsacConfig,
+ usacConfigLengthPrev); /* store previous USAC config */
+ }
+ if (pLatmDemux->m_AudioMuxVersion == 1) {
+ FDK_BITSTREAM tmpBs;
+ UINT ascLen = 0;
+ ascLen = CLatmDemux_GetValue(bs);
+ /* The ascLen could be wrong, so check if validBits<=bufBits*/
+ if (ascLen > FDKgetValidBits(bs)) {
+ ErrorStatus = TRANSPORTDEC_PARSE_ERROR;
+ goto bail;
+ }
+ FDKsyncCache(bs);
+ tmpBs = *bs;
+ tmpBs.hBitBuf.ValidBits = ascLen;
+
+ /* Read ASC */
+ if (pLatmDemux->applyAsc) {
+ if (TRANSPORTDEC_OK !=
+ (ErrorStatus = AudioSpecificConfig_Parse(
+ &pAsc[TPDEC_TRACKINDEX(prog, lay)], &tmpBs, 1,
+ pTpDecCallbacks, configMode, configChanged,
+ AOT_NULL_OBJECT)))
+ goto bail;
+ } else {
+ if (TRANSPORTDEC_OK !=
+ (ErrorStatus = AudioSpecificConfig_Parse(
+ pAscDummy, &tmpBs, 1, pTpDecCallbacks, configMode,
+ configChanged, AOT_NULL_OBJECT)))
+ goto bail;
+ }
+
+ /* The field p_linfo->m_ascLen could be wrong, so check if */
+ if (0 > (INT)FDKgetValidBits(&tmpBs)) {
+ ErrorStatus = TRANSPORTDEC_PARSE_ERROR;
+ goto bail;
+ }
+ FDKpushFor(bs, ascLen); /* position bitstream after ASC */
+ } else {
+ /* Read ASC */
+ if (pLatmDemux->applyAsc) {
+ if (TRANSPORTDEC_OK != (ErrorStatus = AudioSpecificConfig_Parse(
+ &pAsc[TPDEC_TRACKINDEX(prog, lay)],
+ bs, 0, pTpDecCallbacks, configMode,
+ configChanged, AOT_NULL_OBJECT)))
+ goto bail;
+ } else {
+ if (TRANSPORTDEC_OK !=
+ (ErrorStatus = AudioSpecificConfig_Parse(
+ pAscDummy, bs, 0, pTpDecCallbacks, configMode,
+ configChanged, AOT_NULL_OBJECT)))
+ goto bail;
+ }
+ }
+ if (!pLatmDemux->applyAsc) {
+ updateConfig[TPDEC_TRACKINDEX(prog, lay)] = 0;
+ } else {
+ updateConfig[TPDEC_TRACKINDEX(prog, lay)] = 1;
+ }
+
+ if (!pLatmDemux->applyAsc) {
+ if (pAscDummy[TPDEC_TRACKINDEX(prog, lay)].m_aot ==
+ AOT_USAC) { /* flush in case SMC has changed */
+ const UINT usacConfigLength =
+ (UINT)(pAscDummy->m_sc.m_usacConfig.UsacConfigBits + 7) >> 3;
+ if (usacConfigLength > TP_USAC_MAX_CONFIG_LEN) {
+ ErrorStatus = TRANSPORTDEC_PARSE_ERROR;
+ goto bail;
+ }
+ if (usacConfigLength != usacConfigLengthPrev) {
+ FDKmemclear(&pAsc[TPDEC_TRACKINDEX(prog, lay)]
+ .m_sc.m_usacConfig.UsacConfig,
+ TP_USAC_MAX_CONFIG_LEN);
+ FDKmemcpy(&pAsc[TPDEC_TRACKINDEX(prog, lay)]
+ .m_sc.m_usacConfig.UsacConfig,
+ &pAscDummy->m_sc.m_usacConfig.UsacConfig,
+ usacConfigLength); /* store new USAC config */
+ pAsc[TPDEC_TRACKINDEX(prog, lay)]
+ .m_sc.m_usacConfig.UsacConfigBits =
+ pAscDummy->m_sc.m_usacConfig.UsacConfigBits;
+ pLatmDemux->usacExplicitCfgChanged = 1;
+ } else {
+ if (FDKmemcmp(usacConfigPrev,
+ pAscDummy->m_sc.m_usacConfig.UsacConfig,
+ usacConfigLengthPrev)) {
+ FDKmemclear(&pAsc[TPDEC_TRACKINDEX(prog, lay)]
+ .m_sc.m_usacConfig.UsacConfig,
+ TP_USAC_MAX_CONFIG_LEN);
+ FDKmemcpy(&pAsc[TPDEC_TRACKINDEX(prog, lay)]
+ .m_sc.m_usacConfig.UsacConfig,
+ &pAscDummy->m_sc.m_usacConfig.UsacConfig,
+ usacConfigLength); /* store new USAC config */
+ pAsc[TPDEC_TRACKINDEX(prog, lay)]
+ .m_sc.m_usacConfig.UsacConfigBits =
+ pAscDummy->m_sc.m_usacConfig.UsacConfigBits;
+ pLatmDemux->usacExplicitCfgChanged = 1;
+ }
+ }
+
+ if (pAscDummy[TPDEC_TRACKINDEX(prog, lay)]
+ .m_sc.m_usacConfig.m_usacNumElements) {
+ if (pAscDummy[TPDEC_TRACKINDEX(prog, lay)]
+ .m_sc.m_usacConfig.element[0]
+ .extElement.usacExtElementHasAudioPreRoll) {
+ pLatmDemux->newCfgHasAudioPreRoll =
+ 1; /* if dummy parsed cfg has audioPreRoll we first flush
+ before applying new cfg */
+ }
+ }
+ }
+ }
+ }
+
+ p_linfo->m_frameLengthType = FDKreadBits(bs, 3);
+ switch (p_linfo->m_frameLengthType) {
+ case 0:
+ p_linfo->m_bufferFullness = FDKreadBits(bs, 8);
+
+ if (!pLatmDemux->m_allStreamsSameTimeFraming) {
+ if ((lay > 0) &&
+ (pAsc[TPDEC_TRACKINDEX(prog, lay)].m_aot == AOT_AAC_SCAL ||
+ pAsc[TPDEC_TRACKINDEX(prog, lay)].m_aot ==
+ AOT_ER_AAC_SCAL) &&
+ (pAsc[TPDEC_TRACKINDEX(prog, lay - 1)].m_aot == AOT_CELP ||
+ pAsc[TPDEC_TRACKINDEX(prog, lay - 1)].m_aot ==
+ AOT_ER_CELP)) { /* The layer maybe
+ ignored later so
+ read it anyway: */
+ /* coreFrameOffset = */ FDKreadBits(bs, 6);
+ }
+ }
+ break;
+ case 1:
+ p_linfo->m_frameLengthInBits = FDKreadBits(bs, 9);
+ break;
+ case 3:
+ case 4:
+ case 5:
+ /* CELP */
+ case 6:
+ case 7:
+ /* HVXC */
+ default:
+ ErrorStatus = TRANSPORTDEC_PARSE_ERROR;
+ goto bail;
+ } /* switch framelengthtype*/
+
+ } /* layer loop */
+ } /* prog loop */
+
+ pLatmDemux->m_otherDataPresent = FDKreadBits(bs, 1);
+ pLatmDemux->m_otherDataLength = 0;
+
+ if (pLatmDemux->m_otherDataPresent) {
+ if (pLatmDemux->m_AudioMuxVersion == 1) {
+ pLatmDemux->m_otherDataLength = CLatmDemux_GetValue(bs);
+ } else {
+ int otherDataLenEsc = 0;
+ do {
+ pLatmDemux->m_otherDataLength <<= 8; // *= 256
+ otherDataLenEsc = FDKreadBits(bs, 1);
+ pLatmDemux->m_otherDataLength += FDKreadBits(bs, 8);
+ } while (otherDataLenEsc);
+ }
+ if (pLatmDemux->m_audioMuxLengthBytes <
+ (pLatmDemux->m_otherDataLength >> 3)) {
+ ErrorStatus = TRANSPORTDEC_PARSE_ERROR;
+ goto bail;
+ }
+ }
+
+ pLatmDemux->m_crcCheckPresent = FDKreadBits(bs, 1);
+
+ if (pLatmDemux->m_crcCheckPresent) {
+ FDKreadBits(bs, 8);
+ }
+
+ } else {
+ /* audioMuxVersionA > 0 is reserved for future extensions */
+ ErrorStatus = TRANSPORTDEC_UNSUPPORTED_FORMAT;
+ }
+
+ /* Configure source decoder: */
+ if (ErrorStatus == TRANSPORTDEC_OK) {
+ UINT prog;
+ for (prog = 0; prog < pLatmDemux->m_numProgram; prog++) {
+ UINT lay;
+ for (lay = 0; lay < pLatmDemux->m_numLayer[prog]; lay++) {
+ if (updateConfig[TPDEC_TRACKINDEX(prog, lay)] != 0) {
+ int cbError;
+ cbError = pTpDecCallbacks->cbUpdateConfig(
+ pTpDecCallbacks->cbUpdateConfigData,
+ &pAsc[TPDEC_TRACKINDEX(prog, lay)],
+ pAsc[TPDEC_TRACKINDEX(prog, lay)].configMode,
+ &pAsc[TPDEC_TRACKINDEX(prog, lay)].AacConfigChanged);
+ if (cbError == TRANSPORTDEC_NEED_TO_RESTART) {
+ *pfConfigFound = 0;
+ ErrorStatus = TRANSPORTDEC_NEED_TO_RESTART;
+ goto bail;
+ }
+ if (cbError != 0) {
+ *pfConfigFound = 0;
+ if (lay == 0) {
+ ErrorStatus = TRANSPORTDEC_SYNC_ERROR;
+ goto bail;
+ }
+ } else {
+ *pfConfigFound = 1;
+ }
+ } else {
+ *pfConfigFound = 1;
+ }
+ }
+ }
+ }
+
+bail:
+ if (ErrorStatus != TRANSPORTDEC_OK) {
+ UCHAR applyAsc = pLatmDemux->applyAsc;
+ FDKmemclear(pLatmDemux, sizeof(CLatmDemux)); /* reset structure */
+ pLatmDemux->applyAsc = applyAsc;
+ } else {
+ /* no error and config parsing is finished */
+ if (configMode == AC_CM_ALLOC_MEM) pLatmDemux->applyAsc = 0;
+ }
+
+ return (ErrorStatus);
+}
+
+TRANSPORTDEC_ERROR CLatmDemux_ReadPayloadLengthInfo(HANDLE_FDK_BITSTREAM bs,
+ CLatmDemux *pLatmDemux) {
+ TRANSPORTDEC_ERROR ErrorStatus = TRANSPORTDEC_OK;
+ int totalPayloadBits = 0;
+
+ if (pLatmDemux->m_allStreamsSameTimeFraming == 1) {
+ FDK_ASSERT(pLatmDemux->m_numProgram <= LATM_MAX_PROG);
+ for (UINT prog = 0; prog < pLatmDemux->m_numProgram; prog++) {
+ FDK_ASSERT(pLatmDemux->m_numLayer[prog] <= LATM_MAX_LAYER);
+ for (UINT lay = 0; lay < pLatmDemux->m_numLayer[prog]; lay++) {
+ LATM_LAYER_INFO *p_linfo = &pLatmDemux->m_linfo[prog][lay];
+
+ switch (p_linfo->m_frameLengthType) {
+ case 0:
+ p_linfo->m_frameLengthInBits = CLatmDemux_ReadAuChunkLengthInfo(bs);
+ totalPayloadBits += p_linfo->m_frameLengthInBits;
+ break;
+ case 3:
+ case 5:
+ case 7:
+ default:
+ return TRANSPORTDEC_PARSE_ERROR; // AAC_DEC_LATM_INVALIDFRAMELENGTHTYPE;
+ }
+ }
+ }
+ } else {
+ ErrorStatus = TRANSPORTDEC_PARSE_ERROR; // AAC_DEC_LATM_TIMEFRAMING;
+ }
+ if (pLatmDemux->m_audioMuxLengthBytes > (UINT)0 &&
+ totalPayloadBits > (int)pLatmDemux->m_audioMuxLengthBytes * 8) {
+ return TRANSPORTDEC_PARSE_ERROR;
+ }
+
+ return (ErrorStatus);
+}
+
+int CLatmDemux_ReadAuChunkLengthInfo(HANDLE_FDK_BITSTREAM bs) {
+ UCHAR endFlag;
+ int len = 0;
+
+ do {
+ UCHAR tmp = (UCHAR)FDKreadBits(bs, 8);
+ endFlag = (tmp < 255);
+
+ len += tmp;
+
+ } while (endFlag == 0);
+
+ len <<= 3; /* convert from bytes to bits */
+
+ return len;
+}
+
+UINT CLatmDemux_GetFrameLengthInBits(CLatmDemux *pLatmDemux, const UINT prog,
+ const UINT layer) {
+ UINT nFrameLenBits = 0;
+ if (prog < pLatmDemux->m_numProgram) {
+ if (layer < pLatmDemux->m_numLayer[prog]) {
+ nFrameLenBits = pLatmDemux->m_linfo[prog][layer].m_frameLengthInBits;
+ }
+ }
+ return nFrameLenBits;
+}
+
+UINT CLatmDemux_GetOtherDataPresentFlag(CLatmDemux *pLatmDemux) {
+ return pLatmDemux->m_otherDataPresent ? 1 : 0;
+}
+
+UINT CLatmDemux_GetOtherDataLength(CLatmDemux *pLatmDemux) {
+ return pLatmDemux->m_otherDataLength;
+}
+
+UINT CLatmDemux_GetNrOfSubFrames(CLatmDemux *pLatmDemux) {
+ return pLatmDemux->m_noSubFrames;
+}
+
+UINT CLatmDemux_GetNrOfLayers(CLatmDemux *pLatmDemux, const UINT prog) {
+ UINT numLayer = 0;
+ if (prog < pLatmDemux->m_numProgram) {
+ numLayer = pLatmDemux->m_numLayer[prog];
+ }
+ return numLayer;
+}