
- Add 6.1 and 7.1 channel support including downmixer. Per default the decoder creates a 5.1 channel output for all streams with more than six encoded channels. Modified file(s): libPCMutils/include/pcmutils_lib.h libPCMutils/src/pcmutils_lib.cpp libAACdec/include/aacdecoder_lib.h libAACdec/src/aac_rom.h libAACdec/src/aacdecoder.cpp libAACdec/src/aac_ram.cpp libAACdec/src/aacdec_drc.cpp libAACdec/src/aacdecoder_lib.cpp libAACdec/src/aac_rom.cpp libAACdec/src/aacdecoder.h libSBRdec/include/sbrdecoder.h libSBRdec/src/sbrdec_drc.h libSBRdec/src/sbrdecoder.cpp libSBRdec/src/sbr_ram.cpp libSBRdec/src/sbr_ram.h libMpegTPDec/include/tp_data.h libMpegTPDec/include/tpdec_lib.h libMpegTPDec/src/version libMpegTPDec/src/tpdec_asc.cpp libMpegTPEnc/include/tp_data.h libMpegTPEnc/src/version libSYS/include/FDK_audio.h libSYS/src/genericStds.cpp - Fix error concealment modules fade-out/in mechanism. Modified file(s): libAACdec/src/conceal.cpp Bug 9428126 Change-Id: I3230bd2072314b730911cd7ec1740e290cb1d254
1043 lines
29 KiB
C++
1043 lines
29 KiB
C++
|
|
/* -----------------------------------------------------------------------------------------------------------
|
|
Software License for The Fraunhofer FDK AAC Codec Library for Android
|
|
|
|
© Copyright 1995 - 2013 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 5
|
|
#define AACDECODER_LIB_VL2 6
|
|
#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 = ConcealMethodNone;
|
|
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;
|
|
HANDLE_PCM_DOWNMIX hPcmDmx = NULL;
|
|
|
|
/* check decoder handle */
|
|
if (self != NULL) {
|
|
pConcealData = &self->concealCommonData;
|
|
hDrcInfo = self->hDrcInfo;
|
|
hPcmDmx = self->hPcmUtils;
|
|
} else {
|
|
errorStatus = AAC_DEC_INVALID_HANDLE;
|
|
}
|
|
|
|
/* 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_MIN_OUTPUT_CHANNELS:
|
|
if (value < -1 || value > (8)) {
|
|
return AAC_DEC_SET_PARAM_FAIL;
|
|
}
|
|
{
|
|
PCMDMX_ERROR err;
|
|
|
|
err = pcmDmx_SetParam (
|
|
hPcmDmx,
|
|
MIN_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_MAX_OUTPUT_CHANNELS:
|
|
if (value < -1 || value > (8)) {
|
|
return AAC_DEC_SET_PARAM_FAIL;
|
|
}
|
|
{
|
|
PCMDMX_ERROR err;
|
|
|
|
err = pcmDmx_SetParam (
|
|
hPcmDmx,
|
|
MAX_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 (
|
|
hPcmDmx,
|
|
DMX_DUAL_CHANNEL_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:
|
|
if (self != NULL) {
|
|
self->channelOutputMapping = channelMappingTablePassthrough;
|
|
}
|
|
break;
|
|
case 1:
|
|
if (self != NULL) {
|
|
self->channelOutputMapping = channelMappingTableWAV;
|
|
}
|
|
break;
|
|
default:
|
|
errorStatus = AAC_DEC_SET_PARAM_FAIL;
|
|
break;
|
|
}
|
|
break;
|
|
|
|
|
|
case AAC_QMF_LOWPOWER:
|
|
if (value < -1 || value > 1) {
|
|
return AAC_DEC_SET_PARAM_FAIL;
|
|
}
|
|
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->streamInfo.aacNumChannels;
|
|
|
|
|
|
|
|
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;
|
|
int chOutMapIdx = ((self->chMapIndex==0) && (self->streamInfo.numChannels<7)) ? self->streamInfo.numChannels : self->chMapIndex;
|
|
|
|
/* 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 );
|
|
}
|
|
|
|
{
|
|
PCMDMX_ERROR dmxErr;
|
|
INT maxOutCh = 0;
|
|
|
|
dmxErr = pcmDmx_GetParam(self->hPcmUtils, MAX_NUMBER_OF_OUTPUT_CHANNELS, &maxOutCh);
|
|
if ( (dmxErr == PCMDMX_OK) && (maxOutCh == 1) ) {
|
|
/* Disable PS processing if we have to create a mono output signal. */
|
|
self->psPossible = 0;
|
|
}
|
|
}
|
|
|
|
|
|
/* apply SBR processing */
|
|
sbrError = sbrDecoder_Apply ( self->hSbrDecoder,
|
|
pTimeData,
|
|
&self->streamInfo.numChannels,
|
|
&self->streamInfo.sampleRate,
|
|
self->channelOutputMapping[chOutMapIdx],
|
|
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;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
{
|
|
PCMDMX_ERROR dmxErr = PCMDMX_OK;
|
|
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 */
|
|
dmxErr = pcmDmx_ApplyFrame (
|
|
self->hPcmUtils,
|
|
pTimeData,
|
|
self->streamInfo.frameSize,
|
|
&self->streamInfo.numChannels,
|
|
interleaved,
|
|
self->channelType,
|
|
self->channelIndices,
|
|
self->channelOutputMapping,
|
|
NULL
|
|
);
|
|
if (dmxErr == PCMDMX_INVALID_MODE) {
|
|
/* Announce the framework that the current combination of channel configuration and downmix
|
|
* settings are not know to produce a predictable behavior and thus maybe produce strange output. */
|
|
ErrorStatus = AAC_DEC_DECODE_FRAME_ERROR;
|
|
}
|
|
}
|
|
|
|
|
|
/* 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;
|
|
}
|
|
|
|
|
|
|
|
|