diff options
author | Matthias P. Braendli <matthias.braendli@mpb.li> | 2019-11-11 11:38:02 +0100 |
---|---|---|
committer | Matthias P. Braendli <matthias.braendli@mpb.li> | 2019-11-11 11:38:02 +0100 |
commit | 0e5af65c467b2423a0b857ae3ad98c91acc1e190 (patch) | |
tree | d07f69550d8886271e44fe79c4dcfb299cafbd38 /fdk-aac/libMpegTPDec/src | |
parent | efe406d9724f959c8bc2a31802559ca6d41fd897 (diff) | |
download | ODR-AudioEnc-0e5af65c467b2423a0b857ae3ad98c91acc1e190.tar.gz ODR-AudioEnc-0e5af65c467b2423a0b857ae3ad98c91acc1e190.tar.bz2 ODR-AudioEnc-0e5af65c467b2423a0b857ae3ad98c91acc1e190.zip |
Include patched FDK-AAC in the repository
The initial idea was to get the DAB+ patch into upstream, but since
that follows the android source releases, there is no place for a custom
DAB+ patch there.
So instead of having to maintain a patched fdk-aac that has to have the
same .so version as the distribution package on which it is installed,
we prefer having a separate fdk-aac-dab library to avoid collision.
At that point, there's no reason to keep fdk-aac in a separate
repository, as odr-audioenc is the only tool that needs DAB+ encoding
support. Including it here simplifies installation, and makes it
consistent with toolame-dab, also shipped in this repository.
DAB+ decoding support (needed by ODR-SourceCompanion, dablin, etisnoop,
welle.io and others) can be done using upstream FDK-AAC.
Diffstat (limited to 'fdk-aac/libMpegTPDec/src')
-rw-r--r-- | fdk-aac/libMpegTPDec/src/tp_version.h | 118 | ||||
-rw-r--r-- | fdk-aac/libMpegTPDec/src/tpdec_adif.cpp | 158 | ||||
-rw-r--r-- | fdk-aac/libMpegTPDec/src/tpdec_adif.h | 134 | ||||
-rw-r--r-- | fdk-aac/libMpegTPDec/src/tpdec_adts.cpp | 392 | ||||
-rw-r--r-- | fdk-aac/libMpegTPDec/src/tpdec_adts.h | 234 | ||||
-rw-r--r-- | fdk-aac/libMpegTPDec/src/tpdec_asc.cpp | 2592 | ||||
-rw-r--r-- | fdk-aac/libMpegTPDec/src/tpdec_drm.cpp | 148 | ||||
-rw-r--r-- | fdk-aac/libMpegTPDec/src/tpdec_drm.h | 202 | ||||
-rw-r--r-- | fdk-aac/libMpegTPDec/src/tpdec_latm.cpp | 676 | ||||
-rw-r--r-- | fdk-aac/libMpegTPDec/src/tpdec_latm.h | 191 | ||||
-rw-r--r-- | fdk-aac/libMpegTPDec/src/tpdec_lib.cpp | 1820 |
11 files changed, 6665 insertions, 0 deletions
diff --git a/fdk-aac/libMpegTPDec/src/tp_version.h b/fdk-aac/libMpegTPDec/src/tp_version.h new file mode 100644 index 0000000..4faed8c --- /dev/null +++ b/fdk-aac/libMpegTPDec/src/tp_version.h @@ -0,0 +1,118 @@ +/* ----------------------------------------------------------------------------- +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): + + Description: + +*******************************************************************************/ + +#if !defined(TP_VERSION_H) +#define TP_VERSION_H + +/* library info */ +#define TP_LIB_VL0 3 +#define TP_LIB_VL1 0 +#define TP_LIB_VL2 0 +#define TP_LIB_TITLE "MPEG Transport" +#ifdef __ANDROID__ +#define TP_LIB_BUILD_DATE "" +#define TP_LIB_BUILD_TIME "" +#else +#define TP_LIB_BUILD_DATE __DATE__ +#define TP_LIB_BUILD_TIME __TIME__ +#endif +#endif /* !defined(TP_VERSION_H) */ diff --git a/fdk-aac/libMpegTPDec/src/tpdec_adif.cpp b/fdk-aac/libMpegTPDec/src/tpdec_adif.cpp new file mode 100644 index 0000000..ec20b9b --- /dev/null +++ b/fdk-aac/libMpegTPDec/src/tpdec_adif.cpp @@ -0,0 +1,158 @@ +/* ----------------------------------------------------------------------------- +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): Josef Hoepfl + + Description: ADIF reader + +*******************************************************************************/ + +#include "tpdec_adif.h" + +#include "FDK_bitstream.h" +#include "genericStds.h" + +TRANSPORTDEC_ERROR adifRead_DecodeHeader(CAdifHeader *pAdifHeader, + CProgramConfig *pPce, + HANDLE_FDK_BITSTREAM bs) { + int i; + TRANSPORTDEC_ERROR ErrorStatus = TRANSPORTDEC_OK; + UINT startAnchor = FDKgetValidBits(bs); + + if ((INT)startAnchor < MIN_ADIF_HEADERLENGTH) { + return (TRANSPORTDEC_NOT_ENOUGH_BITS); + } + + if (FDKreadBits(bs, 8) != 'A') { + return (TRANSPORTDEC_SYNC_ERROR); + } + if (FDKreadBits(bs, 8) != 'D') { + return (TRANSPORTDEC_SYNC_ERROR); + } + if (FDKreadBits(bs, 8) != 'I') { + return (TRANSPORTDEC_SYNC_ERROR); + } + if (FDKreadBits(bs, 8) != 'F') { + return (TRANSPORTDEC_SYNC_ERROR); + } + + if ((pAdifHeader->CopyrightIdPresent = FDKreadBits(bs, 1)) != 0) + FDKpushBiDirectional(bs, 72); /* CopyrightId */ + + pAdifHeader->OriginalCopy = FDKreadBits(bs, 1); + pAdifHeader->Home = FDKreadBits(bs, 1); + pAdifHeader->BitstreamType = FDKreadBits(bs, 1); + + /* pAdifHeader->BitRate = FDKreadBits(bs, 23); */ + pAdifHeader->BitRate = FDKreadBits(bs, 16); + pAdifHeader->BitRate <<= 7; + pAdifHeader->BitRate |= FDKreadBits(bs, 7); + + pAdifHeader->NumProgramConfigElements = FDKreadBits(bs, 4) + 1; + + if (pAdifHeader->BitstreamType == 0) { + FDKpushBiDirectional(bs, 20); /* adif_buffer_fullness */ + } + + /* Parse all PCEs but keep only one */ + for (i = 0; i < pAdifHeader->NumProgramConfigElements; i++) { + CProgramConfig_Read(pPce, bs, startAnchor); + } + + FDKbyteAlign(bs, startAnchor); + + return (ErrorStatus); +} diff --git a/fdk-aac/libMpegTPDec/src/tpdec_adif.h b/fdk-aac/libMpegTPDec/src/tpdec_adif.h new file mode 100644 index 0000000..72ccc6a --- /dev/null +++ b/fdk-aac/libMpegTPDec/src/tpdec_adif.h @@ -0,0 +1,134 @@ +/* ----------------------------------------------------------------------------- +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): Josef Hoepfl + + Description: ADIF reader + +*******************************************************************************/ + +#ifndef TPDEC_ADIF_H +#define TPDEC_ADIF_H + +#include "tpdec_lib.h" + +#define MIN_ADIF_HEADERLENGTH 63 /* in bits */ + +typedef struct { + INT NumProgramConfigElements; + UINT BitRate; + UCHAR CopyrightIdPresent; + UCHAR OriginalCopy; + UCHAR Home; + UCHAR BitstreamType; +} CAdifHeader; + +/** + * \brief Parse a ADIF header at the given bitstream and store the parsed data + * into a given CAdifHeader and CProgramConfig struct + * + * \param pAdifHeader pointer to a CAdifHeader structure to hold the parsed ADIF + * header data. + * \param pPce pointer to a CProgramConfig structure where the last PCE will + * remain. + * + * \return TRANSPORTDEC_ERROR error code + */ +TRANSPORTDEC_ERROR adifRead_DecodeHeader(CAdifHeader *pAdifHeader, + CProgramConfig *pPce, + HANDLE_FDK_BITSTREAM bs); + +#endif /* TPDEC_ADIF_H */ diff --git a/fdk-aac/libMpegTPDec/src/tpdec_adts.cpp b/fdk-aac/libMpegTPDec/src/tpdec_adts.cpp new file mode 100644 index 0000000..1a4e3fd --- /dev/null +++ b/fdk-aac/libMpegTPDec/src/tpdec_adts.cpp @@ -0,0 +1,392 @@ +/* ----------------------------------------------------------------------------- +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): Josef Hoepfl + + Description: ADTS interface + +*******************************************************************************/ + +#include "tpdec_adts.h" + +#include "FDK_bitstream.h" + +void adtsRead_CrcInit( + HANDLE_ADTS pAdts) /*!< pointer to adts crc info stucture */ +{ + FDKcrcInit(&pAdts->crcInfo, 0x8005, 0xFFFF, 16); +} + +int adtsRead_CrcStartReg( + HANDLE_ADTS pAdts, /*!< pointer to adts stucture */ + HANDLE_FDK_BITSTREAM hBs, /*!< handle to current bit buffer structure */ + int mBits /*!< number of bits in crc region */ +) { + if (pAdts->bs.protection_absent) { + return 0; + } + + return (FDKcrcStartReg(&pAdts->crcInfo, hBs, mBits)); +} + +void adtsRead_CrcEndReg( + HANDLE_ADTS pAdts, /*!< pointer to adts crc info stucture */ + HANDLE_FDK_BITSTREAM hBs, /*!< handle to current bit buffer structure */ + int reg /*!< crc region */ +) { + if (pAdts->bs.protection_absent == 0) { + FDKcrcEndReg(&pAdts->crcInfo, hBs, reg); + } +} + +TRANSPORTDEC_ERROR adtsRead_CrcCheck(HANDLE_ADTS pAdts) { + TRANSPORTDEC_ERROR ErrorStatus = TRANSPORTDEC_OK; + USHORT crc; + + if (pAdts->bs.protection_absent) return TRANSPORTDEC_OK; + + crc = FDKcrcGetCRC(&pAdts->crcInfo); + if (crc != pAdts->crcReadValue) { + return (TRANSPORTDEC_CRC_ERROR); + } + + return (ErrorStatus); +} + +#define Adts_Length_SyncWord 12 +#define Adts_Length_Id 1 +#define Adts_Length_Layer 2 +#define Adts_Length_ProtectionAbsent 1 +#define Adts_Length_Profile 2 +#define Adts_Length_SamplingFrequencyIndex 4 +#define Adts_Length_PrivateBit 1 +#define Adts_Length_ChannelConfiguration 3 +#define Adts_Length_OriginalCopy 1 +#define Adts_Length_Home 1 +#define Adts_Length_CopyrightIdentificationBit 1 +#define Adts_Length_CopyrightIdentificationStart 1 +#define Adts_Length_FrameLength 13 +#define Adts_Length_BufferFullness 11 +#define Adts_Length_NumberOfRawDataBlocksInFrame 2 +#define Adts_Length_CrcCheck 16 + +TRANSPORTDEC_ERROR adtsRead_DecodeHeader(HANDLE_ADTS pAdts, + CSAudioSpecificConfig *pAsc, + HANDLE_FDK_BITSTREAM hBs, + const INT ignoreBufferFullness) { + INT crcReg; + + INT valBits; + INT cmp_buffer_fullness; + int i, adtsHeaderLength; + + STRUCT_ADTS_BS bs; + + CProgramConfig oldPce; + /* Store the old PCE temporarily. Maybe we'll need it later if we + have channelConfig=0 and no PCE in this frame. */ + FDKmemcpy(&oldPce, &pAsc->m_progrConfigElement, sizeof(CProgramConfig)); + + valBits = FDKgetValidBits(hBs) + ADTS_SYNCLENGTH; + + if (valBits < ADTS_HEADERLENGTH) { + return TRANSPORTDEC_NOT_ENOUGH_BITS; + } + + /* adts_fixed_header */ + bs.mpeg_id = FDKreadBits(hBs, Adts_Length_Id); + bs.layer = FDKreadBits(hBs, Adts_Length_Layer); + bs.protection_absent = FDKreadBits(hBs, Adts_Length_ProtectionAbsent); + bs.profile = FDKreadBits(hBs, Adts_Length_Profile); + bs.sample_freq_index = FDKreadBits(hBs, Adts_Length_SamplingFrequencyIndex); + bs.private_bit = FDKreadBits(hBs, Adts_Length_PrivateBit); + bs.channel_config = FDKreadBits(hBs, Adts_Length_ChannelConfiguration); + bs.original = FDKreadBits(hBs, Adts_Length_OriginalCopy); + bs.home = FDKreadBits(hBs, Adts_Length_Home); + + /* adts_variable_header */ + bs.copyright_id = FDKreadBits(hBs, Adts_Length_CopyrightIdentificationBit); + bs.copyright_start = + FDKreadBits(hBs, Adts_Length_CopyrightIdentificationStart); + bs.frame_length = FDKreadBits(hBs, Adts_Length_FrameLength); + bs.adts_fullness = FDKreadBits(hBs, Adts_Length_BufferFullness); + bs.num_raw_blocks = + FDKreadBits(hBs, Adts_Length_NumberOfRawDataBlocksInFrame); + bs.num_pce_bits = 0; + + adtsHeaderLength = ADTS_HEADERLENGTH; + + if (valBits < bs.frame_length * 8) { + goto bail; + } + + if (!bs.protection_absent) { + FDKcrcReset(&pAdts->crcInfo); + FDKpushBack(hBs, 56); /* complete fixed and variable header! */ + crcReg = FDKcrcStartReg(&pAdts->crcInfo, hBs, 0); + FDKpushFor(hBs, 56); + } + + if (!bs.protection_absent && bs.num_raw_blocks > 0) { + if ((INT)FDKgetValidBits(hBs) < bs.num_raw_blocks * 16) { + goto bail; + } + for (i = 0; i < bs.num_raw_blocks; i++) { + pAdts->rawDataBlockDist[i] = (USHORT)FDKreadBits(hBs, 16); + adtsHeaderLength += 16; + } + /* Change raw data blocks to delta values */ + pAdts->rawDataBlockDist[bs.num_raw_blocks] = + bs.frame_length - 7 - bs.num_raw_blocks * 2 - 2; + for (i = bs.num_raw_blocks; i > 0; i--) { + pAdts->rawDataBlockDist[i] -= pAdts->rawDataBlockDist[i - 1]; + } + } + + /* adts_error_check */ + if (!bs.protection_absent) { + USHORT crc_check; + + FDKcrcEndReg(&pAdts->crcInfo, hBs, crcReg); + + if ((INT)FDKgetValidBits(hBs) < Adts_Length_CrcCheck) { + goto bail; + } + + crc_check = FDKreadBits(hBs, Adts_Length_CrcCheck); + adtsHeaderLength += Adts_Length_CrcCheck; + + pAdts->crcReadValue = crc_check; + /* Check header CRC in case of multiple raw data blocks */ + if (bs.num_raw_blocks > 0) { + if (pAdts->crcReadValue != FDKcrcGetCRC(&pAdts->crcInfo)) { + return TRANSPORTDEC_CRC_ERROR; + } + /* Reset CRC for the upcoming raw_data_block() */ + FDKcrcReset(&pAdts->crcInfo); + } + } + + /* check if valid header */ + if ((bs.layer != 0) || // we only support MPEG ADTS + (bs.sample_freq_index >= 13) // we only support 96kHz - 7350kHz + ) { + FDKpushFor(hBs, bs.frame_length * 8); // try again one frame later + return TRANSPORTDEC_UNSUPPORTED_FORMAT; + } + + /* special treatment of id-bit */ + if ((bs.mpeg_id == 0) && (pAdts->decoderCanDoMpeg4 == 0)) { + /* MPEG-2 decoder cannot play MPEG-4 bitstreams */ + + FDKpushFor(hBs, bs.frame_length * 8); // try again one frame later + return TRANSPORTDEC_UNSUPPORTED_FORMAT; + } + + if (!ignoreBufferFullness) { + cmp_buffer_fullness = + bs.frame_length * 8 + + bs.adts_fullness * 32 * getNumberOfEffectiveChannels(bs.channel_config); + + /* Evaluate buffer fullness */ + if (bs.adts_fullness != 0x7FF) { + if (pAdts->BufferFullnesStartFlag) { + if (valBits < cmp_buffer_fullness) { + /* Condition for start of decoding is not fulfilled */ + + /* The current frame will not be decoded */ + FDKpushBack(hBs, adtsHeaderLength); + + if ((cmp_buffer_fullness + adtsHeaderLength) > + (((8192 * 4) << 3) - 7)) { + return TRANSPORTDEC_SYNC_ERROR; + } else { + return TRANSPORTDEC_NOT_ENOUGH_BITS; + } + } else { + pAdts->BufferFullnesStartFlag = 0; + } + } + } + } + + /* Get info from ADTS header */ + AudioSpecificConfig_Init(pAsc); + pAsc->m_aot = (AUDIO_OBJECT_TYPE)(bs.profile + 1); + pAsc->m_samplingFrequencyIndex = bs.sample_freq_index; + pAsc->m_samplingFrequency = SamplingRateTable[bs.sample_freq_index]; + pAsc->m_channelConfiguration = bs.channel_config; + pAsc->m_samplesPerFrame = 1024; + + if (bs.channel_config == 0) { + int pceBits = 0; + UINT alignAnchor = FDKgetValidBits(hBs); + + if (FDKreadBits(hBs, 3) == ID_PCE) { + /* Got luck! Parse the PCE */ + crcReg = adtsRead_CrcStartReg(pAdts, hBs, 0); + + CProgramConfig_Read(&pAsc->m_progrConfigElement, hBs, alignAnchor); + + adtsRead_CrcEndReg(pAdts, hBs, crcReg); + pceBits = alignAnchor - FDKgetValidBits(hBs); + /* store the number of PCE bits */ + bs.num_pce_bits = pceBits; + } else { + /* No PCE in this frame! Push back the ID tag bits. */ + FDKpushBack(hBs, 3); + + /* Encoders do not have to write a PCE in each frame. + So if we already have a valid PCE we have to use it. */ + if (oldPce.isValid && + (bs.sample_freq_index == + pAdts->bs.sample_freq_index) /* we could compare the complete fixed + header (bytes) here! */ + && (bs.channel_config == pAdts->bs.channel_config) /* == 0 */ + && + (bs.mpeg_id == + pAdts->bs.mpeg_id)) { /* Restore previous PCE which is still valid */ + FDKmemcpy(&pAsc->m_progrConfigElement, &oldPce, sizeof(CProgramConfig)); + } else if (bs.mpeg_id == 0) { + /* If not it seems that we have a implicit channel configuration. + This mode is not allowed in the context of ISO/IEC 14496-3. + Skip this frame and try the next one. */ + FDKpushFor(hBs, (bs.frame_length << 3) - adtsHeaderLength - 3); + return TRANSPORTDEC_UNSUPPORTED_FORMAT; + } + /* else { + ISO/IEC 13818-7 implicit channel mapping is allowed. + So just open the box of chocolates to see what we got. + } */ + } + } + + /* Copy bit stream data struct to persistent memory now, once we passed all + * sanity checks above. */ + FDKmemcpy(&pAdts->bs, &bs, sizeof(STRUCT_ADTS_BS)); + + return TRANSPORTDEC_OK; + +bail: + FDKpushBack(hBs, adtsHeaderLength); + return TRANSPORTDEC_NOT_ENOUGH_BITS; +} + +int adtsRead_GetRawDataBlockLength(HANDLE_ADTS pAdts, INT blockNum) { + int length; + + if (pAdts->bs.num_raw_blocks == 0) { + length = + (pAdts->bs.frame_length - 7) + << 3; /* aac_frame_length subtracted by the header size (7 bytes). */ + if (pAdts->bs.protection_absent == 0) + length -= 16; /* substract 16 bit CRC */ + } else { + if (pAdts->bs.protection_absent) { + length = -1; /* raw data block length is unknown */ + } else { + if (blockNum < 0 || blockNum > 3) { + length = -1; + } else { + length = (pAdts->rawDataBlockDist[blockNum] << 3) - 16; + } + } + } + if (blockNum == 0 && length > 0) { + length -= pAdts->bs.num_pce_bits; + } + return length; +} diff --git a/fdk-aac/libMpegTPDec/src/tpdec_adts.h b/fdk-aac/libMpegTPDec/src/tpdec_adts.h new file mode 100644 index 0000000..68f3f63 --- /dev/null +++ b/fdk-aac/libMpegTPDec/src/tpdec_adts.h @@ -0,0 +1,234 @@ +/* ----------------------------------------------------------------------------- +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): Josef Hoepfl + + Description: ADTS interface + +*******************************************************************************/ + +#ifndef TPDEC_ADTS_H +#define TPDEC_ADTS_H + +#include "tpdec_lib.h" + +#define ADTS_SYNCWORD (0xfff) +#define ADTS_SYNCLENGTH (12) /* in bits */ +#define ADTS_HEADERLENGTH (56) /* minimum header size in bits */ +#define ADTS_FIXED_HEADERLENGTH (28) /* in bits */ +#define ADTS_VARIABLE_HEADERLENGTH (ADTS_HEADERLENGTH - ADTS_FIXED_HEADERLENGTH) + +#ifdef CHECK_TWO_SYNCS +#define ADTS_MIN_TP_BUF_SIZE (8191 + 2) +#else +#define ADTS_MIN_TP_BUF_SIZE (8191) +#endif + +#include "FDK_crc.h" + +typedef struct { + /* ADTS header fields */ + UCHAR mpeg_id; + UCHAR layer; + UCHAR protection_absent; + UCHAR profile; + UCHAR sample_freq_index; + UCHAR private_bit; + UCHAR channel_config; + UCHAR original; + UCHAR home; + UCHAR copyright_id; + UCHAR copyright_start; + USHORT frame_length; + USHORT adts_fullness; + UCHAR num_raw_blocks; + UCHAR num_pce_bits; +} STRUCT_ADTS_BS; + +struct STRUCT_ADTS { + STRUCT_ADTS_BS bs; + + UCHAR decoderCanDoMpeg4; + UCHAR BufferFullnesStartFlag; + + FDK_CRCINFO crcInfo; /* CRC state info */ + USHORT crcReadValue; /* CRC value read from bitstream data */ + USHORT rawDataBlockDist[4]; /* distance between each raw data block. Not the + same as found in the bitstream */ +}; + +typedef struct STRUCT_ADTS *HANDLE_ADTS; + +/*! + \brief Initialize ADTS CRC + + The function initialzes the crc buffer and the crc lookup table. + + \return none +*/ +void adtsRead_CrcInit(HANDLE_ADTS pAdts); + +/** + * \brief Starts CRC region with a maximum number of bits + * If mBits is positive zero padding will be used for CRC calculation, if + * there are less than mBits bits available. If mBits is negative no zero + * padding is done. If mBits is zero the memory for the buffer is + * allocated dynamically, the number of bits is not limited. + * + * \param pAdts ADTS data handle + * \param hBs bitstream handle, on which the CRC region referes to + * \param mBits max number of bits in crc region to be considered + * + * \return ID for the created region, -1 in case of an error + */ +int adtsRead_CrcStartReg(HANDLE_ADTS pAdts, HANDLE_FDK_BITSTREAM hBs, + int mBits); + +/** + * \brief Ends CRC region identified by reg + * + * \param pAdts ADTS data handle + * \param hBs bitstream handle, on which the CRC region referes to + * \param reg CRC regions ID returned by adtsRead_CrcStartReg() + * + * \return none + */ +void adtsRead_CrcEndReg(HANDLE_ADTS pAdts, HANDLE_FDK_BITSTREAM hBs, int reg); + +/** + * \brief Check CRC + * + * Checks if the currently calculated CRC matches the CRC field read from the + * bitstream Deletes all CRC regions. + * + * \param pAdts ADTS data handle + * + * \return Returns 0 if they are identical otherwise 1 + */ +TRANSPORTDEC_ERROR adtsRead_CrcCheck(HANDLE_ADTS pAdts); + +/** + * \brief Check if we have a valid ADTS frame at the current bitbuffer position + * + * This function assumes enough bits in buffer for the current frame. + * It reads out the header bits to prepare the bitbuffer for the decode loop. + * In case the header bits show an invalid bitstream/frame, the whole frame is + * skipped. + * + * \param pAdts ADTS data handle which is filled with parsed ADTS header data + * \param bs handle of bitstream from whom the ADTS header is read + * + * \return error status + */ +TRANSPORTDEC_ERROR adtsRead_DecodeHeader(HANDLE_ADTS pAdts, + CSAudioSpecificConfig *pAsc, + HANDLE_FDK_BITSTREAM bs, + const INT ignoreBufferFullness); + +/** + * \brief Get the raw data block length of the given block number. + * + * \param pAdts ADTS data handle + * \param blockNum current raw data block index + * \param pLength pointer to an INT where the length of the given raw data block + * is stored into the returned value might be -1, in which case the raw data + * block length is unknown. + * + * \return error status + */ +int adtsRead_GetRawDataBlockLength(HANDLE_ADTS pAdts, INT blockNum); + +#endif /* TPDEC_ADTS_H */ diff --git a/fdk-aac/libMpegTPDec/src/tpdec_asc.cpp b/fdk-aac/libMpegTPDec/src/tpdec_asc.cpp new file mode 100644 index 0000000..28bc22d --- /dev/null +++ b/fdk-aac/libMpegTPDec/src/tpdec_asc.cpp @@ -0,0 +1,2592 @@ +/* ----------------------------------------------------------------------------- +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_lib.h" +#include "tp_data.h" + +#include "FDK_crc.h" + +#include "common_fix.h" + +/** + * The following arrays provide the IDs of the consecutive elements for each + * channel configuration. Every channel_configuration has to be finalized with + * ID_NONE. + */ +static const MP4_ELEMENT_ID channel_configuration_0[] = {ID_NONE}; +static const MP4_ELEMENT_ID channel_configuration_1[] = {ID_SCE, ID_NONE}; +static const MP4_ELEMENT_ID channel_configuration_2[] = {ID_CPE, ID_NONE}; +static const MP4_ELEMENT_ID channel_configuration_3[] = {ID_SCE, ID_CPE, + ID_NONE}; +static const MP4_ELEMENT_ID channel_configuration_4[] = {ID_SCE, ID_CPE, ID_SCE, + ID_NONE}; +static const MP4_ELEMENT_ID channel_configuration_5[] = {ID_SCE, ID_CPE, ID_CPE, + ID_NONE}; +static const MP4_ELEMENT_ID channel_configuration_6[] = {ID_SCE, ID_CPE, ID_CPE, + ID_LFE, ID_NONE}; +static const MP4_ELEMENT_ID channel_configuration_7[] = { + ID_SCE, ID_CPE, ID_CPE, ID_CPE, ID_LFE, ID_NONE}; +static const MP4_ELEMENT_ID channel_configuration_8[] = { + ID_NONE}; /* reserved */ +static const MP4_ELEMENT_ID channel_configuration_9[] = { + ID_NONE}; /* reserved */ +static const MP4_ELEMENT_ID channel_configuration_10[] = { + ID_NONE}; /* reserved */ +static const MP4_ELEMENT_ID channel_configuration_11[] = { + ID_SCE, ID_CPE, ID_CPE, ID_SCE, ID_LFE, ID_NONE}; +static const MP4_ELEMENT_ID channel_configuration_12[] = { + ID_SCE, ID_CPE, ID_CPE, ID_CPE, ID_LFE, ID_NONE}; +static const MP4_ELEMENT_ID channel_configuration_13[] = { + ID_SCE, ID_CPE, ID_CPE, ID_CPE, ID_CPE, ID_SCE, ID_LFE, ID_LFE, ID_SCE, + ID_CPE, ID_CPE, ID_SCE, ID_CPE, ID_SCE, ID_SCE, ID_CPE, ID_NONE}; +static const MP4_ELEMENT_ID channel_configuration_14[] = { + ID_SCE, ID_CPE, ID_CPE, ID_LFE, ID_CPE, ID_NONE}; + +static const MP4_ELEMENT_ID *channel_configuration_array[] = { + channel_configuration_0, channel_configuration_1, + channel_configuration_2, channel_configuration_3, + channel_configuration_4, channel_configuration_5, + channel_configuration_6, channel_configuration_7, + channel_configuration_8, channel_configuration_9, + channel_configuration_10, channel_configuration_11, + channel_configuration_12, channel_configuration_13, + channel_configuration_14}; + +#define TP_USAC_MAX_CHANNEL_CONFIGURATION_INDEX (13) +#define SC_CHANNEL_CONFIG_TAB_SIZE (TP_USAC_MAX_CHANNEL_CONFIGURATION_INDEX + 1) + +/* channel config structure used for sanity check */ +typedef struct { + SCHAR nCh; /* number of channels */ + SCHAR nSCE; /* number of SCE's */ + SCHAR nCPE; /* number of CPE's */ + SCHAR nLFE; /* number of LFE's */ +} SC_CHANNEL_CONFIG; + +static const SC_CHANNEL_CONFIG sc_chan_config_tab[SC_CHANNEL_CONFIG_TAB_SIZE] = + { + /* nCh, nSCE, nCPE, nLFE, cci */ + {0, 0, 0, 0}, /* 0 */ + {1, 1, 0, 0}, /* 1 */ + {2, 0, 1, 0}, /* 2 */ + {3, 1, 1, 0}, /* 3 */ + {4, 2, 1, 0}, /* 4 */ + {5, 1, 2, 0}, /* 5 */ + {6, 1, 2, 1}, /* 6 */ + {8, 1, 3, 1}, /* 7 */ + {2, 2, 0, 0}, /* 8 */ + {3, 1, 1, 0}, /* 9 */ + {4, 0, 2, 0}, /* 10 */ + {7, 2, 2, 1}, /* 11 */ + {8, 1, 3, 1}, /* 12 */ + {24, 6, 8, 2} /* 13 */ +}; + +void CProgramConfig_Reset(CProgramConfig *pPce) { pPce->elCounter = 0; } + +void CProgramConfig_Init(CProgramConfig *pPce) { + FDKmemclear(pPce, sizeof(CProgramConfig)); + pPce->SamplingFrequencyIndex = 0xf; +} + +int CProgramConfig_IsValid(const CProgramConfig *pPce) { + return ((pPce->isValid) ? 1 : 0); +} + +#define PCE_HEIGHT_EXT_SYNC (0xAC) + +/* + * Read the extension for height info. + * return 0 if successfull, + * -1 if the CRC failed, + * -2 if invalid HeightInfo. + */ +static int CProgramConfig_ReadHeightExt(CProgramConfig *pPce, + HANDLE_FDK_BITSTREAM bs, + int *const bytesAvailable, + const UINT alignmentAnchor) { + int err = 0; + FDK_CRCINFO crcInfo; /* CRC state info */ + INT crcReg; + FDKcrcInit(&crcInfo, 0x07, 0xFF, 8); + crcReg = FDKcrcStartReg(&crcInfo, bs, 0); + UINT startAnchor = FDKgetValidBits(bs); + + FDK_ASSERT(pPce != NULL); + FDK_ASSERT(bs != NULL); + FDK_ASSERT(bytesAvailable != NULL); + + if ((startAnchor >= 24) && (*bytesAvailable >= 3) && + (FDKreadBits(bs, 8) == PCE_HEIGHT_EXT_SYNC)) { + int i; + + for (i = 0; i < pPce->NumFrontChannelElements; i++) { + if ((pPce->FrontElementHeightInfo[i] = (UCHAR)FDKreadBits(bs, 2)) >= + PC_NUM_HEIGHT_LAYER) { + err = -2; /* height information is out of the valid range */ + } + } + for (i = 0; i < pPce->NumSideChannelElements; i++) { + if ((pPce->SideElementHeightInfo[i] = (UCHAR)FDKreadBits(bs, 2)) >= + PC_NUM_HEIGHT_LAYER) { + err = -2; /* height information is out of the valid range */ + } + } + for (i = 0; i < pPce->NumBackChannelElements; i++) { + if ((pPce->BackElementHeightInfo[i] = (UCHAR)FDKreadBits(bs, 2)) >= + PC_NUM_HEIGHT_LAYER) { + err = -2; /* height information is out of the valid range */ + } + } + FDKbyteAlign(bs, alignmentAnchor); + + FDKcrcEndReg(&crcInfo, bs, crcReg); + if ((USHORT)FDKreadBits(bs, 8) != FDKcrcGetCRC(&crcInfo)) { + /* CRC failed */ + err = -1; + } + if (err != 0) { + /* Reset whole height information in case an error occured during parsing. + The return value ensures that pPce->isValid is set to 0 and implicit + channel mapping is used. */ + FDKmemclear(pPce->FrontElementHeightInfo, + sizeof(pPce->FrontElementHeightInfo)); + FDKmemclear(pPce->SideElementHeightInfo, + sizeof(pPce->SideElementHeightInfo)); + FDKmemclear(pPce->BackElementHeightInfo, + sizeof(pPce->BackElementHeightInfo)); + } + } else { + /* No valid extension data found -> restore the initial bitbuffer state */ + FDKpushBack(bs, (INT)startAnchor - (INT)FDKgetValidBits(bs)); + } + + /* Always report the bytes read. */ + *bytesAvailable -= ((INT)startAnchor - (INT)FDKgetValidBits(bs)) >> 3; + + return (err); +} + +void CProgramConfig_Read(CProgramConfig *pPce, HANDLE_FDK_BITSTREAM bs, + UINT alignmentAnchor) { + int i, err = 0; + int commentBytes; + + pPce->NumEffectiveChannels = 0; + pPce->NumChannels = 0; + pPce->ElementInstanceTag = (UCHAR)FDKreadBits(bs, 4); + pPce->Profile = (UCHAR)FDKreadBits(bs, 2); + pPce->SamplingFrequencyIndex = (UCHAR)FDKreadBits(bs, 4); + pPce->NumFrontChannelElements = (UCHAR)FDKreadBits(bs, 4); + pPce->NumSideChannelElements = (UCHAR)FDKreadBits(bs, 4); + pPce->NumBackChannelElements = (UCHAR)FDKreadBits(bs, 4); + pPce->NumLfeChannelElements = (UCHAR)FDKreadBits(bs, 2); + pPce->NumAssocDataElements = (UCHAR)FDKreadBits(bs, 3); + pPce->NumValidCcElements = (UCHAR)FDKreadBits(bs, 4); + + if ((pPce->MonoMixdownPresent = (UCHAR)FDKreadBits(bs, 1)) != 0) { + pPce->MonoMixdownElementNumber = (UCHAR)FDKreadBits(bs, 4); + } + + if ((pPce->StereoMixdownPresent = (UCHAR)FDKreadBits(bs, 1)) != 0) { + pPce->StereoMixdownElementNumber = (UCHAR)FDKreadBits(bs, 4); + } + + if ((pPce->MatrixMixdownIndexPresent = (UCHAR)FDKreadBits(bs, 1)) != 0) { + pPce->MatrixMixdownIndex = (UCHAR)FDKreadBits(bs, 2); + pPce->PseudoSurroundEnable = (UCHAR)FDKreadBits(bs, 1); + } + + for (i = 0; i < pPce->NumFrontChannelElements; i++) { + pPce->FrontElementIsCpe[i] = (UCHAR)FDKreadBits(bs, 1); + pPce->FrontElementTagSelect[i] = (UCHAR)FDKreadBits(bs, 4); + pPce->NumChannels += pPce->FrontElementIsCpe[i] ? 2 : 1; + } + + for (i = 0; i < pPce->NumSideChannelElements; i++) { + pPce->SideElementIsCpe[i] = (UCHAR)FDKreadBits(bs, 1); + pPce->SideElementTagSelect[i] = (UCHAR)FDKreadBits(bs, 4); + pPce->NumChannels += pPce->SideElementIsCpe[i] ? 2 : 1; + } + + for (i = 0; i < pPce->NumBackChannelElements; i++) { + pPce->BackElementIsCpe[i] = (UCHAR)FDKreadBits(bs, 1); + pPce->BackElementTagSelect[i] = (UCHAR)FDKreadBits(bs, 4); + pPce->NumChannels += pPce->BackElementIsCpe[i] ? 2 : 1; + } + + pPce->NumEffectiveChannels = pPce->NumChannels; + + for (i = 0; i < pPce->NumLfeChannelElements; i++) { + pPce->LfeElementTagSelect[i] = (UCHAR)FDKreadBits(bs, 4); + pPce->NumChannels += 1; + } + + for (i = 0; i < pPce->NumAssocDataElements; i++) { + pPce->AssocDataElementTagSelect[i] = (UCHAR)FDKreadBits(bs, 4); + } + + for (i = 0; i < pPce->NumValidCcElements; i++) { + pPce->CcElementIsIndSw[i] = (UCHAR)FDKreadBits(bs, 1); + pPce->ValidCcElementTagSelect[i] = (UCHAR)FDKreadBits(bs, 4); + } + + FDKbyteAlign(bs, alignmentAnchor); + + pPce->CommentFieldBytes = (UCHAR)FDKreadBits(bs, 8); + commentBytes = pPce->CommentFieldBytes; + + /* Search for height info extension and read it if available */ + err = CProgramConfig_ReadHeightExt(pPce, bs, &commentBytes, alignmentAnchor); + + for (i = 0; i < commentBytes; i++) { + UCHAR text; + + text = (UCHAR)FDKreadBits(bs, 8); + + if (i < PC_COMMENTLENGTH) { + pPce->Comment[i] = text; + } + } + + pPce->isValid = (err) ? 0 : 1; +} + +/* + * Compare two program configurations. + * Returns the result of the comparison: + * -1 - completely different + * 0 - completely equal + * 1 - different but same channel configuration + * 2 - different channel configuration but same number of channels + */ +int CProgramConfig_Compare(const CProgramConfig *const pPce1, + const CProgramConfig *const pPce2) { + int result = 0; /* Innocent until proven false. */ + + if (FDKmemcmp(pPce1, pPce2, sizeof(CProgramConfig)) != + 0) { /* Configurations are not completely equal. + So look into details and analyse the channel configurations: */ + result = -1; + + if (pPce1->NumChannels == + pPce2->NumChannels) { /* Now the logic changes. We first assume to have + the same channel configuration and then prove + if this assumption is true. */ + result = 1; + + /* Front channels */ + if (pPce1->NumFrontChannelElements != pPce2->NumFrontChannelElements) { + result = 2; /* different number of front channel elements */ + } else { + int el, numCh1 = 0, numCh2 = 0; + for (el = 0; el < pPce1->NumFrontChannelElements; el += 1) { + if (pPce1->FrontElementHeightInfo[el] != + pPce2->FrontElementHeightInfo[el]) { + result = 2; /* different height info */ + break; + } + numCh1 += pPce1->FrontElementIsCpe[el] ? 2 : 1; + numCh2 += pPce2->FrontElementIsCpe[el] ? 2 : 1; + } + if (numCh1 != numCh2) { + result = 2; /* different number of front channels */ + } + } + /* Side channels */ + if (pPce1->NumSideChannelElements != pPce2->NumSideChannelElements) { + result = 2; /* different number of side channel elements */ + } else { + int el, numCh1 = 0, numCh2 = 0; + for (el = 0; el < pPce1->NumSideChannelElements; el += 1) { + if (pPce1->SideElementHeightInfo[el] != + pPce2->SideElementHeightInfo[el]) { + result = 2; /* different height info */ + break; + } + numCh1 += pPce1->SideElementIsCpe[el] ? 2 : 1; + numCh2 += pPce2->SideElementIsCpe[el] ? 2 : 1; + } + if (numCh1 != numCh2) { + result = 2; /* different number of side channels */ + } + } + /* Back channels */ + if (pPce1->NumBackChannelElements != pPce2->NumBackChannelElements) { + result = 2; /* different number of back channel elements */ + } else { + int el, numCh1 = 0, numCh2 = 0; + for (el = 0; el < pPce1->NumBackChannelElements; el += 1) { + if (pPce1->BackElementHeightInfo[el] != + pPce2->BackElementHeightInfo[el]) { + result = 2; /* different height info */ + break; + } + numCh1 += pPce1->BackElementIsCpe[el] ? 2 : 1; + numCh2 += pPce2->BackElementIsCpe[el] ? 2 : 1; + } + if (numCh1 != numCh2) { + result = 2; /* different number of back channels */ + } + } + /* LFE channels */ + if (pPce1->NumLfeChannelElements != pPce2->NumLfeChannelElements) { + result = 2; /* different number of lfe channels */ + } + /* LFEs are always SCEs so we don't need to count the channels. */ + } + } + + return result; +} + +void CProgramConfig_GetDefault(CProgramConfig *pPce, const UINT channelConfig) { + FDK_ASSERT(pPce != NULL); + + /* Init PCE */ + CProgramConfig_Init(pPce); + pPce->Profile = + 1; /* Set AAC LC because it is the only supported object type. */ + + switch (channelConfig) { + /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ + case 32: /* 7.1 side channel configuration as defined in FDK_audio.h */ + pPce->NumFrontChannelElements = 2; + pPce->FrontElementIsCpe[0] = 0; + pPce->FrontElementIsCpe[1] = 1; + pPce->NumSideChannelElements = 1; + pPce->SideElementIsCpe[0] = 1; + pPce->NumBackChannelElements = 1; + pPce->BackElementIsCpe[0] = 1; + pPce->NumLfeChannelElements = 1; + pPce->NumChannels = 8; + pPce->NumEffectiveChannels = 7; + pPce->isValid = 1; + break; + /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ + case 12: /* 3/0/4.1ch surround back */ + pPce->BackElementIsCpe[1] = 1; + pPce->NumChannels += 1; + pPce->NumEffectiveChannels += 1; + FDK_FALLTHROUGH; + case 11: /* 3/0/3.1ch */ + pPce->NumFrontChannelElements += 2; + pPce->FrontElementIsCpe[0] = 0; + pPce->FrontElementIsCpe[1] = 1; + pPce->NumBackChannelElements += 2; + pPce->BackElementIsCpe[0] = 1; + pPce->BackElementIsCpe[1] += 0; + pPce->NumLfeChannelElements += 1; + pPce->NumChannels += 7; + pPce->NumEffectiveChannels += 6; + pPce->isValid = 1; + break; + /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ + case 14: /* 2/0/0-3/0/2-0.1ch front height */ + pPce->FrontElementHeightInfo[2] = 1; /* Top speaker */ + FDK_FALLTHROUGH; + case 7: /* 5/0/2.1ch front */ + pPce->NumFrontChannelElements += 1; + pPce->FrontElementIsCpe[2] = 1; + pPce->NumChannels += 2; + pPce->NumEffectiveChannels += 2; + FDK_FALLTHROUGH; + case 6: /* 3/0/2.1ch */ + pPce->NumLfeChannelElements += 1; + pPce->NumChannels += 1; + FDK_FALLTHROUGH; + case 5: /* 3/0/2.0ch */ + case 4: /* 3/0/1.0ch */ + pPce->NumBackChannelElements += 1; + pPce->BackElementIsCpe[0] = (channelConfig > 4) ? 1 : 0; + pPce->NumChannels += (channelConfig > 4) ? 2 : 1; + pPce->NumEffectiveChannels += (channelConfig > 4) ? 2 : 1; + FDK_FALLTHROUGH; + case 3: /* 3/0/0.0ch */ + pPce->NumFrontChannelElements += 1; + pPce->FrontElementIsCpe[1] = 1; + pPce->NumChannels += 2; + pPce->NumEffectiveChannels += 2; + FDK_FALLTHROUGH; + case 1: /* 1/0/0.0ch */ + pPce->NumFrontChannelElements += 1; + pPce->FrontElementIsCpe[0] = 0; + pPce->NumChannels += 1; + pPce->NumEffectiveChannels += 1; + pPce->isValid = 1; + break; + /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ + case 2: /* 2/0/0.ch */ + pPce->NumFrontChannelElements = 1; + pPce->FrontElementIsCpe[0] = 1; + pPce->NumChannels += 2; + pPce->NumEffectiveChannels += 2; + pPce->isValid = 1; + break; + /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ + default: + pPce->isValid = 0; /* To be explicit! */ + break; + } + + if (pPce->isValid) { + /* Create valid element instance tags */ + int el, elTagSce = 0, elTagCpe = 0; + + for (el = 0; el < pPce->NumFrontChannelElements; el += 1) { + pPce->FrontElementTagSelect[el] = + (pPce->FrontElementIsCpe[el]) ? elTagCpe++ : elTagSce++; + } + for (el = 0; el < pPce->NumSideChannelElements; el += 1) { + pPce->SideElementTagSelect[el] = + (pPce->SideElementIsCpe[el]) ? elTagCpe++ : elTagSce++; + } + for (el = 0; el < pPce->NumBackChannelElements; el += 1) { + pPce->BackElementTagSelect[el] = + (pPce->BackElementIsCpe[el]) ? elTagCpe++ : elTagSce++; + } + elTagSce = 0; + for (el = 0; el < pPce->NumLfeChannelElements; el += 1) { + pPce->LfeElementTagSelect[el] = elTagSce++; + } + } +} + +/** + * \brief get implicit audio channel type for given channelConfig and MPEG + * ordered channel index + * \param channelConfig MPEG channelConfiguration from 1 upto 14 + * \param index MPEG channel order index + * \return audio channel type. + */ +static void getImplicitAudioChannelTypeAndIndex(AUDIO_CHANNEL_TYPE *chType, + UCHAR *chIndex, + UINT channelConfig, + UINT index) { + if (index < 3) { + *chType = ACT_FRONT; + *chIndex = index; + } else { + switch (channelConfig) { + case 4: /* SCE, CPE, SCE */ + case 5: /* SCE, CPE, CPE */ + case 6: /* SCE, CPE, CPE, LFE */ + switch (index) { + case 3: + case 4: + *chType = ACT_BACK; + *chIndex = index - 3; + break; + case 5: + *chType = ACT_LFE; + *chIndex = 0; + break; + } + break; + case 7: /* SCE,CPE,CPE,CPE,LFE */ + switch (index) { + case 3: + case 4: + *chType = ACT_FRONT; + *chIndex = index; + break; + case 5: + case 6: + *chType = ACT_BACK; + *chIndex = index - 5; + break; + case 7: + *chType = ACT_LFE; + *chIndex = 0; + break; + } + break; + case 11: /* SCE,CPE,CPE,SCE,LFE */ + if (index < 6) { + *chType = ACT_BACK; + *chIndex = index - 3; + } else { + *chType = ACT_LFE; + *chIndex = 0; + } + break; + case 12: /* SCE,CPE,CPE,CPE,LFE */ + if (index < 7) { + *chType = ACT_BACK; + *chIndex = index - 3; + } else { + *chType = ACT_LFE; + *chIndex = 0; + } + break; + case 14: /* SCE,CPE,CPE,LFE,CPE */ + switch (index) { + case 3: + case 4: + *chType = ACT_BACK; + *chIndex = index - 3; + break; + case 5: + *chType = ACT_LFE; + *chIndex = 0; + break; + case 6: + case 7: + *chType = ACT_FRONT_TOP; + *chIndex = index - 6; /* handle the top layer independently */ + break; + } + break; + default: + *chType = ACT_NONE; + break; + } + } +} + +int CProgramConfig_LookupElement(CProgramConfig *pPce, UINT channelConfig, + const UINT tag, const UINT channelIdx, + UCHAR chMapping[], AUDIO_CHANNEL_TYPE chType[], + UCHAR chIndex[], const UINT chDescrLen, + UCHAR *elMapping, MP4_ELEMENT_ID elList[], + MP4_ELEMENT_ID elType) { + if (channelConfig > 0) { + /* Constant channel mapping must have + been set during initialization. */ + if (IS_CHANNEL_ELEMENT(elType)) { + *elMapping = pPce->elCounter; + if (elList[pPce->elCounter] != elType && + !IS_USAC_CHANNEL_ELEMENT(elType)) { + /* Not in the list */ + if ((channelConfig == 2) && + (elType == ID_SCE)) { /* This scenario occurs with HE-AAC v2 streams + of buggy encoders. In other decoder + implementations decoding of this kind of + streams is desired. */ + channelConfig = 1; + } else if ((elList[pPce->elCounter] == ID_LFE) && + (elType == + ID_SCE)) { /* Decode bitstreams which wrongly use ID_SCE + instead of ID_LFE element type. */ + ; + } else { + return 0; + } + } + /* Assume all front channels */ + getImplicitAudioChannelTypeAndIndex( + &chType[channelIdx], &chIndex[channelIdx], channelConfig, channelIdx); + if (elType == ID_CPE || elType == ID_USAC_CPE) { + chType[channelIdx + 1] = chType[channelIdx]; + chIndex[channelIdx + 1] = chIndex[channelIdx] + 1; + } + pPce->elCounter++; + } + /* Accept all non-channel elements, too. */ + return 1; + } else { + if ((!pPce->isValid) || (pPce->NumChannels > chDescrLen)) { + /* Implicit channel mapping. */ + if (IS_USAC_CHANNEL_ELEMENT(elType)) { + *elMapping = pPce->elCounter++; + } else if (IS_MP4_CHANNEL_ELEMENT(elType)) { + /* Store all channel element IDs */ + elList[pPce->elCounter] = elType; + *elMapping = pPce->elCounter++; + } + } else { + /* Accept the additional channel(s), only if the tag is in the lists */ + int isCpe = 0, i; + /* Element counter */ + int ec[PC_NUM_HEIGHT_LAYER] = {0}; + /* Channel counters */ + int cc[PC_NUM_HEIGHT_LAYER] = {0}; + int fc[PC_NUM_HEIGHT_LAYER] = {0}; /* front channel counter */ + int sc[PC_NUM_HEIGHT_LAYER] = {0}; /* side channel counter */ + int bc[PC_NUM_HEIGHT_LAYER] = {0}; /* back channel counter */ + int lc = 0; /* lfe channel counter */ + + /* General MPEG (PCE) composition rules: + - Over all: + <normal height channels><top height channels><bottom height + channels> + - Within each height layer: + <front channels><side channels><back channels> + - Exception: + The LFE channels have no height info and thus they are arranged at + the very end of the normal height layer channels. + */ + + switch (elType) { + case ID_CPE: + isCpe = 1; + FDK_FALLTHROUGH; + case ID_SCE: + /* search in front channels */ + for (i = 0; i < pPce->NumFrontChannelElements; i++) { + int heightLayer = pPce->FrontElementHeightInfo[i]; + if (isCpe == pPce->FrontElementIsCpe[i] && + pPce->FrontElementTagSelect[i] == tag) { + int h, elIdx = ec[heightLayer], chIdx = cc[heightLayer]; + AUDIO_CHANNEL_TYPE aChType = + (AUDIO_CHANNEL_TYPE)((heightLayer << 4) | ACT_FRONT); + for (h = heightLayer - 1; h >= 0; h -= 1) { + int el; + /* Count front channels/elements */ + for (el = 0; el < pPce->NumFrontChannelElements; el += 1) { + if (pPce->FrontElementHeightInfo[el] == h) { + elIdx += 1; + chIdx += (pPce->FrontElementIsCpe[el]) ? 2 : 1; + } + } + /* Count side channels/elements */ + for (el = 0; el < pPce->NumSideChannelElements; el += 1) { + if (pPce->SideElementHeightInfo[el] == h) { + elIdx += 1; + chIdx += (pPce->SideElementIsCpe[el]) ? 2 : 1; + } + } + /* Count back channels/elements */ + for (el = 0; el < pPce->NumBackChannelElements; el += 1) { + if (pPce->BackElementHeightInfo[el] == h) { + elIdx += 1; + chIdx += (pPce->BackElementIsCpe[el]) ? 2 : 1; + } + } + if (h == 0) { /* normal height */ + elIdx += pPce->NumLfeChannelElements; + chIdx += pPce->NumLfeChannelElements; + } + } + chMapping[chIdx] = channelIdx; + chType[chIdx] = aChType; + chIndex[chIdx] = fc[heightLayer]; + if (isCpe) { + chMapping[chIdx + 1] = channelIdx + 1; + chType[chIdx + 1] = aChType; + chIndex[chIdx + 1] = fc[heightLayer] + 1; + } + *elMapping = elIdx; + return 1; + } + ec[heightLayer] += 1; + if (pPce->FrontElementIsCpe[i]) { + cc[heightLayer] += 2; + fc[heightLayer] += 2; + } else { + cc[heightLayer] += 1; + fc[heightLayer] += 1; + } + } + /* search in side channels */ + for (i = 0; i < pPce->NumSideChannelElements; i++) { + int heightLayer = pPce->SideElementHeightInfo[i]; + if (isCpe == pPce->SideElementIsCpe[i] && + pPce->SideElementTagSelect[i] == tag) { + int h, elIdx = ec[heightLayer], chIdx = cc[heightLayer]; + AUDIO_CHANNEL_TYPE aChType = + (AUDIO_CHANNEL_TYPE)((heightLayer << 4) | ACT_SIDE); + for (h = heightLayer - 1; h >= 0; h -= 1) { + int el; + /* Count front channels/elements */ + for (el = 0; el < pPce->NumFrontChannelElements; el += 1) { + if (pPce->FrontElementHeightInfo[el] == h) { + elIdx += 1; + chIdx += (pPce->FrontElementIsCpe[el]) ? 2 : 1; + } + } + /* Count side channels/elements */ + for (el = 0; el < pPce->NumSideChannelElements; el += 1) { + if (pPce->SideElementHeightInfo[el] == h) { + elIdx += 1; + chIdx += (pPce->SideElementIsCpe[el]) ? 2 : 1; + } + } + /* Count back channels/elements */ + for (el = 0; el < pPce->NumBackChannelElements; el += 1) { + if (pPce->BackElementHeightInfo[el] == h) { + elIdx += 1; + chIdx += (pPce->BackElementIsCpe[el]) ? 2 : 1; + } + } + if (h == + 0) { /* LFE channels belong to the normal height layer */ + elIdx += pPce->NumLfeChannelElements; + chIdx += pPce->NumLfeChannelElements; + } + } + chMapping[chIdx] = channelIdx; + chType[chIdx] = aChType; + chIndex[chIdx] = sc[heightLayer]; + if (isCpe) { + chMapping[chIdx + 1] = channelIdx + 1; + chType[chIdx + 1] = aChType; + chIndex[chIdx + 1] = sc[heightLayer] + 1; + } + *elMapping = elIdx; + return 1; + } + ec[heightLayer] += 1; + if (pPce->SideElementIsCpe[i]) { + cc[heightLayer] += 2; + sc[heightLayer] += 2; + } else { + cc[heightLayer] += 1; + sc[heightLayer] += 1; + } + } + /* search in back channels */ + for (i = 0; i < pPce->NumBackChannelElements; i++) { + int heightLayer = pPce->BackElementHeightInfo[i]; + if (isCpe == pPce->BackElementIsCpe[i] && + pPce->BackElementTagSelect[i] == tag) { + int h, elIdx = ec[heightLayer], chIdx = cc[heightLayer]; + AUDIO_CHANNEL_TYPE aChType = + (AUDIO_CHANNEL_TYPE)((heightLayer << 4) | ACT_BACK); + for (h = heightLayer - 1; h >= 0; h -= 1) { + int el; + /* Count front channels/elements */ + for (el = 0; el < pPce->NumFrontChannelElements; el += 1) { + if (pPce->FrontElementHeightInfo[el] == h) { + elIdx += 1; + chIdx += (pPce->FrontElementIsCpe[el]) ? 2 : 1; + } + } + /* Count side channels/elements */ + for (el = 0; el < pPce->NumSideChannelElements; el += 1) { + if (pPce->SideElementHeightInfo[el] == h) { + elIdx += 1; + chIdx += (pPce->SideElementIsCpe[el]) ? 2 : 1; + } + } + /* Count back channels/elements */ + for (el = 0; el < pPce->NumBackChannelElements; el += 1) { + if (pPce->BackElementHeightInfo[el] == h) { + elIdx += 1; + chIdx += (pPce->BackElementIsCpe[el]) ? 2 : 1; + } + } + if (h == 0) { /* normal height */ + elIdx += pPce->NumLfeChannelElements; + chIdx += pPce->NumLfeChannelElements; + } + } + chMapping[chIdx] = channelIdx; + chType[chIdx] = aChType; + chIndex[chIdx] = bc[heightLayer]; + if (isCpe) { + chMapping[chIdx + 1] = channelIdx + 1; + chType[chIdx + 1] = aChType; + chIndex[chIdx + 1] = bc[heightLayer] + 1; + } + *elMapping = elIdx; + return 1; + } + ec[heightLayer] += 1; + if (pPce->BackElementIsCpe[i]) { + cc[heightLayer] += 2; + bc[heightLayer] += 2; + } else { + cc[heightLayer] += 1; + bc[heightLayer] += 1; + } + } + break; + + case ID_LFE: { /* Unfortunately we have to go through all normal height + layer elements to get the position of the LFE + channels. Start with counting the front + channels/elements at normal height */ + for (i = 0; i < pPce->NumFrontChannelElements; i += 1) { + int heightLayer = pPce->FrontElementHeightInfo[i]; + ec[heightLayer] += 1; + cc[heightLayer] += (pPce->FrontElementIsCpe[i]) ? 2 : 1; + } + /* Count side channels/elements at normal height */ + for (i = 0; i < pPce->NumSideChannelElements; i += 1) { + int heightLayer = pPce->SideElementHeightInfo[i]; + ec[heightLayer] += 1; + cc[heightLayer] += (pPce->SideElementIsCpe[i]) ? 2 : 1; + } + /* Count back channels/elements at normal height */ + for (i = 0; i < pPce->NumBackChannelElements; i += 1) { + int heightLayer = pPce->BackElementHeightInfo[i]; + ec[heightLayer] += 1; + cc[heightLayer] += (pPce->BackElementIsCpe[i]) ? 2 : 1; + } + + /* search in lfe channels */ + for (i = 0; i < pPce->NumLfeChannelElements; i++) { + int elIdx = + ec[0]; /* LFE channels belong to the normal height layer */ + int chIdx = cc[0]; + if (pPce->LfeElementTagSelect[i] == tag) { + chMapping[chIdx] = channelIdx; + *elMapping = elIdx; + chType[chIdx] = ACT_LFE; + chIndex[chIdx] = lc; + return 1; + } + ec[0] += 1; + cc[0] += 1; + lc += 1; + } + } break; + + /* Non audio elements */ + case ID_CCE: + /* search in cce channels */ + for (i = 0; i < pPce->NumValidCcElements; i++) { + if (pPce->ValidCcElementTagSelect[i] == tag) { + return 1; + } + } + break; + case ID_DSE: + /* search associated data elements */ + for (i = 0; i < pPce->NumAssocDataElements; i++) { + if (pPce->AssocDataElementTagSelect[i] == tag) { + return 1; + } + } + break; + default: + return 0; + } + return 0; /* not found in any list */ + } + } + + return 1; +} + +#define SPEAKER_PLANE_NORMAL 0 +#define SPEAKER_PLANE_TOP 1 +#define SPEAKER_PLANE_BOTTOM 2 + +void CProgramConfig_GetChannelDescription(const UINT chConfig, + const CProgramConfig *pPce, + AUDIO_CHANNEL_TYPE chType[], + UCHAR chIndex[]) { + FDK_ASSERT(chType != NULL); + FDK_ASSERT(chIndex != NULL); + + if ((chConfig == 0) && (pPce != NULL)) { + if (pPce->isValid) { + int spkPlane, chIdx = 0; + for (spkPlane = SPEAKER_PLANE_NORMAL; spkPlane <= SPEAKER_PLANE_BOTTOM; + spkPlane += 1) { + int elIdx, grpChIdx = 0; + for (elIdx = 0; elIdx < pPce->NumFrontChannelElements; elIdx += 1) { + if (pPce->FrontElementHeightInfo[elIdx] == spkPlane) { + chType[chIdx] = (AUDIO_CHANNEL_TYPE)((spkPlane << 4) | ACT_FRONT); + chIndex[chIdx++] = grpChIdx++; + if (pPce->FrontElementIsCpe[elIdx]) { + chType[chIdx] = (AUDIO_CHANNEL_TYPE)((spkPlane << 4) | ACT_FRONT); + chIndex[chIdx++] = grpChIdx++; + } + } + } + grpChIdx = 0; + for (elIdx = 0; elIdx < pPce->NumSideChannelElements; elIdx += 1) { + if (pPce->SideElementHeightInfo[elIdx] == spkPlane) { + chType[chIdx] = (AUDIO_CHANNEL_TYPE)((spkPlane << 4) | ACT_SIDE); + chIndex[chIdx++] = grpChIdx++; + if (pPce->SideElementIsCpe[elIdx]) { + chType[chIdx] = (AUDIO_CHANNEL_TYPE)((spkPlane << 4) | ACT_SIDE); + chIndex[chIdx++] = grpChIdx++; + } + } + } + grpChIdx = 0; + for (elIdx = 0; elIdx < pPce->NumBackChannelElements; elIdx += 1) { + if (pPce->BackElementHeightInfo[elIdx] == spkPlane) { + chType[chIdx] = (AUDIO_CHANNEL_TYPE)((spkPlane << 4) | ACT_BACK); + chIndex[chIdx++] = grpChIdx++; + if (pPce->BackElementIsCpe[elIdx]) { + chType[chIdx] = (AUDIO_CHANNEL_TYPE)((spkPlane << 4) | ACT_BACK); + chIndex[chIdx++] = grpChIdx++; + } + } + } + grpChIdx = 0; + if (spkPlane == SPEAKER_PLANE_NORMAL) { + for (elIdx = 0; elIdx < pPce->NumLfeChannelElements; elIdx += 1) { + chType[chIdx] = ACT_LFE; + chIndex[chIdx++] = grpChIdx++; + } + } + } + } + } else { + int chIdx; + for (chIdx = 0; chIdx < getNumberOfTotalChannels(chConfig); chIdx += 1) { + getImplicitAudioChannelTypeAndIndex(&chType[chIdx], &chIndex[chIdx], + chConfig, chIdx); + } + } +} + +int CProgramConfig_GetPceChMap(const CProgramConfig *pPce, UCHAR pceChMap[], + const UINT pceChMapLen) { + const UCHAR *nElements = &pPce->NumFrontChannelElements; + const UCHAR *elHeight[3], *elIsCpe[3]; + unsigned chIdx, plane, grp, offset, totCh[3], numCh[3][4]; + + FDK_ASSERT(pPce != NULL); + FDK_ASSERT(pceChMap != NULL); + + /* Init counter: */ + FDKmemclear(totCh, 3 * sizeof(unsigned)); + FDKmemclear(numCh, 3 * 4 * sizeof(unsigned)); + + /* Analyse PCE: */ + elHeight[0] = pPce->FrontElementHeightInfo; + elIsCpe[0] = pPce->FrontElementIsCpe; + elHeight[1] = pPce->SideElementHeightInfo; + elIsCpe[1] = pPce->SideElementIsCpe; + elHeight[2] = pPce->BackElementHeightInfo; + elIsCpe[2] = pPce->BackElementIsCpe; + + for (plane = 0; plane <= SPEAKER_PLANE_BOTTOM; plane += 1) { + for (grp = 0; grp < 3; grp += 1) { /* front, side, back */ + unsigned el; + for (el = 0; el < nElements[grp]; el += 1) { + if (elHeight[grp][el] == plane) { + unsigned elCh = elIsCpe[grp][el] ? 2 : 1; + numCh[plane][grp] += elCh; + totCh[plane] += elCh; + } + } + } + if (plane == SPEAKER_PLANE_NORMAL) { + unsigned elCh = pPce->NumLfeChannelElements; + numCh[plane][grp] += elCh; + totCh[plane] += elCh; + } + } + /* Sanity checks: */ + chIdx = totCh[SPEAKER_PLANE_NORMAL] + totCh[SPEAKER_PLANE_TOP] + + totCh[SPEAKER_PLANE_BOTTOM]; + if (chIdx > pceChMapLen) { + return -1; + } + + /* Create map: */ + offset = grp = 0; + unsigned grpThresh = numCh[SPEAKER_PLANE_NORMAL][grp]; + for (chIdx = 0; chIdx < totCh[SPEAKER_PLANE_NORMAL]; chIdx += 1) { + while ((chIdx >= grpThresh) && (grp < 3)) { + offset += numCh[1][grp] + numCh[2][grp]; + grp += 1; + grpThresh += numCh[SPEAKER_PLANE_NORMAL][grp]; + } + pceChMap[chIdx] = chIdx + offset; + } + offset = 0; + for (grp = 0; grp < 4; grp += 1) { /* front, side, back and lfe */ + offset += numCh[SPEAKER_PLANE_NORMAL][grp]; + for (plane = SPEAKER_PLANE_TOP; plane <= SPEAKER_PLANE_BOTTOM; plane += 1) { + unsigned mapCh; + for (mapCh = 0; mapCh < numCh[plane][grp]; mapCh += 1) { + pceChMap[chIdx++] = offset; + offset += 1; + } + } + } + return 0; +} + +int CProgramConfig_GetElementTable(const CProgramConfig *pPce, + MP4_ELEMENT_ID elList[], + const INT elListSize, UCHAR *pChMapIdx) { + int i, el = 0; + + FDK_ASSERT(elList != NULL); + FDK_ASSERT(pChMapIdx != NULL); + FDK_ASSERT(pPce != NULL); + + *pChMapIdx = 0; + + if ((elListSize < + pPce->NumFrontChannelElements + pPce->NumSideChannelElements + + pPce->NumBackChannelElements + pPce->NumLfeChannelElements) || + (pPce->NumChannels == 0)) { + return 0; + } + + for (i = 0; i < pPce->NumFrontChannelElements; i += 1) { + elList[el++] = (pPce->FrontElementIsCpe[i]) ? ID_CPE : ID_SCE; + } + + for (i = 0; i < pPce->NumSideChannelElements; i += 1) { + elList[el++] = (pPce->SideElementIsCpe[i]) ? ID_CPE : ID_SCE; + } + + for (i = 0; i < pPce->NumBackChannelElements; i += 1) { + elList[el++] = (pPce->BackElementIsCpe[i]) ? ID_CPE : ID_SCE; + } + + for (i = 0; i < pPce->NumLfeChannelElements; i += 1) { + elList[el++] = ID_LFE; + } + + /* Find an corresponding channel configuration if possible */ + switch (pPce->NumChannels) { + case 1: + case 2: + /* One and two channels have no alternatives. */ + *pChMapIdx = pPce->NumChannels; + break; + case 3: + case 4: + case 5: + case 6: { /* Test if the number of channels can be used as channel config: + */ + C_ALLOC_SCRATCH_START(tmpPce, CProgramConfig, 1); + /* Create a PCE for the config to test ... */ + CProgramConfig_GetDefault(tmpPce, pPce->NumChannels); + /* ... and compare it with the given one. */ + *pChMapIdx = (!(CProgramConfig_Compare(pPce, tmpPce) & 0xE)) + ? pPce->NumChannels + : 0; + /* If compare result is 0 or 1 we can be sure that it is channel + * config 11. */ + C_ALLOC_SCRATCH_END(tmpPce, CProgramConfig, 1); + } break; + case 7: { + C_ALLOC_SCRATCH_START(tmpPce, CProgramConfig, 1); + /* Create a PCE for the config to test ... */ + CProgramConfig_GetDefault(tmpPce, 11); + /* ... and compare it with the given one. */ + *pChMapIdx = (!(CProgramConfig_Compare(pPce, tmpPce) & 0xE)) ? 11 : 0; + /* If compare result is 0 or 1 we can be sure that it is channel + * config 11. */ + C_ALLOC_SCRATCH_END(tmpPce, CProgramConfig, 1); + } break; + case 8: { /* Try the four possible 7.1ch configurations. One after the + other. */ + UCHAR testCfg[4] = {32, 14, 12, 7}; + C_ALLOC_SCRATCH_START(tmpPce, CProgramConfig, 1); + for (i = 0; i < 4; i += 1) { + /* Create a PCE for the config to test ... */ + CProgramConfig_GetDefault(tmpPce, testCfg[i]); + /* ... and compare it with the given one. */ + if (!(CProgramConfig_Compare(pPce, tmpPce) & 0xE)) { + /* If the compare result is 0 or 1 than the two channel configurations + * match. */ + /* Explicit mapping of 7.1 side channel configuration to 7.1 rear + * channel mapping. */ + *pChMapIdx = (testCfg[i] == 32) ? 12 : testCfg[i]; + } + } + C_ALLOC_SCRATCH_END(tmpPce, CProgramConfig, 1); + } break; + default: + /* The PCE does not match any predefined channel configuration. */ + *pChMapIdx = 0; + break; + } + + return el; +} + +static AUDIO_OBJECT_TYPE getAOT(HANDLE_FDK_BITSTREAM bs) { + int tmp = 0; + + tmp = FDKreadBits(bs, 5); + if (tmp == AOT_ESCAPE) { + int tmp2 = FDKreadBits(bs, 6); + tmp = 32 + tmp2; + } + + return (AUDIO_OBJECT_TYPE)tmp; +} + +static INT getSampleRate(HANDLE_FDK_BITSTREAM bs, UCHAR *index, int nBits) { + INT sampleRate; + int idx; + + idx = FDKreadBits(bs, nBits); + if (idx == (1 << nBits) - 1) { + if (FDKgetValidBits(bs) < 24) { + return 0; + } + sampleRate = FDKreadBits(bs, 24); + } else { + sampleRate = SamplingRateTable[idx]; + } + + *index = idx; + + return sampleRate; +} + +static TRANSPORTDEC_ERROR GaSpecificConfig_Parse(CSGaSpecificConfig *self, + CSAudioSpecificConfig *asc, + HANDLE_FDK_BITSTREAM bs, + UINT ascStartAnchor) { + TRANSPORTDEC_ERROR ErrorStatus = TRANSPORTDEC_OK; + + self->m_frameLengthFlag = FDKreadBits(bs, 1); + + self->m_dependsOnCoreCoder = FDKreadBits(bs, 1); + + if (self->m_dependsOnCoreCoder) self->m_coreCoderDelay = FDKreadBits(bs, 14); + + self->m_extensionFlag = FDKreadBits(bs, 1); + + if (asc->m_channelConfiguration == 0) { + CProgramConfig_Read(&asc->m_progrConfigElement, bs, ascStartAnchor); + } + + if ((asc->m_aot == AOT_AAC_SCAL) || (asc->m_aot == AOT_ER_AAC_SCAL)) { + self->m_layer = FDKreadBits(bs, 3); + } + + if (self->m_extensionFlag) { + if (asc->m_aot == AOT_ER_BSAC) { + self->m_numOfSubFrame = FDKreadBits(bs, 5); + self->m_layerLength = FDKreadBits(bs, 11); + } + + if ((asc->m_aot == AOT_ER_AAC_LC) || (asc->m_aot == AOT_ER_AAC_LTP) || + (asc->m_aot == AOT_ER_AAC_SCAL) || (asc->m_aot == AOT_ER_AAC_LD)) { + asc->m_vcb11Flag = FDKreadBits(bs, 1); /* aacSectionDataResilienceFlag */ + asc->m_rvlcFlag = + FDKreadBits(bs, 1); /* aacScalefactorDataResilienceFlag */ + asc->m_hcrFlag = FDKreadBits(bs, 1); /* aacSpectralDataResilienceFlag */ + } + + self->m_extensionFlag3 = FDKreadBits(bs, 1); + } + return (ErrorStatus); +} + +static INT skipSbrHeader(HANDLE_FDK_BITSTREAM hBs, int isUsac) { + /* Dummy parse SbrDfltHeader() */ + INT dflt_header_extra1, dflt_header_extra2, bitsToSkip = 0; + + if (!isUsac) { + bitsToSkip = 6; + FDKpushFor(hBs, 6); /* amp res 1, xover freq 3, reserved 2 */ + } + bitsToSkip += 8; + FDKpushFor(hBs, 8); /* start / stop freq */ + bitsToSkip += 2; + dflt_header_extra1 = FDKreadBit(hBs); + dflt_header_extra2 = FDKreadBit(hBs); + bitsToSkip += 5 * dflt_header_extra1 + 6 * dflt_header_extra2; + FDKpushFor(hBs, 5 * dflt_header_extra1 + 6 * dflt_header_extra2); + + return bitsToSkip; +} + +static INT ld_sbr_header(CSAudioSpecificConfig *asc, const INT dsFactor, + HANDLE_FDK_BITSTREAM hBs, CSTpCallBacks *cb) { + const int channelConfiguration = asc->m_channelConfiguration; + int i = 0, j = 0; + INT error = 0; + MP4_ELEMENT_ID element = ID_NONE; + + /* check whether the channelConfiguration is defined in + * channel_configuration_array */ + if (channelConfiguration < 0 || + channelConfiguration > (INT)(sizeof(channel_configuration_array) / + sizeof(MP4_ELEMENT_ID **) - + 1)) { + return TRANSPORTDEC_PARSE_ERROR; + } + + /* read elements of the passed channel_configuration until there is ID_NONE */ + while ((element = channel_configuration_array[channelConfiguration][j]) != + ID_NONE) { + /* Setup LFE element for upsampling too. This is essential especially for + * channel configs where the LFE element is not at the last position for + * example in channel config 13 or 14. It leads to memory leaks if the setup + * of the LFE element would be done later in the core. */ + if (element == ID_SCE || element == ID_CPE || element == ID_LFE) { + error |= cb->cbSbr( + cb->cbSbrData, hBs, asc->m_samplingFrequency / dsFactor, + asc->m_extensionSamplingFrequency / dsFactor, + asc->m_samplesPerFrame / dsFactor, AOT_ER_AAC_ELD, element, i++, 0, 0, + asc->configMode, &asc->SbrConfigChanged, dsFactor); + if (error != TRANSPORTDEC_OK) { + goto bail; + } + } + j++; + } +bail: + return error; +} + +static TRANSPORTDEC_ERROR EldSpecificConfig_Parse(CSAudioSpecificConfig *asc, + HANDLE_FDK_BITSTREAM hBs, + CSTpCallBacks *cb) { + TRANSPORTDEC_ERROR ErrorStatus = TRANSPORTDEC_OK; + CSEldSpecificConfig *esc = &asc->m_sc.m_eldSpecificConfig; + ASC_ELD_EXT_TYPE eldExtType; + int eldExtLen, len, cnt, ldSbrLen = 0, eldExtLenSum, numSbrHeader = 0, + sbrIndex; + + unsigned char downscale_fill_nibble; + + FDKmemclear(esc, sizeof(CSEldSpecificConfig)); + + esc->m_frameLengthFlag = FDKreadBits(hBs, 1); + if (esc->m_frameLengthFlag) { + asc->m_samplesPerFrame = 480; + } else { + asc->m_samplesPerFrame = 512; + } + + asc->m_vcb11Flag = FDKreadBits(hBs, 1); + asc->m_rvlcFlag = FDKreadBits(hBs, 1); + asc->m_hcrFlag = FDKreadBits(hBs, 1); + + esc->m_sbrPresentFlag = FDKreadBits(hBs, 1); + + if (esc->m_sbrPresentFlag == 1) { + esc->m_sbrSamplingRate = + FDKreadBits(hBs, 1); /* 0: single rate, 1: dual rate */ + esc->m_sbrCrcFlag = FDKreadBits(hBs, 1); + + asc->m_extensionSamplingFrequency = asc->m_samplingFrequency + << esc->m_sbrSamplingRate; + + if (cb->cbSbr != NULL) { + /* ELD reduced delay mode: LD-SBR initialization has to know the downscale + information. Postpone LD-SBR initialization and read ELD extension + information first. */ + switch (asc->m_channelConfiguration) { + case 1: + case 2: + numSbrHeader = 1; + break; + case 3: + numSbrHeader = 2; + break; + case 4: + case 5: + case 6: + numSbrHeader = 3; + break; + case 7: + case 11: + case 12: + case 14: + numSbrHeader = 4; + break; + default: + numSbrHeader = 0; + break; + } + for (sbrIndex = 0; sbrIndex < numSbrHeader; sbrIndex++) { + ldSbrLen += skipSbrHeader(hBs, 0); + } + } else { + return TRANSPORTDEC_UNSUPPORTED_FORMAT; + } + } + esc->m_useLdQmfTimeAlign = 0; + + /* new ELD syntax */ + eldExtLenSum = FDKgetValidBits(hBs); + esc->m_downscaledSamplingFrequency = asc->m_samplingFrequency; + /* parse ExtTypeConfigData */ + while ( + ((eldExtType = (ASC_ELD_EXT_TYPE)FDKreadBits(hBs, 4)) != ELDEXT_TERM) && + ((INT)FDKgetValidBits(hBs) >= 0)) { + eldExtLen = len = FDKreadBits(hBs, 4); + if (len == 0xf) { + len = FDKreadBits(hBs, 8); + eldExtLen += len; + + if (len == 0xff) { + len = FDKreadBits(hBs, 16); + eldExtLen += len; + } + } + + switch (eldExtType) { + case ELDEXT_LDSAC: + esc->m_useLdQmfTimeAlign = 1; + if (cb->cbSsc != NULL) { + ErrorStatus = (TRANSPORTDEC_ERROR)cb->cbSsc( + cb->cbSscData, hBs, asc->m_aot, + asc->m_samplingFrequency << esc->m_sbrSamplingRate, + asc->m_samplesPerFrame << esc->m_sbrSamplingRate, + 1, /* stereoConfigIndex */ + -1, /* nTimeSlots: read from bitstream */ + eldExtLen, asc->configMode, &asc->SacConfigChanged); + if (ErrorStatus != TRANSPORTDEC_OK) { + return TRANSPORTDEC_PARSE_ERROR; + } + if (esc->m_downscaledSamplingFrequency != asc->m_samplingFrequency) { + return TRANSPORTDEC_UNSUPPORTED_FORMAT; /* ELDv2 w/ ELD downscaled + mode not allowed */ + } + break; + } + + FDK_FALLTHROUGH; + default: + for (cnt = 0; cnt < eldExtLen; cnt++) { + FDKreadBits(hBs, 8); + } + break; + + case ELDEXT_DOWNSCALEINFO: + UCHAR tmpDownscaleFreqIdx; + esc->m_downscaledSamplingFrequency = + getSampleRate(hBs, &tmpDownscaleFreqIdx, 4); + if (esc->m_downscaledSamplingFrequency == 0) { + return TRANSPORTDEC_PARSE_ERROR; + } + downscale_fill_nibble = FDKreadBits(hBs, 4); + if (downscale_fill_nibble != 0x0) { + return TRANSPORTDEC_PARSE_ERROR; + } + if (esc->m_useLdQmfTimeAlign == 1) { + return TRANSPORTDEC_UNSUPPORTED_FORMAT; /* ELDv2 w/ ELD downscaled + mode not allowed */ + } + break; + } + } + + if ((INT)FDKgetValidBits(hBs) < 0) { + return TRANSPORTDEC_PARSE_ERROR; + } + + if (esc->m_sbrPresentFlag == 1 && numSbrHeader != 0) { + INT dsFactor = 1; /* Downscale factor must be 1 or even for SBR */ + if (esc->m_downscaledSamplingFrequency != 0) { + if (asc->m_samplingFrequency % esc->m_downscaledSamplingFrequency != 0) { + return TRANSPORTDEC_UNSUPPORTED_FORMAT; + } + dsFactor = asc->m_samplingFrequency / esc->m_downscaledSamplingFrequency; + if (dsFactor != 1 && (dsFactor)&1) { + return TRANSPORTDEC_UNSUPPORTED_FORMAT; /* SBR needs an even downscale + factor */ + } + if (dsFactor != 1 && dsFactor != 2 && dsFactor != 4) { + dsFactor = 1; /* don't apply dsf for not yet supported even dsfs */ + } + if ((INT)asc->m_samplesPerFrame % dsFactor != 0) { + return TRANSPORTDEC_UNSUPPORTED_FORMAT; /* frameSize/dsf must be an + integer number */ + } + } + eldExtLenSum = eldExtLenSum - FDKgetValidBits(hBs); + FDKpushBack(hBs, eldExtLenSum + ldSbrLen); + if (0 != ld_sbr_header(asc, dsFactor, hBs, cb)) { + return TRANSPORTDEC_PARSE_ERROR; + } + FDKpushFor(hBs, eldExtLenSum); + } + return (ErrorStatus); +} + +/* +Subroutine to store config in UCHAR buffer. Bit stream position does not change. +*/ +static UINT StoreConfigAsBitstream( + HANDLE_FDK_BITSTREAM hBs, const INT configSize_bits, /* If < 0 (> 0) config + to read is before + (after) current bit + stream position. */ + UCHAR *configTargetBuffer, const USHORT configTargetBufferSize_bytes) { + FDK_BITSTREAM usacConf; + UINT const nBits = fAbs(configSize_bits); + UINT j, tmp; + + if (nBits > 8 * (UINT)configTargetBufferSize_bytes) { + return 1; + } + FDKmemclear(configTargetBuffer, configTargetBufferSize_bytes); + + FDKinitBitStream(&usacConf, configTargetBuffer, configTargetBufferSize_bytes, + nBits, BS_WRITER); + if (configSize_bits < 0) { + FDKpushBack(hBs, nBits); + } + for (j = nBits; j > 31; j -= 32) { + tmp = FDKreadBits(hBs, 32); + FDKwriteBits(&usacConf, tmp, 32); + } + if (j > 0) { + tmp = FDKreadBits(hBs, j); + FDKwriteBits(&usacConf, tmp, j); + } + FDKsyncCache(&usacConf); + if (configSize_bits > 0) { + FDKpushBack(hBs, nBits); + } + + return 0; +} + +/* maps coreSbrFrameLengthIndex to coreCoderFrameLength */ +static const USHORT usacFrameLength[8] = {768, 1024, 2048, 2048, 4096, 0, 0, 0}; +/* maps coreSbrFrameLengthIndex to sbrRatioIndex */ +static const UCHAR sbrRatioIndex[8] = {0, 0, 2, 3, 1, 0, 0, 0}; + +/* + subroutine for parsing extension element configuration: + UsacExtElementConfig() q.v. ISO/IEC FDIS 23003-3:2011(E) Table 14 + rsv603daExtElementConfig() q.v. ISO/IEC DIS 23008-3 Table 13 +*/ +static TRANSPORTDEC_ERROR extElementConfig(CSUsacExtElementConfig *extElement, + HANDLE_FDK_BITSTREAM hBs, + const CSTpCallBacks *cb, + const UCHAR numSignalsInGroup, + const UINT coreFrameLength, + const int subStreamIndex, + const AUDIO_OBJECT_TYPE aot) { + TRANSPORTDEC_ERROR ErrorStatus = TRANSPORTDEC_OK; + + USAC_EXT_ELEMENT_TYPE usacExtElementType = + (USAC_EXT_ELEMENT_TYPE)escapedValue(hBs, 4, 8, 16); + + /* recurve extension elements which are invalid for USAC */ + if (aot == AOT_USAC) { + switch (usacExtElementType) { + case ID_EXT_ELE_FILL: + case ID_EXT_ELE_MPEGS: + case ID_EXT_ELE_SAOC: + case ID_EXT_ELE_AUDIOPREROLL: + case ID_EXT_ELE_UNI_DRC: + break; + default: + usacExtElementType = ID_EXT_ELE_UNKNOWN; + break; + } + } + + extElement->usacExtElementType = usacExtElementType; + int usacExtElementConfigLength = escapedValue(hBs, 4, 8, 16); + extElement->usacExtElementConfigLength = (USHORT)usacExtElementConfigLength; + INT bsAnchor; + + if (FDKreadBit(hBs)) /* usacExtElementDefaultLengthPresent */ + extElement->usacExtElementDefaultLength = escapedValue(hBs, 8, 16, 0) + 1; + else + extElement->usacExtElementDefaultLength = 0; + + extElement->usacExtElementPayloadFrag = FDKreadBit(hBs); + + bsAnchor = (INT)FDKgetValidBits(hBs); + + switch (usacExtElementType) { + case ID_EXT_ELE_UNKNOWN: + case ID_EXT_ELE_FILL: + break; + case ID_EXT_ELE_AUDIOPREROLL: + /* No configuration element */ + extElement->usacExtElementHasAudioPreRoll = 1; + break; + case ID_EXT_ELE_UNI_DRC: { + if (cb->cbUniDrc != NULL) { + ErrorStatus = (TRANSPORTDEC_ERROR)cb->cbUniDrc( + cb->cbUniDrcData, hBs, usacExtElementConfigLength, + 0, /* uniDrcConfig */ + subStreamIndex, 0, aot); + if (ErrorStatus != TRANSPORTDEC_OK) { + return ErrorStatus; + } + } + } break; + default: + break; + } + + /* Adjust bit stream position. This is required because of byte alignment and + * unhandled extensions. */ + { + INT left_bits = (usacExtElementConfigLength << 3) - + (bsAnchor - (INT)FDKgetValidBits(hBs)); + if (left_bits >= 0) { + FDKpushFor(hBs, left_bits); + } else { + /* parsed too many bits */ + ErrorStatus = TRANSPORTDEC_PARSE_ERROR; + } + } + + return ErrorStatus; +} + +/* + subroutine for parsing the USAC / RSVD60 configuration extension: + UsacConfigExtension() q.v. ISO/IEC FDIS 23003-3:2011(E) Table 15 + rsv603daConfigExtension() q.v. ISO/IEC DIS 23008-3 Table 14 +*/ +static TRANSPORTDEC_ERROR configExtension(CSUsacConfig *usc, + HANDLE_FDK_BITSTREAM hBs, + const CSTpCallBacks *cb) { + TRANSPORTDEC_ERROR ErrorStatus = TRANSPORTDEC_OK; + + int numConfigExtensions; + CONFIG_EXT_ID usacConfigExtType; + int usacConfigExtLength; + + numConfigExtensions = (int)escapedValue(hBs, 2, 4, 8) + 1; + for (int confExtIdx = 0; confExtIdx < numConfigExtensions; confExtIdx++) { + INT nbits; + int loudnessInfoSetConfigExtensionPosition = FDKgetValidBits(hBs); + usacConfigExtType = (CONFIG_EXT_ID)escapedValue(hBs, 4, 8, 16); + usacConfigExtLength = (int)escapedValue(hBs, 4, 8, 16); + + /* Start bit position of config extension */ + nbits = (INT)FDKgetValidBits(hBs); + + /* Return an error in case the bitbuffer fill level is too low. */ + if (nbits < usacConfigExtLength * 8) { + return TRANSPORTDEC_PARSE_ERROR; + } + + switch (usacConfigExtType) { + case ID_CONFIG_EXT_FILL: + for (int i = 0; i < usacConfigExtLength; i++) { + if (FDKreadBits(hBs, 8) != 0xa5) { + return TRANSPORTDEC_PARSE_ERROR; + } + } + break; + case ID_CONFIG_EXT_LOUDNESS_INFO: { + if (cb->cbUniDrc != NULL) { + ErrorStatus = (TRANSPORTDEC_ERROR)cb->cbUniDrc( + cb->cbUniDrcData, hBs, usacConfigExtLength, + 1, /* loudnessInfoSet */ + 0, loudnessInfoSetConfigExtensionPosition, AOT_USAC); + if (ErrorStatus != TRANSPORTDEC_OK) { + return ErrorStatus; + } + } + } break; + default: + break; + } + + /* Skip remaining bits. If too many bits were parsed, assume error. */ + usacConfigExtLength = + 8 * usacConfigExtLength - (nbits - (INT)FDKgetValidBits(hBs)); + if (usacConfigExtLength < 0) { + return TRANSPORTDEC_PARSE_ERROR; + } + FDKpushFor(hBs, usacConfigExtLength); + } + + return ErrorStatus; +} + +/* This function unifies decoder config parsing of USAC and RSV60: + rsv603daDecoderConfig() ISO/IEC DIS 23008-3 Table 8 + UsacDecoderConfig() ISO/IEC FDIS 23003-3 Table 6 + */ +static TRANSPORTDEC_ERROR UsacRsv60DecoderConfig_Parse( + CSAudioSpecificConfig *asc, HANDLE_FDK_BITSTREAM hBs, + const CSTpCallBacks *cb) { + TRANSPORTDEC_ERROR ErrorStatus = TRANSPORTDEC_OK; + CSUsacConfig *usc = &asc->m_sc.m_usacConfig; + int i, numberOfElements; + int channelElementIdx = + 0; /* index for elements which contain audio channels (sce, cpe, lfe) */ + SC_CHANNEL_CONFIG sc_chan_config = {0, 0, 0, 0}; + + numberOfElements = (int)escapedValue(hBs, 4, 8, 16) + 1; + usc->m_usacNumElements = numberOfElements; + if (numberOfElements > TP_USAC_MAX_ELEMENTS) { + return TRANSPORTDEC_UNSUPPORTED_FORMAT; + } + usc->m_nUsacChannels = 0; + usc->m_channelConfigurationIndex = asc->m_channelConfiguration; + + if (asc->m_aot == AOT_USAC) { + sc_chan_config = sc_chan_config_tab[usc->m_channelConfigurationIndex]; + + if (sc_chan_config.nCh > (SCHAR)TP_USAC_MAX_SPEAKERS) { + return TRANSPORTDEC_PARSE_ERROR; + } + } + + for (i = 0; i < numberOfElements; i++) { + MP4_ELEMENT_ID usacElementType = (MP4_ELEMENT_ID)( + FDKreadBits(hBs, 2) | USAC_ID_BIT); /* set USAC_ID_BIT to map + usacElementType to + MP4_ELEMENT_ID enum */ + usc->element[i].usacElementType = usacElementType; + + /* sanity check: update element counter */ + if (asc->m_aot == AOT_USAC) { + switch (usacElementType) { + case ID_USAC_SCE: + sc_chan_config.nSCE--; + break; + case ID_USAC_CPE: + sc_chan_config.nCPE--; + break; + case ID_USAC_LFE: + sc_chan_config.nLFE--; + break; + default: + break; + } + if (usc->m_channelConfigurationIndex) { + /* sanity check: no element counter may be smaller zero */ + if (sc_chan_config.nCPE < 0 || sc_chan_config.nSCE < 0 || + sc_chan_config.nLFE < 0) { + return TRANSPORTDEC_PARSE_ERROR; + } + } + } + + switch (usacElementType) { + case ID_USAC_SCE: + /* UsacCoreConfig() ISO/IEC FDIS 23003-3 Table 10 */ + if (FDKreadBit(hBs)) { /* tw_mdct */ + return TRANSPORTDEC_UNSUPPORTED_FORMAT; + } + usc->element[i].m_noiseFilling = FDKreadBits(hBs, 1); + /* end of UsacCoreConfig() */ + if (usc->m_sbrRatioIndex > 0) { + if (cb->cbSbr == NULL) { + return TRANSPORTDEC_UNKOWN_ERROR; + } + /* SbrConfig() ISO/IEC FDIS 23003-3 Table 11 */ + usc->element[i].m_harmonicSBR = FDKreadBit(hBs); + usc->element[i].m_interTes = FDKreadBit(hBs); + usc->element[i].m_pvc = FDKreadBit(hBs); + if (cb->cbSbr(cb->cbSbrData, hBs, asc->m_samplingFrequency, + asc->m_extensionSamplingFrequency, + asc->m_samplesPerFrame, asc->m_aot, ID_SCE, + channelElementIdx, usc->element[i].m_harmonicSBR, + usc->element[i].m_stereoConfigIndex, asc->configMode, + &asc->SbrConfigChanged, 1)) { + return TRANSPORTDEC_PARSE_ERROR; + } + /* end of SbrConfig() */ + } + usc->m_nUsacChannels += 1; + channelElementIdx++; + break; + + case ID_USAC_CPE: + /* UsacCoreConfig() ISO/IEC FDIS 23003-3 Table 10 */ + if (FDKreadBit(hBs)) { /* tw_mdct */ + return TRANSPORTDEC_UNSUPPORTED_FORMAT; + } + usc->element[i].m_noiseFilling = FDKreadBits(hBs, 1); + /* end of UsacCoreConfig() */ + if (usc->m_sbrRatioIndex > 0) { + if (cb->cbSbr == NULL) return TRANSPORTDEC_UNKOWN_ERROR; + /* SbrConfig() ISO/IEC FDIS 23003-3 */ + usc->element[i].m_harmonicSBR = FDKreadBit(hBs); + usc->element[i].m_interTes = FDKreadBit(hBs); + usc->element[i].m_pvc = FDKreadBit(hBs); + { + INT bitsToSkip = skipSbrHeader(hBs, 1); + /* read stereoConfigIndex */ + usc->element[i].m_stereoConfigIndex = FDKreadBits(hBs, 2); + /* rewind */ + FDKpushBack(hBs, bitsToSkip + 2); + } + { + MP4_ELEMENT_ID el_type = + (usc->element[i].m_stereoConfigIndex == 1 || + usc->element[i].m_stereoConfigIndex == 2) + ? ID_SCE + : ID_CPE; + if (cb->cbSbr(cb->cbSbrData, hBs, asc->m_samplingFrequency, + asc->m_extensionSamplingFrequency, + asc->m_samplesPerFrame, asc->m_aot, el_type, + channelElementIdx, usc->element[i].m_harmonicSBR, + usc->element[i].m_stereoConfigIndex, asc->configMode, + &asc->SbrConfigChanged, 1)) { + return TRANSPORTDEC_PARSE_ERROR; + } + } + /* end of SbrConfig() */ + + usc->element[i].m_stereoConfigIndex = + FDKreadBits(hBs, 2); /* Needed in RM5 syntax */ + + if (usc->element[i].m_stereoConfigIndex > 0) { + if (cb->cbSsc != NULL) { + int samplesPerFrame = asc->m_samplesPerFrame; + + if (usc->m_sbrRatioIndex == 1) samplesPerFrame <<= 2; + if (usc->m_sbrRatioIndex == 2) + samplesPerFrame = (samplesPerFrame * 8) / 3; + if (usc->m_sbrRatioIndex == 3) samplesPerFrame <<= 1; + + /* Mps212Config() ISO/IEC FDIS 23003-3 */ + if (cb->cbSsc(cb->cbSscData, hBs, asc->m_aot, + asc->m_extensionSamplingFrequency, samplesPerFrame, + usc->element[i].m_stereoConfigIndex, + usc->m_coreSbrFrameLengthIndex, + 0, /* don't know the length */ + asc->configMode, &asc->SacConfigChanged)) { + return TRANSPORTDEC_PARSE_ERROR; + } + /* end of Mps212Config() */ + } else { + return TRANSPORTDEC_UNKOWN_ERROR; + } + } + } else { + usc->element[i].m_stereoConfigIndex = 0; + } + usc->m_nUsacChannels += 2; + + channelElementIdx++; + break; + + case ID_USAC_LFE: + usc->element[i].m_noiseFilling = 0; + usc->m_nUsacChannels += 1; + if (usc->m_sbrRatioIndex > 0) { + /* Use SBR for upsampling */ + if (cb->cbSbr == NULL) return ErrorStatus = TRANSPORTDEC_UNKOWN_ERROR; + usc->element[i].m_harmonicSBR = (UCHAR)0; + usc->element[i].m_interTes = (UCHAR)0; + usc->element[i].m_pvc = (UCHAR)0; + if (cb->cbSbr(cb->cbSbrData, hBs, asc->m_samplingFrequency, + asc->m_extensionSamplingFrequency, + asc->m_samplesPerFrame, asc->m_aot, ID_LFE, + channelElementIdx, usc->element[i].m_harmonicSBR, + usc->element[i].m_stereoConfigIndex, asc->configMode, + &asc->SbrConfigChanged, 1)) { + return ErrorStatus = TRANSPORTDEC_PARSE_ERROR; + } + } + channelElementIdx++; + break; + + case ID_USAC_EXT: + ErrorStatus = extElementConfig(&usc->element[i].extElement, hBs, cb, 0, + asc->m_samplesPerFrame, 0, asc->m_aot); + + if (ErrorStatus) { + return ErrorStatus; + } + break; + + default: + /* non USAC-element encountered */ + return TRANSPORTDEC_PARSE_ERROR; + } + } + + if (asc->m_aot == AOT_USAC) { + if (usc->m_channelConfigurationIndex) { + /* sanity check: all element counter must be zero */ + if (sc_chan_config.nCPE | sc_chan_config.nSCE | sc_chan_config.nLFE) { + return TRANSPORTDEC_PARSE_ERROR; + } + } else { + /* sanity check: number of audio channels shall be equal to or smaller + * than the accumulated sum of all channels */ + if ((INT)(-2 * sc_chan_config.nCPE - sc_chan_config.nSCE - + sc_chan_config.nLFE) < (INT)usc->numAudioChannels) { + return TRANSPORTDEC_PARSE_ERROR; + } + } + } + + return ErrorStatus; +} + +/* Mapping of coreSbrFrameLengthIndex defined by Table 70 in ISO/IEC 23003-3 */ +static TRANSPORTDEC_ERROR UsacConfig_SetCoreSbrFrameLengthIndex( + CSAudioSpecificConfig *asc, int coreSbrFrameLengthIndex) { + int sbrRatioIndex_val; + + if (coreSbrFrameLengthIndex > 4) { + return TRANSPORTDEC_PARSE_ERROR; /* reserved values */ + } + asc->m_sc.m_usacConfig.m_coreSbrFrameLengthIndex = coreSbrFrameLengthIndex; + asc->m_samplesPerFrame = usacFrameLength[coreSbrFrameLengthIndex]; + sbrRatioIndex_val = sbrRatioIndex[coreSbrFrameLengthIndex]; + asc->m_sc.m_usacConfig.m_sbrRatioIndex = sbrRatioIndex_val; + + if (sbrRatioIndex_val > 0) { + asc->m_sbrPresentFlag = 1; + asc->m_extensionSamplingFrequency = asc->m_samplingFrequency; + asc->m_extensionSamplingFrequencyIndex = asc->m_samplingFrequencyIndex; + switch (sbrRatioIndex_val) { + case 1: /* sbrRatio = 4:1 */ + asc->m_samplingFrequency >>= 2; + asc->m_samplesPerFrame >>= 2; + break; + case 2: /* sbrRatio = 8:3 */ + asc->m_samplingFrequency = (asc->m_samplingFrequency * 3) / 8; + asc->m_samplesPerFrame = (asc->m_samplesPerFrame * 3) / 8; + break; + case 3: /* sbrRatio = 2:1 */ + asc->m_samplingFrequency >>= 1; + asc->m_samplesPerFrame >>= 1; + break; + default: + return TRANSPORTDEC_PARSE_ERROR; + } + asc->m_samplingFrequencyIndex = + getSamplingRateIndex(asc->m_samplingFrequency, 4); + } + + return TRANSPORTDEC_OK; +} + +static TRANSPORTDEC_ERROR UsacConfig_Parse(CSAudioSpecificConfig *asc, + HANDLE_FDK_BITSTREAM hBs, + CSTpCallBacks *cb) { + int usacSamplingFrequency, channelConfigurationIndex, coreSbrFrameLengthIndex; + TRANSPORTDEC_ERROR err = TRANSPORTDEC_OK; + + /* Start bit position of usacConfig */ + INT nbits = (INT)FDKgetValidBits(hBs); + + usacSamplingFrequency = getSampleRate(hBs, &asc->m_samplingFrequencyIndex, 5); + asc->m_samplingFrequency = (UINT)usacSamplingFrequency; + + coreSbrFrameLengthIndex = FDKreadBits(hBs, 3); + if (UsacConfig_SetCoreSbrFrameLengthIndex(asc, coreSbrFrameLengthIndex) != + TRANSPORTDEC_OK) { + return TRANSPORTDEC_PARSE_ERROR; + } + + channelConfigurationIndex = FDKreadBits(hBs, 5); + if (channelConfigurationIndex > 2) { + return TRANSPORTDEC_PARSE_ERROR; /* only channelConfigurationIndex = [1,2] + are supported */ + } + + if (channelConfigurationIndex == 0) { + return TRANSPORTDEC_PARSE_ERROR; /* only channelConfigurationIndex = [1,2] + are supported */ + } + asc->m_channelConfiguration = channelConfigurationIndex; + + err = UsacRsv60DecoderConfig_Parse(asc, hBs, cb); + if (err != TRANSPORTDEC_OK) { + return err; + } + + if (FDKreadBits(hBs, 1)) { /* usacConfigExtensionPresent */ + err = configExtension(&asc->m_sc.m_usacConfig, hBs, cb); + if (err != TRANSPORTDEC_OK) { + return err; + } + } + + /* sanity check whether number of channels signaled in UsacDecoderConfig() + matches the number of channels required by channelConfigurationIndex */ + if ((channelConfigurationIndex > 0) && + (sc_chan_config_tab[channelConfigurationIndex].nCh != + asc->m_sc.m_usacConfig.m_nUsacChannels)) { + return TRANSPORTDEC_PARSE_ERROR; + } + + /* Copy UsacConfig() to asc->m_sc.m_usacConfig.UsacConfig[] buffer. */ + INT configSize_bits = (INT)FDKgetValidBits(hBs) - nbits; + StoreConfigAsBitstream(hBs, configSize_bits, + asc->m_sc.m_usacConfig.UsacConfig, + TP_USAC_MAX_CONFIG_LEN); + asc->m_sc.m_usacConfig.UsacConfigBits = fAbs(configSize_bits); + + return err; +} + +static TRANSPORTDEC_ERROR AudioSpecificConfig_ExtensionParse( + CSAudioSpecificConfig *self, HANDLE_FDK_BITSTREAM bs, CSTpCallBacks *cb) { + TP_ASC_EXTENSION_ID lastAscExt, ascExtId = ASCEXT_UNKOWN; + INT bitsAvailable = (INT)FDKgetValidBits(bs); + + while (bitsAvailable >= 11) { + lastAscExt = ascExtId; + ascExtId = (TP_ASC_EXTENSION_ID)FDKreadBits(bs, 11); + bitsAvailable -= 11; + + switch (ascExtId) { + case ASCEXT_SBR: /* 0x2b7 */ + if ((self->m_extensionAudioObjectType != AOT_SBR) && + (bitsAvailable >= 5)) { + self->m_extensionAudioObjectType = getAOT(bs); + + if ((self->m_extensionAudioObjectType == AOT_SBR) || + (self->m_extensionAudioObjectType == + AOT_ER_BSAC)) { /* Get SBR extension configuration */ + self->m_sbrPresentFlag = FDKreadBits(bs, 1); + if (self->m_aot == AOT_USAC && self->m_sbrPresentFlag > 0 && + self->m_sc.m_usacConfig.m_sbrRatioIndex == 0) { + return TRANSPORTDEC_PARSE_ERROR; + } + + if (self->m_sbrPresentFlag == 1) { + self->m_extensionSamplingFrequency = getSampleRate( + bs, &self->m_extensionSamplingFrequencyIndex, 4); + + if ((INT)self->m_extensionSamplingFrequency <= 0) { + return TRANSPORTDEC_PARSE_ERROR; + } + } + if (self->m_extensionAudioObjectType == AOT_ER_BSAC) { + self->m_extensionChannelConfiguration = FDKreadBits(bs, 4); + } + } + /* Update counter because of variable length fields (AOT and sampling + * rate) */ + bitsAvailable = (INT)FDKgetValidBits(bs); + } + break; + case ASCEXT_PS: /* 0x548 */ + if ((lastAscExt == ASCEXT_SBR) && + (self->m_extensionAudioObjectType == AOT_SBR) && + (bitsAvailable > 0)) { /* Get PS extension configuration */ + self->m_psPresentFlag = FDKreadBits(bs, 1); + bitsAvailable -= 1; + } + break; + case ASCEXT_MPS: /* 0x76a */ + if (self->m_extensionAudioObjectType == AOT_MPEGS) break; + FDK_FALLTHROUGH; + case ASCEXT_LDMPS: /* 0x7cc */ + if ((ascExtId == ASCEXT_LDMPS) && + (self->m_extensionAudioObjectType == AOT_LD_MPEGS)) + break; + if (bitsAvailable >= 1) { + bitsAvailable -= 1; + if (FDKreadBits(bs, 1)) { /* self->m_mpsPresentFlag */ + int sscLen = FDKreadBits(bs, 8); + bitsAvailable -= 8; + if (sscLen == 0xFF) { + sscLen += FDKreadBits(bs, 16); + bitsAvailable -= 16; + } + FDKpushFor(bs, sscLen); /* Skip SSC to be able to read the next + extension if there is one. */ + + bitsAvailable -= sscLen * 8; + } + } + break; + case ASCEXT_SAOC: + if ((ascExtId == ASCEXT_SAOC) && + (self->m_extensionAudioObjectType == AOT_SAOC)) + break; + if (FDKreadBits(bs, 1)) { /* saocPresent */ + int saocscLen = FDKreadBits(bs, 8); + bitsAvailable -= 8; + if (saocscLen == 0xFF) { + saocscLen += FDKreadBits(bs, 16); + bitsAvailable -= 16; + } + FDKpushFor(bs, saocscLen); + bitsAvailable -= saocscLen * 8; + } + break; + default: + /* Just ignore anything. */ + return TRANSPORTDEC_OK; + } + } + + return TRANSPORTDEC_OK; +} + +/* + * API Functions + */ + +void AudioSpecificConfig_Init(CSAudioSpecificConfig *asc) { + FDKmemclear(asc, sizeof(CSAudioSpecificConfig)); + + /* Init all values that should not be zero. */ + asc->m_aot = AOT_NONE; + asc->m_samplingFrequencyIndex = 0xf; + asc->m_epConfig = -1; + asc->m_extensionAudioObjectType = AOT_NULL_OBJECT; + CProgramConfig_Init(&asc->m_progrConfigElement); +} + +TRANSPORTDEC_ERROR AudioSpecificConfig_Parse( + CSAudioSpecificConfig *self, HANDLE_FDK_BITSTREAM bs, + int fExplicitBackwardCompatible, CSTpCallBacks *cb, UCHAR configMode, + UCHAR configChanged, AUDIO_OBJECT_TYPE m_aot) { + TRANSPORTDEC_ERROR ErrorStatus = TRANSPORTDEC_OK; + UINT ascStartAnchor = FDKgetValidBits(bs); + int frameLengthFlag = -1; + + AudioSpecificConfig_Init(self); + + self->configMode = configMode; + self->AacConfigChanged = configChanged; + self->SbrConfigChanged = configChanged; + self->SacConfigChanged = configChanged; + + if (m_aot != AOT_NULL_OBJECT) { + self->m_aot = m_aot; + } else { + self->m_aot = getAOT(bs); + self->m_samplingFrequency = + getSampleRate(bs, &self->m_samplingFrequencyIndex, 4); + if (self->m_samplingFrequency <= 0 || + (self->m_samplingFrequency > 96000 && self->m_aot != 39) || + self->m_samplingFrequency > 4 * 96000) { + return TRANSPORTDEC_PARSE_ERROR; + } + + self->m_channelConfiguration = FDKreadBits(bs, 4); + + /* SBR extension ( explicit non-backwards compatible mode ) */ + self->m_sbrPresentFlag = 0; + self->m_psPresentFlag = 0; + + if (self->m_aot == AOT_SBR || self->m_aot == AOT_PS) { + self->m_extensionAudioObjectType = AOT_SBR; + + self->m_sbrPresentFlag = 1; + if (self->m_aot == AOT_PS) { + self->m_psPresentFlag = 1; + } + + self->m_extensionSamplingFrequency = + getSampleRate(bs, &self->m_extensionSamplingFrequencyIndex, 4); + self->m_aot = getAOT(bs); + + switch (self->m_aot) { + case AOT_AAC_LC: + break; + case AOT_ER_BSAC: + break; + default: + return TRANSPORTDEC_UNSUPPORTED_FORMAT; + } + + if (self->m_aot == AOT_ER_BSAC) { + self->m_extensionChannelConfiguration = FDKreadBits(bs, 4); + } + } else { + self->m_extensionAudioObjectType = AOT_NULL_OBJECT; + } + } + + /* Parse whatever specific configs */ + switch (self->m_aot) { + case AOT_AAC_LC: + case AOT_AAC_SCAL: + case AOT_ER_AAC_LC: + case AOT_ER_AAC_LD: + case AOT_ER_AAC_SCAL: + case AOT_ER_BSAC: + if ((ErrorStatus = GaSpecificConfig_Parse(&self->m_sc.m_gaSpecificConfig, + self, bs, ascStartAnchor)) != + TRANSPORTDEC_OK) { + return (ErrorStatus); + } + frameLengthFlag = self->m_sc.m_gaSpecificConfig.m_frameLengthFlag; + break; + case AOT_MPEGS: + if (cb->cbSsc != NULL) { + if (cb->cbSsc(cb->cbSscData, bs, self->m_aot, self->m_samplingFrequency, + self->m_samplesPerFrame, 1, + -1, /* nTimeSlots: read from bitstream */ + 0, /* don't know the length */ + self->configMode, &self->SacConfigChanged)) { + return TRANSPORTDEC_UNSUPPORTED_FORMAT; + } + } else { + return TRANSPORTDEC_UNSUPPORTED_FORMAT; + } + break; + case AOT_ER_AAC_ELD: + if ((ErrorStatus = EldSpecificConfig_Parse(self, bs, cb)) != + TRANSPORTDEC_OK) { + return (ErrorStatus); + } + frameLengthFlag = self->m_sc.m_eldSpecificConfig.m_frameLengthFlag; + self->m_sbrPresentFlag = self->m_sc.m_eldSpecificConfig.m_sbrPresentFlag; + self->m_extensionSamplingFrequency = + (self->m_sc.m_eldSpecificConfig.m_sbrSamplingRate + 1) * + self->m_samplingFrequency; + break; + case AOT_USAC: + if ((ErrorStatus = UsacConfig_Parse(self, bs, cb)) != TRANSPORTDEC_OK) { + return (ErrorStatus); + } + break; + + default: + return TRANSPORTDEC_UNSUPPORTED_FORMAT; + } + + /* Frame length */ + switch (self->m_aot) { + case AOT_AAC_LC: + case AOT_AAC_SCAL: + case AOT_ER_AAC_LC: + case AOT_ER_AAC_SCAL: + case AOT_ER_BSAC: + /*case AOT_USAC:*/ + if (!frameLengthFlag) + self->m_samplesPerFrame = 1024; + else + self->m_samplesPerFrame = 960; + break; + case AOT_ER_AAC_LD: + if (!frameLengthFlag) + self->m_samplesPerFrame = 512; + else + self->m_samplesPerFrame = 480; + break; + default: + break; + } + + switch (self->m_aot) { + case AOT_ER_AAC_LC: + case AOT_ER_AAC_LD: + case AOT_ER_AAC_ELD: + case AOT_ER_AAC_SCAL: + case AOT_ER_CELP: + case AOT_ER_HVXC: + case AOT_ER_BSAC: + self->m_epConfig = FDKreadBits(bs, 2); + + if (self->m_epConfig > 1) { + return TRANSPORTDEC_UNSUPPORTED_FORMAT; // EPCONFIG; + } + break; + default: + break; + } + + if (fExplicitBackwardCompatible && + (self->m_aot == AOT_AAC_LC || self->m_aot == AOT_ER_AAC_LD || + self->m_aot == AOT_ER_BSAC)) { + ErrorStatus = AudioSpecificConfig_ExtensionParse(self, bs, cb); + } + + /* Copy config() to asc->config[] buffer. */ + if ((ErrorStatus == TRANSPORTDEC_OK) && (self->m_aot == AOT_USAC)) { + INT configSize_bits = (INT)FDKgetValidBits(bs) - (INT)ascStartAnchor; + StoreConfigAsBitstream(bs, configSize_bits, self->config, + TP_USAC_MAX_CONFIG_LEN); + self->configBits = fAbs(configSize_bits); + } + + return (ErrorStatus); +} + +static TRANSPORTDEC_ERROR Drm_xHEAACDecoderConfig( + CSAudioSpecificConfig *asc, HANDLE_FDK_BITSTREAM hBs, int audioMode, + CSTpCallBacks *cb /* use cb == NULL to signal config check only mode */ +) { + TRANSPORTDEC_ERROR ErrorStatus = TRANSPORTDEC_OK; + CSUsacConfig *usc = &asc->m_sc.m_usacConfig; + int elemIdx = 0; + + usc->element[elemIdx].m_stereoConfigIndex = 0; + + usc->m_usacNumElements = 1; /* Currently all extension elements are skipped + -> only one SCE or CPE. */ + + switch (audioMode) { + case 0: /* mono: ID_USAC_SCE */ + usc->element[elemIdx].usacElementType = ID_USAC_SCE; + usc->m_nUsacChannels = 1; + usc->element[elemIdx].m_noiseFilling = FDKreadBits(hBs, 1); + if (usc->m_sbrRatioIndex > 0) { + if (cb == NULL) { + return ErrorStatus; + } + if (cb->cbSbr != NULL) { + usc->element[elemIdx].m_harmonicSBR = FDKreadBit(hBs); + usc->element[elemIdx].m_interTes = FDKreadBit(hBs); + usc->element[elemIdx].m_pvc = FDKreadBit(hBs); + if (cb->cbSbr(cb->cbSbrData, hBs, asc->m_samplingFrequency, + asc->m_extensionSamplingFrequency, + asc->m_samplesPerFrame, asc->m_aot, ID_SCE, elemIdx, + usc->element[elemIdx].m_harmonicSBR, + usc->element[elemIdx].m_stereoConfigIndex, + asc->configMode, &asc->SbrConfigChanged, 1)) { + return ErrorStatus = TRANSPORTDEC_PARSE_ERROR; + } + } + } + break; + case 2: /* stereo: ID_USAC_CPE */ + usc->element[elemIdx].usacElementType = ID_USAC_CPE; + usc->m_nUsacChannels = 2; + usc->element[elemIdx].m_noiseFilling = FDKreadBits(hBs, 1); + if (usc->m_sbrRatioIndex > 0) { + usc->element[elemIdx].m_harmonicSBR = FDKreadBit(hBs); + usc->element[elemIdx].m_interTes = FDKreadBit(hBs); + usc->element[elemIdx].m_pvc = FDKreadBit(hBs); + { + INT bitsToSkip = skipSbrHeader(hBs, 1); + /* read stereoConfigIndex */ + usc->element[elemIdx].m_stereoConfigIndex = FDKreadBits(hBs, 2); + /* rewind */ + FDKpushBack(hBs, bitsToSkip + 2); + } + /* + The application of the following tools is mutually exclusive per audio + stream configuration (see clause 5.3.2, xHE-AAC codec configuration): + - MPS212 parametric stereo tool with residual coding + (stereoConfigIndex>1); and + - QMF based Harmonic Transposer (harmonicSBR==1). + */ + if ((usc->element[elemIdx].m_stereoConfigIndex > 1) && + usc->element[elemIdx].m_harmonicSBR) { + return ErrorStatus = TRANSPORTDEC_PARSE_ERROR; + } + /* + The 4:1 sbrRatio (sbrRatioIndex==1 in [11]) may only be employed: + - in mono operation; or + - in stereo operation if parametric stereo (MPS212) without residual + coding is applied, i.e. if stereoConfigIndex==1 (see clause 5.3.2, + xHE-AAC codec configuration). + */ + if ((usc->m_sbrRatioIndex == 1) && + (usc->element[elemIdx].m_stereoConfigIndex != 1)) { + return ErrorStatus = TRANSPORTDEC_PARSE_ERROR; + } + if (cb == NULL) { + return ErrorStatus; + } + { + MP4_ELEMENT_ID el_type = + (usc->element[elemIdx].m_stereoConfigIndex == 1 || + usc->element[elemIdx].m_stereoConfigIndex == 2) + ? ID_SCE + : ID_CPE; + if (cb->cbSbr == NULL) return ErrorStatus = TRANSPORTDEC_UNKOWN_ERROR; + if (cb->cbSbr(cb->cbSbrData, hBs, asc->m_samplingFrequency, + asc->m_extensionSamplingFrequency, + asc->m_samplesPerFrame, asc->m_aot, el_type, elemIdx, + usc->element[elemIdx].m_harmonicSBR, + usc->element[elemIdx].m_stereoConfigIndex, + asc->configMode, &asc->SbrConfigChanged, 1)) { + return ErrorStatus = TRANSPORTDEC_PARSE_ERROR; + } + } + /*usc->element[elemIdx].m_stereoConfigIndex =*/FDKreadBits(hBs, 2); + if (usc->element[elemIdx].m_stereoConfigIndex > 0) { + if (cb->cbSsc != NULL) { + int samplesPerFrame = asc->m_samplesPerFrame; + + if (usc->m_sbrRatioIndex == 1) samplesPerFrame <<= 2; + if (usc->m_sbrRatioIndex == 2) + samplesPerFrame = (samplesPerFrame * 8) / 3; + if (usc->m_sbrRatioIndex == 3) samplesPerFrame <<= 1; + + ErrorStatus = (TRANSPORTDEC_ERROR)cb->cbSsc( + cb->cbSscData, hBs, + AOT_DRM_USAC, /* syntax differs from MPEG Mps212Config() */ + asc->m_extensionSamplingFrequency, samplesPerFrame, + usc->element[elemIdx].m_stereoConfigIndex, + usc->m_coreSbrFrameLengthIndex, 0, /* don't know the length */ + asc->configMode, &asc->SacConfigChanged); + } else { + /* ErrorStatus = TRANSPORTDEC_UNSUPPORTED_FORMAT; */ + } + } + } + break; + default: + return TRANSPORTDEC_PARSE_ERROR; + } + + return ErrorStatus; +} + +TRANSPORTDEC_ERROR Drm_xHEAACStaticConfig( + CSAudioSpecificConfig *asc, HANDLE_FDK_BITSTREAM bs, int audioMode, + CSTpCallBacks *cb /* use cb == NULL to signal config check only mode */ +) { + int coreSbrFrameLengthIndexDrm = FDKreadBits(bs, 2); + if (UsacConfig_SetCoreSbrFrameLengthIndex( + asc, coreSbrFrameLengthIndexDrm + 1) != TRANSPORTDEC_OK) { + return TRANSPORTDEC_PARSE_ERROR; + } + + asc->m_channelConfiguration = (audioMode) ? 2 : 1; + + if (Drm_xHEAACDecoderConfig(asc, bs, audioMode, cb) != TRANSPORTDEC_OK) { + return TRANSPORTDEC_PARSE_ERROR; + } + + return TRANSPORTDEC_OK; +} + +/* Mapping of DRM audio sampling rate field to MPEG usacSamplingFrequencyIndex + */ +const UCHAR mapSr2MPEGIdx[8] = { + 0x1b, /* 9.6 kHz */ + 0x09, /* 12.0 kHz */ + 0x08, /* 16.0 kHz */ + 0x17, /* 19.2 kHz */ + 0x06, /* 24.0 kHz */ + 0x05, /* 32.0 kHz */ + 0x12, /* 38.4 kHz */ + 0x03 /* 48.0 kHz */ +}; + +TRANSPORTDEC_ERROR DrmRawSdcAudioConfig_Parse( + CSAudioSpecificConfig *self, HANDLE_FDK_BITSTREAM bs, + CSTpCallBacks *cb, /* use cb == NULL to signal config check only mode */ + UCHAR configMode, UCHAR configChanged) { + TRANSPORTDEC_ERROR ErrorStatus = TRANSPORTDEC_OK; + + AudioSpecificConfig_Init(self); + + if ((INT)FDKgetValidBits(bs) < 16) { + ErrorStatus = TRANSPORTDEC_PARSE_ERROR; + goto bail; + } else { + /* DRM - Audio information data entity - type 9 + - Short Id 2 bits (not part of the config buffer) + - Stream Id 2 bits (not part of the config buffer) + - audio coding 2 bits + - SBR flag 1 bit + - audio mode 2 bits + - audio sampling rate 3 bits + - text flag 1 bit + - enhancement flag 1 bit + - coder field 5 bits + - rfa 1 bit */ + + int audioCoding, audioMode, cSamplingFreq, coderField, sfIdx, sbrFlag; + + self->configMode = configMode; + self->AacConfigChanged = configChanged; + self->SbrConfigChanged = configChanged; + self->SacConfigChanged = configChanged; + + /* Read the SDC field */ + audioCoding = FDKreadBits(bs, 2); + sbrFlag = FDKreadBits(bs, 1); + audioMode = FDKreadBits(bs, 2); + cSamplingFreq = FDKreadBits(bs, 3); /* audio sampling rate */ + + FDKreadBits(bs, 2); /* Text and enhancement flag */ + coderField = FDKreadBits(bs, 5); + FDKreadBits(bs, 1); /* rfa */ + + /* Evaluate configuration and fill the ASC */ + if (audioCoding == 3) { + sfIdx = (int)mapSr2MPEGIdx[cSamplingFreq]; + sbrFlag = 0; /* rfa */ + } else { + switch (cSamplingFreq) { + case 0: /* 8 kHz */ + sfIdx = 11; + break; + case 1: /* 12 kHz */ + sfIdx = 9; + break; + case 2: /* 16 kHz */ + sfIdx = 8; + break; + case 3: /* 24 kHz */ + sfIdx = 6; + break; + case 5: /* 48 kHz */ + sfIdx = 3; + break; + case 4: /* reserved */ + case 6: /* reserved */ + case 7: /* reserved */ + default: + ErrorStatus = TRANSPORTDEC_PARSE_ERROR; + goto bail; + } + } + + self->m_samplingFrequencyIndex = sfIdx; + self->m_samplingFrequency = SamplingRateTable[sfIdx]; + + if (sbrFlag) { + UINT i; + int tmp = -1; + self->m_sbrPresentFlag = 1; + self->m_extensionAudioObjectType = AOT_SBR; + self->m_extensionSamplingFrequency = self->m_samplingFrequency << 1; + for (i = 0; + i < (sizeof(SamplingRateTable) / sizeof(SamplingRateTable[0])); + i++) { + if (SamplingRateTable[i] == self->m_extensionSamplingFrequency) { + tmp = i; + break; + } + } + self->m_extensionSamplingFrequencyIndex = tmp; + } + + switch (audioCoding) { + case 0: /* AAC */ + if ((coderField >> 2) && (audioMode != 1)) { + self->m_aot = AOT_DRM_SURROUND; /* Set pseudo AOT for Drm Surround */ + } else { + self->m_aot = AOT_DRM_AAC; /* Set pseudo AOT for Drm AAC */ + } + switch (audioMode) { + case 1: /* parametric stereo */ + self->m_psPresentFlag = 1; + FDK_FALLTHROUGH; + case 0: /* mono */ + self->m_channelConfiguration = 1; + break; + case 2: /* stereo */ + self->m_channelConfiguration = 2; + break; + default: + ErrorStatus = TRANSPORTDEC_PARSE_ERROR; + goto bail; + } + self->m_vcb11Flag = 1; + self->m_hcrFlag = 1; + self->m_samplesPerFrame = 960; + self->m_epConfig = 1; + break; + case 1: /* CELP */ + self->m_aot = AOT_ER_CELP; + self->m_channelConfiguration = 1; + break; + case 2: /* HVXC */ + self->m_aot = AOT_ER_HVXC; + self->m_channelConfiguration = 1; + break; + case 3: /* xHE-AAC */ + { + /* payload is MPEG conform -> no pseudo DRM AOT needed */ + self->m_aot = AOT_USAC; + } + switch (audioMode) { + case 0: /* mono */ + case 2: /* stereo */ + /* codec specific config 8n bits */ + ErrorStatus = Drm_xHEAACStaticConfig(self, bs, audioMode, cb); + break; + default: + ErrorStatus = TRANSPORTDEC_PARSE_ERROR; + goto bail; + } + break; + default: + ErrorStatus = TRANSPORTDEC_PARSE_ERROR; + self->m_aot = AOT_NONE; + break; + } + + if (self->m_psPresentFlag && !self->m_sbrPresentFlag) { + ErrorStatus = TRANSPORTDEC_PARSE_ERROR; + goto bail; + } + } + +bail: + return (ErrorStatus); +} diff --git a/fdk-aac/libMpegTPDec/src/tpdec_drm.cpp b/fdk-aac/libMpegTPDec/src/tpdec_drm.cpp new file mode 100644 index 0000000..27c1c1d --- /dev/null +++ b/fdk-aac/libMpegTPDec/src/tpdec_drm.cpp @@ -0,0 +1,148 @@ +/* ----------------------------------------------------------------------------- +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): Christian Griebel + + Description: DRM transport stuff + +*******************************************************************************/ + +#include "tpdec_drm.h" + +#include "FDK_bitstream.h" + +void drmRead_CrcInit(HANDLE_DRM pDrm) /*!< pointer to drm crc info stucture */ +{ + FDK_ASSERT(pDrm != NULL); + + FDKcrcInit(&pDrm->crcInfo, 0x001d, 0xFFFF, 8); +} + +int drmRead_CrcStartReg( + HANDLE_DRM pDrm, /*!< pointer to drm stucture */ + HANDLE_FDK_BITSTREAM hBs, /*!< handle to current bit buffer structure */ + int mBits /*!< number of bits in crc region */ +) { + FDK_ASSERT(pDrm != NULL); + + FDKcrcReset(&pDrm->crcInfo); + + pDrm->crcReadValue = FDKreadBits(hBs, 8); + + return (FDKcrcStartReg(&pDrm->crcInfo, hBs, mBits)); +} + +void drmRead_CrcEndReg( + HANDLE_DRM pDrm, /*!< pointer to drm crc info stucture */ + HANDLE_FDK_BITSTREAM hBs, /*!< handle to current bit buffer structure */ + int reg /*!< crc region */ +) { + FDK_ASSERT(pDrm != NULL); + + FDKcrcEndReg(&pDrm->crcInfo, hBs, reg); +} + +TRANSPORTDEC_ERROR drmRead_CrcCheck(HANDLE_DRM pDrm) { + TRANSPORTDEC_ERROR ErrorStatus = TRANSPORTDEC_OK; + USHORT crc; + + crc = FDKcrcGetCRC(&pDrm->crcInfo) ^ 0xFF; + if (crc != pDrm->crcReadValue) { + return (TRANSPORTDEC_CRC_ERROR); + } + + return (ErrorStatus); +} diff --git a/fdk-aac/libMpegTPDec/src/tpdec_drm.h b/fdk-aac/libMpegTPDec/src/tpdec_drm.h new file mode 100644 index 0000000..09822dc --- /dev/null +++ b/fdk-aac/libMpegTPDec/src/tpdec_drm.h @@ -0,0 +1,202 @@ +/* ----------------------------------------------------------------------------- +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): Josef Hoepfl + + Description: DRM interface + +*******************************************************************************/ + +#ifndef TPDEC_DRM_H +#define TPDEC_DRM_H + +#include "tpdec_lib.h" + +#include "FDK_crc.h" + +typedef struct { + FDK_CRCINFO crcInfo; /* CRC state info */ + USHORT crcReadValue; /* CRC value read from bitstream data */ + +} STRUCT_DRM; + +typedef STRUCT_DRM *HANDLE_DRM; + +/*! + \brief Initialize DRM CRC + + The function initialzes the crc buffer and the crc lookup table. + + \return none +*/ +void drmRead_CrcInit(HANDLE_DRM pDrm); + +/** + * \brief Starts CRC region with a maximum number of bits + * If mBits is positive zero padding will be used for CRC calculation, if + * there are less than mBits bits available. If mBits is negative no zero + * padding is done. If mBits is zero the memory for the buffer is + * allocated dynamically, the number of bits is not limited. + * + * \param pDrm DRM data handle + * \param hBs bitstream handle, on which the CRC region referes to + * \param mBits max number of bits in crc region to be considered + * + * \return ID for the created region, -1 in case of an error + */ +int drmRead_CrcStartReg(HANDLE_DRM pDrm, HANDLE_FDK_BITSTREAM hBs, int mBits); + +/** + * \brief Ends CRC region identified by reg + * + * \param pDrm DRM data handle + * \param hBs bitstream handle, on which the CRC region referes to + * \param reg CRC regions ID returned by drmRead_CrcStartReg() + * + * \return none + */ +void drmRead_CrcEndReg(HANDLE_DRM pDrm, HANDLE_FDK_BITSTREAM hBs, int reg); + +/** + * \brief Check CRC + * + * Checks if the currently calculated CRC matches the CRC field read from the + * bitstream Deletes all CRC regions. + * + * \param pDrm DRM data handle + * + * \return Returns 0 if they are identical otherwise 1 + */ +TRANSPORTDEC_ERROR drmRead_CrcCheck(HANDLE_DRM pDrm); + +/** + * \brief Check if we have a valid DRM frame at the current bitbuffer position + * + * This function assumes enough bits in buffer for the current frame. + * It reads out the header bits to prepare the bitbuffer for the decode loop. + * In case the header bits show an invalid bitstream/frame, the whole frame is + * skipped. + * + * \param pDrm DRM data handle which is filled with parsed DRM header data + * \param bs handle of bitstream from whom the DRM header is read + * + * \return error status + */ +TRANSPORTDEC_ERROR drmRead_DecodeHeader(HANDLE_DRM pDrm, + HANDLE_FDK_BITSTREAM bs); + +/** + * \brief Parse a Drm specific SDC audio config from a given bitstream handle. + * + * \param pAsc A pointer to an allocated + * CSAudioSpecificConfig struct. + * \param hBs Bitstream handle. + * \param cb A pointer to structure holding callback + * information Note: A NULL pointer for cb can be used to signal a "Check Config + * only functionality" + * \param configMode Config modes: memory allocation mode or + * config change detection mode + * \param configChanged Indicates a config change + * + * \return Total element count including all SCE, CPE and LFE. + */ +TRANSPORTDEC_ERROR DrmRawSdcAudioConfig_Parse(CSAudioSpecificConfig *pAsc, + HANDLE_FDK_BITSTREAM hBs, + CSTpCallBacks *cb, + const UCHAR configMode, + const UCHAR configChanged); + +#endif /* TPDEC_DRM_H */ 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; +} diff --git a/fdk-aac/libMpegTPDec/src/tpdec_latm.h b/fdk-aac/libMpegTPDec/src/tpdec_latm.h new file mode 100644 index 0000000..6af553d --- /dev/null +++ b/fdk-aac/libMpegTPDec/src/tpdec_latm.h @@ -0,0 +1,191 @@ +/* ----------------------------------------------------------------------------- +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: + +*******************************************************************************/ + +#ifndef TPDEC_LATM_H +#define TPDEC_LATM_H + +#include "tpdec_lib.h" + +#include "FDK_bitstream.h" + +#define MIN_LATM_HEADERLENGTH 9 +#define MIN_LOAS_HEADERLENGTH MIN_LATM_HEADERLENGTH + 24 /* both in bits */ +#define MIN_TP_BUF_SIZE_LOAS (8194) + +enum { + LATM_MAX_PROG = 1, + LATM_MAX_LAYER = 1, + LATM_MAX_VAR_CHUNKS = 16, + LATM_MAX_ID = 16 +}; + +typedef struct { + UINT m_frameLengthType; + UINT m_bufferFullness; + UINT m_streamID; + UINT m_frameLengthInBits; +} LATM_LAYER_INFO; + +typedef struct { + LATM_LAYER_INFO m_linfo[LATM_MAX_PROG][LATM_MAX_LAYER]; + UINT m_taraBufferFullness; + UINT m_otherDataLength; + UINT m_audioMuxLengthBytes; /* Length of LOAS payload */ + + UCHAR m_useSameStreamMux; + UCHAR m_AudioMuxVersion; + UCHAR m_AudioMuxVersionA; + UCHAR m_allStreamsSameTimeFraming; + UCHAR m_noSubFrames; + UCHAR m_numProgram; + UCHAR m_numLayer[LATM_MAX_PROG]; + + UCHAR m_otherDataPresent; + UCHAR m_crcCheckPresent; + + SCHAR BufferFullnessAchieved; + UCHAR + usacExplicitCfgChanged; /* explicit config in case of USAC and LOAS/LATM + must be compared to IPF cfg */ + UCHAR applyAsc; /* apply ASC immediate without flushing */ + UCHAR newCfgHasAudioPreRoll; /* the new (dummy parsed) config has an + AudioPreRoll */ +} CLatmDemux; + +int CLatmDemux_ReadAuChunkLengthInfo(HANDLE_FDK_BITSTREAM bs); + +TRANSPORTDEC_ERROR CLatmDemux_Read(HANDLE_FDK_BITSTREAM bs, + CLatmDemux *pLatmDemux, TRANSPORT_TYPE tt, + CSTpCallBacks *pTpDecCallbacks, + CSAudioSpecificConfig *pAsc, + int *pfConfigFound, + const INT ignoreBufferFullness); + +/** + * \brief Read StreamMuxConfig + * \param bs bit stream handle as data source + * \param pLatmDemux pointer to CLatmDemux struct of current LATM context + * \param pTpDecCallbacks Call back structure for configuration callbacks + * \param pAsc pointer to a ASC for configuration storage + * \param pfConfigFound pointer to a flag which is set to 1 if a configuration + * was found and processed successfully + * \param configMode Config modes: memory allocation mode or config change + * detection mode + * \param configChanged Indicates a config change + * \return error code + */ +TRANSPORTDEC_ERROR CLatmDemux_ReadStreamMuxConfig( + HANDLE_FDK_BITSTREAM bs, CLatmDemux *pLatmDemux, + CSTpCallBacks *pTpDecCallbacks, CSAudioSpecificConfig *pAsc, + int *pfConfigFound, UCHAR configMode, UCHAR configChanged); + +TRANSPORTDEC_ERROR CLatmDemux_ReadPayloadLengthInfo(HANDLE_FDK_BITSTREAM bs, + CLatmDemux *pLatmDemux); + +UINT CLatmDemux_GetFrameLengthInBits(CLatmDemux *pLatmDemux, const UINT prog, + const UINT layer); +UINT CLatmDemux_GetOtherDataPresentFlag(CLatmDemux *pLatmDemux); +UINT CLatmDemux_GetOtherDataLength(CLatmDemux *pLatmDemux); +UINT CLatmDemux_GetNrOfSubFrames(CLatmDemux *pLatmDemux); +UINT CLatmDemux_GetNrOfLayers(CLatmDemux *pLatmDemux, const UINT program); + +#endif /* TPDEC_LATM_H */ diff --git a/fdk-aac/libMpegTPDec/src/tpdec_lib.cpp b/fdk-aac/libMpegTPDec/src/tpdec_lib.cpp new file mode 100644 index 0000000..1976cb9 --- /dev/null +++ b/fdk-aac/libMpegTPDec/src/tpdec_lib.cpp @@ -0,0 +1,1820 @@ +/* ----------------------------------------------------------------------------- +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): Manuel Jander + + Description: MPEG Transport decoder + +*******************************************************************************/ + +#include "tpdec_lib.h" + +/* library version */ +#include "tp_version.h" + +#include "tp_data.h" + +#include "tpdec_adts.h" + +#include "tpdec_adif.h" + +#include "tpdec_latm.h" + +#include "tpdec_drm.h" + +#include "FDK_crc.h" + +#define MODULE_NAME "transportDec" + +typedef union { + STRUCT_ADTS adts; + + CAdifHeader adif; + + CLatmDemux latm; + + STRUCT_DRM drm; + +} transportdec_parser_t; + +#define MHAS_CONFIG_PRESENT 0x001 +#define MHAS_UI_PRESENT 0x002 + +struct TRANSPORTDEC { + TRANSPORT_TYPE transportFmt; /*!< MPEG4 transportDec type. */ + + CSTpCallBacks callbacks; /*!< Struct holding callback and its data */ + + FDK_BITSTREAM bitStream[1]; /* Bitstream reader */ + UCHAR *bsBuffer; /* Internal bitstreamd data buffer */ + + transportdec_parser_t parser; /* Format specific parser structs. */ + + CSAudioSpecificConfig asc[(1 * 1) + 1]; /* Audio specific config from the last + config found. One additional + CSAudioSpecificConfig is used + temporarily for parsing. */ + CCtrlCFGChange ctrlCFGChange[(1 * 1)]; /* Controls config change */ + + UINT globalFramePos; /* Global transport frame reference bit position. */ + UINT accessUnitAnchor[1]; /* Current access unit start bit position. */ + INT auLength[1]; /* Length of current access unit. */ + INT numberOfRawDataBlocks; /* Current number of raw data blocks contained + remaining from the current transport frame. */ + UINT avgBitRate; /* Average bit rate used for frame loss estimation. */ + UINT lastValidBufferFullness; /* Last valid buffer fullness value for frame + loss estimation */ + INT remainder; /* Reminder in division during lost access unit estimation. */ + INT missingAccessUnits; /* Estimated missing access units. */ + UINT burstPeriod; /* Data burst period in mili seconds. */ + UINT holdOffFrames; /* Amount of frames that were already hold off due to + buffer fullness condition not being met. */ + UINT flags; /* Flags. */ + INT targetLayout; /* CICP target layout. */ + UINT *pLoudnessInfoSetPosition; /* Reference and start position (bits) and + length (bytes) of loudnessInfoSet within + rsv603daConfig. */ +}; + +/* Flag bitmasks for "flags" member of struct TRANSPORTDEC */ +#define TPDEC_SYNCOK 1 +#define TPDEC_MINIMIZE_DELAY 2 +#define TPDEC_IGNORE_BUFFERFULLNESS 4 +#define TPDEC_EARLY_CONFIG 8 +#define TPDEC_LOST_FRAMES_PENDING 16 +#define TPDEC_CONFIG_FOUND 32 +#define TPDEC_USE_ELEM_SKIPPING 64 + +/* force config/content change */ +#define TPDEC_FORCE_CONFIG_CHANGE 1 +#define TPDEC_FORCE_CONTENT_CHANGE 2 + +/* skip packet */ +#define TPDEC_SKIP_PACKET 1 + +C_ALLOC_MEM(Ram_TransportDecoder, struct TRANSPORTDEC, 1) +C_ALLOC_MEM(Ram_TransportDecoderBuffer, UCHAR, (8192 * 4)) + +HANDLE_TRANSPORTDEC transportDec_Open(const TRANSPORT_TYPE transportFmt, + const UINT flags, const UINT nrOfLayers) { + HANDLE_TRANSPORTDEC hInput; + + hInput = GetRam_TransportDecoder(0); + if (hInput == NULL) { + return NULL; + } + + /* Init transportDec struct. */ + hInput->transportFmt = transportFmt; + + switch (transportFmt) { + case TT_MP4_ADIF: + break; + + case TT_MP4_ADTS: + if (flags & TP_FLAG_MPEG4) + hInput->parser.adts.decoderCanDoMpeg4 = 1; + else + hInput->parser.adts.decoderCanDoMpeg4 = 0; + adtsRead_CrcInit(&hInput->parser.adts); + hInput->parser.adts.BufferFullnesStartFlag = 1; + hInput->numberOfRawDataBlocks = 0; + break; + + case TT_DRM: + drmRead_CrcInit(&hInput->parser.drm); + break; + + case TT_MP4_LATM_MCP0: + case TT_MP4_LATM_MCP1: + hInput->parser.latm.usacExplicitCfgChanged = 0; + hInput->parser.latm.applyAsc = 1; + break; + case TT_MP4_LOAS: + hInput->parser.latm.usacExplicitCfgChanged = 0; + hInput->parser.latm.applyAsc = 1; + break; + case TT_MP4_RAW: + break; + + default: + FreeRam_TransportDecoder(&hInput); + hInput = NULL; + break; + } + + if (hInput != NULL) { + /* Create bitstream */ + { + hInput->bsBuffer = GetRam_TransportDecoderBuffer(0); + if (hInput->bsBuffer == NULL) { + transportDec_Close(&hInput); + return NULL; + } + if (nrOfLayers > 1) { + transportDec_Close(&hInput); + return NULL; + } + for (UINT i = 0; i < nrOfLayers; i++) { + FDKinitBitStream(&hInput->bitStream[i], hInput->bsBuffer, (8192 * 4), 0, + BS_READER); + } + } + hInput->burstPeriod = 0; + } + + return hInput; +} + +TRANSPORTDEC_ERROR transportDec_OutOfBandConfig(HANDLE_TRANSPORTDEC hTp, + UCHAR *conf, const UINT length, + UINT layer) { + int i; + + TRANSPORTDEC_ERROR err = TRANSPORTDEC_OK; + + FDK_BITSTREAM bs; + HANDLE_FDK_BITSTREAM hBs = &bs; + + int fConfigFound = 0; + + UCHAR configChanged = 0; + UCHAR configMode = AC_CM_DET_CFG_CHANGE; + + UCHAR tmpConf[1024]; + if (length > 1024) { + return TRANSPORTDEC_UNSUPPORTED_FORMAT; + } + FDKmemcpy(tmpConf, conf, length); + FDKinitBitStream(hBs, tmpConf, 1024, length << 3, BS_READER); + + for (i = 0; i < 2; i++) { + if (i > 0) { + FDKpushBack(hBs, (INT)length * 8 - (INT)FDKgetValidBits(hBs)); + configMode = AC_CM_ALLOC_MEM; + } + + /* config transport decoder */ + switch (hTp->transportFmt) { + case TT_MP4_LATM_MCP0: + case TT_MP4_LATM_MCP1: + case TT_MP4_LOAS: { + if (layer != 0) { + return TRANSPORTDEC_INVALID_PARAMETER; + } + CLatmDemux *pLatmDemux = &hTp->parser.latm; + err = CLatmDemux_ReadStreamMuxConfig(hBs, pLatmDemux, &hTp->callbacks, + hTp->asc, &fConfigFound, + configMode, configChanged); + if (err != TRANSPORTDEC_OK) { + return err; + } + } break; + default: + fConfigFound = 1; + err = AudioSpecificConfig_Parse(&hTp->asc[(1 * 1)], hBs, 1, + &hTp->callbacks, configMode, + configChanged, AOT_NULL_OBJECT); + if (err == TRANSPORTDEC_OK) { + int errC; + + hTp->asc[layer] = hTp->asc[(1 * 1)]; + errC = hTp->callbacks.cbUpdateConfig( + hTp->callbacks.cbUpdateConfigData, &hTp->asc[layer], + hTp->asc[layer].configMode, &hTp->asc[layer].AacConfigChanged); + if (errC != 0) { + err = TRANSPORTDEC_PARSE_ERROR; + } + } + break; + case TT_DRM: + fConfigFound = 1; + err = DrmRawSdcAudioConfig_Parse(&hTp->asc[layer], hBs, &hTp->callbacks, + configMode, configChanged); + if (err == TRANSPORTDEC_OK) { + int errC; + + errC = hTp->callbacks.cbUpdateConfig( + hTp->callbacks.cbUpdateConfigData, &hTp->asc[layer], + hTp->asc[layer].configMode, &hTp->asc[layer].AacConfigChanged); + if (errC != 0) { + err = TRANSPORTDEC_PARSE_ERROR; + } + } + break; + } + + if (err == TRANSPORTDEC_OK) { + if ((i == 0) && (hTp->asc[layer].AacConfigChanged || + hTp->asc[layer].SbrConfigChanged || + hTp->asc[layer].SacConfigChanged)) { + int errC; + + configChanged = 1; + errC = hTp->callbacks.cbFreeMem(hTp->callbacks.cbFreeMemData, + &hTp->asc[layer]); + if (errC != 0) { + err = TRANSPORTDEC_PARSE_ERROR; + } + } + } + } + + if (err == TRANSPORTDEC_OK && fConfigFound) { + hTp->flags |= TPDEC_CONFIG_FOUND; + } + + return err; +} + +TRANSPORTDEC_ERROR transportDec_InBandConfig(HANDLE_TRANSPORTDEC hTp, + UCHAR *newConfig, + const UINT newConfigLength, + const UCHAR buildUpStatus, + UCHAR *configChanged, UINT layer, + UCHAR *implicitExplicitCfgDiff) { + int errC; + FDK_BITSTREAM bs; + HANDLE_FDK_BITSTREAM hBs = &bs; + TRANSPORTDEC_ERROR err = TRANSPORTDEC_OK; + int fConfigFound = 0; + UCHAR configMode = AC_CM_ALLOC_MEM; + *implicitExplicitCfgDiff = 0; + + FDK_ASSERT(hTp->asc->m_aot == AOT_USAC); + + FDKinitBitStream(hBs, newConfig, TP_USAC_MAX_CONFIG_LEN, newConfigLength << 3, + BS_READER); + + if ((hTp->ctrlCFGChange[layer].flushStatus == TPDEC_FLUSH_OFF) && + (hTp->ctrlCFGChange[layer].buildUpStatus != + TPDEC_RSV60_BUILD_UP_IDLE_IN_BAND)) { + if (hTp->asc->m_aot == AOT_USAC) { + if ((UINT)(hTp->asc->m_sc.m_usacConfig.UsacConfigBits + 7) >> 3 == + newConfigLength) { + if (0 == FDKmemcmp(newConfig, hTp->asc->m_sc.m_usacConfig.UsacConfig, + newConfigLength)) { + if (hTp->parser.latm.usacExplicitCfgChanged) { /* configChange from + LOAS/LATM parser */ + hTp->parser.latm.usacExplicitCfgChanged = 0; + hTp->ctrlCFGChange[layer].flushCnt = 0; + hTp->ctrlCFGChange[layer].flushStatus = + TPDEC_USAC_DASH_IPF_FLUSH_ON; + hTp->ctrlCFGChange[layer].buildUpCnt = 0; + hTp->ctrlCFGChange[layer].buildUpStatus = TPDEC_BUILD_UP_OFF; + } else { + *configChanged = 0; + return err; + } + } else { + *implicitExplicitCfgDiff = 1; + } + } else { + *implicitExplicitCfgDiff = 1; + } + /* ISO/IEC 23003-3:2012/FDAM 3:2016(E) Annex F.2: explicit and implicit + * config shall be identical. */ + if (*implicitExplicitCfgDiff) { + switch (hTp->transportFmt) { + case TT_MP4_LATM_MCP0: + case TT_MP4_LATM_MCP1: + case TT_MP4_LOAS: + /* reset decoder to initial state to achieve definite behavior after + * error in config */ + hTp->callbacks.cbFreeMem(hTp->callbacks.cbFreeMemData, + &hTp->asc[layer]); + hTp->parser.latm.usacExplicitCfgChanged = 0; + hTp->parser.latm.applyAsc = 1; + err = TRANSPORTDEC_PARSE_ERROR; + goto bail; + default: + break; + } + } + } + } + + { + if ((hTp->ctrlCFGChange[layer].flushStatus == TPDEC_FLUSH_OFF) && + (hTp->ctrlCFGChange[layer].buildUpStatus != + TPDEC_RSV60_BUILD_UP_IDLE_IN_BAND)) { + hTp->ctrlCFGChange[layer].flushCnt = 0; + hTp->ctrlCFGChange[layer].buildUpCnt = 0; + hTp->ctrlCFGChange[layer].buildUpStatus = TPDEC_BUILD_UP_OFF; + if (hTp->asc->m_aot == AOT_USAC) { + hTp->ctrlCFGChange[layer].flushStatus = TPDEC_USAC_DASH_IPF_FLUSH_ON; + } + } + + if ((hTp->ctrlCFGChange[layer].flushStatus == + TPDEC_RSV60_DASH_IPF_ATSC_FLUSH_ON) || + (hTp->ctrlCFGChange[layer].flushStatus == + TPDEC_USAC_DASH_IPF_FLUSH_ON)) { + SCHAR counter = 0; + if (hTp->asc->m_aot == AOT_USAC) { + counter = TPDEC_USAC_NUM_CONFIG_CHANGE_FRAMES; + } + if (hTp->ctrlCFGChange[layer].flushCnt >= counter) { + hTp->ctrlCFGChange[layer].flushCnt = 0; + hTp->ctrlCFGChange[layer].flushStatus = TPDEC_FLUSH_OFF; + hTp->ctrlCFGChange[layer].forceCfgChange = 0; + if (hTp->asc->m_aot == AOT_USAC) { + hTp->ctrlCFGChange[layer].buildUpCnt = + TPDEC_USAC_NUM_CONFIG_CHANGE_FRAMES - 1; + hTp->ctrlCFGChange[layer].buildUpStatus = TPDEC_USAC_BUILD_UP_ON; + } + } + + /* Activate flush mode. After that continue with build up mode in core */ + if (hTp->callbacks.cbCtrlCFGChange(hTp->callbacks.cbCtrlCFGChangeData, + &hTp->ctrlCFGChange[layer]) != 0) { + err = TRANSPORTDEC_PARSE_ERROR; + } + + if ((hTp->ctrlCFGChange[layer].flushStatus == + TPDEC_RSV60_DASH_IPF_ATSC_FLUSH_ON) || + (hTp->ctrlCFGChange[layer].flushStatus == + TPDEC_USAC_DASH_IPF_FLUSH_ON)) { + hTp->ctrlCFGChange[layer].flushCnt++; + return err; + } + } + + if (hTp->asc->m_aot == AOT_USAC) { + fConfigFound = 1; + + if (err == TRANSPORTDEC_OK) { + *configChanged = 0; + configMode = AC_CM_DET_CFG_CHANGE; + + for (int i = 0; i < 2; i++) { + if (i > 0) { + FDKpushBack(hBs, newConfigLength * 8 - FDKgetValidBits(hBs)); + configMode = AC_CM_ALLOC_MEM; + } + /* config transport decoder */ + err = AudioSpecificConfig_Parse( + &hTp->asc[(1 * 1)], hBs, 0, &hTp->callbacks, configMode, + *configChanged, hTp->asc[layer].m_aot); + if (err == TRANSPORTDEC_OK) { + hTp->asc[layer] = hTp->asc[(1 * 1)]; + errC = hTp->callbacks.cbUpdateConfig( + hTp->callbacks.cbUpdateConfigData, &hTp->asc[layer], + hTp->asc[layer].configMode, &hTp->asc[layer].AacConfigChanged); + if (errC != 0) { + err = TRANSPORTDEC_PARSE_ERROR; + } + } + + if (err == TRANSPORTDEC_OK) { + if ((i == 0) && (hTp->asc[layer].AacConfigChanged || + hTp->asc[layer].SbrConfigChanged || + hTp->asc[layer].SacConfigChanged)) { + *configChanged = 1; + errC = hTp->callbacks.cbFreeMem(hTp->callbacks.cbFreeMemData, + &hTp->asc[layer]); + if (errC != 0) { + err = TRANSPORTDEC_PARSE_ERROR; + } + } + } + + /* if an error is detected terminate config parsing to avoid that an + * invalid config is accepted in the second pass */ + if (err != TRANSPORTDEC_OK) { + break; + } + } + } + } + + bail: + /* save new config */ + if (err == TRANSPORTDEC_OK) { + if (hTp->asc->m_aot == AOT_USAC) { + hTp->asc->m_sc.m_usacConfig.UsacConfigBits = newConfigLength << 3; + FDKmemcpy(hTp->asc->m_sc.m_usacConfig.UsacConfig, newConfig, + newConfigLength); + /* in case of USAC reset transportDecoder variables here because + * otherwise without IPF they are not reset */ + hTp->ctrlCFGChange[layer].flushCnt = 0; + hTp->ctrlCFGChange[layer].flushStatus = TPDEC_FLUSH_OFF; + hTp->ctrlCFGChange[layer].buildUpCnt = 0; + hTp->ctrlCFGChange[layer].buildUpStatus = TPDEC_BUILD_UP_OFF; + } + } else { + hTp->numberOfRawDataBlocks = 0; + + /* If parsing error while config found, clear ctrlCFGChange-struct */ + hTp->ctrlCFGChange[layer].flushCnt = 0; + hTp->ctrlCFGChange[layer].flushStatus = TPDEC_FLUSH_OFF; + hTp->ctrlCFGChange[layer].buildUpCnt = 0; + hTp->ctrlCFGChange[layer].buildUpStatus = TPDEC_BUILD_UP_OFF; + hTp->ctrlCFGChange[layer].cfgChanged = 0; + hTp->ctrlCFGChange[layer].contentChanged = 0; + hTp->ctrlCFGChange[layer].forceCfgChange = 0; + + hTp->callbacks.cbCtrlCFGChange(hTp->callbacks.cbCtrlCFGChangeData, + &hTp->ctrlCFGChange[layer]); + } + } + + if (err == TRANSPORTDEC_OK && fConfigFound) { + hTp->flags |= TPDEC_CONFIG_FOUND; + } + + return err; +} + +int transportDec_RegisterAscCallback(HANDLE_TRANSPORTDEC hTpDec, + const cbUpdateConfig_t cbUpdateConfig, + void *user_data) { + if (hTpDec == NULL) { + return -1; + } + hTpDec->callbacks.cbUpdateConfig = cbUpdateConfig; + hTpDec->callbacks.cbUpdateConfigData = user_data; + return 0; +} + +int transportDec_RegisterFreeMemCallback(HANDLE_TRANSPORTDEC hTpDec, + const cbFreeMem_t cbFreeMem, + void *user_data) { + if (hTpDec == NULL) { + return -1; + } + hTpDec->callbacks.cbFreeMem = cbFreeMem; + hTpDec->callbacks.cbFreeMemData = user_data; + return 0; +} + +int transportDec_RegisterCtrlCFGChangeCallback( + HANDLE_TRANSPORTDEC hTpDec, const cbCtrlCFGChange_t cbCtrlCFGChange, + void *user_data) { + if (hTpDec == NULL) { + return -1; + } + hTpDec->callbacks.cbCtrlCFGChange = cbCtrlCFGChange; + hTpDec->callbacks.cbCtrlCFGChangeData = user_data; + return 0; +} + +int transportDec_RegisterSscCallback(HANDLE_TRANSPORTDEC hTpDec, + const cbSsc_t cbSsc, void *user_data) { + if (hTpDec == NULL) { + return -1; + } + hTpDec->callbacks.cbSsc = cbSsc; + hTpDec->callbacks.cbSscData = user_data; + return 0; +} + +int transportDec_RegisterSbrCallback(HANDLE_TRANSPORTDEC hTpDec, + const cbSbr_t cbSbr, void *user_data) { + if (hTpDec == NULL) { + return -1; + } + hTpDec->callbacks.cbSbr = cbSbr; + hTpDec->callbacks.cbSbrData = user_data; + return 0; +} + +int transportDec_RegisterUsacCallback(HANDLE_TRANSPORTDEC hTpDec, + const cbUsac_t cbUsac, void *user_data) { + if (hTpDec == NULL) { + return -1; + } + hTpDec->callbacks.cbUsac = cbUsac; + hTpDec->callbacks.cbUsacData = user_data; + return 0; +} + +int transportDec_RegisterUniDrcConfigCallback(HANDLE_TRANSPORTDEC hTpDec, + const cbUniDrc_t cbUniDrc, + void *user_data, + UINT *pLoudnessInfoSetPosition) { + if (hTpDec == NULL) { + return -1; + } + + hTpDec->callbacks.cbUniDrc = cbUniDrc; + hTpDec->callbacks.cbUniDrcData = user_data; + + hTpDec->pLoudnessInfoSetPosition = pLoudnessInfoSetPosition; + return 0; +} + +TRANSPORTDEC_ERROR transportDec_FillData(const HANDLE_TRANSPORTDEC hTp, + UCHAR *pBuffer, const UINT bufferSize, + UINT *pBytesValid, const INT layer) { + HANDLE_FDK_BITSTREAM hBs; + + if ((hTp == NULL) || (layer >= 1)) { + return TRANSPORTDEC_INVALID_PARAMETER; + } + + /* set bitbuffer shortcut */ + hBs = &hTp->bitStream[layer]; + + if (TT_IS_PACKET(hTp->transportFmt)) { + if (hTp->numberOfRawDataBlocks == 0) { + FDKresetBitbuffer(hBs); + FDKfeedBuffer(hBs, pBuffer, bufferSize, pBytesValid); + if (*pBytesValid != 0) { + return TRANSPORTDEC_TOO_MANY_BITS; + } + } + } else { + /* ... else feed bitbuffer with new stream data (append). */ + + if (*pBytesValid == 0) { + /* nothing to do */ + return TRANSPORTDEC_OK; + } + + if (hTp->numberOfRawDataBlocks <= 0) { + FDKfeedBuffer(hBs, pBuffer, bufferSize, pBytesValid); + } + } + + return TRANSPORTDEC_OK; +} + +HANDLE_FDK_BITSTREAM transportDec_GetBitstream(const HANDLE_TRANSPORTDEC hTp, + const UINT layer) { + return &hTp->bitStream[layer]; +} + +TRANSPORT_TYPE transportDec_GetFormat(const HANDLE_TRANSPORTDEC hTp) { + return hTp->transportFmt; +} + +INT transportDec_GetBufferFullness(const HANDLE_TRANSPORTDEC hTp) { + INT bufferFullness = -1; + + switch (hTp->transportFmt) { + case TT_MP4_ADTS: + if (hTp->parser.adts.bs.adts_fullness != 0x7ff) { + bufferFullness = hTp->parser.adts.bs.frame_length * 8 + + hTp->parser.adts.bs.adts_fullness * 32 * + getNumberOfEffectiveChannels( + hTp->parser.adts.bs.channel_config); + } + break; + case TT_MP4_LOAS: + case TT_MP4_LATM_MCP0: + case TT_MP4_LATM_MCP1: + if (hTp->parser.latm.m_linfo[0][0].m_bufferFullness != 0xff) { + bufferFullness = hTp->parser.latm.m_linfo[0][0].m_bufferFullness; + } + break; + default: + break; + } + + return bufferFullness; +} + +/** + * \brief adjust bit stream position and the end of an access unit. + * \param hTp transport decoder handle. + * \return error code. + */ +static TRANSPORTDEC_ERROR transportDec_AdjustEndOfAccessUnit( + HANDLE_TRANSPORTDEC hTp) { + HANDLE_FDK_BITSTREAM hBs = &hTp->bitStream[0]; + TRANSPORTDEC_ERROR err = TRANSPORTDEC_OK; + + switch (hTp->transportFmt) { + case TT_MP4_ADIF: + /* Do byte align at the end of raw_data_block() because UsacFrame() is not + * byte aligned. */ + FDKbyteAlign(hBs, hTp->accessUnitAnchor[0]); + break; + case TT_MP4_LOAS: + case TT_MP4_LATM_MCP0: + case TT_MP4_LATM_MCP1: + if (hTp->numberOfRawDataBlocks == 0) { + /* Do byte align at the end of AudioMuxElement. */ + FDKbyteAlign(hBs, hTp->globalFramePos); + + /* Check global frame length */ + if (hTp->transportFmt == TT_MP4_LOAS && + hTp->parser.latm.m_audioMuxLengthBytes > 0) { + int loasOffset; + + loasOffset = ((INT)hTp->parser.latm.m_audioMuxLengthBytes * 8 + + (INT)FDKgetValidBits(hBs)) - + (INT)hTp->globalFramePos; + if (loasOffset != 0) { + FDKpushBiDirectional(hBs, loasOffset); + /* For ELD and other payloads there is an unknown amount of padding, + so ignore unread bits, but throw an error only if too many bits + where read. */ + if (loasOffset < 0) { + err = TRANSPORTDEC_PARSE_ERROR; + } + } + } + } + break; + + case TT_MP4_ADTS: + if (hTp->parser.adts.bs.protection_absent == 0) { + int offset; + + /* Calculate offset to end of AU */ + offset = hTp->parser.adts + .rawDataBlockDist[hTp->parser.adts.bs.num_raw_blocks - + hTp->numberOfRawDataBlocks] + << 3; + /* CAUTION: The PCE (if available) is declared to be a part of the + * header! */ + offset -= (INT)hTp->accessUnitAnchor[0] - (INT)FDKgetValidBits(hBs) + + 16 + hTp->parser.adts.bs.num_pce_bits; + FDKpushBiDirectional(hBs, offset); + } + if (hTp->parser.adts.bs.num_raw_blocks > 0 && + hTp->parser.adts.bs.protection_absent == 0) { + /* Note this CRC read currently happens twice because of + * transportDec_CrcCheck() */ + hTp->parser.adts.crcReadValue = FDKreadBits(hBs, 16); + } + if (hTp->numberOfRawDataBlocks == 0) { + /* Check global frame length */ + if (hTp->parser.adts.bs.protection_absent == 0) { + int offset; + + offset = (hTp->parser.adts.bs.frame_length * 8 - ADTS_SYNCLENGTH + + (INT)FDKgetValidBits(hBs)) - + (INT)hTp->globalFramePos; + if (offset != 0) { + FDKpushBiDirectional(hBs, offset); + } + } + } + break; + + default: + break; + } + + return err; +} + +/** + * \brief Determine additional buffer fullness contraint due to burst data + * reception. The parameter TPDEC_PARAM_BURSTPERIOD must have been set as a + * precondition. + * \param hTp transport decoder handle. + * \param bufferFullness the buffer fullness value of the first frame to be + * decoded. + * \param bitsAvail the amount of available bits at the end of the first frame + * to be decoded. + * \return error code + */ +static TRANSPORTDEC_ERROR additionalHoldOffNeeded(HANDLE_TRANSPORTDEC hTp, + INT bufferFullness, + INT bitsAvail) { + INT checkLengthBits, avgBitsPerFrame; + INT maxAU; /* maximum number of frames per Master Frame */ + INT samplesPerFrame = hTp->asc->m_samplesPerFrame; + INT samplingFrequency = (INT)hTp->asc->m_samplingFrequency; + + if ((hTp->avgBitRate == 0) || (hTp->burstPeriod == 0)) { + return TRANSPORTDEC_OK; + } + if ((samplesPerFrame == 0) || (samplingFrequency == 0)) { + return TRANSPORTDEC_NOT_ENOUGH_BITS; + } + + /* One Master Frame is sent every hTp->burstPeriod ms */ + maxAU = hTp->burstPeriod * samplingFrequency + (samplesPerFrame * 1000 - 1); + maxAU = maxAU / (samplesPerFrame * 1000); + /* Subtract number of frames which were already held off. */ + maxAU -= hTp->holdOffFrames; + + avgBitsPerFrame = hTp->avgBitRate * samplesPerFrame + (samplingFrequency - 1); + avgBitsPerFrame = avgBitsPerFrame / samplingFrequency; + + /* Consider worst case of bufferFullness quantization. */ + switch (hTp->transportFmt) { + case TT_MP4_ADIF: + case TT_MP4_ADTS: + case TT_MP4_LOAS: + case TT_MP4_LATM_MCP0: + case TT_MP4_LATM_MCP1: + bufferFullness += 31; + break; + default: /* added to avoid compiler warning */ + break; /* added to avoid compiler warning */ + } + + checkLengthBits = bufferFullness + (maxAU - 1) * avgBitsPerFrame; + + /* Check if buffer is big enough to fullfill buffer fullness condition */ + if ((checkLengthBits /*+headerBits*/) > (((8192 * 4) << 3) - 7)) { + return TRANSPORTDEC_SYNC_ERROR; + } + + if (bitsAvail < checkLengthBits) { + return TRANSPORTDEC_NOT_ENOUGH_BITS; + } else { + return TRANSPORTDEC_OK; + } +} + +static TRANSPORTDEC_ERROR transportDec_readHeader( + HANDLE_TRANSPORTDEC hTp, HANDLE_FDK_BITSTREAM hBs, int syncLength, + int ignoreBufferFullness, int *pRawDataBlockLength, + int *pfTraverseMoreFrames, int *pSyncLayerFrameBits, int *pfConfigFound, + int *pHeaderBits) { + TRANSPORTDEC_ERROR err = TRANSPORTDEC_OK; + int rawDataBlockLength = *pRawDataBlockLength; + int fTraverseMoreFrames = + (pfTraverseMoreFrames != NULL) ? *pfTraverseMoreFrames : 0; + int syncLayerFrameBits = + (pSyncLayerFrameBits != NULL) ? *pSyncLayerFrameBits : 0; + int fConfigFound = (pfConfigFound != NULL) ? *pfConfigFound : 0; + int startPos; + + startPos = (INT)FDKgetValidBits(hBs); + + switch (hTp->transportFmt) { + case TT_MP4_ADTS: + if (hTp->numberOfRawDataBlocks <= 0) { + int i, errC; + + hTp->globalFramePos = FDKgetValidBits(hBs); + + UCHAR configChanged = 0; + UCHAR configMode = AC_CM_DET_CFG_CHANGE; + + for (i = 0; i < 2; i++) { + if (i > 0) { + FDKpushBack(hBs, + (INT)hTp->globalFramePos - (INT)FDKgetValidBits(hBs)); + configMode = AC_CM_ALLOC_MEM; + } + + /* Parse ADTS header */ + err = adtsRead_DecodeHeader(&hTp->parser.adts, &hTp->asc[0], hBs, + ignoreBufferFullness); + if (err != TRANSPORTDEC_OK) { + if (err != TRANSPORTDEC_NOT_ENOUGH_BITS) { + err = TRANSPORTDEC_SYNC_ERROR; + } + } else { + errC = hTp->callbacks.cbUpdateConfig( + hTp->callbacks.cbUpdateConfigData, &hTp->asc[0], configMode, + &configChanged); + if (errC != 0) { + if (errC == TRANSPORTDEC_NEED_TO_RESTART) { + err = TRANSPORTDEC_NEED_TO_RESTART; + goto bail; + } else { + err = TRANSPORTDEC_SYNC_ERROR; + } + } else { + fConfigFound = 1; + hTp->numberOfRawDataBlocks = + hTp->parser.adts.bs.num_raw_blocks + 1; + } + } + + if (err == TRANSPORTDEC_OK) { + if ((i == 0) && configChanged) { + errC = hTp->callbacks.cbFreeMem(hTp->callbacks.cbFreeMemData, + &hTp->asc[0]); + if (errC != 0) { + err = TRANSPORTDEC_PARSE_ERROR; + } + } + } + } + } else { + /* Reset CRC because the next bits are the beginning of a + * raw_data_block() */ + FDKcrcReset(&hTp->parser.adts.crcInfo); + hTp->parser.adts.bs.num_pce_bits = 0; + } + if (err == TRANSPORTDEC_OK) { + hTp->numberOfRawDataBlocks--; + rawDataBlockLength = adtsRead_GetRawDataBlockLength( + &hTp->parser.adts, + (hTp->parser.adts.bs.num_raw_blocks - hTp->numberOfRawDataBlocks)); + if (rawDataBlockLength <= 0) { + /* No further frame traversal possible. */ + fTraverseMoreFrames = 0; + } + syncLayerFrameBits = (hTp->parser.adts.bs.frame_length << 3) - + (startPos - (INT)FDKgetValidBits(hBs)) - + syncLength; + if (syncLayerFrameBits <= 0) { + err = TRANSPORTDEC_SYNC_ERROR; + } + } else { + hTp->numberOfRawDataBlocks = 0; + } + break; + case TT_MP4_LOAS: + if (hTp->numberOfRawDataBlocks <= 0) { + syncLayerFrameBits = (INT)FDKreadBits(hBs, 13); + hTp->parser.latm.m_audioMuxLengthBytes = syncLayerFrameBits; + syncLayerFrameBits <<= 3; + } + FDK_FALLTHROUGH; + case TT_MP4_LATM_MCP1: + case TT_MP4_LATM_MCP0: + if (hTp->numberOfRawDataBlocks <= 0) { + hTp->globalFramePos = FDKgetValidBits(hBs); + + err = CLatmDemux_Read(hBs, &hTp->parser.latm, hTp->transportFmt, + &hTp->callbacks, hTp->asc, &fConfigFound, + ignoreBufferFullness); + + if (err != TRANSPORTDEC_OK) { + if ((err != TRANSPORTDEC_NOT_ENOUGH_BITS) && + !TPDEC_IS_FATAL_ERROR(err)) { + err = TRANSPORTDEC_SYNC_ERROR; + } + } else { + hTp->numberOfRawDataBlocks = + CLatmDemux_GetNrOfSubFrames(&hTp->parser.latm); + if (hTp->transportFmt == TT_MP4_LOAS) { + syncLayerFrameBits -= startPos - (INT)FDKgetValidBits(hBs) - (13); + } + } + } else { + err = CLatmDemux_ReadPayloadLengthInfo(hBs, &hTp->parser.latm); + if (err != TRANSPORTDEC_OK) { + err = TRANSPORTDEC_SYNC_ERROR; + } + } + if (err == TRANSPORTDEC_OK) { + int layer; + rawDataBlockLength = 0; + for (layer = 0; + layer < (int)CLatmDemux_GetNrOfLayers(&hTp->parser.latm, 0); + layer += 1) { + rawDataBlockLength += + CLatmDemux_GetFrameLengthInBits(&hTp->parser.latm, 0, layer); + } + hTp->numberOfRawDataBlocks--; + } else { + hTp->numberOfRawDataBlocks = 0; + } + break; + default: { syncLayerFrameBits = 0; } break; + } + +bail: + + *pRawDataBlockLength = rawDataBlockLength; + + if (pHeaderBits != NULL) { + *pHeaderBits += startPos - (INT)FDKgetValidBits(hBs); + } + + for (int i = 0; i < (1 * 1); i++) { + /* If parsing error while config found, clear ctrlCFGChange-struct */ + if (hTp->ctrlCFGChange[i].cfgChanged && err != TRANSPORTDEC_OK) { + hTp->numberOfRawDataBlocks = 0; + hTp->ctrlCFGChange[i].flushCnt = 0; + hTp->ctrlCFGChange[i].flushStatus = TPDEC_FLUSH_OFF; + hTp->ctrlCFGChange[i].buildUpCnt = 0; + hTp->ctrlCFGChange[i].buildUpStatus = TPDEC_BUILD_UP_OFF; + hTp->ctrlCFGChange[i].cfgChanged = 0; + hTp->ctrlCFGChange[i].contentChanged = 0; + hTp->ctrlCFGChange[i].forceCfgChange = 0; + + hTp->callbacks.cbCtrlCFGChange(hTp->callbacks.cbCtrlCFGChangeData, + &hTp->ctrlCFGChange[i]); + } + } + + if (pfConfigFound != NULL) { + *pfConfigFound = fConfigFound; + } + + if (pfTraverseMoreFrames != NULL) { + *pfTraverseMoreFrames = fTraverseMoreFrames; + } + if (pSyncLayerFrameBits != NULL) { + *pSyncLayerFrameBits = syncLayerFrameBits; + } + + return err; +} + +/* How many bits to advance for synchronization search. */ +#define TPDEC_SYNCSKIP 8 + +static TRANSPORTDEC_ERROR synchronization(HANDLE_TRANSPORTDEC hTp, + INT *pHeaderBits) { + TRANSPORTDEC_ERROR err = TRANSPORTDEC_OK, errFirstFrame = TRANSPORTDEC_OK; + HANDLE_FDK_BITSTREAM hBs = &hTp->bitStream[0]; + + INT syncLayerFrameBits = 0; /* Length of sync layer frame (i.e. LOAS) */ + INT rawDataBlockLength = 0, rawDataBlockLengthPrevious; + INT totalBits; + INT headerBits = 0, headerBitsFirstFrame = 0, headerBitsPrevious; + INT numFramesTraversed = 0, fTraverseMoreFrames, + fConfigFound = (hTp->flags & TPDEC_CONFIG_FOUND), startPosFirstFrame = -1; + INT numRawDataBlocksFirstFrame = 0, numRawDataBlocksPrevious, + globalFramePosFirstFrame = 0, rawDataBlockLengthFirstFrame = 0; + INT ignoreBufferFullness = + hTp->flags & + (TPDEC_LOST_FRAMES_PENDING | TPDEC_IGNORE_BUFFERFULLNESS | TPDEC_SYNCOK); + UINT endTpFrameBitsPrevious = 0; + + /* Synch parameters */ + INT syncLength; /* Length of sync word in bits */ + UINT syncWord; /* Sync word to be found */ + UINT syncMask; /* Mask for sync word (for adding one bit, so comprising one + bit less) */ + C_ALLOC_SCRATCH_START(contextFirstFrame, transportdec_parser_t, 1); + + totalBits = (INT)FDKgetValidBits(hBs); + + if (totalBits <= 0) { + err = TRANSPORTDEC_NOT_ENOUGH_BITS; + goto bail; + } + + fTraverseMoreFrames = + (hTp->flags & (TPDEC_MINIMIZE_DELAY | TPDEC_EARLY_CONFIG)) && + !(hTp->flags & TPDEC_SYNCOK); + + /* Set transport specific sync parameters */ + switch (hTp->transportFmt) { + case TT_MP4_ADTS: + syncWord = ADTS_SYNCWORD; + syncLength = ADTS_SYNCLENGTH; + break; + case TT_MP4_LOAS: + syncWord = 0x2B7; + syncLength = 11; + break; + default: + syncWord = 0; + syncLength = 0; + break; + } + + syncMask = (1 << syncLength) - 1; + + do { + INT bitsAvail = 0; /* Bits available in bitstream buffer */ + INT checkLengthBits; /* Helper to check remaining bits and buffer boundaries + */ + UINT synch; /* Current sync word read from bitstream */ + + headerBitsPrevious = headerBits; + + bitsAvail = (INT)FDKgetValidBits(hBs); + + if (hTp->numberOfRawDataBlocks == 0) { + /* search synchword */ + + FDK_ASSERT((bitsAvail % TPDEC_SYNCSKIP) == 0); + + if ((bitsAvail - syncLength) < TPDEC_SYNCSKIP) { + err = TRANSPORTDEC_NOT_ENOUGH_BITS; + headerBits = 0; + } else { + synch = FDKreadBits(hBs, syncLength); + + if (!(hTp->flags & TPDEC_SYNCOK)) { + for (; (bitsAvail - syncLength) >= TPDEC_SYNCSKIP; + bitsAvail -= TPDEC_SYNCSKIP) { + if (synch == syncWord) { + break; + } + synch = ((synch << TPDEC_SYNCSKIP) & syncMask) | + FDKreadBits(hBs, TPDEC_SYNCSKIP); + } + } + if (synch != syncWord) { + /* No correct syncword found. */ + err = TRANSPORTDEC_SYNC_ERROR; + } else { + err = TRANSPORTDEC_OK; + } + headerBits = syncLength; + } + } else { + headerBits = 0; + } + + /* Save previous raw data block data */ + rawDataBlockLengthPrevious = rawDataBlockLength; + numRawDataBlocksPrevious = hTp->numberOfRawDataBlocks; + + /* Parse transport header (raw data block granularity) */ + + if (err == TRANSPORTDEC_OK) { + err = transportDec_readHeader(hTp, hBs, syncLength, ignoreBufferFullness, + &rawDataBlockLength, &fTraverseMoreFrames, + &syncLayerFrameBits, &fConfigFound, + &headerBits); + if (TPDEC_IS_FATAL_ERROR(err)) { + /* Rewind - TPDEC_SYNCSKIP, in order to look for a synch one bit ahead + * next time. Ensure that the bit amount lands at a multiple of + * TPDEC_SYNCSKIP. */ + FDKpushBiDirectional( + hBs, -headerBits + TPDEC_SYNCSKIP + (bitsAvail % TPDEC_SYNCSKIP)); + + goto bail; + } + } + + bitsAvail -= headerBits; + + checkLengthBits = syncLayerFrameBits; + + /* Check if the whole frame would fit the bitstream buffer */ + if (err == TRANSPORTDEC_OK) { + if ((checkLengthBits + headerBits) > (((8192 * 4) << 3) - 7)) { + /* We assume that the size of the transport bit buffer has been + chosen to meet all system requirements, thus this condition + is considered a synchronisation error. */ + err = TRANSPORTDEC_SYNC_ERROR; + } else { + if (bitsAvail < checkLengthBits) { + err = TRANSPORTDEC_NOT_ENOUGH_BITS; + } + } + } + + if (err == TRANSPORTDEC_NOT_ENOUGH_BITS) { + /* Enforce reading of new data */ + hTp->numberOfRawDataBlocks = 0; + break; + } + + if (err == TRANSPORTDEC_SYNC_ERROR) { + int bits; + + /* Enforce re-sync of transport headers. */ + hTp->numberOfRawDataBlocks = 0; + + /* Ensure that the bit amount lands at a multiple of TPDEC_SYNCSKIP */ + bits = (bitsAvail + headerBits) % TPDEC_SYNCSKIP; + /* Rewind - TPDEC_SYNCSKIP, in order to look for a synch one bit ahead + * next time. */ + FDKpushBiDirectional(hBs, -(headerBits - TPDEC_SYNCSKIP) + bits); + headerBits = 0; + } + + /* Frame traversal */ + if (fTraverseMoreFrames) { + /* Save parser context for early config discovery "rewind all frames" */ + if ((hTp->flags & TPDEC_EARLY_CONFIG) && + !(hTp->flags & TPDEC_MINIMIZE_DELAY)) { + /* ignore buffer fullness if just traversing additional frames for ECD + */ + ignoreBufferFullness = 1; + + /* Save context in order to return later */ + if (err == TRANSPORTDEC_OK && startPosFirstFrame == -1) { + startPosFirstFrame = FDKgetValidBits(hBs); + numRawDataBlocksFirstFrame = hTp->numberOfRawDataBlocks; + globalFramePosFirstFrame = hTp->globalFramePos; + rawDataBlockLengthFirstFrame = rawDataBlockLength; + headerBitsFirstFrame = headerBits; + errFirstFrame = err; + FDKmemcpy(contextFirstFrame, &hTp->parser, + sizeof(transportdec_parser_t)); + } + + /* Break when config was found or it is not possible anymore to find a + * config */ + if (startPosFirstFrame != -1 && + (fConfigFound || err != TRANSPORTDEC_OK)) { + /* In case of ECD and sync error, do not rewind anywhere. */ + if (err == TRANSPORTDEC_SYNC_ERROR) { + startPosFirstFrame = -1; + fConfigFound = 0; + numFramesTraversed = 0; + } + break; + } + } + + if (err == TRANSPORTDEC_OK) { + FDKpushFor(hBs, rawDataBlockLength); + numFramesTraversed++; + endTpFrameBitsPrevious = (INT)FDKgetValidBits(hBs); + /* Ignore error here itentionally. */ + transportDec_AdjustEndOfAccessUnit(hTp); + endTpFrameBitsPrevious -= FDKgetValidBits(hBs); + } + } + } while (fTraverseMoreFrames || + (err == TRANSPORTDEC_SYNC_ERROR && !(hTp->flags & TPDEC_SYNCOK))); + + /* Restore context in case of ECD frame traversal */ + if (startPosFirstFrame != -1 && (fConfigFound || err != TRANSPORTDEC_OK)) { + FDKpushBiDirectional(hBs, FDKgetValidBits(hBs) - startPosFirstFrame); + FDKmemcpy(&hTp->parser, contextFirstFrame, sizeof(transportdec_parser_t)); + hTp->numberOfRawDataBlocks = numRawDataBlocksFirstFrame; + hTp->globalFramePos = globalFramePosFirstFrame; + rawDataBlockLength = rawDataBlockLengthFirstFrame; + headerBits = headerBitsFirstFrame; + err = errFirstFrame; + numFramesTraversed = 0; + } + + /* Additional burst data mode buffer fullness check. */ + if (!(hTp->flags & (TPDEC_LOST_FRAMES_PENDING | TPDEC_IGNORE_BUFFERFULLNESS | + TPDEC_SYNCOK)) && + err == TRANSPORTDEC_OK) { + err = additionalHoldOffNeeded(hTp, transportDec_GetBufferFullness(hTp), + FDKgetValidBits(hBs) - syncLayerFrameBits); + if (err == TRANSPORTDEC_NOT_ENOUGH_BITS) { + hTp->holdOffFrames++; + } + } + + /* Rewind for retry because of not enough bits */ + if (err == TRANSPORTDEC_NOT_ENOUGH_BITS) { + FDKpushBack(hBs, headerBits); + headerBits = 0; + } else { + /* reset hold off frame counter */ + hTp->holdOffFrames = 0; + } + + /* Return to last good frame in case of frame traversal but not ECD. */ + if (numFramesTraversed > 0) { + FDKpushBack(hBs, rawDataBlockLengthPrevious + endTpFrameBitsPrevious); + if (err != TRANSPORTDEC_OK) { + hTp->numberOfRawDataBlocks = numRawDataBlocksPrevious; + headerBits = headerBitsPrevious; + rawDataBlockLength = rawDataBlockLengthPrevious; + } + err = TRANSPORTDEC_OK; + } + +bail: + hTp->auLength[0] = rawDataBlockLength; + + /* Detect pointless TRANSPORTDEC_NOT_ENOUGH_BITS error case, where the bit + buffer is already full, or no new burst packet fits. Recover by advancing + the bit buffer. */ + if ((totalBits > 0) && (TRANSPORTDEC_NOT_ENOUGH_BITS == err) && + (FDKgetValidBits(hBs) >= + (((8192 * 4) * 8 - ((hTp->avgBitRate * hTp->burstPeriod) / 1000)) - + 7))) { + FDKpushFor(hBs, TPDEC_SYNCSKIP); + err = TRANSPORTDEC_SYNC_ERROR; + } + + if (err == TRANSPORTDEC_OK) { + hTp->flags |= TPDEC_SYNCOK; + } + + if (fConfigFound) { + hTp->flags |= TPDEC_CONFIG_FOUND; + } + + if (pHeaderBits != NULL) { + *pHeaderBits = headerBits; + } + + if (err == TRANSPORTDEC_SYNC_ERROR) { + hTp->flags &= ~TPDEC_SYNCOK; + } + + C_ALLOC_SCRATCH_END(contextFirstFrame, transportdec_parser_t, 1); + + return err; +} + +/** + * \brief Synchronize to stream and estimate the amount of missing access units + * due to a current synchronization error in case of constant average bit rate. + */ +static TRANSPORTDEC_ERROR transportDec_readStream(HANDLE_TRANSPORTDEC hTp, + const UINT layer) { + TRANSPORTDEC_ERROR error = TRANSPORTDEC_OK; + HANDLE_FDK_BITSTREAM hBs = &hTp->bitStream[layer]; + + INT headerBits; + INT bitDistance, bfDelta; + + /* Obtain distance to next synch word */ + bitDistance = (INT)FDKgetValidBits(hBs); + error = synchronization(hTp, &headerBits); + bitDistance -= (INT)FDKgetValidBits(hBs); + + FDK_ASSERT(bitDistance >= 0); + + INT nAU = -1; + + if (error == TRANSPORTDEC_SYNC_ERROR || + (hTp->flags & TPDEC_LOST_FRAMES_PENDING)) { + /* Check if estimating lost access units is feasible. */ + if (hTp->avgBitRate > 0 && hTp->asc[0].m_samplesPerFrame > 0 && + hTp->asc[0].m_samplingFrequency > 0) { + if (error == TRANSPORTDEC_OK) { + int aj; + + aj = transportDec_GetBufferFullness(hTp); + if (aj > 0) { + bfDelta = aj; + } else { + bfDelta = 0; + } + /* sync was ok: last of a series of bad access units. */ + hTp->flags &= ~TPDEC_LOST_FRAMES_PENDING; + /* Add up bitDistance until end of the current frame. Later we substract + this frame from the grand total, since this current successfully + synchronized frame should not be skipped of course; but it must be + accounted into the bufferfulness math. */ + bitDistance += hTp->auLength[0]; + } else { + if (!(hTp->flags & TPDEC_LOST_FRAMES_PENDING)) { + /* sync not ok: one of many bad access units. */ + hTp->flags |= TPDEC_LOST_FRAMES_PENDING; + bfDelta = -(INT)hTp->lastValidBufferFullness; + } else { + bfDelta = 0; + } + } + + { + int num, denom; + + /* Obtain estimate of number of lost frames */ + num = (INT)hTp->asc[0].m_samplingFrequency * (bfDelta + bitDistance) + + hTp->remainder; + denom = hTp->avgBitRate * hTp->asc[0].m_samplesPerFrame; + if (num > 0) { + nAU = num / denom; + hTp->remainder = num % denom; + } else { + hTp->remainder = num; + } + + if (error == TRANSPORTDEC_OK) { + /* Final adjustment of remainder, taken -1 into account because + current frame should not be skipped, thus substract -1 or do + nothing instead of +1-1 accordingly. */ + if ((denom - hTp->remainder) >= hTp->remainder) { + nAU--; + } + + if (nAU < 0) { + /* There was one frame too much concealed, so unfortunately we will + * have to skip one good frame. */ + transportDec_EndAccessUnit(hTp); + error = synchronization(hTp, &headerBits); + nAU = -1; + } + hTp->remainder = 0; + /* Enforce last missed frames to be concealed. */ + if (nAU > 0) { + FDKpushBack(hBs, headerBits); + } + } + } + } + } + + /* Be sure that lost frames are handled correctly. This is necessary due to + some sync error sequences where later it turns out that there is not enough + data, but the bits upto the sync word are discarded, thus causing a value + of nAU > 0 */ + if (nAU > 0) { + error = TRANSPORTDEC_SYNC_ERROR; + } + + hTp->missingAccessUnits = nAU; + + return error; +} + +/* returns error code */ +TRANSPORTDEC_ERROR transportDec_ReadAccessUnit(const HANDLE_TRANSPORTDEC hTp, + const UINT layer) { + TRANSPORTDEC_ERROR err = TRANSPORTDEC_OK; + HANDLE_FDK_BITSTREAM hBs; + + if (!hTp) { + return TRANSPORTDEC_INVALID_PARAMETER; + } + + hBs = &hTp->bitStream[layer]; + + if ((INT)FDKgetValidBits(hBs) <= 0) { + /* This is only relevant for RAW and ADIF cases. + * For streaming formats err will get overwritten. */ + err = TRANSPORTDEC_NOT_ENOUGH_BITS; + hTp->numberOfRawDataBlocks = 0; + } + + switch (hTp->transportFmt) { + case TT_MP4_ADIF: + /* Read header if not already done */ + if (!(hTp->flags & TPDEC_CONFIG_FOUND)) { + int i; + CProgramConfig *pce; + INT bsStart = FDKgetValidBits(hBs); + UCHAR configChanged = 0; + UCHAR configMode = AC_CM_DET_CFG_CHANGE; + + for (i = 0; i < 2; i++) { + if (i > 0) { + FDKpushBack(hBs, bsStart - FDKgetValidBits(hBs)); + configMode = AC_CM_ALLOC_MEM; + } + + AudioSpecificConfig_Init(&hTp->asc[0]); + pce = &hTp->asc[0].m_progrConfigElement; + err = adifRead_DecodeHeader(&hTp->parser.adif, pce, hBs); + if (err) goto bail; + + /* Map adif header to ASC */ + hTp->asc[0].m_aot = (AUDIO_OBJECT_TYPE)(pce->Profile + 1); + hTp->asc[0].m_samplingFrequencyIndex = pce->SamplingFrequencyIndex; + hTp->asc[0].m_samplingFrequency = + SamplingRateTable[pce->SamplingFrequencyIndex]; + hTp->asc[0].m_channelConfiguration = 0; + hTp->asc[0].m_samplesPerFrame = 1024; + hTp->avgBitRate = hTp->parser.adif.BitRate; + + /* Call callback to decoder. */ + { + int errC; + + errC = hTp->callbacks.cbUpdateConfig( + hTp->callbacks.cbUpdateConfigData, &hTp->asc[0], configMode, + &configChanged); + if (errC == 0) { + hTp->flags |= TPDEC_CONFIG_FOUND; + } else { + err = TRANSPORTDEC_PARSE_ERROR; + goto bail; + } + } + + if (err == TRANSPORTDEC_OK) { + if ((i == 0) && configChanged) { + int errC; + errC = hTp->callbacks.cbFreeMem(hTp->callbacks.cbFreeMemData, + &hTp->asc[0]); + if (errC != 0) { + err = TRANSPORTDEC_PARSE_ERROR; + } + } + } + } + } + hTp->auLength[layer] = -1; /* Access Unit data length is unknown. */ + break; + + case TT_MP4_RAW: + case TT_DRM: + /* One Access Unit was filled into buffer. + So get the length out of the buffer. */ + hTp->auLength[layer] = FDKgetValidBits(hBs); + hTp->flags |= TPDEC_SYNCOK; + break; + + case TT_MP4_LATM_MCP0: + case TT_MP4_LATM_MCP1: + if (err == TRANSPORTDEC_OK) { + int fConfigFound = hTp->flags & TPDEC_CONFIG_FOUND; + err = transportDec_readHeader(hTp, hBs, 0, 1, &hTp->auLength[layer], + NULL, NULL, &fConfigFound, NULL); + if (fConfigFound) { + hTp->flags |= TPDEC_CONFIG_FOUND; + } + } + break; + + case TT_MP4_ADTS: + case TT_MP4_LOAS: + err = transportDec_readStream(hTp, layer); + break; + + default: + err = TRANSPORTDEC_UNSUPPORTED_FORMAT; + break; + } + + if (err == TRANSPORTDEC_OK) { + hTp->accessUnitAnchor[layer] = FDKgetValidBits(hBs); + } else { + hTp->accessUnitAnchor[layer] = 0; + } + +bail: + return err; +} + +TRANSPORTDEC_ERROR transportDec_GetAsc(const HANDLE_TRANSPORTDEC hTp, + const UINT layer, + CSAudioSpecificConfig *asc) { + TRANSPORTDEC_ERROR err = TRANSPORTDEC_OK; + + if (hTp != NULL) { + *asc = hTp->asc[layer]; + err = TRANSPORTDEC_OK; + } else { + err = TRANSPORTDEC_INVALID_PARAMETER; + } + return err; +} + +INT transportDec_GetAuBitsRemaining(const HANDLE_TRANSPORTDEC hTp, + const UINT layer) { + INT bits; + + if (hTp->accessUnitAnchor[layer] > 0 && hTp->auLength[layer] > 0) { + bits = (INT)FDKgetValidBits(&hTp->bitStream[layer]); + if (bits >= 0) { + bits = hTp->auLength[layer] - ((INT)hTp->accessUnitAnchor[layer] - bits); + } + } else { + bits = FDKgetValidBits(&hTp->bitStream[layer]); + } + + return bits; +} + +INT transportDec_GetAuBitsTotal(const HANDLE_TRANSPORTDEC hTp, + const UINT layer) { + return hTp->auLength[layer]; +} + +TRANSPORTDEC_ERROR transportDec_GetMissingAccessUnitCount( + INT *pNAccessUnits, HANDLE_TRANSPORTDEC hTp) { + *pNAccessUnits = hTp->missingAccessUnits; + + return TRANSPORTDEC_OK; +} + +/* Inform the transportDec layer that reading of access unit has finished. */ +TRANSPORTDEC_ERROR transportDec_EndAccessUnit(HANDLE_TRANSPORTDEC hTp) { + TRANSPORTDEC_ERROR err = TRANSPORTDEC_OK; + + switch (hTp->transportFmt) { + case TT_MP4_LOAS: + case TT_MP4_LATM_MCP0: + case TT_MP4_LATM_MCP1: { + HANDLE_FDK_BITSTREAM hBs = &hTp->bitStream[0]; + if (hTp->numberOfRawDataBlocks == 0) { + /* Read other data if available. */ + if (CLatmDemux_GetOtherDataPresentFlag(&hTp->parser.latm)) { + int otherDataLen = CLatmDemux_GetOtherDataLength(&hTp->parser.latm); + + if ((INT)FDKgetValidBits(hBs) >= otherDataLen) { + FDKpushFor(hBs, otherDataLen); + } else { + /* Do byte align at the end of AudioMuxElement. */ + if (hTp->numberOfRawDataBlocks == 0) { + FDKbyteAlign(hBs, hTp->globalFramePos); + } + return TRANSPORTDEC_NOT_ENOUGH_BITS; + } + } + } else { + /* If bit buffer has not more bits but hTp->numberOfRawDataBlocks > 0 + then too many bits were read and obviously no more RawDataBlocks can + be read. Set numberOfRawDataBlocks to zero to attempt a new sync + attempt. */ + if ((INT)FDKgetValidBits(hBs) <= 0) { + hTp->numberOfRawDataBlocks = 0; + } + } + } break; + default: + break; + } + + err = transportDec_AdjustEndOfAccessUnit(hTp); + + switch (hTp->transportFmt) { + default: + break; + } + + return err; +} + +TRANSPORTDEC_ERROR transportDec_SetParam(const HANDLE_TRANSPORTDEC hTp, + const TPDEC_PARAM param, + const INT value) { + TRANSPORTDEC_ERROR error = TRANSPORTDEC_OK; + + if (hTp == NULL) { + return TRANSPORTDEC_INVALID_PARAMETER; + } + + switch (param) { + case TPDEC_PARAM_MINIMIZE_DELAY: + if (value) { + hTp->flags |= TPDEC_MINIMIZE_DELAY; + } else { + hTp->flags &= ~TPDEC_MINIMIZE_DELAY; + } + break; + case TPDEC_PARAM_EARLY_CONFIG: + if (value) { + hTp->flags |= TPDEC_EARLY_CONFIG; + } else { + hTp->flags &= ~TPDEC_EARLY_CONFIG; + } + break; + case TPDEC_PARAM_IGNORE_BUFFERFULLNESS: + if (value) { + hTp->flags |= TPDEC_IGNORE_BUFFERFULLNESS; + } else { + hTp->flags &= ~TPDEC_IGNORE_BUFFERFULLNESS; + } + break; + case TPDEC_PARAM_SET_BITRATE: + hTp->avgBitRate = value; + break; + case TPDEC_PARAM_BURST_PERIOD: + hTp->burstPeriod = value; + break; + case TPDEC_PARAM_RESET: { + int i; + + for (i = 0; i < (1 * 1); i++) { + FDKresetBitbuffer(&hTp->bitStream[i]); + hTp->auLength[i] = 0; + hTp->accessUnitAnchor[i] = 0; + } + hTp->flags &= ~(TPDEC_SYNCOK | TPDEC_LOST_FRAMES_PENDING); + if (hTp->transportFmt != TT_MP4_ADIF) { + hTp->flags &= ~TPDEC_CONFIG_FOUND; + } + hTp->remainder = 0; + hTp->avgBitRate = 0; + hTp->missingAccessUnits = 0; + hTp->numberOfRawDataBlocks = 0; + hTp->globalFramePos = 0; + hTp->holdOffFrames = 0; + } break; + case TPDEC_PARAM_TARGETLAYOUT: + hTp->targetLayout = value; + break; + case TPDEC_PARAM_FORCE_CONFIG_CHANGE: + hTp->ctrlCFGChange[value].forceCfgChange = TPDEC_FORCE_CONFIG_CHANGE; + break; + case TPDEC_PARAM_USE_ELEM_SKIPPING: + if (value) { + hTp->flags |= TPDEC_USE_ELEM_SKIPPING; + } else { + hTp->flags &= ~TPDEC_USE_ELEM_SKIPPING; + } + break; + } + + return error; +} + +UINT transportDec_GetNrOfSubFrames(HANDLE_TRANSPORTDEC hTp) { + UINT nSubFrames = 0; + + if (hTp == NULL) return 0; + + if (hTp->transportFmt == TT_MP4_LATM_MCP1 || + hTp->transportFmt == TT_MP4_LATM_MCP0 || hTp->transportFmt == TT_MP4_LOAS) + nSubFrames = CLatmDemux_GetNrOfSubFrames(&hTp->parser.latm); + else if (hTp->transportFmt == TT_MP4_ADTS) + nSubFrames = hTp->parser.adts.bs.num_raw_blocks; + + return nSubFrames; +} + +void transportDec_Close(HANDLE_TRANSPORTDEC *phTp) { + if (phTp != NULL) { + if (*phTp != NULL) { + FreeRam_TransportDecoderBuffer(&(*phTp)->bsBuffer); + FreeRam_TransportDecoder(phTp); + } + } +} + +TRANSPORTDEC_ERROR transportDec_GetLibInfo(LIB_INFO *info) { + int i; + + if (info == NULL) { + return TRANSPORTDEC_UNKOWN_ERROR; + } + + /* search for next free tab */ + for (i = 0; i < FDK_MODULE_LAST; i++) { + if (info[i].module_id == FDK_NONE) break; + } + if (i == FDK_MODULE_LAST) return TRANSPORTDEC_UNKOWN_ERROR; + info += i; + + info->module_id = FDK_TPDEC; +#ifdef __ANDROID__ + info->build_date = ""; + info->build_time = ""; +#else + info->build_date = __DATE__; + info->build_time = __TIME__; +#endif + info->title = TP_LIB_TITLE; + info->version = LIB_VERSION(TP_LIB_VL0, TP_LIB_VL1, TP_LIB_VL2); + LIB_VERSION_STRING(info); + info->flags = 0 | CAPF_ADIF | CAPF_ADTS | CAPF_LATM | CAPF_LOAS | + CAPF_RAWPACKETS | CAPF_DRM; + + return TRANSPORTDEC_OK; /* FDKERR_NOERROR; */ +} + +int transportDec_CrcStartReg(HANDLE_TRANSPORTDEC pTp, INT mBits) { + switch (pTp->transportFmt) { + case TT_MP4_ADTS: + return adtsRead_CrcStartReg(&pTp->parser.adts, &pTp->bitStream[0], mBits); + case TT_DRM: + return drmRead_CrcStartReg(&pTp->parser.drm, &pTp->bitStream[0], mBits); + default: + return -1; + } +} + +void transportDec_CrcEndReg(HANDLE_TRANSPORTDEC pTp, INT reg) { + switch (pTp->transportFmt) { + case TT_MP4_ADTS: + adtsRead_CrcEndReg(&pTp->parser.adts, &pTp->bitStream[0], reg); + break; + case TT_DRM: + drmRead_CrcEndReg(&pTp->parser.drm, &pTp->bitStream[0], reg); + break; + default: + break; + } +} + +TRANSPORTDEC_ERROR transportDec_CrcCheck(HANDLE_TRANSPORTDEC pTp) { + switch (pTp->transportFmt) { + case TT_MP4_ADTS: + if ((pTp->parser.adts.bs.num_raw_blocks > 0) && + (pTp->parser.adts.bs.protection_absent == 0)) { + transportDec_AdjustEndOfAccessUnit(pTp); + } + return adtsRead_CrcCheck(&pTp->parser.adts); + case TT_DRM: + return drmRead_CrcCheck(&pTp->parser.drm); + default: + return TRANSPORTDEC_OK; + } +} + +TRANSPORTDEC_ERROR transportDec_DrmRawSdcAudioConfig_Check(UCHAR *conf, + const UINT length) { + CSAudioSpecificConfig asc; + FDK_BITSTREAM bs; + HANDLE_FDK_BITSTREAM hBs = &bs; + + FDKinitBitStream(hBs, conf, BUFSIZE_DUMMY_VALUE, length << 3, BS_READER); + + TRANSPORTDEC_ERROR err = + DrmRawSdcAudioConfig_Parse(&asc, hBs, NULL, (UCHAR)AC_CM_ALLOC_MEM, 0); + + return err; +} |