| /* ----------------------------------------------------------------------------- |
| 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 = (INT)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 = (INT)FDKgetValidBits(hMpsBsData); |
| |
| err = SpatialDecParseSpecificConfigHeader( |
| hMpsBsData, |
| &pMpegSurroundDecoder->spatialSpecificConfigBackup, coreCodec, |
| pMpegSurroundDecoder->upmixType); |
| |
| bitsRead = (bitsRead - (INT)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; |
| } |
| } |
| FDK_FALLTHROUGH; |
| 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 - (INT)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); |
| } |