mirror of
https://github.com/mstorsjo/fdk-aac.git
synced 2025-02-21 13:20:36 +01:00
Test: atest DecoderTestXheAac ; atest DecoderTestAacDrc Change-Id: I0001e0996a970e91a21bfe8ba051fdba0c06c219
1996 lines
67 KiB
C++
1996 lines
67 KiB
C++
/* -----------------------------------------------------------------------------
|
|
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;
|
|
};
|
|
|
|
SACDEC_ERROR
|
|
static sscCheckOutOfBand(const SPATIAL_SPECIFIC_CONFIG *pSsc,
|
|
const INT coreCodec, const INT sampleRate,
|
|
const INT frameSize);
|
|
|
|
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 frameSize,
|
|
INT stereoConfigIndex, INT coreSbrFrameLengthIndex, INT configBytes,
|
|
const UCHAR configMode, UCHAR *configChanged) {
|
|
SACDEC_ERROR err = MPS_OK;
|
|
SPATIAL_SPECIFIC_CONFIG spatialSpecificConfig;
|
|
SPATIAL_SPECIFIC_CONFIG *pSsc =
|
|
&pMpegSurroundDecoder->spatialSpecificConfigBackup;
|
|
|
|
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);
|
|
pSsc = &spatialSpecificConfig;
|
|
} 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);
|
|
pSsc = &spatialSpecificConfig;
|
|
} else {
|
|
err = SpatialDecParseSpecificConfig(
|
|
hBs, &pMpegSurroundDecoder->spatialSpecificConfigBackup,
|
|
configBytes, coreCodec);
|
|
}
|
|
break;
|
|
default:
|
|
err = MPS_UNSUPPORTED_FORMAT;
|
|
break;
|
|
}
|
|
|
|
if (err != MPS_OK) {
|
|
goto bail;
|
|
}
|
|
|
|
err = sscCheckOutOfBand(pSsc, coreCodec, samplingRate, frameSize);
|
|
|
|
if (err != MPS_OK) {
|
|
goto bail;
|
|
}
|
|
|
|
if (configMode & AC_CM_DET_CFG_CHANGE) {
|
|
return err;
|
|
}
|
|
|
|
if (configMode & AC_CM_ALLOC_MEM) {
|
|
if (*configChanged) {
|
|
err = mpegSurroundDecoder_Open(&pMpegSurroundDecoder, stereoConfigIndex,
|
|
NULL);
|
|
if (err) {
|
|
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) {
|
|
if (pSsc->samplingFreq > 96000) return MPS_PARSE_ERROR;
|
|
if (pSsc->samplingFreq < 8000) 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;
|
|
}
|
|
|
|
/* now we are sure there were no parsing errors */
|
|
|
|
return MPS_OK;
|
|
}
|
|
|
|
/**
|
|
* \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);
|
|
|
|
/* check ssc for parse errors */
|
|
if (sscParseCheck(pSsc) != MPS_OK) {
|
|
err = MPS_PARSE_ERROR;
|
|
}
|
|
|
|
/* 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;
|
|
pGC->flags_requested &= ~QMF_FLAG_CLDFB;
|
|
}
|
|
|
|
return err;
|
|
}
|
|
|
|
/**
|
|
* \brief Check out-of-band config
|
|
*
|
|
* \param pSsc spatial specific config handle.
|
|
* \param coreCodec core codec.
|
|
* \param sampleRate sampling frequency.
|
|
*
|
|
* \return errorStatus
|
|
*/
|
|
SACDEC_ERROR
|
|
sscCheckOutOfBand(const SPATIAL_SPECIFIC_CONFIG *pSsc, const INT coreCodec,
|
|
const INT sampleRate, const INT frameSize) {
|
|
FDK_ASSERT(pSsc != NULL);
|
|
int qmfBands = 0;
|
|
|
|
/* check ssc for parse errors */
|
|
if (sscParseCheck(pSsc) != MPS_OK) {
|
|
return MPS_PARSE_ERROR;
|
|
}
|
|
|
|
switch (coreCodec) {
|
|
case AOT_USAC:
|
|
case AOT_DRM_USAC:
|
|
/* ISO/IEC 23003-1:2007(E), Chapter 6.3.3, Support for lower and higher
|
|
* sampling frequencies */
|
|
if (pSsc->samplingFreq >= 55426) {
|
|
return MPS_PARSE_ERROR;
|
|
}
|
|
break;
|
|
case AOT_ER_AAC_LD:
|
|
case AOT_ER_AAC_ELD:
|
|
/* core fs and mps fs must match */
|
|
if (pSsc->samplingFreq != sampleRate) {
|
|
return MPS_PARSE_ERROR;
|
|
}
|
|
|
|
/* ISO/IEC 14496-3:2009 FDAM 3: Chapter 1.5.2.3, Levels for the Low Delay
|
|
* AAC v2 profile */
|
|
if (pSsc->samplingFreq > 48000) {
|
|
return MPS_PARSE_ERROR;
|
|
}
|
|
|
|
qmfBands = mpegSurroundDecoder_GetNrOfQmfBands(pSsc, pSsc->samplingFreq);
|
|
switch (frameSize) {
|
|
case 480:
|
|
if (!((qmfBands == 32) && (pSsc->nTimeSlots == 15))) {
|
|
return MPS_PARSE_ERROR;
|
|
}
|
|
break;
|
|
case 960:
|
|
if (!((qmfBands == 64) && (pSsc->nTimeSlots == 15))) {
|
|
return MPS_PARSE_ERROR;
|
|
}
|
|
break;
|
|
case 512:
|
|
if (!(((qmfBands == 32) && (pSsc->nTimeSlots == 16)) ||
|
|
((qmfBands == 64) && (pSsc->nTimeSlots == 8)))) {
|
|
return MPS_PARSE_ERROR;
|
|
}
|
|
break;
|
|
case 1024:
|
|
if (!((qmfBands == 64) && (pSsc->nTimeSlots == 16))) {
|
|
return MPS_PARSE_ERROR;
|
|
}
|
|
break;
|
|
default:
|
|
return MPS_PARSE_ERROR;
|
|
}
|
|
break;
|
|
default:
|
|
return MPS_PARSE_ERROR;
|
|
break;
|
|
}
|
|
|
|
return MPS_OK;
|
|
}
|
|
|
|
/**
|
|
* \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. */
|
|
if (pMpegSurroundDecoder->pQmfDomain->globalConf.nBandsAnalysis == 0) {
|
|
err = MPS_UNSUPPORTED_FORMAT;
|
|
goto bail;
|
|
}
|
|
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);
|
|
}
|