/* -----------------------------------------------------------------------------
|
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;
|
}
|