mirror of
https://github.com/mstorsjo/fdk-aac.git
synced 2025-06-05 22:39:13 +02:00
Snapshot 2bda038c16
Change-Id: If584e579464f28b97d50e51fc76ba654a5536c54
This commit is contained in:
989
libAACdec/src/aacdecoder_lib.cpp
Normal file
989
libAACdec/src/aacdecoder_lib.cpp
Normal file
@ -0,0 +1,989 @@
|
||||
|
||||
/* -----------------------------------------------------------------------------------------------------------
|
||||
Software License for The Fraunhofer FDK AAC Codec Library for Android
|
||||
|
||||
<EFBFBD> Copyright 1995 - 2012 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-4 AAC Decoder **************************
|
||||
|
||||
Author(s): Manuel Jander
|
||||
Description:
|
||||
|
||||
******************************************************************************/
|
||||
|
||||
#include "aacdecoder_lib.h"
|
||||
|
||||
#include "aac_ram.h"
|
||||
#include "aacdecoder.h"
|
||||
#include "tpdec_lib.h"
|
||||
#include "FDK_core.h" /* FDK_tools version info */
|
||||
|
||||
|
||||
#include "sbrdecoder.h"
|
||||
|
||||
|
||||
|
||||
|
||||
#include "conceal.h"
|
||||
|
||||
#include "aacdec_drc.h"
|
||||
|
||||
|
||||
|
||||
/* Decoder library info */
|
||||
#define AACDECODER_LIB_VL0 2
|
||||
#define AACDECODER_LIB_VL1 4
|
||||
#define AACDECODER_LIB_VL2 4
|
||||
#define AACDECODER_LIB_TITLE "AAC Decoder Lib"
|
||||
#define AACDECODER_LIB_BUILD_DATE __DATE__
|
||||
#define AACDECODER_LIB_BUILD_TIME __TIME__
|
||||
|
||||
static AAC_DECODER_ERROR
|
||||
setConcealMethod ( const HANDLE_AACDECODER self,
|
||||
const INT method );
|
||||
|
||||
|
||||
LINKSPEC_CPP AAC_DECODER_ERROR aacDecoder_GetFreeBytes ( const HANDLE_AACDECODER self, UINT *pFreeBytes){
|
||||
|
||||
/* reset free bytes */
|
||||
*pFreeBytes = 0;
|
||||
|
||||
/* check handle */
|
||||
if(!self)
|
||||
return AAC_DEC_INVALID_HANDLE;
|
||||
|
||||
/* return nr of free bytes */
|
||||
HANDLE_FDK_BITSTREAM hBs = transportDec_GetBitstream(self->hInput, 0);
|
||||
*pFreeBytes = FDKgetFreeBits(hBs) >> 3;
|
||||
|
||||
/* success */
|
||||
return AAC_DEC_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Config Decoder using a CSAudioSpecificConfig struct.
|
||||
*/
|
||||
static
|
||||
LINKSPEC_CPP AAC_DECODER_ERROR aacDecoder_Config(HANDLE_AACDECODER self, const CSAudioSpecificConfig *pAscStruct)
|
||||
{
|
||||
AAC_DECODER_ERROR err;
|
||||
|
||||
/* Initialize AAC core decoder, and update self->streaminfo */
|
||||
err = CAacDecoder_Init(self, pAscStruct);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
LINKSPEC_CPP AAC_DECODER_ERROR aacDecoder_ConfigRaw (
|
||||
HANDLE_AACDECODER self,
|
||||
UCHAR *conf[],
|
||||
const UINT length[] )
|
||||
{
|
||||
AAC_DECODER_ERROR err = AAC_DEC_OK;
|
||||
TRANSPORTDEC_ERROR errTp;
|
||||
UINT layer, nrOfLayers = self->nrOfLayers;
|
||||
|
||||
for(layer = 0; layer < nrOfLayers; layer++){
|
||||
if(length[layer] > 0){
|
||||
errTp = transportDec_OutOfBandConfig(self->hInput, conf[layer], length[layer], layer);
|
||||
if (errTp != TRANSPORTDEC_OK) {
|
||||
switch (errTp) {
|
||||
case TRANSPORTDEC_NEED_TO_RESTART:
|
||||
err = AAC_DEC_NEED_TO_RESTART;
|
||||
break;
|
||||
case TRANSPORTDEC_UNSUPPORTED_FORMAT:
|
||||
err = AAC_DEC_UNSUPPORTED_FORMAT;
|
||||
break;
|
||||
default:
|
||||
err = AAC_DEC_UNKNOWN;
|
||||
break;
|
||||
}
|
||||
/* if baselayer is OK we continue decoding */
|
||||
if(layer >= 1){
|
||||
self->nrOfLayers = layer;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static INT aacDecoder_ConfigCallback(void *handle, const CSAudioSpecificConfig *pAscStruct)
|
||||
{
|
||||
HANDLE_AACDECODER self = (HANDLE_AACDECODER)handle;
|
||||
AAC_DECODER_ERROR err = AAC_DEC_OK;
|
||||
TRANSPORTDEC_ERROR errTp;
|
||||
|
||||
{
|
||||
{
|
||||
err = aacDecoder_Config(self, pAscStruct);
|
||||
}
|
||||
}
|
||||
if (err == AAC_DEC_OK) {
|
||||
if ( self->flags & (AC_USAC|AC_RSVD50|AC_LD|AC_ELD)
|
||||
&& CConcealment_GetDelay(&self->concealCommonData) > 0 )
|
||||
{
|
||||
/* Revert to error concealment method Noise Substitution.
|
||||
Because interpolation is not implemented for USAC/RSVD50 or
|
||||
the additional delay is unwanted for low delay codecs. */
|
||||
setConcealMethod(self, 1);
|
||||
#ifdef DEBUG
|
||||
FDKprintf(" Concealment method was reverted to 1 !\n");
|
||||
#endif
|
||||
}
|
||||
errTp = TRANSPORTDEC_OK;
|
||||
} else {
|
||||
if (IS_INIT_ERROR(err)) {
|
||||
errTp = TRANSPORTDEC_UNSUPPORTED_FORMAT;
|
||||
} /* Fatal errors */
|
||||
else if (err == AAC_DEC_NEED_TO_RESTART) {
|
||||
errTp = TRANSPORTDEC_NEED_TO_RESTART;
|
||||
} else {
|
||||
errTp = TRANSPORTDEC_UNKOWN_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
return errTp;
|
||||
}
|
||||
|
||||
|
||||
|
||||
LINKSPEC_CPP AAC_DECODER_ERROR
|
||||
aacDecoder_AncDataInit ( HANDLE_AACDECODER self,
|
||||
UCHAR *buffer,
|
||||
int size )
|
||||
{
|
||||
CAncData *ancData = &self->ancData;
|
||||
|
||||
return CAacDecoder_AncDataInit(ancData, buffer, size);
|
||||
}
|
||||
|
||||
|
||||
LINKSPEC_CPP AAC_DECODER_ERROR
|
||||
aacDecoder_AncDataGet ( HANDLE_AACDECODER self,
|
||||
int index,
|
||||
UCHAR **ptr,
|
||||
int *size )
|
||||
{
|
||||
CAncData *ancData = &self->ancData;
|
||||
|
||||
return CAacDecoder_AncDataGet(ancData, index, ptr, size);
|
||||
}
|
||||
|
||||
|
||||
static AAC_DECODER_ERROR
|
||||
setConcealMethod ( const HANDLE_AACDECODER self, /*!< Handle of the decoder instance */
|
||||
const INT method )
|
||||
{
|
||||
AAC_DECODER_ERROR errorStatus = AAC_DEC_OK;
|
||||
CConcealParams *pConcealData = NULL;
|
||||
HANDLE_SBRDECODER hSbrDec = NULL;
|
||||
HANDLE_AAC_DRC hDrcInfo = NULL;
|
||||
HANDLE_PCM_DOWNMIX hPcmDmx = NULL;
|
||||
CConcealmentMethod backupMethod;
|
||||
int backupDelay = 0;
|
||||
int bsDelay = 0;
|
||||
|
||||
/* check decoder handle */
|
||||
if (self != NULL) {
|
||||
pConcealData = &self->concealCommonData;
|
||||
hSbrDec = self->hSbrDecoder;
|
||||
hDrcInfo = self->hDrcInfo;
|
||||
hPcmDmx = self->hPcmUtils;
|
||||
}
|
||||
|
||||
|
||||
/* Get current method/delay */
|
||||
backupMethod = CConcealment_GetMethod(pConcealData);
|
||||
backupDelay = CConcealment_GetDelay(pConcealData);
|
||||
|
||||
/* Be sure to set AAC and SBR concealment method simultaneously! */
|
||||
errorStatus =
|
||||
CConcealment_SetParams(
|
||||
pConcealData,
|
||||
(int)method, // concealMethod
|
||||
AACDEC_CONCEAL_PARAM_NOT_SPECIFIED, // concealFadeOutSlope
|
||||
AACDEC_CONCEAL_PARAM_NOT_SPECIFIED, // concealFadeInSlope
|
||||
AACDEC_CONCEAL_PARAM_NOT_SPECIFIED, // concealMuteRelease
|
||||
AACDEC_CONCEAL_PARAM_NOT_SPECIFIED // concealComfNoiseLevel
|
||||
);
|
||||
if ( (errorStatus != AAC_DEC_OK)
|
||||
&& (errorStatus != AAC_DEC_INVALID_HANDLE) ) {
|
||||
goto bail;
|
||||
}
|
||||
|
||||
/* Get new delay */
|
||||
bsDelay = CConcealment_GetDelay(pConcealData);
|
||||
|
||||
{
|
||||
SBR_ERROR sbrErr = SBRDEC_OK;
|
||||
|
||||
/* set SBR bitstream delay */
|
||||
sbrErr = sbrDecoder_SetParam (
|
||||
hSbrDec,
|
||||
SBR_SYSTEM_BITSTREAM_DELAY,
|
||||
bsDelay
|
||||
);
|
||||
|
||||
switch (sbrErr) {
|
||||
case SBRDEC_OK:
|
||||
case SBRDEC_NOT_INITIALIZED:
|
||||
if (self != NULL) {
|
||||
/* save the param value and set later
|
||||
(when SBR has been initialized) */
|
||||
self->sbrParams.bsDelay = bsDelay;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
errorStatus = AAC_DEC_SET_PARAM_FAIL;
|
||||
goto bail;
|
||||
}
|
||||
}
|
||||
|
||||
errorStatus =
|
||||
aacDecoder_drcSetParam (
|
||||
hDrcInfo,
|
||||
DRC_BS_DELAY,
|
||||
bsDelay
|
||||
);
|
||||
if ( (errorStatus != AAC_DEC_OK)
|
||||
&& (errorStatus != AAC_DEC_INVALID_HANDLE) ) {
|
||||
goto bail;
|
||||
}
|
||||
|
||||
if (errorStatus == AAC_DEC_OK) {
|
||||
PCMDMX_ERROR err =
|
||||
pcmDmx_SetParam (
|
||||
hPcmDmx,
|
||||
DMX_BS_DATA_DELAY,
|
||||
bsDelay
|
||||
);
|
||||
switch (err) {
|
||||
case PCMDMX_INVALID_HANDLE:
|
||||
errorStatus = AAC_DEC_INVALID_HANDLE;
|
||||
case PCMDMX_OK:
|
||||
break;
|
||||
default:
|
||||
errorStatus = AAC_DEC_SET_PARAM_FAIL;
|
||||
goto bail;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bail:
|
||||
if ( (errorStatus != AAC_DEC_OK)
|
||||
&& (errorStatus != AAC_DEC_INVALID_HANDLE) )
|
||||
{
|
||||
/* Revert to the initial state */
|
||||
CConcealment_SetParams (
|
||||
pConcealData,
|
||||
(int)backupMethod,
|
||||
AACDEC_CONCEAL_PARAM_NOT_SPECIFIED,
|
||||
AACDEC_CONCEAL_PARAM_NOT_SPECIFIED,
|
||||
AACDEC_CONCEAL_PARAM_NOT_SPECIFIED,
|
||||
AACDEC_CONCEAL_PARAM_NOT_SPECIFIED
|
||||
);
|
||||
/* Revert SBR bitstream delay */
|
||||
sbrDecoder_SetParam (
|
||||
hSbrDec,
|
||||
SBR_SYSTEM_BITSTREAM_DELAY,
|
||||
backupDelay
|
||||
);
|
||||
/* Revert DRC bitstream delay */
|
||||
aacDecoder_drcSetParam (
|
||||
hDrcInfo,
|
||||
DRC_BS_DELAY,
|
||||
backupDelay
|
||||
);
|
||||
/* Revert PCM mixdown bitstream delay */
|
||||
pcmDmx_SetParam (
|
||||
hPcmDmx,
|
||||
DMX_BS_DATA_DELAY,
|
||||
backupDelay
|
||||
);
|
||||
}
|
||||
|
||||
return errorStatus;
|
||||
}
|
||||
|
||||
|
||||
LINKSPEC_CPP AAC_DECODER_ERROR
|
||||
aacDecoder_SetParam ( const HANDLE_AACDECODER self, /*!< Handle of the decoder instance */
|
||||
const AACDEC_PARAM param, /*!< Parameter to set */
|
||||
const INT value) /*!< Parameter valued */
|
||||
{
|
||||
AAC_DECODER_ERROR errorStatus = AAC_DEC_OK;
|
||||
CConcealParams *pConcealData = NULL;
|
||||
HANDLE_AAC_DRC hDrcInfo = NULL;
|
||||
|
||||
/* check decoder handle */
|
||||
if (self != NULL) {
|
||||
pConcealData = &self->concealCommonData;
|
||||
hDrcInfo = self->hDrcInfo;
|
||||
}
|
||||
|
||||
/* configure the subsystems */
|
||||
switch (param)
|
||||
{
|
||||
case AAC_PCM_OUTPUT_INTERLEAVED:
|
||||
if (value < 0 || value > 1) {
|
||||
return AAC_DEC_SET_PARAM_FAIL;
|
||||
}
|
||||
if (self == NULL) {
|
||||
return AAC_DEC_INVALID_HANDLE;
|
||||
}
|
||||
self->outputInterleaved = value;
|
||||
break;
|
||||
|
||||
case AAC_PCM_OUTPUT_CHANNELS:
|
||||
{
|
||||
PCMDMX_ERROR err;
|
||||
|
||||
err = pcmDmx_SetParam (
|
||||
self->hPcmUtils,
|
||||
NUMBER_OF_OUTPUT_CHANNELS,
|
||||
value );
|
||||
|
||||
switch (err) {
|
||||
case PCMDMX_OK:
|
||||
break;
|
||||
case PCMDMX_INVALID_HANDLE:
|
||||
return AAC_DEC_INVALID_HANDLE;
|
||||
default:
|
||||
return AAC_DEC_SET_PARAM_FAIL;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case AAC_PCM_DUAL_CHANNEL_OUTPUT_MODE:
|
||||
{
|
||||
PCMDMX_ERROR err;
|
||||
|
||||
err = pcmDmx_SetParam (
|
||||
self->hPcmUtils,
|
||||
DUAL_CHANNEL_DOWNMIX_MODE,
|
||||
value );
|
||||
|
||||
switch (err) {
|
||||
case PCMDMX_OK:
|
||||
break;
|
||||
case PCMDMX_INVALID_HANDLE:
|
||||
return AAC_DEC_INVALID_HANDLE;
|
||||
default:
|
||||
return AAC_DEC_SET_PARAM_FAIL;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case AAC_PCM_OUTPUT_CHANNEL_MAPPING:
|
||||
switch (value) {
|
||||
case 0:
|
||||
self->channelOutputMapping = channelMappingTablePassthrough;
|
||||
break;
|
||||
case 1:
|
||||
self->channelOutputMapping = channelMappingTableWAV;
|
||||
break;
|
||||
default:
|
||||
errorStatus = AAC_DEC_SET_PARAM_FAIL;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
case AAC_QMF_LOWPOWER:
|
||||
if (self == NULL) {
|
||||
return AAC_DEC_INVALID_HANDLE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set QMF mode (might be overriden)
|
||||
* 0:HQ (complex)
|
||||
* 1:LP (partially complex)
|
||||
*/
|
||||
self->qmfModeUser = (QMF_MODE)value;
|
||||
break;
|
||||
|
||||
|
||||
case AAC_DRC_ATTENUATION_FACTOR:
|
||||
/* DRC compression factor (where 0 is no and 127 is max compression) */
|
||||
errorStatus =
|
||||
aacDecoder_drcSetParam (
|
||||
hDrcInfo,
|
||||
DRC_CUT_SCALE,
|
||||
value
|
||||
);
|
||||
break;
|
||||
|
||||
case AAC_DRC_BOOST_FACTOR:
|
||||
/* DRC boost factor (where 0 is no and 127 is max boost) */
|
||||
errorStatus =
|
||||
aacDecoder_drcSetParam (
|
||||
hDrcInfo,
|
||||
DRC_BOOST_SCALE,
|
||||
value
|
||||
);
|
||||
break;
|
||||
|
||||
case AAC_DRC_REFERENCE_LEVEL:
|
||||
/* DRC reference level quantized in 0.25dB steps using values [0..127] it is '-' for analog scaling */
|
||||
errorStatus =
|
||||
aacDecoder_drcSetParam (
|
||||
hDrcInfo,
|
||||
TARGET_REF_LEVEL,
|
||||
value
|
||||
);
|
||||
break;
|
||||
|
||||
case AAC_DRC_HEAVY_COMPRESSION:
|
||||
/* Don't need to overwrite cut/boost values */
|
||||
errorStatus =
|
||||
aacDecoder_drcSetParam (
|
||||
hDrcInfo,
|
||||
APPLY_HEAVY_COMPRESSION,
|
||||
value
|
||||
);
|
||||
break;
|
||||
|
||||
|
||||
case AAC_TPDEC_CLEAR_BUFFER:
|
||||
transportDec_SetParam(self->hInput, TPDEC_PARAM_RESET, 1);
|
||||
self->streamInfo.numLostAccessUnits = 0;
|
||||
self->streamInfo.numBadBytes = 0;
|
||||
self->streamInfo.numTotalBytes = 0;
|
||||
/* aacDecoder_SignalInterruption(self); */
|
||||
break;
|
||||
|
||||
case AAC_CONCEAL_METHOD:
|
||||
/* Changing the concealment method can introduce additional bitstream delay. And
|
||||
that in turn affects sub libraries and modules which makes the whole thing quite
|
||||
complex. So the complete changing routine is packed into a helper function which
|
||||
keeps all modules and libs in a consistent state even in the case an error occures. */
|
||||
errorStatus = setConcealMethod ( self, value );
|
||||
break;
|
||||
|
||||
default:
|
||||
return AAC_DEC_SET_PARAM_FAIL;
|
||||
} /* switch(param) */
|
||||
|
||||
return (errorStatus);
|
||||
}
|
||||
|
||||
|
||||
LINKSPEC_CPP HANDLE_AACDECODER aacDecoder_Open(TRANSPORT_TYPE transportFmt, UINT nrOfLayers)
|
||||
{
|
||||
AAC_DECODER_INSTANCE *aacDec = NULL;
|
||||
HANDLE_TRANSPORTDEC pIn;
|
||||
int err = 0;
|
||||
|
||||
/* Allocate transport layer struct. */
|
||||
pIn = transportDec_Open(transportFmt, TP_FLAG_MPEG4);
|
||||
if (pIn == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
transportDec_SetParam(pIn, TPDEC_PARAM_IGNORE_BUFFERFULLNESS, 1);
|
||||
|
||||
/* Allocate AAC decoder core struct. */
|
||||
aacDec = CAacDecoder_Open(transportFmt);
|
||||
|
||||
if (aacDec == NULL) {
|
||||
transportDec_Close(&pIn);
|
||||
goto bail;
|
||||
}
|
||||
aacDec->hInput = pIn;
|
||||
|
||||
aacDec->nrOfLayers = nrOfLayers;
|
||||
|
||||
aacDec->channelOutputMapping = channelMappingTableWAV;
|
||||
|
||||
/* Register Config Update callback. */
|
||||
transportDec_RegisterAscCallback(pIn, aacDecoder_ConfigCallback, (void*)aacDec);
|
||||
|
||||
/* open SBR decoder */
|
||||
if ( SBRDEC_OK != sbrDecoder_Open ( &aacDec->hSbrDecoder )) {
|
||||
err = -1;
|
||||
goto bail;
|
||||
}
|
||||
aacDec->qmfModeUser = NOT_DEFINED;
|
||||
transportDec_RegisterSbrCallback(aacDec->hInput, (cbSbr_t)sbrDecoder_Header, (void*)aacDec->hSbrDecoder);
|
||||
|
||||
|
||||
pcmDmx_Open( &aacDec->hPcmUtils );
|
||||
if (aacDec->hPcmUtils == NULL) {
|
||||
err = -1;
|
||||
goto bail;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Assure that all modules have same delay */
|
||||
if ( setConcealMethod(aacDec, CConcealment_GetMethod(&aacDec->concealCommonData)) ) {
|
||||
err = -1;
|
||||
goto bail;
|
||||
}
|
||||
|
||||
bail:
|
||||
if (err == -1) {
|
||||
aacDecoder_Close(aacDec);
|
||||
aacDec = NULL;
|
||||
}
|
||||
return aacDec;
|
||||
}
|
||||
|
||||
LINKSPEC_CPP AAC_DECODER_ERROR aacDecoder_Fill(
|
||||
HANDLE_AACDECODER self,
|
||||
UCHAR *pBuffer[],
|
||||
const UINT bufferSize[],
|
||||
UINT *pBytesValid
|
||||
)
|
||||
{
|
||||
TRANSPORTDEC_ERROR tpErr;
|
||||
/* loop counter for layers; if not TT_MP4_RAWPACKETS used as index for only
|
||||
available layer */
|
||||
INT layer = 0;
|
||||
INT nrOfLayers = self->nrOfLayers;
|
||||
|
||||
{
|
||||
for (layer = 0; layer < nrOfLayers; layer++){
|
||||
{
|
||||
tpErr = transportDec_FillData( self->hInput, pBuffer[layer], bufferSize[layer], &pBytesValid[layer], layer );
|
||||
if (tpErr != TRANSPORTDEC_OK) {
|
||||
return AAC_DEC_UNKNOWN; /* Must be an internal error */
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return AAC_DEC_OK;
|
||||
}
|
||||
|
||||
|
||||
static void aacDecoder_SignalInterruption(HANDLE_AACDECODER self)
|
||||
{
|
||||
CAacDecoder_SignalInterruption(self);
|
||||
|
||||
if ( self->hSbrDecoder != NULL ) {
|
||||
sbrDecoder_SetParam(self->hSbrDecoder, SBR_BS_INTERRUPTION, 0);
|
||||
}
|
||||
}
|
||||
|
||||
static void aacDecoder_UpdateBitStreamCounters(CStreamInfo *pSi, HANDLE_FDK_BITSTREAM hBs, int nBits, AAC_DECODER_ERROR ErrorStatus)
|
||||
{
|
||||
/* calculate bit difference (amount of bits moved forward) */
|
||||
nBits = nBits - FDKgetValidBits(hBs);
|
||||
|
||||
/* Note: The amount of bits consumed might become negative when parsing a
|
||||
bit stream with several sub frames, and we find out at the last sub frame
|
||||
that the total frame length does not match the sum of sub frame length.
|
||||
If this happens, the transport decoder might want to rewind to the supposed
|
||||
ending of the transport frame, and this position might be before the last
|
||||
access unit beginning. */
|
||||
|
||||
/* Calc bitrate. */
|
||||
if (pSi->frameSize > 0) {
|
||||
pSi->bitRate = (nBits * pSi->sampleRate)/pSi->frameSize;
|
||||
}
|
||||
|
||||
/* bit/byte counters */
|
||||
{
|
||||
int nBytes;
|
||||
|
||||
nBytes = nBits>>3;
|
||||
pSi->numTotalBytes += nBytes;
|
||||
if (IS_OUTPUT_VALID(ErrorStatus)) {
|
||||
pSi->numTotalAccessUnits++;
|
||||
}
|
||||
if (IS_DECODE_ERROR(ErrorStatus)) {
|
||||
pSi->numBadBytes += nBytes;
|
||||
pSi->numBadAccessUnits++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static INT aacDecoder_EstimateNumberOfLostFrames(HANDLE_AACDECODER self)
|
||||
{
|
||||
INT n;
|
||||
|
||||
transportDec_GetMissingAccessUnitCount( &n, self->hInput);
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
LINKSPEC_CPP AAC_DECODER_ERROR aacDecoder_DecodeFrame(
|
||||
HANDLE_AACDECODER self,
|
||||
INT_PCM *pTimeData,
|
||||
const INT timeDataSize,
|
||||
const UINT flags)
|
||||
{
|
||||
AAC_DECODER_ERROR ErrorStatus;
|
||||
INT layer;
|
||||
INT nBits;
|
||||
INT interleaved = self->outputInterleaved;
|
||||
HANDLE_FDK_BITSTREAM hBs;
|
||||
int fTpInterruption = 0; /* Transport originated interruption detection. */
|
||||
int fTpConceal = 0; /* Transport originated concealment. */
|
||||
|
||||
|
||||
if (self == NULL) {
|
||||
return AAC_DEC_INVALID_HANDLE;
|
||||
}
|
||||
|
||||
if (flags & AACDEC_INTR) {
|
||||
self->streamInfo.numLostAccessUnits = 0;
|
||||
}
|
||||
|
||||
hBs = transportDec_GetBitstream(self->hInput, 0);
|
||||
|
||||
/* Get current bits position for bitrate calculation. */
|
||||
nBits = FDKgetValidBits(hBs);
|
||||
if (! (flags & (AACDEC_CONCEAL | AACDEC_FLUSH) ) )
|
||||
{
|
||||
TRANSPORTDEC_ERROR err;
|
||||
|
||||
for(layer = 0; layer < self->nrOfLayers; layer++)
|
||||
{
|
||||
err = transportDec_ReadAccessUnit(self->hInput, layer);
|
||||
if (err != TRANSPORTDEC_OK) {
|
||||
switch (err) {
|
||||
case TRANSPORTDEC_NOT_ENOUGH_BITS:
|
||||
ErrorStatus = AAC_DEC_NOT_ENOUGH_BITS;
|
||||
goto bail;
|
||||
case TRANSPORTDEC_SYNC_ERROR:
|
||||
self->streamInfo.numLostAccessUnits = aacDecoder_EstimateNumberOfLostFrames(self);
|
||||
fTpInterruption = 1;
|
||||
break;
|
||||
case TRANSPORTDEC_NEED_TO_RESTART:
|
||||
ErrorStatus = AAC_DEC_NEED_TO_RESTART;
|
||||
goto bail;
|
||||
case TRANSPORTDEC_CRC_ERROR:
|
||||
fTpConceal = 1;
|
||||
break;
|
||||
default:
|
||||
ErrorStatus = AAC_DEC_UNKNOWN;
|
||||
goto bail;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (self->streamInfo.numLostAccessUnits > 0) {
|
||||
self->streamInfo.numLostAccessUnits--;
|
||||
}
|
||||
}
|
||||
|
||||
/* Signal bit stream interruption to other modules if required. */
|
||||
if ( fTpInterruption || (flags & (AACDEC_INTR|AACDEC_CLRHIST)) )
|
||||
{
|
||||
aacDecoder_SignalInterruption(self);
|
||||
if ( ! (flags & AACDEC_INTR) ) {
|
||||
ErrorStatus = AAC_DEC_TRANSPORT_SYNC_ERROR;
|
||||
goto bail;
|
||||
}
|
||||
}
|
||||
|
||||
/* Empty bit buffer in case of flush request. */
|
||||
if (flags & AACDEC_FLUSH)
|
||||
{
|
||||
transportDec_SetParam(self->hInput, TPDEC_PARAM_RESET, 1);
|
||||
self->streamInfo.numLostAccessUnits = 0;
|
||||
self->streamInfo.numBadBytes = 0;
|
||||
self->streamInfo.numTotalBytes = 0;
|
||||
}
|
||||
|
||||
|
||||
ErrorStatus = CAacDecoder_DecodeFrame(self,
|
||||
flags | (fTpConceal ? AACDEC_CONCEAL : 0),
|
||||
pTimeData,
|
||||
timeDataSize,
|
||||
interleaved);
|
||||
|
||||
if (!(flags & (AACDEC_CONCEAL|AACDEC_FLUSH))) {
|
||||
TRANSPORTDEC_ERROR tpErr;
|
||||
tpErr = transportDec_EndAccessUnit(self->hInput);
|
||||
if (tpErr != TRANSPORTDEC_OK) {
|
||||
self->frameOK = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* If the current pTimeData does not contain a valid signal, there nothing else we can do, so bail. */
|
||||
if ( ! IS_OUTPUT_VALID(ErrorStatus) ) {
|
||||
goto bail;
|
||||
}
|
||||
|
||||
{
|
||||
/* Export data into streaminfo structure */
|
||||
self->streamInfo.sampleRate = self->streamInfo.aacSampleRate;
|
||||
self->streamInfo.frameSize = self->streamInfo.aacSamplesPerFrame;
|
||||
self->streamInfo.numChannels = self->aacChannels;
|
||||
}
|
||||
|
||||
|
||||
|
||||
CAacDecoder_SyncQmfMode(self);
|
||||
|
||||
/* sbr decoder */
|
||||
|
||||
if (ErrorStatus || (flags & AACDEC_CONCEAL) || self->pAacDecoderStaticChannelInfo[0]->concealmentInfo.concealState > ConcealState_FadeIn)
|
||||
{
|
||||
self->frameOK = 0; /* if an error has occured do concealment in the SBR decoder too */
|
||||
}
|
||||
|
||||
if (self->sbrEnabled)
|
||||
{
|
||||
SBR_ERROR sbrError = SBRDEC_OK;
|
||||
|
||||
/* set params */
|
||||
sbrDecoder_SetParam ( self->hSbrDecoder,
|
||||
SBR_SYSTEM_BITSTREAM_DELAY,
|
||||
self->sbrParams.bsDelay);
|
||||
|
||||
if ( self->streamInfo.aot == AOT_ER_AAC_ELD ) {
|
||||
/* Configure QMF */
|
||||
sbrDecoder_SetParam ( self->hSbrDecoder,
|
||||
SBR_LD_QMF_TIME_ALIGN,
|
||||
(self->flags & AC_LD_MPS) ? 1 : 0 );
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/* apply SBR processing */
|
||||
sbrError = sbrDecoder_Apply ( self->hSbrDecoder,
|
||||
pTimeData,
|
||||
&self->streamInfo.numChannels,
|
||||
&self->streamInfo.sampleRate,
|
||||
self->channelOutputMapping[self->aacChannels-1],
|
||||
interleaved,
|
||||
self->frameOK,
|
||||
&self->psPossible);
|
||||
|
||||
|
||||
if (sbrError == SBRDEC_OK) {
|
||||
|
||||
/* Update data in streaminfo structure. Assume that the SBR upsampling factor is either 1 or 2 */
|
||||
self->flags |= AC_SBR_PRESENT;
|
||||
if (self->streamInfo.aacSampleRate != self->streamInfo.sampleRate) {
|
||||
if (self->streamInfo.frameSize == 768) {
|
||||
self->streamInfo.frameSize = (self->streamInfo.aacSamplesPerFrame * 8) / 3;
|
||||
} else {
|
||||
self->streamInfo.frameSize = self->streamInfo.aacSamplesPerFrame << 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (self->psPossible) {
|
||||
self->flags |= AC_PS_PRESENT;
|
||||
self->channelType[0] = ACT_FRONT;
|
||||
self->channelType[1] = ACT_FRONT;
|
||||
self->channelIndices[0] = 0;
|
||||
self->channelIndices[1] = 1;
|
||||
} else {
|
||||
self->flags &= ~AC_PS_PRESENT;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if ( flags & (AACDEC_INTR | AACDEC_CLRHIST) ) {
|
||||
/* delete data from the past (e.g. mixdown coeficients) */
|
||||
pcmDmx_Reset( self->hPcmUtils, PCMDMX_RESET_BS_DATA );
|
||||
}
|
||||
/* do PCM post processing */
|
||||
pcmDmx_ApplyFrame (
|
||||
self->hPcmUtils,
|
||||
pTimeData,
|
||||
self->streamInfo.frameSize,
|
||||
&self->streamInfo.numChannels,
|
||||
interleaved,
|
||||
self->channelType,
|
||||
self->channelIndices,
|
||||
self->channelOutputMapping
|
||||
);
|
||||
|
||||
|
||||
|
||||
/* Signal interruption to take effect in next frame. */
|
||||
if ( flags & AACDEC_FLUSH ) {
|
||||
aacDecoder_SignalInterruption(self);
|
||||
}
|
||||
|
||||
/* Update externally visible copy of flags */
|
||||
self->streamInfo.flags = self->flags;
|
||||
|
||||
bail:
|
||||
|
||||
/* Update Statistics */
|
||||
aacDecoder_UpdateBitStreamCounters(&self->streamInfo, hBs, nBits, ErrorStatus);
|
||||
|
||||
return ErrorStatus;
|
||||
}
|
||||
|
||||
LINKSPEC_CPP void aacDecoder_Close ( HANDLE_AACDECODER self )
|
||||
{
|
||||
if (self == NULL)
|
||||
return;
|
||||
|
||||
|
||||
|
||||
if (self->hPcmUtils != NULL) {
|
||||
pcmDmx_Close( &self->hPcmUtils );
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (self->hSbrDecoder != NULL) {
|
||||
sbrDecoder_Close(&self->hSbrDecoder);
|
||||
}
|
||||
|
||||
if (self->hInput != NULL) {
|
||||
transportDec_Close(&self->hInput);
|
||||
}
|
||||
|
||||
CAacDecoder_Close(self);
|
||||
}
|
||||
|
||||
|
||||
LINKSPEC_CPP CStreamInfo* aacDecoder_GetStreamInfo ( HANDLE_AACDECODER self )
|
||||
{
|
||||
return CAacDecoder_GetStreamInfo(self);
|
||||
}
|
||||
|
||||
LINKSPEC_CPP INT aacDecoder_GetLibInfo ( LIB_INFO *info )
|
||||
{
|
||||
int i;
|
||||
|
||||
if (info == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
sbrDecoder_GetLibInfo( info );
|
||||
transportDec_GetLibInfo( info );
|
||||
FDK_toolsGetLibInfo( info );
|
||||
pcmDmx_GetLibInfo( info );
|
||||
|
||||
/* 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_AACDEC;
|
||||
/* build own library info */
|
||||
info->version = LIB_VERSION(AACDECODER_LIB_VL0, AACDECODER_LIB_VL1, AACDECODER_LIB_VL2);
|
||||
LIB_VERSION_STRING(info);
|
||||
info->build_date = AACDECODER_LIB_BUILD_DATE;
|
||||
info->build_time = AACDECODER_LIB_BUILD_TIME;
|
||||
info->title = AACDECODER_LIB_TITLE;
|
||||
|
||||
/* Set flags */
|
||||
info->flags = 0
|
||||
| CAPF_AAC_LC
|
||||
| CAPF_AAC_VCB11
|
||||
| CAPF_AAC_HCR
|
||||
| CAPF_AAC_RVLC
|
||||
| CAPF_ER_AAC_LD
|
||||
| CAPF_ER_AAC_ELD
|
||||
| CAPF_AAC_CONCEALMENT
|
||||
| CAPF_AAC_DRC
|
||||
|
||||
| CAPF_AAC_MPEG4
|
||||
|
||||
|
||||
| CAPF_AAC_1024
|
||||
| CAPF_AAC_960
|
||||
|
||||
| CAPF_AAC_512
|
||||
|
||||
| CAPF_AAC_480
|
||||
|
||||
;
|
||||
/* End of flags */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
Reference in New Issue
Block a user