aboutsummaryrefslogtreecommitdiffstats
path: root/libSACdec/src/sac_dec_lib.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'libSACdec/src/sac_dec_lib.cpp')
-rw-r--r--libSACdec/src/sac_dec_lib.cpp1919
1 files changed, 1919 insertions, 0 deletions
diff --git a/libSACdec/src/sac_dec_lib.cpp b/libSACdec/src/sac_dec_lib.cpp
new file mode 100644
index 0000000..ebf9bee
--- /dev/null
+++ b/libSACdec/src/sac_dec_lib.cpp
@@ -0,0 +1,1919 @@
+/* -----------------------------------------------------------------------------
+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 surround decoder library *************************
+
+ Author(s):
+
+ Description: SAC Decoder Library Interface
+
+*******************************************************************************/
+
+#include "sac_dec_lib.h"
+#include "sac_dec_interface.h"
+#include "sac_dec.h"
+#include "sac_bitdec.h"
+#include "FDK_matrixCalloc.h"
+
+#define MPS_DATA_BUFFER_SIZE (2048)
+
+/**
+ * \brief MPEG Surround data indication.
+ **/
+typedef enum {
+ MPEGS_ANCTYPE_FRAME = 0, /*!< MPEG Surround frame, see ISO/IEC 23003-1 */
+ MPEGS_ANCTYPE_HEADER_AND_FRAME = 1, /*!< MPEG Surround header and MPEG
+ Surround frame, see ISO/IEC 23003-1 */
+ MPEGS_ANCTYPE_RESERVED_1 = 2, /*!< reserved, see ISO/IEC 23003-1 */
+ MPEGS_ANCTYPE_RESERVED_2 = 3 /*!< reserved, see ISO/IEC 23003-1*/
+} MPEGS_ANCTYPE;
+
+/**
+ * \brief MPEG Surround data segment indication.
+ **/
+typedef enum {
+ MPEGS_CONTINUE = 0, /*!< Indicates if data segment continues a data block. */
+ MPEGS_STOP = 1, /*!< Indicates if data segment ends a data block. */
+ MPEGS_START = 2, /*!< Indicates if data segment begins a data block. */
+ MPEGS_START_STOP =
+ 3 /*!< Indicates if data segment begins and ends a data block. */
+} MPEGS_ANCSTARTSTOP;
+
+/**
+ * \brief MPEG Surround synchronizaiton state.
+ *
+ * CAUTION: Changing the enumeration values can break the sync mechanism
+ *because it is based on comparing the state values.
+ **/
+typedef enum {
+ MPEGS_SYNC_LOST =
+ 0, /*!< Indicates lost sync because of current discontinuity. */
+ MPEGS_SYNC_FOUND = 1, /*!< Parsed a valid header and (re)intialization was
+ successfully completed. */
+ MPEGS_SYNC_COMPLETE = 2 /*!< In sync and continuous. Found an independent
+ frame in addition to MPEGS_SYNC_FOUND.
+ Precondition: MPEGS_SYNC_FOUND. */
+} MPEGS_SYNCSTATE;
+
+/**
+ * \brief MPEG Surround operation mode.
+ **/
+typedef enum {
+ MPEGS_OPMODE_EMM = 0, /*!< Mode: Enhanced Matrix Mode (Blind) */
+ MPEGS_OPMODE_MPS_PAYLOAD = 1, /*!< Mode: Normal, Stereo or Binaural */
+ MPEGS_OPMODE_NO_MPS_PAYLOAD = 2 /*!< Mode: no MPEG Surround payload */
+} MPEGS_OPMODE;
+
+/**
+ * \brief MPEG Surround init flags.
+ **/
+typedef enum {
+ MPEGS_INIT_OK = 0x00000000, /*!< indicate correct initialization */
+ MPEGS_INIT_ENFORCE_REINIT =
+ 0x00000001, /*!< indicate complete initialization */
+
+ MPEGS_INIT_CHANGE_OUTPUT_MODE =
+ 0x00000010, /*!< indicate change of the output mode */
+ MPEGS_INIT_CHANGE_PARTIALLY_COMPLEX =
+ 0x00000020, /*!< indicate change of low power/high quality */
+ MPEGS_INIT_CHANGE_TIME_FREQ_INTERFACE =
+ 0x00000040, /*!< indicate change of qmf/time interface */
+ MPEGS_INIT_CHANGE_HEADER = 0x00000080, /*!< indicate change of header */
+
+ MPEGS_INIT_ERROR_PAYLOAD =
+ 0x00000100, /*!< indicate payload/ancType/ancStartStop error */
+
+ MPEGS_INIT_BS_INTERRUPTION =
+ 0x00001000, /*!< indicate bitstream interruption */
+ MPEGS_INIT_CLEAR_HISTORY =
+ 0x00002000, /*!< indicate that all states shall be cleared */
+
+ /* Re-initialization of submodules */
+
+ MPEGS_INIT_CHANGE_CONCEAL_PARAMS = 0x00100000, /*!< indicate a change of at
+ least one error concealment
+ param */
+
+ /* No re-initialization needed, currently not used */
+ MPEGS_INIT_CHANGE_BYPASS_MODE =
+ 0x01000000, /*!< indicate change of bypass mode */
+
+ /* Re-initialization needed, currently not used */
+ MPEGS_INIT_ERROR_ANC_TYPE = 0x10000000, /*!< indicate ancType error*/
+ MPEGS_INIT_ERROR_ANC_STARTSTOP =
+ 0x20000000 /*!< indicate ancStartStop error */
+} MPEGS_INIT_FLAGS;
+
+struct MpegSurroundDecoder {
+ HANDLE_FDK_QMF_DOMAIN pQmfDomain;
+ UCHAR mpsData[MPS_DATA_BUFFER_SIZE]; /* Buffer for MPS payload accross more
+ than one segment */
+ INT mpsDataBits; /* Amount of bits in mpsData */
+ /* MPEG Surround decoder */
+ SPATIAL_SPECIFIC_CONFIG spatialSpecificConfig[1]; /* SSC delay line which is
+ used during decoding */
+ spatialDec *pSpatialDec;
+ SPATIAL_SPECIFIC_CONFIG
+ spatialSpecificConfigBackup; /* SSC used while parsing */
+
+ /* Creation parameter */
+ UCHAR mpegSurroundDecoderLevel;
+ /* Run-time parameter */
+ UCHAR mpegSurroundSscIsGlobalCfg; /* Flag telling that the SSC
+ (::spatialSpecificConfig) is a
+ out-of-band configuration. */
+ UCHAR mpegSurroundUseTimeInterface;
+
+ SPATIAL_BS_FRAME
+ bsFrames[1]; /* Bitstream Structs that contain data read from the
+ SpatialFrame() bitstream element */
+ BS_LL_STATE llState; /* Bit stream parser state memory */
+ UCHAR bsFrameParse; /* Current parse frame context index */
+ UCHAR bsFrameDecode; /* Current decode/apply frame context index */
+ UCHAR bsFrameDelay; /* Amount of frames delay between parsing and processing.
+ Required i.e. for interpolation error concealment. */
+
+ /* User prameters */
+ SPATIALDEC_PARAM mpegSurroundUserParams;
+
+ /* Internal flags */
+ SPATIAL_DEC_UPMIX_TYPE upmixType;
+ int initFlags[1];
+ MPEGS_ANCSTARTSTOP ancStartStopPrev;
+ MPEGS_SYNCSTATE fOnSync[1];
+
+ /* Inital decoder configuration */
+ SPATIAL_DEC_CONFIG decConfig;
+};
+
+static SACDEC_ERROR sscParseCheck(const SPATIAL_SPECIFIC_CONFIG *pSsc);
+
+/**
+ * \brief Get the number of QMF bands from the sampling frequency (in Hz)
+ **/
+static int mpegSurroundDecoder_GetNrOfQmfBands(
+ const SPATIAL_SPECIFIC_CONFIG *pSsc, UINT sampleRate) {
+ UINT samplingFrequency = sampleRate;
+ int qmfBands = 64;
+
+ if (pSsc != NULL) {
+ switch (pSsc->coreCodec) {
+ case AOT_USAC:
+ if ((pSsc->stereoConfigIndex == 3)) {
+ static const UCHAR mapIdx2QmfBands[3] = {24, 32, 16};
+ FDK_ASSERT((pSsc->coreSbrFrameLengthIndex >= 2) &&
+ (pSsc->coreSbrFrameLengthIndex <= 4));
+ qmfBands = mapIdx2QmfBands[pSsc->coreSbrFrameLengthIndex - 2];
+ }
+ return qmfBands;
+ default:
+ samplingFrequency = pSsc->samplingFreq;
+ break;
+ }
+ }
+
+ /* number of QMF bands depend on sampling frequency, see FDIS 23003-1:2006
+ * Chapter 6.3.3 */
+ if (samplingFrequency < 27713) {
+ qmfBands = 32;
+ }
+ if (samplingFrequency > 55426) {
+ qmfBands = 128;
+ }
+
+ return qmfBands;
+}
+
+/**
+ * \brief Analyse init flags
+ **/
+static int mpegSurroundDecoder_CalcInitFlags(SPATIAL_SPECIFIC_CONFIG *pSsc1,
+ SPATIAL_SPECIFIC_CONFIG *pSsc2,
+ int upmixTypeFlag,
+ int binauralQualityFlag,
+ int partiallyComplexFlag,
+ int *ctrlFlags) {
+ /* Analyse core coder */
+ if (pSsc1->coreCodec != pSsc2->coreCodec) {
+ *ctrlFlags |= MASK_MPEGS_INIT_ALL_STATES;
+ *ctrlFlags |= MASK_MPEGS_INIT_ALL_PARAMS;
+ } else {
+ /* Analyse elements for initialization of space analysis qmf filterbank */
+ if ((partiallyComplexFlag) || (pSsc1->treeConfig != pSsc2->treeConfig) ||
+ (pSsc1->samplingFreq != pSsc2->samplingFreq)) {
+ *ctrlFlags |= MPEGS_INIT_STATES_ANA_QMF_FILTER;
+ *ctrlFlags |= MPEGS_INIT_STATES_ANA_HYB_FILTER;
+ }
+
+ /* Analyse elements for initialization of space synthesis qmf filterbank */
+ if ((upmixTypeFlag) || (partiallyComplexFlag) ||
+ (pSsc1->treeConfig != pSsc2->treeConfig) ||
+ (pSsc1->samplingFreq != pSsc2->samplingFreq) ||
+ (pSsc1->bsFixedGainDMX != pSsc2->bsFixedGainDMX)) {
+ *ctrlFlags |= MPEGS_INIT_STATES_SYN_QMF_FILTER;
+ }
+
+ /* Analyse elements for initialization of decorrelator */
+ if ((upmixTypeFlag) || (partiallyComplexFlag) ||
+ (pSsc1->treeConfig != pSsc2->treeConfig) ||
+ (pSsc1->samplingFreq != pSsc2->samplingFreq) ||
+ (pSsc1->decorrConfig != pSsc2->decorrConfig)) {
+ *ctrlFlags |= MPEGS_INIT_STATES_DECORRELATOR;
+ }
+
+ /* Analyse elements for initialization of m1 and m2 calculation */
+ if ((upmixTypeFlag) || (binauralQualityFlag) ||
+ (pSsc1->treeConfig != pSsc2->treeConfig) ||
+ (pSsc1->samplingFreq != pSsc2->samplingFreq))
+
+ {
+ *ctrlFlags |= MPEGS_INIT_STATES_M1M2;
+ }
+
+ /* Analyse elements for initialization of GES */
+ if ((upmixTypeFlag) || (pSsc1->treeConfig != pSsc2->treeConfig) ||
+ (pSsc1->tempShapeConfig != pSsc2->tempShapeConfig)) {
+ *ctrlFlags |= MPEGS_INIT_STATES_GES;
+ }
+
+ /* Analyse elements for initialization of FDreverb */
+ if ((upmixTypeFlag) || (binauralQualityFlag) || (partiallyComplexFlag) ||
+ (pSsc1->samplingFreq != pSsc2->samplingFreq) ||
+ (pSsc1->nTimeSlots != pSsc2->nTimeSlots)) {
+ *ctrlFlags |= MPEGS_INIT_STATES_REVERB;
+ }
+
+ /* Reset previous frame data whenever the config changes */
+ if (*ctrlFlags & MPEGS_INIT_CONFIG) {
+ *ctrlFlags |= MPEGS_INIT_STATES_PARAM;
+ }
+ }
+
+ return MPS_OK;
+}
+
+/**
+ * \brief Reset MPEG Surround status info
+ **/
+static void updateMpegSurroundDecoderStatus(
+ CMpegSurroundDecoder *pMpegSurroundDecoder, int initFlags,
+ MPEGS_SYNCSTATE fOnSync, MPEGS_ANCSTARTSTOP ancStartStopPrev) {
+ pMpegSurroundDecoder->initFlags[pMpegSurroundDecoder->bsFrameDecode] |=
+ initFlags;
+ if ((pMpegSurroundDecoder->mpegSurroundSscIsGlobalCfg != 0) &&
+ (pMpegSurroundDecoder->fOnSync[pMpegSurroundDecoder->bsFrameDecode] >=
+ MPEGS_SYNC_FOUND) &&
+ (fOnSync < MPEGS_SYNC_FOUND)) {
+ pMpegSurroundDecoder->fOnSync[pMpegSurroundDecoder->bsFrameDecode] =
+ MPEGS_SYNC_FOUND;
+ } else {
+ pMpegSurroundDecoder->fOnSync[pMpegSurroundDecoder->bsFrameDecode] =
+ fOnSync;
+ }
+ pMpegSurroundDecoder->ancStartStopPrev = ancStartStopPrev;
+}
+
+static SACDEC_ERROR mpegSurroundDecoder_Create(
+ CMpegSurroundDecoder **pMpegSurroundDecoder, int stereoConfigIndex,
+ HANDLE_FDK_QMF_DOMAIN pQmfDomain);
+
+SAC_INSTANCE_AVAIL
+mpegSurroundDecoder_IsFullMpegSurroundDecoderInstanceAvailable(
+ CMpegSurroundDecoder *pMpegSurroundDecoder) {
+ SAC_INSTANCE_AVAIL instanceAvailable = SAC_INSTANCE_NOT_FULL_AVAILABLE;
+
+ if (pMpegSurroundDecoder->pSpatialDec != NULL) {
+ instanceAvailable = SAC_INSTANCE_FULL_AVAILABLE;
+ }
+
+ return instanceAvailable;
+}
+
+SACDEC_ERROR mpegSurroundDecoder_Open(
+ CMpegSurroundDecoder **pMpegSurroundDecoder, int stereoConfigIndex,
+ HANDLE_FDK_QMF_DOMAIN pQmfDomain) {
+ SACDEC_ERROR error;
+
+ error = mpegSurroundDecoder_Create(pMpegSurroundDecoder, stereoConfigIndex,
+ pQmfDomain);
+
+ return error;
+}
+
+/**
+ * \brief Renamed function from getUpmixType to check_UParam_Build_DecConfig.
+ * This function checks if user params, decoder config and SSC are valid
+ * and if the decoder build can handle all this settings.
+ * The upmix type may be modified by this function.
+ * It is called in initMpegSurroundDecoder() after the ssc parse check,
+ * to have all checks in one place and to ensure these checks are always
+ * performed if config changes (inband and out-of-band).
+ *
+ * \param pUserParams User data handle.
+ * \param pDecConfig decoder config handle.
+ * \param pSsc spatial specific config handle.
+ * \param pUpmixType upmix type which is set by this function
+ *
+ * \return MPS_OK on sucess, and else on failure.
+ */
+static SACDEC_ERROR check_UParam_Build_DecConfig(
+ SPATIALDEC_PARAM const *pUserParams, SPATIAL_DEC_CONFIG const *pDecConfig,
+ const SPATIAL_SPECIFIC_CONFIG *pSsc, SPATIAL_DEC_UPMIX_TYPE *pUpmixType) {
+ int dmxChannels, outChannels, maxNumOutChannels;
+
+ FDK_ASSERT(pUserParams != NULL);
+ FDK_ASSERT(pUpmixType != NULL);
+
+ /* checks if implementation can handle the Ssc */
+
+ switch (pSsc->treeConfig) {
+ case SPATIALDEC_MODE_RSVD7: /* 212 */
+ dmxChannels = 1;
+ outChannels = 2;
+ break;
+ default:
+ return MPS_UNSUPPORTED_CONFIG;
+ }
+
+ /* ------------------------------------------- */
+
+ /* Analyse pDecConfig params */
+ switch (pDecConfig->binauralMode) {
+ case BINAURAL_NONE:
+ break;
+ default:
+ return MPS_UNSUPPORTED_CONFIG;
+ }
+
+ switch (pDecConfig->decoderMode) {
+ case EXT_HQ_ONLY:
+ break;
+ default:
+ return MPS_UNSUPPORTED_CONFIG;
+ }
+
+ switch (pDecConfig->maxNumOutputChannels) {
+ case OUTPUT_CHANNELS_DEFAULT:
+ /* No special restrictions -> Get the level restriction: */
+ switch (pDecConfig->decoderLevel) {
+ case DECODER_LEVEL_0:
+ maxNumOutChannels = 2;
+ break;
+ default:
+ return MPS_UNSUPPORTED_CONFIG;
+ }
+ break;
+ case OUTPUT_CHANNELS_2_0:
+ maxNumOutChannels = 2;
+ break;
+ default:
+ return MPS_UNSUPPORTED_CONFIG;
+ }
+ /* ------------------------- */
+
+ /* check if we can handle user params */
+ if (pUserParams->blindEnable == 1) {
+ return MPS_UNSUPPORTED_CONFIG;
+ }
+ {
+ switch ((SAC_DEC_OUTPUT_MODE)pUserParams->outputMode) {
+ case SACDEC_OUT_MODE_NORMAL:
+ if (maxNumOutChannels >= outChannels) {
+ *pUpmixType = UPMIX_TYPE_NORMAL;
+ } else {
+ { *pUpmixType = UPMIX_TYPE_BYPASS; }
+ }
+ break;
+ case SACDEC_OUT_MODE_STEREO:
+ if (dmxChannels == 1) {
+ if (outChannels == 2) {
+ *pUpmixType = UPMIX_TYPE_NORMAL;
+ }
+ } else {
+ *pUpmixType = UPMIX_TYPE_BYPASS;
+ }
+ break;
+ case SACDEC_OUT_MODE_6CHANNEL:
+ if (outChannels > 6) {
+ { *pUpmixType = UPMIX_TYPE_BYPASS; }
+ } else {
+ *pUpmixType = UPMIX_TYPE_NORMAL;
+ }
+ break;
+ default:
+ return MPS_UNSUPPORTED_CONFIG;
+ }
+ }
+
+ return MPS_OK;
+}
+
+/**
+ * \brief Init MPEG Surround decoder.
+ **/
+static SACDEC_ERROR initMpegSurroundDecoder(
+ CMpegSurroundDecoder *pMpegSurroundDecoder) {
+ SACDEC_ERROR err;
+ int initFlags = MPEGS_INIT_NONE, initFlagsDec;
+ int upmixTypeCurr = pMpegSurroundDecoder->upmixType;
+
+ FDK_ASSERT(pMpegSurroundDecoder != NULL);
+
+ SPATIAL_SPECIFIC_CONFIG *const pSSCinput =
+ &pMpegSurroundDecoder->spatialSpecificConfigBackup;
+ SPATIAL_SPECIFIC_CONFIG *const pSSCtarget =
+ &pMpegSurroundDecoder
+ ->spatialSpecificConfig[pMpegSurroundDecoder->bsFrameDecode];
+ initFlagsDec =
+ pMpegSurroundDecoder->initFlags[pMpegSurroundDecoder->bsFrameDecode];
+
+ if (pSSCinput->coreCodec != AOT_USAC) {
+ /* here we check if we have a valid Ssc */
+ err = sscParseCheck(pSSCinput);
+ if (err != MPS_OK) goto bail;
+ }
+
+ /* here we check if Ssc matches build; also check UParams and DecConfig */
+ /* if desired upmixType is changes */
+ err = check_UParam_Build_DecConfig(
+ &pMpegSurroundDecoder->mpegSurroundUserParams,
+ &pMpegSurroundDecoder->decConfig, pSSCinput,
+ &pMpegSurroundDecoder->upmixType);
+ if (err != MPS_OK) goto bail;
+
+ /* init config */
+ if (initFlagsDec & MPEGS_INIT_CHANGE_HEADER) {
+ initFlags |= MPEGS_INIT_CONFIG;
+ }
+ /* init all states */
+ if (initFlagsDec & MPEGS_INIT_CLEAR_HISTORY) {
+ initFlags |= MASK_MPEGS_INIT_ALL_STATES;
+ }
+ if (initFlagsDec & MPEGS_INIT_CHANGE_CONCEAL_PARAMS) {
+ initFlags |= MPEGS_INIT_PARAMS_ERROR_CONCEALMENT;
+ }
+
+ if (initFlagsDec & MPEGS_INIT_ENFORCE_REINIT) {
+ /* init all states */
+ initFlags |= MASK_MPEGS_INIT_ALL_STATES;
+ initFlags |= MASK_MPEGS_INIT_ALL_PARAMS;
+ } else {
+ /* analyse states which have to be initialized */
+ mpegSurroundDecoder_CalcInitFlags(
+ pSSCtarget, pSSCinput,
+ (upmixTypeCurr !=
+ pMpegSurroundDecoder->upmixType), /* upmixType changed */
+ 0, (initFlagsDec & MPEGS_INIT_CHANGE_PARTIALLY_COMPLEX) ? 1 : 0,
+ &initFlags);
+ }
+
+ {
+ int nrOfQmfBands;
+ FDKmemcpy(pSSCtarget, pSSCinput, sizeof(SPATIAL_SPECIFIC_CONFIG));
+
+ nrOfQmfBands = mpegSurroundDecoder_GetNrOfQmfBands(
+ pSSCtarget, pSSCtarget->samplingFreq);
+ err = FDK_SpatialDecInit(
+ pMpegSurroundDecoder->pSpatialDec,
+ &pMpegSurroundDecoder->bsFrames[pMpegSurroundDecoder->bsFrameDecode],
+ pSSCtarget, nrOfQmfBands, pMpegSurroundDecoder->upmixType,
+ &pMpegSurroundDecoder->mpegSurroundUserParams, initFlags);
+
+ if (err != MPS_OK) goto bail;
+
+ /* Signal that we got a header and can go on decoding */
+ if (err == MPS_OK) {
+ initFlagsDec = MPEGS_INIT_OK;
+ {
+ pMpegSurroundDecoder->fOnSync[pMpegSurroundDecoder->bsFrameDecode] =
+ MPEGS_SYNC_FOUND;
+ }
+ }
+ }
+
+bail:
+ pMpegSurroundDecoder->initFlags[pMpegSurroundDecoder->bsFrameDecode] =
+ initFlagsDec;
+ return err;
+}
+
+/**
+ * \brief Init MPEG Surround decoder.
+ **/
+SACDEC_ERROR mpegSurroundDecoder_Init(
+ CMpegSurroundDecoder *pMpegSurroundDecoder) {
+ SACDEC_ERROR err = MPS_OK;
+
+ if (pMpegSurroundDecoder->initFlags[pMpegSurroundDecoder->bsFrameDecode]) {
+ err = initMpegSurroundDecoder(pMpegSurroundDecoder);
+ }
+ return err;
+}
+
+/**
+ * \brief Open MPEG Surround decoder.
+ **/
+static SACDEC_ERROR mpegSurroundDecoder_Create(
+ CMpegSurroundDecoder **pMpegSurroundDecoder, int stereoConfigIndex,
+ HANDLE_FDK_QMF_DOMAIN pQmfDomain) {
+ SACDEC_ERROR err = MPS_OK;
+ CMpegSurroundDecoder *sacDec = NULL;
+ spatialDec *self = NULL;
+
+ /* decoderLevel decoderMode maxNumOutputChannels binauralMode */
+ static const SPATIAL_DEC_CONFIG decConfig = {
+ (CFG_LEVEL)(0), EXT_HQ_ONLY, OUTPUT_CHANNELS_DEFAULT, BINAURAL_NONE};
+
+ if (*pMpegSurroundDecoder == NULL) {
+ FDK_ALLOCATE_MEMORY_1D(*pMpegSurroundDecoder, 1, CMpegSurroundDecoder)
+
+ for (int i = 0; i < 1; i++) {
+ err = SpatialDecCreateBsFrame(&(*pMpegSurroundDecoder)->bsFrames[i],
+ &(*pMpegSurroundDecoder)->llState);
+ if (err != MPS_OK) {
+ sacDec = *pMpegSurroundDecoder;
+ goto bail;
+ }
+ }
+ (*pMpegSurroundDecoder)->pQmfDomain = pQmfDomain;
+
+ (*pMpegSurroundDecoder)->bsFrameDelay = 1;
+ (*pMpegSurroundDecoder)->bsFrameParse = 0;
+ (*pMpegSurroundDecoder)->bsFrameDecode = 0;
+
+ return err;
+ } else {
+ sacDec = *pMpegSurroundDecoder;
+ }
+
+ if (sacDec->pSpatialDec == NULL) {
+ if ((self = FDK_SpatialDecOpen(&decConfig, stereoConfigIndex)) == NULL) {
+ err = MPS_OUTOFMEMORY;
+ goto bail;
+ }
+ } else {
+ self = sacDec->pSpatialDec;
+ }
+
+ self->pQmfDomain = sacDec->pQmfDomain;
+
+ sacDec->pSpatialDec = self;
+
+ /* default parameter set */
+ sacDec->mpegSurroundUserParams.outputMode = SACDEC_OUT_MODE_NORMAL;
+ sacDec->mpegSurroundUserParams.blindEnable = 0;
+ sacDec->mpegSurroundUserParams.bypassMode = 0;
+ sacDec->mpegSurroundUserParams.concealMethod = 1;
+ sacDec->mpegSurroundUserParams.concealNumKeepFrames = 10;
+ sacDec->mpegSurroundUserParams.concealFadeOutSlopeLength = 5;
+ sacDec->mpegSurroundUserParams.concealFadeInSlopeLength = 5;
+ sacDec->mpegSurroundUserParams.concealNumReleaseFrames = 3;
+ sacDec->mpegSurroundSscIsGlobalCfg = 0;
+ sacDec->mpegSurroundUseTimeInterface = 1;
+ sacDec->mpegSurroundDecoderLevel = decConfig.decoderLevel;
+
+ sacDec->upmixType = UPMIX_TYPE_NORMAL;
+
+ /* signalize spatial decoder re-initalization */
+ updateMpegSurroundDecoderStatus(sacDec, MPEGS_INIT_ENFORCE_REINIT,
+ MPEGS_SYNC_LOST, MPEGS_STOP);
+
+ /* return decoder instance */
+ *pMpegSurroundDecoder = sacDec;
+ sacDec->decConfig = decConfig;
+
+ SpatialDecInitParserContext(sacDec->pSpatialDec);
+
+ return err;
+
+bail:
+ if (sacDec != NULL) {
+ mpegSurroundDecoder_Close(sacDec);
+ }
+ *pMpegSurroundDecoder = NULL;
+ if (err == MPS_OK) {
+ return MPS_OUTOFMEMORY;
+ } else {
+ return err;
+ }
+}
+
+/**
+ * \brief Config MPEG Surround decoder.
+ **/
+SACDEC_ERROR mpegSurroundDecoder_Config(
+ CMpegSurroundDecoder *pMpegSurroundDecoder, HANDLE_FDK_BITSTREAM hBs,
+ AUDIO_OBJECT_TYPE coreCodec, INT samplingRate, INT stereoConfigIndex,
+ INT coreSbrFrameLengthIndex, INT configBytes, const UCHAR configMode,
+ UCHAR *configChanged) {
+ SACDEC_ERROR err = MPS_OK;
+ SPATIAL_SPECIFIC_CONFIG spatialSpecificConfig;
+
+ switch (coreCodec) {
+ case AOT_DRM_USAC:
+ case AOT_USAC:
+ if (configMode == AC_CM_DET_CFG_CHANGE) {
+ /* In config detection mode write spatial specific config parameters
+ * into temporarily allocated structure */
+ err = SpatialDecParseMps212Config(
+ hBs, &spatialSpecificConfig, samplingRate, coreCodec,
+ stereoConfigIndex, coreSbrFrameLengthIndex);
+ } else {
+ err = SpatialDecParseMps212Config(
+ hBs, &pMpegSurroundDecoder->spatialSpecificConfigBackup,
+ samplingRate, coreCodec, stereoConfigIndex,
+ coreSbrFrameLengthIndex);
+ }
+ break;
+ case AOT_ER_AAC_ELD:
+ case AOT_ER_AAC_LD:
+ if (configMode == AC_CM_DET_CFG_CHANGE) {
+ /* In config detection mode write spatial specific config parameters
+ * into temporarily allocated structure */
+ err = SpatialDecParseSpecificConfig(hBs, &spatialSpecificConfig,
+ configBytes, coreCodec);
+ } else {
+ err = SpatialDecParseSpecificConfig(
+ hBs, &pMpegSurroundDecoder->spatialSpecificConfigBackup,
+ configBytes, coreCodec);
+ }
+ break;
+ default:
+ err = MPS_UNSUPPORTED_FORMAT;
+ break;
+ }
+
+ if (err != MPS_OK) {
+ goto bail;
+ }
+
+ if (configMode & AC_CM_DET_CFG_CHANGE) {
+ return err;
+ }
+
+ if (configMode & AC_CM_ALLOC_MEM) {
+ if (*configChanged) {
+ if ((err = mpegSurroundDecoder_Open(&pMpegSurroundDecoder,
+ stereoConfigIndex, NULL))) {
+ return err;
+ }
+ }
+ }
+
+ {
+ SPATIAL_SPECIFIC_CONFIG *sscParse =
+ &pMpegSurroundDecoder
+ ->spatialSpecificConfig[pMpegSurroundDecoder->bsFrameParse];
+
+ if (FDK_SpatialDecCompareSpatialSpecificConfigHeader(
+ &pMpegSurroundDecoder->spatialSpecificConfigBackup, sscParse)) {
+ pMpegSurroundDecoder->initFlags[pMpegSurroundDecoder->bsFrameParse] |=
+ MPEGS_INIT_CHANGE_HEADER;
+ /* Error resilience code */
+ if (pMpegSurroundDecoder->pSpatialDec == NULL) {
+ err = MPS_NOTOK;
+ goto bail;
+ }
+ SpatialDecInitParserContext(pMpegSurroundDecoder->pSpatialDec);
+ pMpegSurroundDecoder->pSpatialDec->pConfigCurrent =
+ &pMpegSurroundDecoder
+ ->spatialSpecificConfig[pMpegSurroundDecoder->bsFrameDecode];
+ }
+ }
+
+ if (err == MPS_OK) {
+ /* We got a valid out-of-band configuration so label it accordingly. */
+ pMpegSurroundDecoder->mpegSurroundSscIsGlobalCfg = 1;
+ }
+
+bail:
+ return err;
+}
+
+/**
+ * \brief Determine MPEG Surround operation mode.
+ **/
+static MPEGS_OPMODE mpegSurroundOperationMode(
+ CMpegSurroundDecoder *pMpegSurroundDecoder, int mpsDataBits) {
+ MPEGS_OPMODE mode;
+
+ {
+ if ((mpsDataBits > 0) &&
+ (pMpegSurroundDecoder->mpegSurroundUserParams.blindEnable == 0)) {
+ mode = MPEGS_OPMODE_MPS_PAYLOAD; /* Mode: Normal, Stereo or Binaural */
+ } else {
+ mode = MPEGS_OPMODE_NO_MPS_PAYLOAD; /* Mode: No MPEG Surround Payload */
+ updateMpegSurroundDecoderStatus(pMpegSurroundDecoder,
+ MPEGS_INIT_ERROR_PAYLOAD, MPEGS_SYNC_LOST,
+ MPEGS_STOP);
+ }
+ }
+
+ return (mode);
+}
+
+/**
+ * \brief Check ssc for parse errors.
+ * This one is called in initMpegSurroundDecoder()
+ * to ensure checking of inband and out-of-band mps configs.
+ * Only parse errors checked here! Check for valid config is done
+ * in check_UParam_Build_DecConfig()!
+ *
+ * \param pSsc spatial specific config handle.
+ *
+ * \return MPS_OK on sucess, and else on parse error.
+ */
+static SACDEC_ERROR sscParseCheck(const SPATIAL_SPECIFIC_CONFIG *pSsc) {
+ SACDEC_ERROR err = MPS_OK;
+
+ if (pSsc->samplingFreq > 96000) return MPS_PARSE_ERROR;
+ if (pSsc->samplingFreq < 8000) return MPS_PARSE_ERROR;
+
+ switch (pSsc->freqRes) {
+ case SPATIALDEC_FREQ_RES_28:
+ case SPATIALDEC_FREQ_RES_20:
+ case SPATIALDEC_FREQ_RES_14:
+ case SPATIALDEC_FREQ_RES_10:
+ case SPATIALDEC_FREQ_RES_23:
+ case SPATIALDEC_FREQ_RES_15:
+ case SPATIALDEC_FREQ_RES_12:
+ case SPATIALDEC_FREQ_RES_9:
+ case SPATIALDEC_FREQ_RES_7:
+ case SPATIALDEC_FREQ_RES_5:
+ case SPATIALDEC_FREQ_RES_4:
+ break;
+ case SPATIALDEC_FREQ_RES_40: /* 40 doesn't exist in ISO/IEC 23003-1 */
+ default:
+ return MPS_PARSE_ERROR;
+ }
+
+ if ((pSsc->treeConfig < 0) || (pSsc->treeConfig > 7)) {
+ return MPS_PARSE_ERROR;
+ }
+
+ if ((pSsc->quantMode < 0) || (pSsc->quantMode > 2)) {
+ return MPS_PARSE_ERROR;
+ }
+
+ if (pSsc->tempShapeConfig == 3) {
+ return MPS_PARSE_ERROR;
+ }
+
+ if (pSsc->decorrConfig == 3) {
+ return MPS_PARSE_ERROR;
+ }
+
+ /* now we are sure there were no parsing errors */
+
+ return err;
+}
+
+/**
+ * \brief Check number of time slots
+ *
+ * Basically the mps frame length must be a multiple of the core coder frame
+ * length. The below table shows all valid configurations in detail. See ISO/IEC
+ * 23003-1: "Table 4A - Allowed values for bsFrameLength in the Baseline MPEG
+ * Surround Profile"
+ *
+ * Downmix Coder Downmix Code Allowed values for bsFrameLength
+ * Allowed frame sizes for normal, downsampled and upsampled MPS Framelength
+ * (QMF Samples)
+ *
+ * AAC 1024 16 15, 31, 47, 63 1024 2048 3072 4096
+ * downsampled MPS 32 31, 63 1024 2048 upsampled MPS
+ * 8 7, 15, 23, 31, 39, 47, 55, 63, 71 1024 2048 3072 4096
+ * 5120 6144 7168 8192 9216
+ *
+ * AAC 960 15 14, 29, 44, 59 960 1920 2880 3840
+ * downsampled MPS 30 29, 59 960 1920 upsampled MPS
+ * 7,5 14, 29, 44, 59 1920 3840 5760 7680
+ *
+ * HE-AAC 1024/2048 32 31, 63 2048 4096 downsampled MPS
+ * 64 63 2048 upsampled MPS
+ * 16 15, 31, 47, 63 2048 4096 6144 8192
+ *
+ * HE-AAC 960/1920 30 29, 59 1920 3840 downsampled MPS
+ * 60 59 1920 upsampled MPS
+ * 15 14, 29, 44, 59 1920 3840 5760 7680
+ *
+ * BSAC 16 15, 31, 47, 63 1024 2048 3072 4096
+ * downsampled MPS 32 31, 63 1024 2048 upsampled MPS
+ * 8 7, 15, 23, 31, 39, 47, 55, 63, 71 1024 2048 3072 4096
+ * 5120 6144 7168 8192 9216
+ *
+ * BSAC with SBR 32 31, 63 2048 4096 downsampled MPS
+ * 64 63 2048 upsampled MPS
+ * 16 15, 31, 47, 63 2048 4096 6144 8192
+ *
+ * AAC LD 512 8 7, 15, 23, 31, 39, 47, 55, 63, 71
+ * 512 1024 1536 2048 2560 3072 3584 4096 4608 downsampled MPS
+ * 16 15, 31, 47, 63 512 1024 1536 2048
+ *
+ * AAC ELD 512 8 7, 15, 23, 31, 39, 47, 55, 63, 71
+ * 512 1024 1536 2048 2560 3072 3584 4096 4608 downsampled MPS
+ * 16 15, 31, 47, 63 512 1024 1536 2048
+ *
+ * AAC ELD with SBR 512/1024 16 15, 31, 47, 63 1024 2048 3072 4096
+ * downsampled MPS 32 31, 63 1024 2048 upsampled MPS
+ * 8 7, 15, 23, 31, 39, 47, 55, 63, 71 1024 2048 3072 4096
+ * 5120 6144 7168 8192 9216
+ *
+ * MPEG1/2 Layer II 18 17, 35, 53, 71 1152 2304 3456 4608
+ * downsampled MPS 36 35, 71 1152 2304
+ *
+ * MPEG1/2 Layer III 18 17, 35, 53, 71 1152 2304 3456 4608
+ * downsampled MPS 36 35, 71 1152 2304
+ *
+ * \param frameLength
+ * \param qmfBands
+ * \param timeSlots
+ *
+ * \return error code
+ */
+SACDEC_ERROR checkTimeSlots(int frameLength, int qmfBands, int timeSlots) {
+ int len;
+ int maxFrameLength;
+
+ if (qmfBands == 64) {
+ /* normal MPEG Surround */
+ switch (frameLength) {
+ case 960:
+ case 1920:
+ maxFrameLength = 3840;
+ break;
+ case 1024:
+ case 2048:
+ maxFrameLength = 4096;
+ break;
+ case 512:
+ case 1152:
+ maxFrameLength = 4608;
+ break;
+ default:
+ return MPS_PARSE_ERROR;
+ }
+ } else if (qmfBands == 32) {
+ /* downsampled MPEG Surround */
+ switch (frameLength) {
+ case 960:
+ case 1920:
+ maxFrameLength = 1920;
+ break;
+ case 512:
+ case 1024:
+ case 2048:
+ maxFrameLength = 2048;
+ break;
+ case 1152:
+ maxFrameLength = 2304;
+ break;
+ default:
+ return MPS_PARSE_ERROR;
+ }
+ } else if (qmfBands == 128) {
+ /* upsampled MPEG Surround */
+ switch (frameLength) {
+ case 1920:
+ maxFrameLength = 7680;
+ break;
+ case 1024:
+ maxFrameLength = 9216;
+ break;
+ case 2048:
+ maxFrameLength = 8192;
+ break;
+ case 512:
+ case 960:
+ case 1152:
+ /* no break, no support for upsampled MPEG Surround */
+ default:
+ return MPS_PARSE_ERROR;
+ }
+ } else {
+ return MPS_PARSE_ERROR;
+ }
+
+ len = frameLength;
+
+ while (len <= maxFrameLength) {
+ if (len == timeSlots * qmfBands) {
+ return MPS_OK;
+ }
+ len += frameLength;
+ }
+ return MPS_PARSE_ERROR;
+}
+
+/**
+ * \brief Check ssc for consistency (e.g. bit errors could cause trouble)
+ * First of currently two ssc-checks.
+ * This (old) one is called in mpegSurroundDecoder_Apply()
+ * only if inband mps config is contained in stream.
+ *
+ * New ssc check is split in two functions sscParseCheck() and
+ * check_UParam_Build_DecConfig(). sscParseCheck() checks only for correct
+ * parsing. check_UParam_Build_DecConfig() is used to check if we have a
+ * valid config. Both are called in initMpegSurroundDecoder() to ensure
+ * checking of inband and out-of-band mps configs.
+ *
+ * If this function can be integrated into the new functions.
+ * We can remove this one.
+ *
+ * \param pSsc spatial specific config handle.
+ * \param frameLength
+ * \param sampleRate
+ *
+ * \return MPS_OK on sucess, and else on failure.
+ */
+static SACDEC_ERROR sscCheckInBand(SPATIAL_SPECIFIC_CONFIG *pSsc,
+ int frameLength, int sampleRate) {
+ SACDEC_ERROR err = MPS_OK;
+ int qmfBands;
+
+ FDK_ASSERT(pSsc != NULL);
+
+ /* core fs and mps fs must match */
+ if (pSsc->samplingFreq != sampleRate) {
+ err = MPS_PARSE_ERROR /* MPEGSDEC_SSC_PARSE_ERROR */;
+ }
+
+ qmfBands = mpegSurroundDecoder_GetNrOfQmfBands(pSsc, pSsc->samplingFreq);
+
+ if (checkTimeSlots(frameLength, qmfBands, pSsc->nTimeSlots) != MPS_OK) {
+ err = MPS_PARSE_ERROR;
+ }
+
+ return err;
+}
+
+SACDEC_ERROR
+mpegSurroundDecoder_ConfigureQmfDomain(
+ CMpegSurroundDecoder *pMpegSurroundDecoder,
+ SAC_INPUT_CONFIG sac_dec_interface, UINT coreSamplingRate,
+ AUDIO_OBJECT_TYPE coreCodec) {
+ SACDEC_ERROR err = MPS_OK;
+ FDK_QMF_DOMAIN_GC *pGC = NULL;
+
+ if (pMpegSurroundDecoder == NULL) {
+ return MPS_INVALID_HANDLE;
+ }
+
+ FDK_ASSERT(pMpegSurroundDecoder->pSpatialDec);
+
+ pGC = &pMpegSurroundDecoder->pQmfDomain->globalConf;
+ if (pMpegSurroundDecoder->mpegSurroundSscIsGlobalCfg) {
+ SPATIAL_SPECIFIC_CONFIG *pSSC =
+ &pMpegSurroundDecoder->spatialSpecificConfigBackup;
+ if (sac_dec_interface == SAC_INTERFACE_TIME) {
+ /* For SAC_INTERFACE_QMF these parameters are set by SBR. */
+ pGC->nBandsAnalysis_requested = mpegSurroundDecoder_GetNrOfQmfBands(
+ pSSC, coreSamplingRate); /* coreSamplingRate == outputSamplingRate for
+ SAC_INTERFACE_TIME */
+ pGC->nBandsSynthesis_requested = pGC->nBandsAnalysis_requested;
+ pGC->nInputChannels_requested =
+ fMax((UINT)pSSC->nInputChannels, (UINT)pGC->nInputChannels_requested);
+ }
+ pGC->nOutputChannels_requested =
+ fMax((UINT)pSSC->nOutputChannels, (UINT)pGC->nOutputChannels_requested);
+ } else {
+ if (sac_dec_interface == SAC_INTERFACE_TIME) {
+ /* For SAC_INTERFACE_QMF these parameters are set by SBR. */
+ pGC->nBandsAnalysis_requested = mpegSurroundDecoder_GetNrOfQmfBands(
+ NULL, coreSamplingRate); /* coreSamplingRate == outputSamplingRate for
+ SAC_INTERFACE_TIME */
+ pGC->nBandsSynthesis_requested = pGC->nBandsAnalysis_requested;
+ pGC->nInputChannels_requested =
+ pMpegSurroundDecoder->pSpatialDec->createParams.maxNumInputChannels;
+ }
+ pGC->nOutputChannels_requested =
+ pMpegSurroundDecoder->pSpatialDec->createParams.maxNumOutputChannels;
+ }
+ pGC->nQmfProcBands_requested = 64;
+ pGC->nQmfProcChannels_requested =
+ fMin((INT)pGC->nInputChannels_requested,
+ pMpegSurroundDecoder->pSpatialDec->createParams.maxNumInputChannels);
+
+ if (coreCodec == AOT_ER_AAC_ELD) {
+ pGC->flags_requested |= QMF_FLAG_MPSLDFB;
+ }
+
+ return err;
+}
+
+/**
+ * \brief Decode MPEG Surround frame.
+ **/
+int mpegSurroundDecoder_ParseNoHeader(
+ CMpegSurroundDecoder *pMpegSurroundDecoder, HANDLE_FDK_BITSTREAM hBs,
+ int *pMpsDataBits, int fGlobalIndependencyFlag) {
+ SACDEC_ERROR err = MPS_OK;
+ SPATIAL_SPECIFIC_CONFIG *sscParse;
+ int bitsAvail, numSacBits;
+
+ if (pMpegSurroundDecoder == NULL || hBs == NULL) {
+ return MPS_INVALID_HANDLE;
+ }
+
+ sscParse = &pMpegSurroundDecoder
+ ->spatialSpecificConfig[pMpegSurroundDecoder->bsFrameParse];
+
+ bitsAvail = FDKgetValidBits(hBs);
+
+ /* First spatial specific config is parsed into spatialSpecificConfigBackup,
+ * second spatialSpecificConfigBackup is copied into
+ * spatialSpecificConfig[bsFrameDecode] */
+ if (pMpegSurroundDecoder->initFlags[pMpegSurroundDecoder->bsFrameParse]) {
+ FDKmemcpy(sscParse, &pMpegSurroundDecoder->spatialSpecificConfigBackup,
+ sizeof(SPATIAL_SPECIFIC_CONFIG));
+ pMpegSurroundDecoder->fOnSync[pMpegSurroundDecoder->bsFrameParse] =
+ MPEGS_SYNC_FOUND;
+ }
+
+ if (bitsAvail <= 0) {
+ err = MPS_PARSE_ERROR;
+ } else {
+ err = SpatialDecParseFrameData(
+ pMpegSurroundDecoder->pSpatialDec,
+ &pMpegSurroundDecoder->bsFrames[pMpegSurroundDecoder->bsFrameParse],
+ hBs, sscParse, (UPMIXTYPE)pMpegSurroundDecoder->upmixType,
+ fGlobalIndependencyFlag);
+ if (err == MPS_OK) {
+ pMpegSurroundDecoder->bsFrames[pMpegSurroundDecoder->bsFrameParse]
+ .newBsData = 1;
+ }
+ }
+
+ numSacBits = bitsAvail - (INT)FDKgetValidBits(hBs);
+
+ if (numSacBits > bitsAvail) {
+ pMpegSurroundDecoder->bsFrames[pMpegSurroundDecoder->bsFrameParse]
+ .newBsData = 0;
+ err = MPS_PARSE_ERROR;
+ }
+
+ *pMpsDataBits -= numSacBits;
+
+ return err;
+}
+
+/**
+ * \brief Check, if ancType is valid.
+ **/
+static int isValidAncType(CMpegSurroundDecoder *pMpegSurroundDecoder,
+ int ancType) {
+ int ret = 1;
+
+ if ((ancType != MPEGS_ANCTYPE_HEADER_AND_FRAME) &&
+ (ancType != MPEGS_ANCTYPE_FRAME)) {
+ ret = 0;
+ }
+
+ if (ret == 0) {
+ updateMpegSurroundDecoderStatus(pMpegSurroundDecoder,
+ MPEGS_INIT_ERROR_PAYLOAD, MPEGS_SYNC_LOST,
+ MPEGS_STOP);
+ }
+
+ return (ret);
+}
+
+/**
+ * \brief Check, if ancStartStop is valid.
+ **/
+static int isValidAncStartStop(CMpegSurroundDecoder *pMpegSurroundDecoder,
+ int ancStartStop) {
+ int ret = 1;
+
+ switch (ancStartStop) {
+ case MPEGS_START:
+ /* Sequence start - start and continue - start not allowed */
+ if ((pMpegSurroundDecoder->ancStartStopPrev == MPEGS_START) ||
+ (pMpegSurroundDecoder->ancStartStopPrev == MPEGS_CONTINUE)) {
+ ret = 0;
+ }
+ break;
+
+ case MPEGS_STOP:
+ /* MPS payload of the previous frame must be valid if current type is stop
+ Sequence startstop - stop and stop - stop not allowed
+ Sequence startstop - continue and stop - continue are allowed */
+ if ((pMpegSurroundDecoder->ancStartStopPrev == MPEGS_STOP) ||
+ (pMpegSurroundDecoder->ancStartStopPrev == MPEGS_START_STOP)) {
+ ret = 0;
+ }
+ break;
+
+ case MPEGS_CONTINUE:
+ case MPEGS_START_STOP:
+ /* No error detection possible for this states */
+ break;
+ }
+
+ if (ret == 0) {
+ updateMpegSurroundDecoderStatus(pMpegSurroundDecoder,
+ MPEGS_INIT_ERROR_PAYLOAD, MPEGS_SYNC_LOST,
+ MPEGS_STOP);
+ } else {
+ pMpegSurroundDecoder->ancStartStopPrev = (MPEGS_ANCSTARTSTOP)ancStartStop;
+ }
+
+ return (ret);
+}
+
+int mpegSurroundDecoder_Parse(CMpegSurroundDecoder *pMpegSurroundDecoder,
+ HANDLE_FDK_BITSTREAM hBs, int *pMpsDataBits,
+ AUDIO_OBJECT_TYPE coreCodec, int sampleRate,
+ int frameSize, int fGlobalIndependencyFlag) {
+ SACDEC_ERROR err = MPS_OK;
+ SPATIAL_SPECIFIC_CONFIG *sscParse;
+ SPATIAL_BS_FRAME *bsFrame;
+ HANDLE_FDK_BITSTREAM hMpsBsData = NULL;
+ FDK_BITSTREAM mpsBsData;
+ int mpsDataBits = *pMpsDataBits;
+ int mpsBsBits;
+ MPEGS_ANCTYPE ancType;
+ MPEGS_ANCSTARTSTOP ancStartStop;
+
+ if (pMpegSurroundDecoder == NULL) {
+ return MPS_INVALID_HANDLE;
+ }
+
+ FDK_ASSERT(pMpegSurroundDecoder->pSpatialDec);
+
+ mpsBsBits = FDKgetValidBits(hBs);
+
+ sscParse = &pMpegSurroundDecoder
+ ->spatialSpecificConfig[pMpegSurroundDecoder->bsFrameParse];
+ bsFrame = &pMpegSurroundDecoder->bsFrames[pMpegSurroundDecoder->bsFrameParse];
+
+ /*
+ Find operation mode of mpeg surround decoder:
+ - MPEGS_OPMODE_EMM: Mode: Enhanced Matrix Mode (Blind)
+ - MPEGS_OPMODE_MPS_PAYLOAD: Mode: Normal, Stereo or Binaural
+ - MPEGS_OPMODE_NO_MPS_PAYLOAD: Mode: No MpegSurround Payload
+ */
+ {
+ /* Parse ancType and ancStartStop */
+ ancType = (MPEGS_ANCTYPE)FDKreadBits(hBs, 2);
+ ancStartStop = (MPEGS_ANCSTARTSTOP)FDKreadBits(hBs, 2);
+ mpsDataBits -= 4;
+
+ /* Set valid anc type flag, if ancType signals a payload with either header
+ * and frame or frame */
+ if (isValidAncType(pMpegSurroundDecoder, ancType)) {
+ /* Set valid anc startstop flag, if transmitted sequence is not illegal */
+ if (isValidAncStartStop(pMpegSurroundDecoder, ancStartStop)) {
+ switch (ancStartStop) {
+ case MPEGS_START:
+ /* Assuming that core coder frame size (AAC) is smaller than MPS
+ coder frame size. Save audio data for next frame. */
+ if (mpsDataBits > MPS_DATA_BUFFER_SIZE * 8) {
+ err = MPS_NOTOK;
+ goto bail;
+ }
+ for (int i = 0; i < mpsDataBits / 8; i++) {
+ pMpegSurroundDecoder->mpsData[i] = FDKreadBits(hBs, 8);
+ }
+ pMpegSurroundDecoder->mpsDataBits = mpsDataBits;
+ break;
+
+ case MPEGS_CONTINUE:
+ case MPEGS_STOP:
+ /* Assuming that core coder frame size (AAC) is smaller than MPS
+ coder frame size. Save audio data for next frame. */
+ if ((pMpegSurroundDecoder->mpsDataBits + mpsDataBits) >
+ MPS_DATA_BUFFER_SIZE * 8) {
+ err = MPS_NOTOK;
+ goto bail;
+ }
+ for (int i = 0; i < mpsDataBits / 8; i++) {
+ pMpegSurroundDecoder
+ ->mpsData[(pMpegSurroundDecoder->mpsDataBits / 8) + i] =
+ FDKreadBits(hBs, 8);
+ }
+ pMpegSurroundDecoder->mpsDataBits += mpsDataBits;
+ FDKinitBitStream(&mpsBsData, pMpegSurroundDecoder->mpsData,
+ MAX_BUFSIZE_BYTES,
+ pMpegSurroundDecoder->mpsDataBits, BS_READER);
+ hMpsBsData = &mpsBsData;
+ break;
+
+ case MPEGS_START_STOP:
+ pMpegSurroundDecoder->mpsDataBits = mpsDataBits;
+ hMpsBsData = hBs;
+ break;
+
+ default:
+ FDK_ASSERT(0);
+ }
+
+ if ((ancStartStop == MPEGS_STOP) ||
+ (ancStartStop == MPEGS_START_STOP)) {
+ switch (ancType) {
+ case MPEGS_ANCTYPE_HEADER_AND_FRAME: {
+ int parseResult, bitsRead;
+ SPATIAL_SPECIFIC_CONFIG spatialSpecificConfigTmp =
+ pMpegSurroundDecoder->spatialSpecificConfigBackup;
+
+ /* Parse spatial specific config */
+ bitsRead = FDKgetValidBits(hMpsBsData);
+
+ err = SpatialDecParseSpecificConfigHeader(
+ hMpsBsData,
+ &pMpegSurroundDecoder->spatialSpecificConfigBackup, coreCodec,
+ pMpegSurroundDecoder->upmixType);
+
+ bitsRead = (bitsRead - FDKgetValidBits(hMpsBsData));
+ parseResult = ((err == MPS_OK) ? bitsRead : -bitsRead);
+
+ if (parseResult < 0) {
+ parseResult = -parseResult;
+ err = MPS_PARSE_ERROR;
+ } else if (err == MPS_OK) {
+ /* Check SSC for consistency (e.g. bit errors could cause
+ * trouble) */
+ err = sscCheckInBand(
+ &pMpegSurroundDecoder->spatialSpecificConfigBackup,
+ frameSize, sampleRate);
+ }
+ if (err != MPS_OK) {
+ pMpegSurroundDecoder->spatialSpecificConfigBackup =
+ spatialSpecificConfigTmp;
+ break;
+ }
+
+ pMpegSurroundDecoder->mpsDataBits -= parseResult;
+
+ /* Initiate re-initialization, if header has changed */
+ if (FDK_SpatialDecCompareSpatialSpecificConfigHeader(
+ &pMpegSurroundDecoder->spatialSpecificConfigBackup,
+ sscParse) == MPS_UNEQUAL_SSC) {
+ pMpegSurroundDecoder
+ ->initFlags[pMpegSurroundDecoder->bsFrameParse] |=
+ MPEGS_INIT_CHANGE_HEADER;
+ SpatialDecInitParserContext(pMpegSurroundDecoder->pSpatialDec);
+ /* We found a valid in-band configuration. Therefore any
+ * previous config is invalid now. */
+ pMpegSurroundDecoder->mpegSurroundSscIsGlobalCfg = 0;
+ }
+ }
+ case MPEGS_ANCTYPE_FRAME:
+
+ if (pMpegSurroundDecoder
+ ->initFlags[pMpegSurroundDecoder->bsFrameParse] &
+ MPEGS_INIT_ERROR_PAYLOAD) {
+ err = MPS_PARSE_ERROR;
+ break;
+ }
+
+ /* First spatial specific config is parsed into
+ * spatialSpecificConfigBackup, second spatialSpecificConfigBackup
+ * is copied into spatialSpecificConfig[bsFrameDecode] */
+ if (pMpegSurroundDecoder
+ ->initFlags[pMpegSurroundDecoder->bsFrameParse]) {
+ FDKmemcpy(sscParse,
+ &pMpegSurroundDecoder->spatialSpecificConfigBackup,
+ sizeof(SPATIAL_SPECIFIC_CONFIG));
+ pMpegSurroundDecoder
+ ->fOnSync[pMpegSurroundDecoder->bsFrameParse] =
+ MPEGS_SYNC_FOUND;
+ }
+
+ if (pMpegSurroundDecoder
+ ->fOnSync[pMpegSurroundDecoder->bsFrameParse] >=
+ MPEGS_SYNC_FOUND) {
+ int nbits = 0, bitsAvail;
+
+ if (err != MPS_OK) {
+ break;
+ }
+
+ bitsAvail = FDKgetValidBits(hMpsBsData);
+
+ if (bitsAvail <= 0) {
+ err = MPS_PARSE_ERROR;
+ } else {
+ err = SpatialDecParseFrameData(
+ pMpegSurroundDecoder->pSpatialDec, bsFrame, hMpsBsData,
+ sscParse, (UPMIXTYPE)pMpegSurroundDecoder->upmixType,
+ fGlobalIndependencyFlag);
+ if (err == MPS_OK) {
+ bsFrame->newBsData = 1;
+ }
+ }
+
+ nbits = bitsAvail - (INT)FDKgetValidBits(hMpsBsData);
+
+ if ((nbits > bitsAvail) ||
+ (nbits > pMpegSurroundDecoder->mpsDataBits) ||
+ (pMpegSurroundDecoder->mpsDataBits > nbits + 7 &&
+ !IS_LOWDELAY(coreCodec))) {
+ bsFrame->newBsData = 0;
+ err = MPS_PARSE_ERROR;
+ break;
+ }
+ pMpegSurroundDecoder->mpsDataBits -= nbits;
+ }
+ break;
+
+ default: /* added to avoid compiler warning */
+ err = MPS_NOTOK;
+ break; /* added to avoid compiler warning */
+ } /* switch (ancType) */
+
+ if (err == MPS_OK) {
+ pMpegSurroundDecoder->ancStartStopPrev = ancStartStop;
+ } else {
+ updateMpegSurroundDecoderStatus(pMpegSurroundDecoder,
+ MPEGS_INIT_ERROR_PAYLOAD,
+ MPEGS_SYNC_LOST, MPEGS_STOP);
+ pMpegSurroundDecoder->mpsDataBits = 0;
+ }
+ } /* (ancStartStop == MPEGS_STOP) || (ancStartStop == MPEGS_START_STOP)
+ */
+ } /* validAncStartStop */
+ } /* validAncType */
+ }
+
+bail:
+
+ *pMpsDataBits -= (mpsBsBits - FDKgetValidBits(hBs));
+
+ return err;
+}
+
+int mpegSurroundDecoder_Apply(CMpegSurroundDecoder *pMpegSurroundDecoder,
+ INT_PCM *input, PCM_MPS *pTimeData,
+ const int timeDataSize, int timeDataFrameSize,
+ int *nChannels, int *frameSize, int sampleRate,
+ AUDIO_OBJECT_TYPE coreCodec,
+ AUDIO_CHANNEL_TYPE channelType[],
+ UCHAR channelIndices[],
+ const FDK_channelMapDescr *const mapDescr) {
+ SACDEC_ERROR err = MPS_OK;
+ PCM_MPS *pTimeOut = pTimeData;
+ UINT initControlFlags = 0, controlFlags = 0;
+ int timeDataRequiredSize = 0;
+ int newData;
+
+ if (pMpegSurroundDecoder == NULL) {
+ return MPS_INVALID_HANDLE;
+ }
+
+ FDK_ASSERT(pMpegSurroundDecoder->pSpatialDec);
+
+ if (!FDK_chMapDescr_isValid(mapDescr)) {
+ return MPS_INVALID_HANDLE;
+ }
+
+ if ((*nChannels <= 0) || (*nChannels > 2)) {
+ return MPS_NOTOK;
+ }
+
+ pMpegSurroundDecoder->pSpatialDec->pConfigCurrent =
+ &pMpegSurroundDecoder
+ ->spatialSpecificConfig[pMpegSurroundDecoder->bsFrameDecode];
+ newData = pMpegSurroundDecoder->bsFrames[pMpegSurroundDecoder->bsFrameParse]
+ .newBsData;
+
+ switch (mpegSurroundOperationMode(pMpegSurroundDecoder, 1000)) {
+ case MPEGS_OPMODE_MPS_PAYLOAD:
+ if (pMpegSurroundDecoder
+ ->initFlags[pMpegSurroundDecoder->bsFrameDecode]) {
+ err = initMpegSurroundDecoder(pMpegSurroundDecoder);
+ }
+
+ if (err == MPS_OK) {
+ if ((pMpegSurroundDecoder
+ ->fOnSync[pMpegSurroundDecoder->bsFrameDecode] !=
+ MPEGS_SYNC_COMPLETE) &&
+ (pMpegSurroundDecoder->bsFrames[pMpegSurroundDecoder->bsFrameDecode]
+ .bsIndependencyFlag == 1)) {
+ /* We got a valid header and independently decodeable frame data.
+ -> Go to the next sync level and start processing. */
+ pMpegSurroundDecoder->fOnSync[pMpegSurroundDecoder->bsFrameDecode] =
+ MPEGS_SYNC_COMPLETE;
+ }
+ } else {
+ /* We got a valid config header but found an error while parsing the
+ bitstream. Wait for the next independent frame and apply error
+ conealment in the meantime. */
+ pMpegSurroundDecoder->fOnSync[pMpegSurroundDecoder->bsFrameDecode] =
+ MPEGS_SYNC_FOUND;
+ controlFlags |= MPEGS_CONCEAL;
+ err = MPS_OK;
+ }
+ /*
+ Concealment:
+ - Bitstream is available, no sync found during bitstream processing
+ - Bitstream is available, sync lost due to corrupted bitstream
+ - Bitstream is available, sync found but no independent frame
+ */
+ if (pMpegSurroundDecoder->fOnSync[pMpegSurroundDecoder->bsFrameDecode] !=
+ MPEGS_SYNC_COMPLETE) {
+ controlFlags |= MPEGS_CONCEAL;
+ }
+ break;
+
+ case MPEGS_OPMODE_NO_MPS_PAYLOAD:
+ /* Concealment: No bitstream is available */
+ controlFlags |= MPEGS_CONCEAL;
+ break;
+
+ default:
+ err = MPS_NOTOK;
+ }
+
+ if (err != MPS_OK) {
+ goto bail;
+ }
+
+ /*
+ * Force BypassMode if choosen by user
+ */
+ if (pMpegSurroundDecoder->mpegSurroundUserParams.bypassMode) {
+ controlFlags |= MPEGS_BYPASSMODE;
+ }
+
+ if (pMpegSurroundDecoder->initFlags[pMpegSurroundDecoder->bsFrameDecode]) {
+ int startWithDfltCfg = 0;
+ /*
+ * Init with a default configuration if we came here and are still not
+ * initialized.
+ */
+ if (pMpegSurroundDecoder->initFlags[pMpegSurroundDecoder->bsFrameDecode] &
+ MPEGS_INIT_ENFORCE_REINIT) {
+ /* Get default spatial specific config */
+ if (FDK_SpatialDecInitDefaultSpatialSpecificConfig(
+ &pMpegSurroundDecoder->spatialSpecificConfigBackup, coreCodec,
+ *nChannels, sampleRate,
+ *frameSize /
+ mpegSurroundDecoder_GetNrOfQmfBands(NULL, sampleRate),
+ pMpegSurroundDecoder->mpegSurroundDecoderLevel,
+ pMpegSurroundDecoder->mpegSurroundUserParams.blindEnable)) {
+ err = MPS_NOTOK;
+ goto bail;
+ }
+
+ /* Initiate re-initialization, if header has changed */
+ if (FDK_SpatialDecCompareSpatialSpecificConfigHeader(
+ &pMpegSurroundDecoder->spatialSpecificConfigBackup,
+ &pMpegSurroundDecoder->spatialSpecificConfig
+ [pMpegSurroundDecoder->bsFrameDecode]) == MPS_UNEQUAL_SSC) {
+ pMpegSurroundDecoder->initFlags[pMpegSurroundDecoder->bsFrameDecode] |=
+ MPEGS_INIT_CHANGE_HEADER;
+ SpatialDecInitParserContext(pMpegSurroundDecoder->pSpatialDec);
+ }
+
+ startWithDfltCfg = 1;
+ }
+
+ /* First spatial specific config is parsed into spatialSpecificConfigBackup,
+ * second spatialSpecificConfigBackup is copied into spatialSpecificConfig
+ */
+ err = initMpegSurroundDecoder(pMpegSurroundDecoder);
+
+ if (startWithDfltCfg) {
+ /* initialized with default config, but no sync found */
+ /* maybe use updateMpegSurroundDecoderStatus later on */
+ pMpegSurroundDecoder->fOnSync[pMpegSurroundDecoder->bsFrameDecode] =
+ MPEGS_SYNC_LOST;
+ }
+
+ /* Since we do not have state MPEGS_SYNC_COMPLETE apply concealment */
+ controlFlags |= MPEGS_CONCEAL;
+
+ if (err != MPS_OK) {
+ goto bail;
+ }
+ }
+
+ /*
+ * Process MPEG Surround Audio
+ */
+ initControlFlags = controlFlags;
+
+ /* Check that provided output buffer is large enough. */
+ timeDataRequiredSize =
+ (timeDataFrameSize *
+ pMpegSurroundDecoder->pSpatialDec->numOutputChannelsAT *
+ pMpegSurroundDecoder->pQmfDomain->globalConf.nBandsSynthesis) /
+ pMpegSurroundDecoder->pQmfDomain->globalConf.nBandsAnalysis;
+ if (timeDataSize < timeDataRequiredSize) {
+ err = MPS_OUTPUT_BUFFER_TOO_SMALL;
+ goto bail;
+ }
+
+ if ((pMpegSurroundDecoder->pSpatialDec->pConfigCurrent->syntaxFlags &
+ SACDEC_SYNTAX_USAC) &&
+ (pMpegSurroundDecoder->pSpatialDec->stereoConfigIndex > 1)) {
+ FDK_ASSERT(timeDataRequiredSize >= timeDataFrameSize * *nChannels);
+ /* Place samples comprising QMF time slots spaced at QMF output Band raster
+ * to allow slot wise processing */
+ int timeDataFrameSizeOut =
+ (timeDataFrameSize *
+ pMpegSurroundDecoder->pQmfDomain->globalConf.nBandsSynthesis) /
+ pMpegSurroundDecoder->pQmfDomain->globalConf.nBandsAnalysis;
+ pMpegSurroundDecoder->pQmfDomain->globalConf.TDinput =
+ pTimeData + timeDataFrameSizeOut - timeDataFrameSize;
+ for (int i = *nChannels - 1; i >= 0; i--) {
+ FDKmemmove(pTimeData + (i + 1) * timeDataFrameSizeOut - timeDataFrameSize,
+ pTimeData + timeDataFrameSize * i,
+ sizeof(PCM_MPS) * timeDataFrameSize);
+ FDKmemclear(pTimeData + i * timeDataFrameSizeOut,
+ sizeof(PCM_MPS) * (timeDataFrameSizeOut - timeDataFrameSize));
+ }
+ } else {
+ if (pMpegSurroundDecoder->mpegSurroundUseTimeInterface) {
+ FDKmemcpy(input, pTimeData,
+ sizeof(INT_PCM) * (*nChannels) * (*frameSize));
+ pMpegSurroundDecoder->pQmfDomain->globalConf.TDinput = input;
+ }
+ }
+
+ /*
+ * Process MPEG Surround Audio
+ */
+ err = SpatialDecApplyFrame(
+ pMpegSurroundDecoder->pSpatialDec,
+ &pMpegSurroundDecoder->bsFrames[pMpegSurroundDecoder->bsFrameDecode],
+ pMpegSurroundDecoder->mpegSurroundUseTimeInterface ? INPUTMODE_TIME
+ : INPUTMODE_QMF_SBR,
+ pMpegSurroundDecoder->pQmfDomain->globalConf.TDinput, NULL, NULL,
+ pTimeOut, *frameSize, &controlFlags, *nChannels, mapDescr);
+ *nChannels = pMpegSurroundDecoder->pSpatialDec->numOutputChannelsAT;
+
+ if (err !=
+ MPS_OK) { /* A fatal error occured. Go back to start and try again: */
+ updateMpegSurroundDecoderStatus(pMpegSurroundDecoder,
+ MPEGS_INIT_ENFORCE_REINIT, MPEGS_SYNC_LOST,
+ MPEGS_STOP);
+ *frameSize =
+ 0; /* Declare that framework can not use the data in pTimeOut. */
+ } else {
+ if (((controlFlags & MPEGS_CONCEAL) &&
+ !(initControlFlags & MPEGS_CONCEAL)) ||
+ (pMpegSurroundDecoder->pSpatialDec->errInt !=
+ MPS_OK)) { /* Account for errors that occured in
+ SpatialDecApplyFrame(): */
+ updateMpegSurroundDecoderStatus(pMpegSurroundDecoder,
+ MPEGS_INIT_ERROR_PAYLOAD, MPEGS_SYNC_LOST,
+ MPEGS_STOP);
+ }
+ }
+
+ if ((err == MPS_OK) && !(controlFlags & MPEGS_BYPASSMODE) &&
+ !(pMpegSurroundDecoder->upmixType == UPMIX_TYPE_BYPASS)) {
+ SpatialDecChannelProperties(pMpegSurroundDecoder->pSpatialDec, channelType,
+ channelIndices, mapDescr);
+ }
+
+bail:
+
+ if (newData) {
+ /* numParameterSetsPrev shall only be read in the decode process, because of
+ that we can update this state variable here */
+ pMpegSurroundDecoder->pSpatialDec->numParameterSetsPrev =
+ pMpegSurroundDecoder->bsFrames[pMpegSurroundDecoder->bsFrameDecode]
+ .numParameterSets;
+ }
+
+ return (err);
+}
+
+/**
+ * \brief Free config dependent MPEG Surround memory.
+ **/
+SACDEC_ERROR mpegSurroundDecoder_FreeMem(
+ CMpegSurroundDecoder *pMpegSurroundDecoder) {
+ SACDEC_ERROR err = MPS_OK;
+
+ if (pMpegSurroundDecoder != NULL) {
+ FDK_SpatialDecClose(pMpegSurroundDecoder->pSpatialDec);
+ pMpegSurroundDecoder->pSpatialDec = NULL;
+ }
+
+ return err;
+}
+
+/**
+ * \brief Close MPEG Surround decoder.
+ **/
+void mpegSurroundDecoder_Close(CMpegSurroundDecoder *pMpegSurroundDecoder) {
+ if (pMpegSurroundDecoder != NULL) {
+ FDK_SpatialDecClose(pMpegSurroundDecoder->pSpatialDec);
+ pMpegSurroundDecoder->pSpatialDec = NULL;
+
+ for (int i = 0; i < 1; i++) {
+ SpatialDecCloseBsFrame(&pMpegSurroundDecoder->bsFrames[i]);
+ }
+
+ FDK_FREE_MEMORY_1D(pMpegSurroundDecoder);
+ }
+}
+
+#define SACDEC_VL0 2
+#define SACDEC_VL1 0
+#define SACDEC_VL2 0
+
+int mpegSurroundDecoder_GetLibInfo(LIB_INFO *info) {
+ int i;
+
+ if (info == NULL) {
+ return -1;
+ }
+
+ /* 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 -1;
+
+ info += i;
+
+ info->module_id = FDK_MPSDEC;
+#ifdef __ANDROID__
+ info->build_date = "";
+ info->build_time = "";
+#else
+ info->build_date = __DATE__;
+ info->build_time = __TIME__;
+#endif
+ info->title = "MPEG Surround Decoder";
+ info->version = LIB_VERSION(SACDEC_VL0, SACDEC_VL1, SACDEC_VL2);
+ LIB_VERSION_STRING(info);
+ info->flags = 0 | CAPF_MPS_LD | CAPF_MPS_USAC | CAPF_MPS_HQ |
+ CAPF_MPS_1CH_IN | CAPF_MPS_2CH_OUT; /* end flags */
+
+ return 0;
+}
+
+SACDEC_ERROR mpegSurroundDecoder_SetParam(
+ CMpegSurroundDecoder *pMpegSurroundDecoder, const SACDEC_PARAM param,
+ const INT value) {
+ SACDEC_ERROR err = MPS_OK;
+ SPATIALDEC_PARAM *pUserParams = NULL;
+
+ /* check decoder handle */
+ if (pMpegSurroundDecoder != NULL) {
+ /* init local shortcuts */
+ pUserParams = &pMpegSurroundDecoder->mpegSurroundUserParams;
+ } else {
+ err = MPS_INVALID_HANDLE;
+ /* check the parameter values before exiting. */
+ }
+
+ /* apply param value */
+ switch (param) {
+ case SACDEC_OUTPUT_MODE:
+ switch ((SAC_DEC_OUTPUT_MODE)value) {
+ case SACDEC_OUT_MODE_NORMAL:
+ case SACDEC_OUT_MODE_STEREO:
+ break;
+ default:
+ err = MPS_INVALID_PARAMETER;
+ }
+ if (err == MPS_OK) {
+ if (0) {
+ err = MPS_INVALID_PARAMETER;
+ } else if (pUserParams->outputMode != (UCHAR)value) {
+ pUserParams->outputMode = (UCHAR)value;
+ pMpegSurroundDecoder
+ ->initFlags[pMpegSurroundDecoder->bsFrameDecode] |=
+ MPEGS_INIT_CHANGE_OUTPUT_MODE;
+ }
+ }
+ break;
+
+ case SACDEC_INTERFACE:
+ if (value < 0 || value > 1) {
+ err = MPS_INVALID_PARAMETER;
+ }
+ if (err != MPS_OK) {
+ goto bail;
+ }
+ if (pMpegSurroundDecoder->mpegSurroundUseTimeInterface != (UCHAR)value) {
+ pMpegSurroundDecoder->mpegSurroundUseTimeInterface = (UCHAR)value;
+ pMpegSurroundDecoder->initFlags[pMpegSurroundDecoder->bsFrameDecode] |=
+ MPEGS_INIT_CHANGE_TIME_FREQ_INTERFACE;
+ }
+ break;
+
+ case SACDEC_BS_INTERRUPTION:
+ if ((err == MPS_OK) && (value != 0)) {
+ updateMpegSurroundDecoderStatus(pMpegSurroundDecoder,
+ MPEGS_INIT_BS_INTERRUPTION,
+ MPEGS_SYNC_LOST, MPEGS_STOP);
+ }
+ break;
+
+ case SACDEC_CLEAR_HISTORY:
+ if ((err == MPS_OK) && (value != 0)) {
+ /* Just reset the states and go on. */
+ updateMpegSurroundDecoderStatus(pMpegSurroundDecoder,
+ MPEGS_INIT_CLEAR_HISTORY,
+ MPEGS_SYNC_LOST, MPEGS_STOP);
+ }
+ break;
+
+ case SACDEC_CONCEAL_NUM_KEEP_FRAMES:
+ if (value < 0) { /* Check valid value range */
+ err = MPS_INVALID_PARAMETER;
+ }
+ if (err != MPS_OK) {
+ goto bail;
+ }
+ if (pUserParams->concealNumKeepFrames != (UINT)value) {
+ pUserParams->concealNumKeepFrames = (UINT)value;
+ pMpegSurroundDecoder->initFlags[pMpegSurroundDecoder->bsFrameDecode] |=
+ MPEGS_INIT_CHANGE_CONCEAL_PARAMS;
+ }
+ break;
+
+ case SACDEC_CONCEAL_FADE_OUT_SLOPE_LENGTH:
+ if (value < 0) { /* Check valid value range */
+ err = MPS_INVALID_PARAMETER;
+ }
+ if (err != MPS_OK) {
+ goto bail;
+ }
+ if (pUserParams->concealFadeOutSlopeLength != (UINT)value) {
+ pUserParams->concealFadeOutSlopeLength = (UINT)value;
+ pMpegSurroundDecoder->initFlags[pMpegSurroundDecoder->bsFrameDecode] |=
+ MPEGS_INIT_CHANGE_CONCEAL_PARAMS;
+ }
+ break;
+
+ case SACDEC_CONCEAL_FADE_IN_SLOPE_LENGTH:
+ if (value < 0) { /* Check valid value range */
+ err = MPS_INVALID_PARAMETER;
+ }
+ if (err != MPS_OK) {
+ goto bail;
+ }
+ if (pUserParams->concealFadeInSlopeLength != (UINT)value) {
+ pUserParams->concealFadeInSlopeLength = (UINT)value;
+ pMpegSurroundDecoder->initFlags[pMpegSurroundDecoder->bsFrameDecode] |=
+ MPEGS_INIT_CHANGE_CONCEAL_PARAMS;
+ }
+ break;
+
+ case SACDEC_CONCEAL_NUM_RELEASE_FRAMES:
+ if (value < 0) { /* Check valid value range */
+ err = MPS_INVALID_PARAMETER;
+ }
+ if (err != MPS_OK) {
+ goto bail;
+ }
+ if (pUserParams->concealNumReleaseFrames != (UINT)value) {
+ pUserParams->concealNumReleaseFrames = (UINT)value;
+ pMpegSurroundDecoder->initFlags[pMpegSurroundDecoder->bsFrameDecode] |=
+ MPEGS_INIT_CHANGE_CONCEAL_PARAMS;
+ }
+ break;
+
+ default:
+ err = MPS_INVALID_PARAMETER;
+ break;
+ } /* switch(param) */
+
+bail:
+ return err;
+}
+
+SACDEC_ERROR mpegSurroundDecoder_IsPseudoLR(
+ CMpegSurroundDecoder *pMpegSurroundDecoder, int *bsPseudoLr) {
+ if (pMpegSurroundDecoder != NULL) {
+ const SPATIAL_SPECIFIC_CONFIG *sscDecode =
+ &pMpegSurroundDecoder
+ ->spatialSpecificConfig[pMpegSurroundDecoder->bsFrameDecode];
+ *bsPseudoLr = (int)sscDecode->bsPseudoLr;
+ return MPS_OK;
+ } else
+ return MPS_INVALID_HANDLE;
+}
+
+/**
+ * \brief Get the signal delay caused by the MPEG Surround decoder module.
+ **/
+UINT mpegSurroundDecoder_GetDelay(const CMpegSurroundDecoder *self) {
+ INT outputDelay = 0;
+
+ if (self != NULL) {
+ const SPATIAL_SPECIFIC_CONFIG *sscDecode =
+ &self->spatialSpecificConfig[self->bsFrameDecode];
+ AUDIO_OBJECT_TYPE coreCodec = sscDecode->coreCodec;
+
+ /* See chapter 4.5 (delay and synchronization) of ISO/IEC FDIS 23003-1 and
+ chapter 5.4.3 of ISO/IEC FDIS 23003-2 for details on the following
+ figures. */
+
+ if (coreCodec > AOT_NULL_OBJECT) {
+ if (IS_LOWDELAY(coreCodec)) {
+ /* All low delay variants (ER-AAC-(E)LD): */
+ outputDelay += 256;
+ } else if (!IS_USAC(coreCodec)) {
+ /* By the method of elimination this is the GA (AAC-LC, HE-AAC, ...)
+ * branch: */
+ outputDelay += 320 + 257; /* cos to exp delay + QMF synthesis */
+ if (self->mpegSurroundUseTimeInterface) {
+ outputDelay += 320 + 384; /* QMF and hybrid analysis */
+ }
+ }
+ }
+ }
+
+ return (outputDelay);
+}