mirror of
https://github.com/mstorsjo/fdk-aac.git
synced 2024-12-13 08:56:25 +01:00
b5dfe8f92d
In the bug the SBR decoder has already set up 9 channels and tries to allocate one more channel. The assignment of the QMF channels to SBR channels fails since the QMF domain manages only 8+1 channels instead of 10 channels as reqeusted by SBR. Here we have added a check in sbrDecoder_InitElement() which will return with a parse error in case additional SBR channels would exceed the maximum number of SBR channels. This solves the potential heap buffer overflow. Bug: 158762825 Test: atest DecoderTestAacDrc DecoderTestAacFormat DecoderTestXheAac Change-Id: I0150ac6d5a47ffce883010f531928656eebc619e
2010 lines
64 KiB
C++
2010 lines
64 KiB
C++
/* -----------------------------------------------------------------------------
|
|
Software License for The Fraunhofer FDK AAC Codec Library for Android
|
|
|
|
© Copyright 1995 - 2020 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
|
|
----------------------------------------------------------------------------- */
|
|
|
|
/**************************** SBR decoder library ******************************
|
|
|
|
Author(s):
|
|
|
|
Description:
|
|
|
|
*******************************************************************************/
|
|
|
|
/*!
|
|
\file
|
|
\brief SBR decoder frontend
|
|
This module provides a frontend to the SBR decoder. The function openSBR() is
|
|
called for initialization. The function sbrDecoder_Apply() is called for each
|
|
frame. sbr_Apply() will call the required functions to decode the raw SBR data
|
|
(provided by env_extr.cpp), to decode the envelope data and noise floor levels
|
|
[decodeSbrData()], and to finally apply SBR to the current frame [sbr_dec()].
|
|
|
|
\sa sbrDecoder_Apply(), \ref documentationOverview
|
|
*/
|
|
|
|
/*!
|
|
\page documentationOverview Overview of important information resources and
|
|
source code documentation
|
|
|
|
As part of this documentation you can find more extensive descriptions about
|
|
key concepts and algorithms at the following locations:
|
|
|
|
<h2>Programming</h2>
|
|
|
|
\li Buffer management: sbrDecoder_Apply() and sbr_dec()
|
|
\li Internal scale factors to maximize SNR on fixed point processors:
|
|
#QMF_SCALE_FACTOR \li Special mantissa-exponent format: Created in
|
|
requantizeEnvelopeData() and used in calculateSbrEnvelope()
|
|
|
|
<h2>Algorithmic details</h2>
|
|
\li About the SBR data format: \ref SBR_HEADER_ELEMENT and \ref
|
|
SBR_STANDARD_ELEMENT \li Details about the bitstream decoder: env_extr.cpp \li
|
|
Details about the QMF filterbank and the provided polyphase implementation:
|
|
qmf_dec.cpp \li Details about the transposer: lpp_tran.cpp \li Details about
|
|
the envelope adjuster: env_calc.cpp
|
|
|
|
*/
|
|
|
|
#include "sbrdecoder.h"
|
|
|
|
#include "FDK_bitstream.h"
|
|
|
|
#include "sbrdec_freq_sca.h"
|
|
#include "env_extr.h"
|
|
#include "sbr_dec.h"
|
|
#include "env_dec.h"
|
|
#include "FDK_crc.h"
|
|
#include "sbr_ram.h"
|
|
#include "sbr_rom.h"
|
|
#include "lpp_tran.h"
|
|
#include "transcendent.h"
|
|
|
|
#include "sbrdec_drc.h"
|
|
|
|
#include "psbitdec.h"
|
|
|
|
/* Decoder library info */
|
|
#define SBRDECODER_LIB_VL0 3
|
|
#define SBRDECODER_LIB_VL1 1
|
|
#define SBRDECODER_LIB_VL2 0
|
|
#define SBRDECODER_LIB_TITLE "SBR Decoder"
|
|
#ifdef SUPPRESS_BUILD_DATE_INFO
|
|
#define SBRDECODER_LIB_BUILD_DATE ""
|
|
#define SBRDECODER_LIB_BUILD_TIME ""
|
|
#else
|
|
#define SBRDECODER_LIB_BUILD_DATE __DATE__
|
|
#define SBRDECODER_LIB_BUILD_TIME __TIME__
|
|
#endif
|
|
|
|
static void setFrameErrorFlag(SBR_DECODER_ELEMENT *pSbrElement, UCHAR value) {
|
|
if (pSbrElement != NULL) {
|
|
switch (value) {
|
|
case FRAME_ERROR_ALLSLOTS:
|
|
FDKmemset(pSbrElement->frameErrorFlag, FRAME_ERROR,
|
|
sizeof(pSbrElement->frameErrorFlag));
|
|
break;
|
|
default:
|
|
pSbrElement->frameErrorFlag[pSbrElement->useFrameSlot] = value;
|
|
}
|
|
}
|
|
}
|
|
|
|
static UCHAR getHeaderSlot(UCHAR currentSlot, UCHAR hdrSlotUsage[(1) + 1]) {
|
|
UINT occupied = 0;
|
|
int s;
|
|
UCHAR slot = hdrSlotUsage[currentSlot];
|
|
|
|
FDK_ASSERT((1) + 1 < 32);
|
|
|
|
for (s = 0; s < (1) + 1; s++) {
|
|
if ((hdrSlotUsage[s] == slot) && (s != slot)) {
|
|
occupied = 1;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (occupied) {
|
|
occupied = 0;
|
|
|
|
for (s = 0; s < (1) + 1; s++) {
|
|
occupied |= 1 << hdrSlotUsage[s];
|
|
}
|
|
for (s = 0; s < (1) + 1; s++) {
|
|
if (!(occupied & 0x1)) {
|
|
slot = s;
|
|
break;
|
|
}
|
|
occupied >>= 1;
|
|
}
|
|
}
|
|
|
|
return slot;
|
|
}
|
|
|
|
static void copySbrHeader(HANDLE_SBR_HEADER_DATA hDst,
|
|
const HANDLE_SBR_HEADER_DATA hSrc) {
|
|
/* copy the whole header memory (including pointers) */
|
|
FDKmemcpy(hDst, hSrc, sizeof(SBR_HEADER_DATA));
|
|
|
|
/* update pointers */
|
|
hDst->freqBandData.freqBandTable[0] = hDst->freqBandData.freqBandTableLo;
|
|
hDst->freqBandData.freqBandTable[1] = hDst->freqBandData.freqBandTableHi;
|
|
}
|
|
|
|
static int compareSbrHeader(const HANDLE_SBR_HEADER_DATA hHdr1,
|
|
const HANDLE_SBR_HEADER_DATA hHdr2) {
|
|
int result = 0;
|
|
|
|
/* compare basic data */
|
|
result |= (hHdr1->syncState != hHdr2->syncState) ? 1 : 0;
|
|
result |= (hHdr1->status != hHdr2->status) ? 1 : 0;
|
|
result |= (hHdr1->frameErrorFlag != hHdr2->frameErrorFlag) ? 1 : 0;
|
|
result |= (hHdr1->numberTimeSlots != hHdr2->numberTimeSlots) ? 1 : 0;
|
|
result |=
|
|
(hHdr1->numberOfAnalysisBands != hHdr2->numberOfAnalysisBands) ? 1 : 0;
|
|
result |= (hHdr1->timeStep != hHdr2->timeStep) ? 1 : 0;
|
|
result |= (hHdr1->sbrProcSmplRate != hHdr2->sbrProcSmplRate) ? 1 : 0;
|
|
|
|
/* compare bitstream data */
|
|
result |=
|
|
FDKmemcmp(&hHdr1->bs_data, &hHdr2->bs_data, sizeof(SBR_HEADER_DATA_BS));
|
|
result |=
|
|
FDKmemcmp(&hHdr1->bs_dflt, &hHdr2->bs_dflt, sizeof(SBR_HEADER_DATA_BS));
|
|
result |= FDKmemcmp(&hHdr1->bs_info, &hHdr2->bs_info,
|
|
sizeof(SBR_HEADER_DATA_BS_INFO));
|
|
|
|
/* compare frequency band data */
|
|
result |= FDKmemcmp(&hHdr1->freqBandData, &hHdr2->freqBandData,
|
|
(8 + MAX_NUM_LIMITERS + 1) * sizeof(UCHAR));
|
|
result |= FDKmemcmp(hHdr1->freqBandData.freqBandTableLo,
|
|
hHdr2->freqBandData.freqBandTableLo,
|
|
(MAX_FREQ_COEFFS / 2 + 1) * sizeof(UCHAR));
|
|
result |= FDKmemcmp(hHdr1->freqBandData.freqBandTableHi,
|
|
hHdr2->freqBandData.freqBandTableHi,
|
|
(MAX_FREQ_COEFFS + 1) * sizeof(UCHAR));
|
|
result |= FDKmemcmp(hHdr1->freqBandData.freqBandTableNoise,
|
|
hHdr2->freqBandData.freqBandTableNoise,
|
|
(MAX_NOISE_COEFFS + 1) * sizeof(UCHAR));
|
|
result |=
|
|
FDKmemcmp(hHdr1->freqBandData.v_k_master, hHdr2->freqBandData.v_k_master,
|
|
(MAX_FREQ_COEFFS + 1) * sizeof(UCHAR));
|
|
|
|
return result;
|
|
}
|
|
|
|
/*!
|
|
\brief Reset SBR decoder.
|
|
|
|
Reset should only be called if SBR has been sucessfully detected by
|
|
an appropriate checkForPayload() function.
|
|
|
|
\return Error code.
|
|
*/
|
|
static SBR_ERROR sbrDecoder_ResetElement(HANDLE_SBRDECODER self,
|
|
int sampleRateIn, int sampleRateOut,
|
|
int samplesPerFrame,
|
|
const MP4_ELEMENT_ID elementID,
|
|
const int elementIndex,
|
|
const int overlap) {
|
|
SBR_ERROR sbrError = SBRDEC_OK;
|
|
HANDLE_SBR_HEADER_DATA hSbrHeader;
|
|
UINT qmfFlags = 0;
|
|
|
|
int i, synDownsampleFac;
|
|
|
|
/* USAC: assuming theoretical case 8 kHz output sample rate with 4:1 SBR */
|
|
const int sbr_min_sample_rate_in = IS_USAC(self->coreCodec) ? 2000 : 6400;
|
|
|
|
/* Check in/out samplerates */
|
|
if (sampleRateIn < sbr_min_sample_rate_in || sampleRateIn > (96000)) {
|
|
sbrError = SBRDEC_UNSUPPORTED_CONFIG;
|
|
goto bail;
|
|
}
|
|
|
|
if (sampleRateOut > (96000)) {
|
|
sbrError = SBRDEC_UNSUPPORTED_CONFIG;
|
|
goto bail;
|
|
}
|
|
|
|
/* Set QMF mode flags */
|
|
if (self->flags & SBRDEC_LOW_POWER) qmfFlags |= QMF_FLAG_LP;
|
|
|
|
if (self->coreCodec == AOT_ER_AAC_ELD) {
|
|
if (self->flags & SBRDEC_LD_MPS_QMF) {
|
|
qmfFlags |= QMF_FLAG_MPSLDFB;
|
|
} else {
|
|
qmfFlags |= QMF_FLAG_CLDFB;
|
|
}
|
|
}
|
|
|
|
/* Set downsampling factor for synthesis filter bank */
|
|
if (sampleRateOut == 0) {
|
|
/* no single rate mode */
|
|
sampleRateOut =
|
|
sampleRateIn
|
|
<< 1; /* In case of implicit signalling, assume dual rate SBR */
|
|
}
|
|
|
|
if (sampleRateIn == sampleRateOut) {
|
|
synDownsampleFac = 2;
|
|
self->flags |= SBRDEC_DOWNSAMPLE;
|
|
} else {
|
|
synDownsampleFac = 1;
|
|
self->flags &= ~SBRDEC_DOWNSAMPLE;
|
|
}
|
|
|
|
self->synDownsampleFac = synDownsampleFac;
|
|
self->sampleRateOut = sampleRateOut;
|
|
|
|
{
|
|
for (i = 0; i < (1) + 1; i++) {
|
|
int setDflt;
|
|
hSbrHeader = &(self->sbrHeader[elementIndex][i]);
|
|
setDflt = ((hSbrHeader->syncState == SBR_NOT_INITIALIZED) ||
|
|
(self->flags & SBRDEC_FORCE_RESET))
|
|
? 1
|
|
: 0;
|
|
|
|
/* init a default header such that we can at least do upsampling later */
|
|
sbrError = initHeaderData(hSbrHeader, sampleRateIn, sampleRateOut,
|
|
self->downscaleFactor, samplesPerFrame,
|
|
self->flags, setDflt);
|
|
|
|
/* Set synchState to UPSAMPLING in case it already is initialized */
|
|
hSbrHeader->syncState = hSbrHeader->syncState > UPSAMPLING
|
|
? UPSAMPLING
|
|
: hSbrHeader->syncState;
|
|
}
|
|
}
|
|
|
|
if (sbrError != SBRDEC_OK) {
|
|
goto bail;
|
|
}
|
|
|
|
if (!self->pQmfDomain->globalConf.qmfDomainExplicitConfig) {
|
|
self->pQmfDomain->globalConf.flags_requested |= qmfFlags;
|
|
self->pQmfDomain->globalConf.nBandsAnalysis_requested =
|
|
self->sbrHeader[elementIndex][0].numberOfAnalysisBands;
|
|
self->pQmfDomain->globalConf.nBandsSynthesis_requested =
|
|
(synDownsampleFac == 1) ? 64 : 32; /* may be overwritten by MPS */
|
|
self->pQmfDomain->globalConf.nBandsSynthesis_requested /=
|
|
self->downscaleFactor;
|
|
self->pQmfDomain->globalConf.nQmfTimeSlots_requested =
|
|
self->sbrHeader[elementIndex][0].numberTimeSlots *
|
|
self->sbrHeader[elementIndex][0].timeStep;
|
|
self->pQmfDomain->globalConf.nQmfOvTimeSlots_requested = overlap;
|
|
self->pQmfDomain->globalConf.nQmfProcBands_requested = 64; /* always 64 */
|
|
self->pQmfDomain->globalConf.nQmfProcChannels_requested =
|
|
1; /* may be overwritten by MPS */
|
|
}
|
|
|
|
/* Init SBR channels going to be assigned to a SBR element */
|
|
{
|
|
int ch;
|
|
for (ch = 0; ch < self->pSbrElement[elementIndex]->nChannels; ch++) {
|
|
int headerIndex =
|
|
getHeaderSlot(self->pSbrElement[elementIndex]->useFrameSlot,
|
|
self->pSbrElement[elementIndex]->useHeaderSlot);
|
|
|
|
/* and create sbrDec */
|
|
sbrError =
|
|
createSbrDec(self->pSbrElement[elementIndex]->pSbrChannel[ch],
|
|
&self->sbrHeader[elementIndex][headerIndex],
|
|
&self->pSbrElement[elementIndex]->transposerSettings,
|
|
synDownsampleFac, qmfFlags, self->flags, overlap, ch,
|
|
self->codecFrameSize);
|
|
|
|
if (sbrError != SBRDEC_OK) {
|
|
goto bail;
|
|
}
|
|
}
|
|
}
|
|
|
|
// FDKmemclear(sbr_OverlapBuffer, sizeof(sbr_OverlapBuffer));
|
|
|
|
if (self->numSbrElements == 1) {
|
|
switch (self->coreCodec) {
|
|
case AOT_AAC_LC:
|
|
case AOT_SBR:
|
|
case AOT_PS:
|
|
case AOT_ER_AAC_SCAL:
|
|
case AOT_DRM_AAC:
|
|
case AOT_DRM_SURROUND:
|
|
if (CreatePsDec(&self->hParametricStereoDec, samplesPerFrame)) {
|
|
sbrError = SBRDEC_CREATE_ERROR;
|
|
goto bail;
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* Init frame delay slot handling */
|
|
self->pSbrElement[elementIndex]->useFrameSlot = 0;
|
|
for (i = 0; i < ((1) + 1); i++) {
|
|
self->pSbrElement[elementIndex]->useHeaderSlot[i] = i;
|
|
}
|
|
|
|
bail:
|
|
|
|
return sbrError;
|
|
}
|
|
|
|
/*!
|
|
\brief Assign QMF domain provided QMF channels to SBR channels.
|
|
|
|
\return void
|
|
*/
|
|
static void sbrDecoder_AssignQmfChannels2SbrChannels(HANDLE_SBRDECODER self) {
|
|
int ch, el, absCh_offset = 0;
|
|
for (el = 0; el < self->numSbrElements; el++) {
|
|
if (self->pSbrElement[el] != NULL) {
|
|
for (ch = 0; ch < self->pSbrElement[el]->nChannels; ch++) {
|
|
FDK_ASSERT(((absCh_offset + ch) < ((8) + (1))) &&
|
|
((absCh_offset + ch) < ((8) + (1))));
|
|
self->pSbrElement[el]->pSbrChannel[ch]->SbrDec.qmfDomainInCh =
|
|
&self->pQmfDomain->QmfDomainIn[absCh_offset + ch];
|
|
self->pSbrElement[el]->pSbrChannel[ch]->SbrDec.qmfDomainOutCh =
|
|
&self->pQmfDomain->QmfDomainOut[absCh_offset + ch];
|
|
}
|
|
absCh_offset += self->pSbrElement[el]->nChannels;
|
|
}
|
|
}
|
|
}
|
|
|
|
SBR_ERROR sbrDecoder_Open(HANDLE_SBRDECODER *pSelf,
|
|
HANDLE_FDK_QMF_DOMAIN pQmfDomain) {
|
|
HANDLE_SBRDECODER self = NULL;
|
|
SBR_ERROR sbrError = SBRDEC_OK;
|
|
int elIdx;
|
|
|
|
if ((pSelf == NULL) || (pQmfDomain == NULL)) {
|
|
return SBRDEC_INVALID_ARGUMENT;
|
|
}
|
|
|
|
/* Get memory for this instance */
|
|
self = GetRam_SbrDecoder();
|
|
if (self == NULL) {
|
|
sbrError = SBRDEC_MEM_ALLOC_FAILED;
|
|
goto bail;
|
|
}
|
|
|
|
self->pQmfDomain = pQmfDomain;
|
|
|
|
/*
|
|
Already zero because of calloc
|
|
self->numSbrElements = 0;
|
|
self->numSbrChannels = 0;
|
|
self->codecFrameSize = 0;
|
|
*/
|
|
|
|
self->numDelayFrames = (1); /* set to the max value by default */
|
|
|
|
/* Initialize header sync state */
|
|
for (elIdx = 0; elIdx < (8); elIdx += 1) {
|
|
int i;
|
|
for (i = 0; i < (1) + 1; i += 1) {
|
|
self->sbrHeader[elIdx][i].syncState = SBR_NOT_INITIALIZED;
|
|
}
|
|
}
|
|
|
|
*pSelf = self;
|
|
|
|
bail:
|
|
return sbrError;
|
|
}
|
|
|
|
/**
|
|
* \brief determine if the given core codec AOT can be processed or not.
|
|
* \param coreCodec core codec audio object type.
|
|
* \return 1 if SBR can be processed, 0 if SBR cannot be processed/applied.
|
|
*/
|
|
static int sbrDecoder_isCoreCodecValid(AUDIO_OBJECT_TYPE coreCodec) {
|
|
switch (coreCodec) {
|
|
case AOT_AAC_LC:
|
|
case AOT_SBR:
|
|
case AOT_PS:
|
|
case AOT_ER_AAC_SCAL:
|
|
case AOT_ER_AAC_ELD:
|
|
case AOT_DRM_AAC:
|
|
case AOT_DRM_SURROUND:
|
|
case AOT_USAC:
|
|
return 1;
|
|
default:
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
static void sbrDecoder_DestroyElement(HANDLE_SBRDECODER self,
|
|
const int elementIndex) {
|
|
if (self->pSbrElement[elementIndex] != NULL) {
|
|
int ch;
|
|
|
|
for (ch = 0; ch < SBRDEC_MAX_CH_PER_ELEMENT; ch++) {
|
|
if (self->pSbrElement[elementIndex]->pSbrChannel[ch] != NULL) {
|
|
deleteSbrDec(self->pSbrElement[elementIndex]->pSbrChannel[ch]);
|
|
FreeRam_SbrDecChannel(
|
|
&self->pSbrElement[elementIndex]->pSbrChannel[ch]);
|
|
self->numSbrChannels -= 1;
|
|
}
|
|
}
|
|
FreeRam_SbrDecElement(&self->pSbrElement[elementIndex]);
|
|
self->numSbrElements -= 1;
|
|
}
|
|
}
|
|
|
|
SBR_ERROR sbrDecoder_InitElement(
|
|
HANDLE_SBRDECODER self, const int sampleRateIn, const int sampleRateOut,
|
|
const int samplesPerFrame, const AUDIO_OBJECT_TYPE coreCodec,
|
|
const MP4_ELEMENT_ID elementID, const int elementIndex,
|
|
const UCHAR harmonicSBR, const UCHAR stereoConfigIndex,
|
|
const UCHAR configMode, UCHAR *configChanged, const INT downscaleFactor) {
|
|
SBR_ERROR sbrError = SBRDEC_OK;
|
|
int chCnt = 0;
|
|
int nSbrElementsStart;
|
|
int nSbrChannelsStart;
|
|
if (self == NULL) {
|
|
return SBRDEC_INVALID_ARGUMENT;
|
|
}
|
|
|
|
nSbrElementsStart = self->numSbrElements;
|
|
nSbrChannelsStart = self->numSbrChannels;
|
|
|
|
/* Check core codec AOT */
|
|
if (!sbrDecoder_isCoreCodecValid(coreCodec) || elementIndex >= (8)) {
|
|
sbrError = SBRDEC_UNSUPPORTED_CONFIG;
|
|
goto bail;
|
|
}
|
|
|
|
if (elementID != ID_SCE && elementID != ID_CPE && elementID != ID_LFE) {
|
|
sbrError = SBRDEC_UNSUPPORTED_CONFIG;
|
|
goto bail;
|
|
}
|
|
|
|
if (self->sampleRateIn == sampleRateIn &&
|
|
self->codecFrameSize == samplesPerFrame && self->coreCodec == coreCodec &&
|
|
self->pSbrElement[elementIndex] != NULL &&
|
|
self->pSbrElement[elementIndex]->elementID == elementID &&
|
|
!(self->flags & SBRDEC_FORCE_RESET) &&
|
|
((sampleRateOut == 0) ? 1 : (self->sampleRateOut == sampleRateOut)) &&
|
|
((harmonicSBR == 2) ? 1
|
|
: (self->harmonicSBR ==
|
|
harmonicSBR)) /* The value 2 signalizes that
|
|
harmonicSBR shall be ignored in
|
|
the config change detection */
|
|
) {
|
|
/* Nothing to do */
|
|
return SBRDEC_OK;
|
|
} else {
|
|
if (configMode & AC_CM_DET_CFG_CHANGE) {
|
|
*configChanged = 1;
|
|
}
|
|
}
|
|
|
|
/* reaching this point the SBR-decoder gets (re-)configured */
|
|
|
|
/* The flags field is used for all elements! */
|
|
self->flags &=
|
|
(SBRDEC_FORCE_RESET | SBRDEC_FLUSH); /* Keep the global flags. They will
|
|
be reset after decoding. */
|
|
self->flags |= (downscaleFactor > 1) ? SBRDEC_ELD_DOWNSCALE : 0;
|
|
self->flags |= (coreCodec == AOT_ER_AAC_ELD) ? SBRDEC_ELD_GRID : 0;
|
|
self->flags |= (coreCodec == AOT_ER_AAC_SCAL) ? SBRDEC_SYNTAX_SCAL : 0;
|
|
self->flags |=
|
|
(coreCodec == AOT_DRM_AAC) ? SBRDEC_SYNTAX_SCAL | SBRDEC_SYNTAX_DRM : 0;
|
|
self->flags |= (coreCodec == AOT_DRM_SURROUND)
|
|
? SBRDEC_SYNTAX_SCAL | SBRDEC_SYNTAX_DRM
|
|
: 0;
|
|
self->flags |= (coreCodec == AOT_USAC) ? SBRDEC_SYNTAX_USAC : 0;
|
|
/* Robustness: Take integer division rounding into consideration. E.g. 22050
|
|
* Hz with 4:1 SBR => 5512 Hz core sampling rate. */
|
|
self->flags |= (sampleRateIn == sampleRateOut / 4) ? SBRDEC_QUAD_RATE : 0;
|
|
self->flags |= (harmonicSBR == 1) ? SBRDEC_USAC_HARMONICSBR : 0;
|
|
|
|
if (configMode & AC_CM_DET_CFG_CHANGE) {
|
|
return SBRDEC_OK;
|
|
}
|
|
|
|
self->sampleRateIn = sampleRateIn;
|
|
self->codecFrameSize = samplesPerFrame;
|
|
self->coreCodec = coreCodec;
|
|
self->harmonicSBR = harmonicSBR;
|
|
self->downscaleFactor = downscaleFactor;
|
|
|
|
/* Init SBR elements */
|
|
{
|
|
int elChannels, ch;
|
|
|
|
if (self->pSbrElement[elementIndex] == NULL) {
|
|
self->pSbrElement[elementIndex] = GetRam_SbrDecElement(elementIndex);
|
|
if (self->pSbrElement[elementIndex] == NULL) {
|
|
sbrError = SBRDEC_MEM_ALLOC_FAILED;
|
|
goto bail;
|
|
}
|
|
self->numSbrElements++;
|
|
} else {
|
|
self->numSbrChannels -= self->pSbrElement[elementIndex]->nChannels;
|
|
}
|
|
|
|
/* Determine amount of channels for this element */
|
|
switch (elementID) {
|
|
case ID_NONE:
|
|
case ID_CPE:
|
|
elChannels = 2;
|
|
break;
|
|
case ID_LFE:
|
|
case ID_SCE:
|
|
elChannels = 1;
|
|
break;
|
|
default:
|
|
elChannels = 0;
|
|
break;
|
|
}
|
|
|
|
/* Handle case of Parametric Stereo */
|
|
if (elementIndex == 0 && elementID == ID_SCE) {
|
|
switch (coreCodec) {
|
|
case AOT_AAC_LC:
|
|
case AOT_SBR:
|
|
case AOT_PS:
|
|
case AOT_ER_AAC_SCAL:
|
|
case AOT_DRM_AAC:
|
|
case AOT_DRM_SURROUND:
|
|
elChannels = 2;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* Sanity check to avoid memory leaks */
|
|
if (elChannels < self->pSbrElement[elementIndex]->nChannels ||
|
|
(self->numSbrChannels + elChannels) > (8) + (1)) {
|
|
self->numSbrChannels += self->pSbrElement[elementIndex]->nChannels;
|
|
sbrError = SBRDEC_PARSE_ERROR;
|
|
goto bail;
|
|
}
|
|
|
|
/* Save element ID for sanity checks and to have a fallback for concealment.
|
|
*/
|
|
self->pSbrElement[elementIndex]->elementID = elementID;
|
|
self->pSbrElement[elementIndex]->nChannels = elChannels;
|
|
|
|
for (ch = 0; ch < elChannels; ch++) {
|
|
if (self->pSbrElement[elementIndex]->pSbrChannel[ch] == NULL) {
|
|
self->pSbrElement[elementIndex]->pSbrChannel[ch] =
|
|
GetRam_SbrDecChannel(chCnt);
|
|
if (self->pSbrElement[elementIndex]->pSbrChannel[ch] == NULL) {
|
|
sbrError = SBRDEC_MEM_ALLOC_FAILED;
|
|
goto bail;
|
|
}
|
|
}
|
|
self->numSbrChannels++;
|
|
|
|
sbrDecoder_drcInitChannel(&self->pSbrElement[elementIndex]
|
|
->pSbrChannel[ch]
|
|
->SbrDec.sbrDrcChannel);
|
|
|
|
chCnt++;
|
|
}
|
|
}
|
|
|
|
if (!self->pQmfDomain->globalConf.qmfDomainExplicitConfig) {
|
|
self->pQmfDomain->globalConf.nInputChannels_requested =
|
|
self->numSbrChannels;
|
|
self->pQmfDomain->globalConf.nOutputChannels_requested =
|
|
fMax((INT)self->numSbrChannels,
|
|
(INT)self->pQmfDomain->globalConf.nOutputChannels_requested);
|
|
}
|
|
|
|
/* Make sure each SBR channel has one QMF channel assigned even if
|
|
* numSbrChannels or element set-up has changed. */
|
|
sbrDecoder_AssignQmfChannels2SbrChannels(self);
|
|
|
|
/* clear error flags for all delay slots */
|
|
FDKmemclear(self->pSbrElement[elementIndex]->frameErrorFlag,
|
|
((1) + 1) * sizeof(UCHAR));
|
|
|
|
{
|
|
int overlap;
|
|
|
|
if (coreCodec == AOT_ER_AAC_ELD) {
|
|
overlap = 0;
|
|
} else if (self->flags & SBRDEC_QUAD_RATE) {
|
|
overlap = (3 * 4);
|
|
} else {
|
|
overlap = (3 * 2);
|
|
}
|
|
/* Initialize this instance */
|
|
sbrError = sbrDecoder_ResetElement(self, sampleRateIn, sampleRateOut,
|
|
samplesPerFrame, elementID, elementIndex,
|
|
overlap);
|
|
}
|
|
|
|
bail:
|
|
if (sbrError != SBRDEC_OK) {
|
|
if ((nSbrElementsStart < self->numSbrElements) ||
|
|
(nSbrChannelsStart < self->numSbrChannels)) {
|
|
/* Free the memory allocated for this element */
|
|
sbrDecoder_DestroyElement(self, elementIndex);
|
|
} else if ((elementIndex < (8)) &&
|
|
(self->pSbrElement[elementIndex] !=
|
|
NULL)) { /* Set error flag to trigger concealment */
|
|
setFrameErrorFlag(self->pSbrElement[elementIndex], FRAME_ERROR);
|
|
}
|
|
}
|
|
|
|
return sbrError;
|
|
}
|
|
|
|
/**
|
|
* \brief Free config dependent SBR memory.
|
|
* \param self SBR decoder instance handle
|
|
*/
|
|
SBR_ERROR sbrDecoder_FreeMem(HANDLE_SBRDECODER *self) {
|
|
int i;
|
|
int elIdx;
|
|
|
|
if (self != NULL && *self != NULL) {
|
|
for (i = 0; i < (8); i++) {
|
|
sbrDecoder_DestroyElement(*self, i);
|
|
}
|
|
|
|
for (elIdx = 0; elIdx < (8); elIdx += 1) {
|
|
for (i = 0; i < (1) + 1; i += 1) {
|
|
(*self)->sbrHeader[elIdx][i].syncState = SBR_NOT_INITIALIZED;
|
|
}
|
|
}
|
|
}
|
|
|
|
return SBRDEC_OK;
|
|
}
|
|
|
|
/**
|
|
* \brief Apply decoded SBR header for one element.
|
|
* \param self SBR decoder instance handle
|
|
* \param hSbrHeader SBR header handle to be processed.
|
|
* \param hSbrChannel pointer array to the SBR element channels corresponding to
|
|
* the SBR header.
|
|
* \param headerStatus header status value returned from SBR header parser.
|
|
* \param numElementChannels amount of channels for the SBR element whos header
|
|
* is to be processed.
|
|
*/
|
|
static SBR_ERROR sbrDecoder_HeaderUpdate(HANDLE_SBRDECODER self,
|
|
HANDLE_SBR_HEADER_DATA hSbrHeader,
|
|
SBR_HEADER_STATUS headerStatus,
|
|
HANDLE_SBR_CHANNEL hSbrChannel[],
|
|
const int numElementChannels) {
|
|
SBR_ERROR errorStatus = SBRDEC_OK;
|
|
|
|
/*
|
|
change of control data, reset decoder
|
|
*/
|
|
errorStatus = resetFreqBandTables(hSbrHeader, self->flags);
|
|
|
|
if (errorStatus == SBRDEC_OK) {
|
|
if (hSbrHeader->syncState == UPSAMPLING && headerStatus != HEADER_RESET) {
|
|
#if (SBRDEC_MAX_HB_FADE_FRAMES > 0)
|
|
int ch;
|
|
for (ch = 0; ch < numElementChannels; ch += 1) {
|
|
hSbrChannel[ch]->SbrDec.highBandFadeCnt = SBRDEC_MAX_HB_FADE_FRAMES;
|
|
}
|
|
|
|
#endif
|
|
/* As the default header would limit the frequency range,
|
|
lowSubband and highSubband must be patched. */
|
|
hSbrHeader->freqBandData.lowSubband = hSbrHeader->numberOfAnalysisBands;
|
|
hSbrHeader->freqBandData.highSubband = hSbrHeader->numberOfAnalysisBands;
|
|
}
|
|
|
|
/* Trigger a reset before processing this slot */
|
|
hSbrHeader->status |= SBRDEC_HDR_STAT_RESET;
|
|
}
|
|
|
|
return errorStatus;
|
|
}
|
|
|
|
INT sbrDecoder_Header(HANDLE_SBRDECODER self, HANDLE_FDK_BITSTREAM hBs,
|
|
const INT sampleRateIn, const INT sampleRateOut,
|
|
const INT samplesPerFrame,
|
|
const AUDIO_OBJECT_TYPE coreCodec,
|
|
const MP4_ELEMENT_ID elementID, const INT elementIndex,
|
|
const UCHAR harmonicSBR, const UCHAR stereoConfigIndex,
|
|
const UCHAR configMode, UCHAR *configChanged,
|
|
const INT downscaleFactor) {
|
|
SBR_HEADER_STATUS headerStatus;
|
|
HANDLE_SBR_HEADER_DATA hSbrHeader;
|
|
SBR_ERROR sbrError = SBRDEC_OK;
|
|
int headerIndex;
|
|
UINT flagsSaved =
|
|
0; /* flags should not be changed in AC_CM_DET_CFG_CHANGE - mode after
|
|
parsing */
|
|
|
|
if (self == NULL || elementIndex >= (8)) {
|
|
return SBRDEC_UNSUPPORTED_CONFIG;
|
|
}
|
|
|
|
if (!sbrDecoder_isCoreCodecValid(coreCodec)) {
|
|
return SBRDEC_UNSUPPORTED_CONFIG;
|
|
}
|
|
|
|
if (configMode & AC_CM_DET_CFG_CHANGE) {
|
|
flagsSaved = self->flags; /* store */
|
|
}
|
|
|
|
sbrError = sbrDecoder_InitElement(
|
|
self, sampleRateIn, sampleRateOut, samplesPerFrame, coreCodec, elementID,
|
|
elementIndex, harmonicSBR, stereoConfigIndex, configMode, configChanged,
|
|
downscaleFactor);
|
|
|
|
if ((sbrError != SBRDEC_OK) || (elementID == ID_LFE)) {
|
|
goto bail;
|
|
}
|
|
|
|
if (configMode & AC_CM_DET_CFG_CHANGE) {
|
|
hSbrHeader = NULL;
|
|
} else {
|
|
headerIndex = getHeaderSlot(self->pSbrElement[elementIndex]->useFrameSlot,
|
|
self->pSbrElement[elementIndex]->useHeaderSlot);
|
|
|
|
hSbrHeader = &(self->sbrHeader[elementIndex][headerIndex]);
|
|
}
|
|
|
|
headerStatus = sbrGetHeaderData(hSbrHeader, hBs, self->flags, 0, configMode);
|
|
|
|
if (coreCodec == AOT_USAC) {
|
|
if (configMode & AC_CM_DET_CFG_CHANGE) {
|
|
self->flags = flagsSaved; /* restore */
|
|
}
|
|
return sbrError;
|
|
}
|
|
|
|
if (configMode & AC_CM_ALLOC_MEM) {
|
|
SBR_DECODER_ELEMENT *pSbrElement;
|
|
|
|
pSbrElement = self->pSbrElement[elementIndex];
|
|
|
|
/* Sanity check */
|
|
if (pSbrElement != NULL) {
|
|
if ((elementID == ID_CPE && pSbrElement->nChannels != 2) ||
|
|
(elementID != ID_CPE && pSbrElement->nChannels != 1)) {
|
|
return SBRDEC_UNSUPPORTED_CONFIG;
|
|
}
|
|
if (headerStatus == HEADER_RESET) {
|
|
sbrError = sbrDecoder_HeaderUpdate(self, hSbrHeader, headerStatus,
|
|
pSbrElement->pSbrChannel,
|
|
pSbrElement->nChannels);
|
|
|
|
if (sbrError == SBRDEC_OK) {
|
|
hSbrHeader->syncState = SBR_HEADER;
|
|
hSbrHeader->status |= SBRDEC_HDR_STAT_UPDATE;
|
|
} else {
|
|
hSbrHeader->syncState = SBR_NOT_INITIALIZED;
|
|
hSbrHeader->status = HEADER_ERROR;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
bail:
|
|
if (configMode & AC_CM_DET_CFG_CHANGE) {
|
|
self->flags = flagsSaved; /* restore */
|
|
}
|
|
return sbrError;
|
|
}
|
|
|
|
SBR_ERROR sbrDecoder_SetParam(HANDLE_SBRDECODER self, const SBRDEC_PARAM param,
|
|
const INT value) {
|
|
SBR_ERROR errorStatus = SBRDEC_OK;
|
|
|
|
/* configure the subsystems */
|
|
switch (param) {
|
|
case SBR_SYSTEM_BITSTREAM_DELAY:
|
|
if (value < 0 || value > (1)) {
|
|
errorStatus = SBRDEC_SET_PARAM_FAIL;
|
|
break;
|
|
}
|
|
if (self == NULL) {
|
|
errorStatus = SBRDEC_NOT_INITIALIZED;
|
|
} else {
|
|
self->numDelayFrames = (UCHAR)value;
|
|
}
|
|
break;
|
|
case SBR_QMF_MODE:
|
|
if (self == NULL) {
|
|
errorStatus = SBRDEC_NOT_INITIALIZED;
|
|
} else {
|
|
if (value == 1) {
|
|
self->flags |= SBRDEC_LOW_POWER;
|
|
} else {
|
|
self->flags &= ~SBRDEC_LOW_POWER;
|
|
}
|
|
}
|
|
break;
|
|
case SBR_LD_QMF_TIME_ALIGN:
|
|
if (self == NULL) {
|
|
errorStatus = SBRDEC_NOT_INITIALIZED;
|
|
} else {
|
|
if (value == 1) {
|
|
self->flags |= SBRDEC_LD_MPS_QMF;
|
|
} else {
|
|
self->flags &= ~SBRDEC_LD_MPS_QMF;
|
|
}
|
|
}
|
|
break;
|
|
case SBR_FLUSH_DATA:
|
|
if (value != 0) {
|
|
if (self == NULL) {
|
|
errorStatus = SBRDEC_NOT_INITIALIZED;
|
|
} else {
|
|
self->flags |= SBRDEC_FLUSH;
|
|
}
|
|
}
|
|
break;
|
|
case SBR_CLEAR_HISTORY:
|
|
if (value != 0) {
|
|
if (self == NULL) {
|
|
errorStatus = SBRDEC_NOT_INITIALIZED;
|
|
} else {
|
|
self->flags |= SBRDEC_FORCE_RESET;
|
|
}
|
|
}
|
|
break;
|
|
case SBR_BS_INTERRUPTION: {
|
|
int elementIndex;
|
|
|
|
if (self == NULL) {
|
|
errorStatus = SBRDEC_NOT_INITIALIZED;
|
|
break;
|
|
}
|
|
|
|
/* Loop over SBR elements */
|
|
for (elementIndex = 0; elementIndex < self->numSbrElements;
|
|
elementIndex++) {
|
|
if (self->pSbrElement[elementIndex] != NULL) {
|
|
HANDLE_SBR_HEADER_DATA hSbrHeader;
|
|
int headerIndex =
|
|
getHeaderSlot(self->pSbrElement[elementIndex]->useFrameSlot,
|
|
self->pSbrElement[elementIndex]->useHeaderSlot);
|
|
|
|
hSbrHeader = &(self->sbrHeader[elementIndex][headerIndex]);
|
|
|
|
/* Set sync state UPSAMPLING for the corresponding slot.
|
|
This switches off bitstream parsing until a new header arrives. */
|
|
hSbrHeader->syncState = UPSAMPLING;
|
|
hSbrHeader->status |= SBRDEC_HDR_STAT_UPDATE;
|
|
}
|
|
}
|
|
} break;
|
|
|
|
case SBR_SKIP_QMF:
|
|
if (self == NULL) {
|
|
errorStatus = SBRDEC_NOT_INITIALIZED;
|
|
} else {
|
|
if (value == 1) {
|
|
self->flags |= SBRDEC_SKIP_QMF_ANA;
|
|
} else {
|
|
self->flags &= ~SBRDEC_SKIP_QMF_ANA;
|
|
}
|
|
if (value == 2) {
|
|
self->flags |= SBRDEC_SKIP_QMF_SYN;
|
|
} else {
|
|
self->flags &= ~SBRDEC_SKIP_QMF_SYN;
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
errorStatus = SBRDEC_SET_PARAM_FAIL;
|
|
break;
|
|
} /* switch(param) */
|
|
|
|
return (errorStatus);
|
|
}
|
|
|
|
static SBRDEC_DRC_CHANNEL *sbrDecoder_drcGetChannel(
|
|
const HANDLE_SBRDECODER self, const INT channel) {
|
|
SBRDEC_DRC_CHANNEL *pSbrDrcChannelData = NULL;
|
|
int elementIndex, elChanIdx = 0, numCh = 0;
|
|
|
|
for (elementIndex = 0; (elementIndex < (8)) && (numCh <= channel);
|
|
elementIndex++) {
|
|
SBR_DECODER_ELEMENT *pSbrElement = self->pSbrElement[elementIndex];
|
|
int c, elChannels;
|
|
|
|
elChanIdx = 0;
|
|
if (pSbrElement == NULL) break;
|
|
|
|
/* Determine amount of channels for this element */
|
|
switch (pSbrElement->elementID) {
|
|
case ID_CPE:
|
|
elChannels = 2;
|
|
break;
|
|
case ID_LFE:
|
|
case ID_SCE:
|
|
elChannels = 1;
|
|
break;
|
|
case ID_NONE:
|
|
default:
|
|
elChannels = 0;
|
|
break;
|
|
}
|
|
|
|
/* Limit with actual allocated element channels */
|
|
elChannels = fMin(elChannels, pSbrElement->nChannels);
|
|
|
|
for (c = 0; (c < elChannels) && (numCh <= channel); c++) {
|
|
if (pSbrElement->pSbrChannel[elChanIdx] != NULL) {
|
|
numCh++;
|
|
elChanIdx++;
|
|
}
|
|
}
|
|
}
|
|
elementIndex -= 1;
|
|
elChanIdx -= 1;
|
|
|
|
if (elChanIdx < 0 || elementIndex < 0) {
|
|
return NULL;
|
|
}
|
|
|
|
if (self->pSbrElement[elementIndex] != NULL) {
|
|
if (self->pSbrElement[elementIndex]->pSbrChannel[elChanIdx] != NULL) {
|
|
pSbrDrcChannelData = &self->pSbrElement[elementIndex]
|
|
->pSbrChannel[elChanIdx]
|
|
->SbrDec.sbrDrcChannel;
|
|
}
|
|
}
|
|
|
|
return (pSbrDrcChannelData);
|
|
}
|
|
|
|
SBR_ERROR sbrDecoder_drcFeedChannel(HANDLE_SBRDECODER self, INT ch,
|
|
UINT numBands, FIXP_DBL *pNextFact_mag,
|
|
INT nextFact_exp,
|
|
SHORT drcInterpolationScheme,
|
|
UCHAR winSequence, USHORT *pBandTop) {
|
|
SBRDEC_DRC_CHANNEL *pSbrDrcChannelData = NULL;
|
|
int band, isValidData = 0;
|
|
|
|
if (self == NULL) {
|
|
return SBRDEC_NOT_INITIALIZED;
|
|
}
|
|
if (ch > (8) || pNextFact_mag == NULL) {
|
|
return SBRDEC_SET_PARAM_FAIL;
|
|
}
|
|
|
|
/* Search for gain values different to 1.0f */
|
|
for (band = 0; band < (int)numBands; band += 1) {
|
|
if (!((pNextFact_mag[band] == FL2FXCONST_DBL(0.5)) &&
|
|
(nextFact_exp == 1)) &&
|
|
!((pNextFact_mag[band] == (FIXP_DBL)MAXVAL_DBL) &&
|
|
(nextFact_exp == 0))) {
|
|
isValidData = 1;
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* Find the right SBR channel */
|
|
pSbrDrcChannelData = sbrDecoder_drcGetChannel(self, ch);
|
|
|
|
if (pSbrDrcChannelData != NULL) {
|
|
if (pSbrDrcChannelData->enable ||
|
|
isValidData) { /* Activate processing only with real and valid data */
|
|
int i;
|
|
|
|
pSbrDrcChannelData->enable = 1;
|
|
pSbrDrcChannelData->numBandsNext = numBands;
|
|
|
|
pSbrDrcChannelData->winSequenceNext = winSequence;
|
|
pSbrDrcChannelData->drcInterpolationSchemeNext = drcInterpolationScheme;
|
|
pSbrDrcChannelData->nextFact_exp = nextFact_exp;
|
|
|
|
for (i = 0; i < (int)numBands; i++) {
|
|
pSbrDrcChannelData->bandTopNext[i] = pBandTop[i];
|
|
pSbrDrcChannelData->nextFact_mag[i] = pNextFact_mag[i];
|
|
}
|
|
}
|
|
}
|
|
|
|
return SBRDEC_OK;
|
|
}
|
|
|
|
void sbrDecoder_drcDisable(HANDLE_SBRDECODER self, INT ch) {
|
|
SBRDEC_DRC_CHANNEL *pSbrDrcChannelData = NULL;
|
|
|
|
if ((self == NULL) || (ch > (8)) || (self->numSbrElements == 0) ||
|
|
(self->numSbrChannels == 0)) {
|
|
return;
|
|
}
|
|
|
|
/* Find the right SBR channel */
|
|
pSbrDrcChannelData = sbrDecoder_drcGetChannel(self, ch);
|
|
|
|
if (pSbrDrcChannelData != NULL) {
|
|
sbrDecoder_drcInitChannel(pSbrDrcChannelData);
|
|
}
|
|
}
|
|
|
|
SBR_ERROR sbrDecoder_Parse(HANDLE_SBRDECODER self, HANDLE_FDK_BITSTREAM hBs,
|
|
UCHAR *pDrmBsBuffer, USHORT drmBsBufferSize,
|
|
int *count, int bsPayLen, int crcFlag,
|
|
MP4_ELEMENT_ID prevElement, int elementIndex,
|
|
UINT acFlags, UINT acElFlags[]) {
|
|
SBR_DECODER_ELEMENT *hSbrElement = NULL;
|
|
HANDLE_SBR_HEADER_DATA hSbrHeader = NULL;
|
|
HANDLE_SBR_CHANNEL *pSbrChannel;
|
|
|
|
SBR_FRAME_DATA *hFrameDataLeft = NULL;
|
|
SBR_FRAME_DATA *hFrameDataRight = NULL;
|
|
SBR_FRAME_DATA frameDataLeftCopy;
|
|
SBR_FRAME_DATA frameDataRightCopy;
|
|
|
|
SBR_ERROR errorStatus = SBRDEC_OK;
|
|
SBR_HEADER_STATUS headerStatus = HEADER_NOT_PRESENT;
|
|
|
|
INT startPos = FDKgetValidBits(hBs);
|
|
FDK_CRCINFO crcInfo;
|
|
INT crcReg = 0;
|
|
USHORT sbrCrc = 0;
|
|
UINT crcPoly;
|
|
UINT crcStartValue = 0;
|
|
UINT crcLen;
|
|
|
|
HANDLE_FDK_BITSTREAM hBsOriginal = hBs;
|
|
FDK_BITSTREAM bsBwd;
|
|
|
|
const int fGlobalIndependencyFlag = acFlags & AC_INDEP;
|
|
const int bs_pvc = acElFlags[elementIndex] & AC_EL_USAC_PVC;
|
|
const int bs_interTes = acElFlags[elementIndex] & AC_EL_USAC_ITES;
|
|
int stereo;
|
|
int fDoDecodeSbrData = 1;
|
|
int alignBits = 0;
|
|
|
|
int lastSlot, lastHdrSlot = 0, thisHdrSlot = 0;
|
|
|
|
if (*count <= 0) {
|
|
setFrameErrorFlag(self->pSbrElement[elementIndex], FRAME_ERROR);
|
|
return SBRDEC_OK;
|
|
}
|
|
|
|
/* SBR sanity checks */
|
|
if (self == NULL) {
|
|
errorStatus = SBRDEC_NOT_INITIALIZED;
|
|
goto bail;
|
|
}
|
|
|
|
/* Reverse bits of DRM SBR payload */
|
|
if ((self->flags & SBRDEC_SYNTAX_DRM) && *count > 0) {
|
|
int dataBytes, dataBits;
|
|
|
|
FDK_ASSERT(drmBsBufferSize >= (512));
|
|
dataBits = *count;
|
|
|
|
if (dataBits > ((512) * 8)) {
|
|
/* do not flip more data than needed */
|
|
dataBits = (512) * 8;
|
|
}
|
|
|
|
dataBytes = (dataBits + 7) >> 3;
|
|
|
|
int j;
|
|
|
|
if ((j = (int)FDKgetValidBits(hBs)) != 8) {
|
|
FDKpushBiDirectional(hBs, (j - 8));
|
|
}
|
|
|
|
j = 0;
|
|
for (; dataBytes > 0; dataBytes--) {
|
|
int i;
|
|
UCHAR tmpByte;
|
|
UCHAR buffer = 0x00;
|
|
|
|
tmpByte = (UCHAR)FDKreadBits(hBs, 8);
|
|
for (i = 0; i < 4; i++) {
|
|
int shift = 2 * i + 1;
|
|
buffer |= (tmpByte & (0x08 >> i)) << shift;
|
|
buffer |= (tmpByte & (0x10 << i)) >> shift;
|
|
}
|
|
pDrmBsBuffer[j++] = buffer;
|
|
FDKpushBack(hBs, 16);
|
|
}
|
|
|
|
FDKinitBitStream(&bsBwd, pDrmBsBuffer, (512), dataBits, BS_READER);
|
|
|
|
/* Use reversed data */
|
|
hBs = &bsBwd;
|
|
bsPayLen = *count;
|
|
}
|
|
|
|
/* Remember start position of SBR element */
|
|
startPos = FDKgetValidBits(hBs);
|
|
|
|
/* SBR sanity checks */
|
|
if (self->pSbrElement[elementIndex] == NULL) {
|
|
errorStatus = SBRDEC_NOT_INITIALIZED;
|
|
goto bail;
|
|
}
|
|
hSbrElement = self->pSbrElement[elementIndex];
|
|
|
|
lastSlot = (hSbrElement->useFrameSlot > 0) ? hSbrElement->useFrameSlot - 1
|
|
: self->numDelayFrames;
|
|
lastHdrSlot = hSbrElement->useHeaderSlot[lastSlot];
|
|
thisHdrSlot = getHeaderSlot(
|
|
hSbrElement->useFrameSlot,
|
|
hSbrElement->useHeaderSlot); /* Get a free header slot not used by
|
|
frames not processed yet. */
|
|
|
|
/* Assign the free slot to store a new header if there is one. */
|
|
hSbrHeader = &self->sbrHeader[elementIndex][thisHdrSlot];
|
|
|
|
pSbrChannel = hSbrElement->pSbrChannel;
|
|
stereo = (hSbrElement->elementID == ID_CPE) ? 1 : 0;
|
|
|
|
hFrameDataLeft = &self->pSbrElement[elementIndex]
|
|
->pSbrChannel[0]
|
|
->frameData[hSbrElement->useFrameSlot];
|
|
if (stereo) {
|
|
hFrameDataRight = &self->pSbrElement[elementIndex]
|
|
->pSbrChannel[1]
|
|
->frameData[hSbrElement->useFrameSlot];
|
|
}
|
|
|
|
/* store frameData; new parsed frameData possibly corrupted */
|
|
FDKmemcpy(&frameDataLeftCopy, hFrameDataLeft, sizeof(SBR_FRAME_DATA));
|
|
if (stereo) {
|
|
FDKmemcpy(&frameDataRightCopy, hFrameDataRight, sizeof(SBR_FRAME_DATA));
|
|
}
|
|
|
|
/* reset PS flag; will be set after PS was found */
|
|
self->flags &= ~SBRDEC_PS_DECODED;
|
|
|
|
if (hSbrHeader->status & SBRDEC_HDR_STAT_UPDATE) {
|
|
/* Got a new header from extern (e.g. from an ASC) */
|
|
headerStatus = HEADER_OK;
|
|
hSbrHeader->status &= ~SBRDEC_HDR_STAT_UPDATE;
|
|
} else if (thisHdrSlot != lastHdrSlot) {
|
|
/* Copy the last header into this slot otherwise the
|
|
header compare will trigger more HEADER_RESETs than needed. */
|
|
copySbrHeader(hSbrHeader, &self->sbrHeader[elementIndex][lastHdrSlot]);
|
|
}
|
|
|
|
/*
|
|
Check if bit stream data is valid and matches the element context
|
|
*/
|
|
if (((prevElement != ID_SCE) && (prevElement != ID_CPE)) ||
|
|
prevElement != hSbrElement->elementID) {
|
|
/* In case of LFE we also land here, since there is no LFE SBR element (do
|
|
* upsampling only) */
|
|
fDoDecodeSbrData = 0;
|
|
}
|
|
|
|
if (fDoDecodeSbrData) {
|
|
if ((INT)FDKgetValidBits(hBs) <= 0) {
|
|
fDoDecodeSbrData = 0;
|
|
}
|
|
}
|
|
|
|
/*
|
|
SBR CRC-check
|
|
*/
|
|
if (fDoDecodeSbrData) {
|
|
if (crcFlag) {
|
|
switch (self->coreCodec) {
|
|
case AOT_DRM_AAC:
|
|
case AOT_DRM_SURROUND:
|
|
crcPoly = 0x001d;
|
|
crcLen = 8;
|
|
crcStartValue = 0x000000ff;
|
|
break;
|
|
default:
|
|
crcPoly = 0x0633;
|
|
crcLen = 10;
|
|
crcStartValue = 0x00000000;
|
|
break;
|
|
}
|
|
sbrCrc = (USHORT)FDKreadBits(hBs, crcLen);
|
|
/* Setup CRC decoder */
|
|
FDKcrcInit(&crcInfo, crcPoly, crcStartValue, crcLen);
|
|
/* Start CRC region */
|
|
crcReg = FDKcrcStartReg(&crcInfo, hBs, 0);
|
|
}
|
|
} /* if (fDoDecodeSbrData) */
|
|
|
|
/*
|
|
Read in the header data and issue a reset if change occured
|
|
*/
|
|
if (fDoDecodeSbrData) {
|
|
int sbrHeaderPresent;
|
|
|
|
if (self->flags & (SBRDEC_SYNTAX_RSVD50 | SBRDEC_SYNTAX_USAC)) {
|
|
SBR_HEADER_DATA_BS_INFO newSbrInfo;
|
|
int sbrInfoPresent;
|
|
|
|
if (bs_interTes) {
|
|
self->flags |= SBRDEC_USAC_ITES;
|
|
} else {
|
|
self->flags &= ~SBRDEC_USAC_ITES;
|
|
}
|
|
|
|
if (fGlobalIndependencyFlag) {
|
|
self->flags |= SBRDEC_USAC_INDEP;
|
|
sbrInfoPresent = 1;
|
|
sbrHeaderPresent = 1;
|
|
} else {
|
|
self->flags &= ~SBRDEC_USAC_INDEP;
|
|
sbrInfoPresent = FDKreadBit(hBs);
|
|
if (sbrInfoPresent) {
|
|
sbrHeaderPresent = FDKreadBit(hBs);
|
|
} else {
|
|
sbrHeaderPresent = 0;
|
|
}
|
|
}
|
|
|
|
if (sbrInfoPresent) {
|
|
newSbrInfo.ampResolution = FDKreadBit(hBs);
|
|
newSbrInfo.xover_band = FDKreadBits(hBs, 4);
|
|
newSbrInfo.sbr_preprocessing = FDKreadBit(hBs);
|
|
if (bs_pvc) {
|
|
newSbrInfo.pvc_mode = FDKreadBits(hBs, 2);
|
|
/* bs_pvc_mode: 0 -> no PVC, 1 -> PVC mode 1, 2 -> PVC mode 2, 3 ->
|
|
* reserved */
|
|
if (newSbrInfo.pvc_mode > 2) {
|
|
headerStatus = HEADER_ERROR;
|
|
}
|
|
if (stereo && newSbrInfo.pvc_mode > 0) {
|
|
/* bs_pvc is always transmitted but pvc_mode is set to zero in case
|
|
* of stereo SBR. The config might be wrong but we cannot tell for
|
|
* sure. */
|
|
newSbrInfo.pvc_mode = 0;
|
|
}
|
|
} else {
|
|
newSbrInfo.pvc_mode = 0;
|
|
}
|
|
if (headerStatus != HEADER_ERROR) {
|
|
if (FDKmemcmp(&hSbrHeader->bs_info, &newSbrInfo,
|
|
sizeof(SBR_HEADER_DATA_BS_INFO))) {
|
|
/* in case of ampResolution and preprocessing change no full reset
|
|
* required */
|
|
/* HEADER reset would trigger HBE transposer reset which breaks
|
|
* eSbr_3_Eaa.mp4 */
|
|
if ((hSbrHeader->bs_info.pvc_mode != newSbrInfo.pvc_mode) ||
|
|
(hSbrHeader->bs_info.xover_band != newSbrInfo.xover_band)) {
|
|
headerStatus = HEADER_RESET;
|
|
} else {
|
|
headerStatus = HEADER_OK;
|
|
}
|
|
|
|
hSbrHeader->bs_info = newSbrInfo;
|
|
} else {
|
|
headerStatus = HEADER_OK;
|
|
}
|
|
}
|
|
}
|
|
if (headerStatus == HEADER_ERROR) {
|
|
/* Corrupt SBR info data, do not decode and switch to UPSAMPLING */
|
|
hSbrHeader->syncState = UPSAMPLING;
|
|
fDoDecodeSbrData = 0;
|
|
sbrHeaderPresent = 0;
|
|
}
|
|
|
|
if (sbrHeaderPresent && fDoDecodeSbrData) {
|
|
int useDfltHeader;
|
|
|
|
useDfltHeader = FDKreadBit(hBs);
|
|
|
|
if (useDfltHeader) {
|
|
sbrHeaderPresent = 0;
|
|
if (FDKmemcmp(&hSbrHeader->bs_data, &hSbrHeader->bs_dflt,
|
|
sizeof(SBR_HEADER_DATA_BS)) ||
|
|
hSbrHeader->syncState != SBR_ACTIVE) {
|
|
hSbrHeader->bs_data = hSbrHeader->bs_dflt;
|
|
headerStatus = HEADER_RESET;
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
sbrHeaderPresent = FDKreadBit(hBs);
|
|
}
|
|
|
|
if (sbrHeaderPresent) {
|
|
headerStatus = sbrGetHeaderData(hSbrHeader, hBs, self->flags, 1, 0);
|
|
}
|
|
|
|
if (headerStatus == HEADER_RESET) {
|
|
errorStatus = sbrDecoder_HeaderUpdate(
|
|
self, hSbrHeader, headerStatus, pSbrChannel, hSbrElement->nChannels);
|
|
|
|
if (errorStatus == SBRDEC_OK) {
|
|
hSbrHeader->syncState = SBR_HEADER;
|
|
} else {
|
|
hSbrHeader->syncState = SBR_NOT_INITIALIZED;
|
|
headerStatus = HEADER_ERROR;
|
|
}
|
|
}
|
|
|
|
if (errorStatus != SBRDEC_OK) {
|
|
fDoDecodeSbrData = 0;
|
|
}
|
|
} /* if (fDoDecodeSbrData) */
|
|
|
|
/*
|
|
Print debugging output only if state has changed
|
|
*/
|
|
|
|
/* read frame data */
|
|
if ((hSbrHeader->syncState >= SBR_HEADER) && fDoDecodeSbrData) {
|
|
int sbrFrameOk;
|
|
/* read the SBR element data */
|
|
if (!stereo && (self->hParametricStereoDec != NULL)) {
|
|
/* update slot index for PS bitstream parsing */
|
|
self->hParametricStereoDec->bsLastSlot =
|
|
self->hParametricStereoDec->bsReadSlot;
|
|
self->hParametricStereoDec->bsReadSlot = hSbrElement->useFrameSlot;
|
|
}
|
|
sbrFrameOk = sbrGetChannelElement(
|
|
hSbrHeader, hFrameDataLeft, (stereo) ? hFrameDataRight : NULL,
|
|
&pSbrChannel[0]->prevFrameData,
|
|
pSbrChannel[0]->SbrDec.PvcStaticData.pvc_mode_last, hBs,
|
|
(stereo) ? NULL : self->hParametricStereoDec, self->flags,
|
|
self->pSbrElement[elementIndex]->transposerSettings.overlap);
|
|
|
|
if (!sbrFrameOk) {
|
|
fDoDecodeSbrData = 0;
|
|
} else {
|
|
INT valBits;
|
|
|
|
if (bsPayLen > 0) {
|
|
valBits = bsPayLen - ((INT)startPos - (INT)FDKgetValidBits(hBs));
|
|
} else {
|
|
valBits = (INT)FDKgetValidBits(hBs);
|
|
}
|
|
|
|
/* sanity check of remaining bits */
|
|
if (valBits < 0) {
|
|
fDoDecodeSbrData = 0;
|
|
} else {
|
|
switch (self->coreCodec) {
|
|
case AOT_SBR:
|
|
case AOT_PS:
|
|
case AOT_AAC_LC: {
|
|
/* This sanity check is only meaningful with General Audio
|
|
* bitstreams */
|
|
alignBits = valBits & 0x7;
|
|
|
|
if (valBits > alignBits) {
|
|
fDoDecodeSbrData = 0;
|
|
}
|
|
} break;
|
|
default:
|
|
/* No sanity check available */
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
/* The returned bit count will not be the actual payload size since we did
|
|
not parse the frame data. Return an error so that the caller can react
|
|
respectively. */
|
|
errorStatus = SBRDEC_PARSE_ERROR;
|
|
}
|
|
|
|
if (crcFlag && (hSbrHeader->syncState >= SBR_HEADER) && fDoDecodeSbrData) {
|
|
FDKpushFor(hBs, alignBits);
|
|
FDKcrcEndReg(&crcInfo, hBs, crcReg); /* End CRC region */
|
|
FDKpushBack(hBs, alignBits);
|
|
/* Check CRC */
|
|
if ((FDKcrcGetCRC(&crcInfo) ^ crcStartValue) != sbrCrc) {
|
|
fDoDecodeSbrData = 0;
|
|
if (headerStatus != HEADER_NOT_PRESENT) {
|
|
headerStatus = HEADER_ERROR;
|
|
hSbrHeader->syncState = SBR_NOT_INITIALIZED;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!fDoDecodeSbrData) {
|
|
/* Set error flag for this slot to trigger concealment */
|
|
setFrameErrorFlag(self->pSbrElement[elementIndex], FRAME_ERROR);
|
|
/* restore old frameData for concealment */
|
|
FDKmemcpy(hFrameDataLeft, &frameDataLeftCopy, sizeof(SBR_FRAME_DATA));
|
|
if (stereo) {
|
|
FDKmemcpy(hFrameDataRight, &frameDataRightCopy, sizeof(SBR_FRAME_DATA));
|
|
}
|
|
errorStatus = SBRDEC_PARSE_ERROR;
|
|
} else {
|
|
/* Everything seems to be ok so clear the error flag */
|
|
setFrameErrorFlag(self->pSbrElement[elementIndex], FRAME_OK);
|
|
}
|
|
|
|
if (!stereo) {
|
|
/* Turn coupling off explicitely to avoid access to absent right frame data
|
|
that might occur with corrupt bitstreams. */
|
|
hFrameDataLeft->coupling = COUPLING_OFF;
|
|
}
|
|
|
|
bail:
|
|
|
|
if (self != NULL) {
|
|
if (self->flags & SBRDEC_SYNTAX_DRM) {
|
|
hBs = hBsOriginal;
|
|
}
|
|
|
|
if (errorStatus != SBRDEC_NOT_INITIALIZED) {
|
|
int useOldHdr =
|
|
((headerStatus == HEADER_NOT_PRESENT) ||
|
|
(headerStatus == HEADER_ERROR) ||
|
|
(headerStatus == HEADER_RESET && errorStatus == SBRDEC_PARSE_ERROR))
|
|
? 1
|
|
: 0;
|
|
|
|
if (!useOldHdr && (thisHdrSlot != lastHdrSlot) && (hSbrHeader != NULL)) {
|
|
useOldHdr |=
|
|
(compareSbrHeader(hSbrHeader,
|
|
&self->sbrHeader[elementIndex][lastHdrSlot]) == 0)
|
|
? 1
|
|
: 0;
|
|
}
|
|
|
|
if (hSbrElement != NULL) {
|
|
if (useOldHdr != 0) {
|
|
/* Use the old header for this frame */
|
|
hSbrElement->useHeaderSlot[hSbrElement->useFrameSlot] = lastHdrSlot;
|
|
} else {
|
|
/* Use the new header for this frame */
|
|
hSbrElement->useHeaderSlot[hSbrElement->useFrameSlot] = thisHdrSlot;
|
|
}
|
|
|
|
/* Move frame pointer to the next slot which is up to be decoded/applied
|
|
* next */
|
|
hSbrElement->useFrameSlot =
|
|
(hSbrElement->useFrameSlot + 1) % (self->numDelayFrames + 1);
|
|
}
|
|
}
|
|
}
|
|
|
|
*count -= startPos - (INT)FDKgetValidBits(hBs);
|
|
|
|
return errorStatus;
|
|
}
|
|
|
|
/**
|
|
* \brief Render one SBR element into time domain signal.
|
|
* \param self SBR decoder handle
|
|
* \param timeData pointer to output buffer
|
|
* \param channelMapping pointer to UCHAR array where next 2 channel offsets are
|
|
* stored.
|
|
* \param elementIndex enumerating index of the SBR element to render.
|
|
* \param numInChannels number of channels from core coder.
|
|
* \param numOutChannels pointer to a location to return number of output
|
|
* channels.
|
|
* \param psPossible flag indicating if PS is possible or not.
|
|
* \return SBRDEC_OK if successfull, else error code
|
|
*/
|
|
static SBR_ERROR sbrDecoder_DecodeElement(
|
|
HANDLE_SBRDECODER self, LONG *input, LONG *timeData, const int timeDataSize,
|
|
const FDK_channelMapDescr *const mapDescr, const int mapIdx,
|
|
int channelIndex, const int elementIndex, const int numInChannels,
|
|
int *numOutChannels, const int psPossible) {
|
|
SBR_DECODER_ELEMENT *hSbrElement = self->pSbrElement[elementIndex];
|
|
HANDLE_SBR_CHANNEL *pSbrChannel =
|
|
self->pSbrElement[elementIndex]->pSbrChannel;
|
|
HANDLE_SBR_HEADER_DATA hSbrHeader =
|
|
&self->sbrHeader[elementIndex]
|
|
[hSbrElement->useHeaderSlot[hSbrElement->useFrameSlot]];
|
|
HANDLE_PS_DEC h_ps_d = self->hParametricStereoDec;
|
|
|
|
/* get memory for frame data from scratch */
|
|
SBR_FRAME_DATA *hFrameDataLeft = NULL;
|
|
SBR_FRAME_DATA *hFrameDataRight = NULL;
|
|
|
|
SBR_ERROR errorStatus = SBRDEC_OK;
|
|
|
|
INT strideOut, offset0 = 255, offset0_block = 0, offset1 = 255,
|
|
offset1_block = 0;
|
|
INT codecFrameSize = self->codecFrameSize;
|
|
|
|
int stereo = (hSbrElement->elementID == ID_CPE) ? 1 : 0;
|
|
int numElementChannels =
|
|
hSbrElement
|
|
->nChannels; /* Number of channels of the current SBR element */
|
|
|
|
hFrameDataLeft =
|
|
&hSbrElement->pSbrChannel[0]->frameData[hSbrElement->useFrameSlot];
|
|
if (stereo) {
|
|
hFrameDataRight =
|
|
&hSbrElement->pSbrChannel[1]->frameData[hSbrElement->useFrameSlot];
|
|
}
|
|
|
|
if (self->flags & SBRDEC_FLUSH) {
|
|
if (self->numFlushedFrames > self->numDelayFrames) {
|
|
int hdrIdx;
|
|
/* No valid SBR payload available, hence switch to upsampling (in all
|
|
* headers) */
|
|
for (hdrIdx = 0; hdrIdx < ((1) + 1); hdrIdx += 1) {
|
|
self->sbrHeader[elementIndex][hdrIdx].syncState = UPSAMPLING;
|
|
}
|
|
} else {
|
|
/* Move frame pointer to the next slot which is up to be decoded/applied
|
|
* next */
|
|
hSbrElement->useFrameSlot =
|
|
(hSbrElement->useFrameSlot + 1) % (self->numDelayFrames + 1);
|
|
/* Update header and frame data pointer because they have already been set
|
|
*/
|
|
hSbrHeader =
|
|
&self->sbrHeader[elementIndex]
|
|
[hSbrElement
|
|
->useHeaderSlot[hSbrElement->useFrameSlot]];
|
|
hFrameDataLeft =
|
|
&hSbrElement->pSbrChannel[0]->frameData[hSbrElement->useFrameSlot];
|
|
if (stereo) {
|
|
hFrameDataRight =
|
|
&hSbrElement->pSbrChannel[1]->frameData[hSbrElement->useFrameSlot];
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Update the header error flag */
|
|
hSbrHeader->frameErrorFlag =
|
|
hSbrElement->frameErrorFlag[hSbrElement->useFrameSlot];
|
|
|
|
/*
|
|
Prepare filterbank for upsampling if no valid bit stream data is available.
|
|
*/
|
|
if (hSbrHeader->syncState == SBR_NOT_INITIALIZED) {
|
|
errorStatus =
|
|
initHeaderData(hSbrHeader, self->sampleRateIn, self->sampleRateOut,
|
|
self->downscaleFactor, codecFrameSize, self->flags,
|
|
1 /* SET_DEFAULT_HDR */
|
|
);
|
|
|
|
if (errorStatus != SBRDEC_OK) {
|
|
return errorStatus;
|
|
}
|
|
|
|
hSbrHeader->syncState = UPSAMPLING;
|
|
|
|
errorStatus = sbrDecoder_HeaderUpdate(self, hSbrHeader, HEADER_NOT_PRESENT,
|
|
pSbrChannel, hSbrElement->nChannels);
|
|
|
|
if (errorStatus != SBRDEC_OK) {
|
|
hSbrHeader->syncState = SBR_NOT_INITIALIZED;
|
|
return errorStatus;
|
|
}
|
|
}
|
|
|
|
/* reset */
|
|
if (hSbrHeader->status & SBRDEC_HDR_STAT_RESET) {
|
|
int ch;
|
|
int applySbrProc = (hSbrHeader->syncState == SBR_ACTIVE ||
|
|
(hSbrHeader->frameErrorFlag == 0 &&
|
|
hSbrHeader->syncState == SBR_HEADER));
|
|
for (ch = 0; ch < numElementChannels; ch++) {
|
|
SBR_ERROR errorStatusTmp = SBRDEC_OK;
|
|
|
|
errorStatusTmp = resetSbrDec(
|
|
&pSbrChannel[ch]->SbrDec, hSbrHeader, &pSbrChannel[ch]->prevFrameData,
|
|
self->synDownsampleFac, self->flags, pSbrChannel[ch]->frameData);
|
|
|
|
if (errorStatusTmp != SBRDEC_OK) {
|
|
hSbrHeader->syncState = UPSAMPLING;
|
|
}
|
|
}
|
|
if (applySbrProc) {
|
|
hSbrHeader->status &= ~SBRDEC_HDR_STAT_RESET;
|
|
}
|
|
}
|
|
|
|
/* decoding */
|
|
if ((hSbrHeader->syncState == SBR_ACTIVE) ||
|
|
((hSbrHeader->syncState == SBR_HEADER) &&
|
|
(hSbrHeader->frameErrorFlag == 0))) {
|
|
errorStatus = SBRDEC_OK;
|
|
|
|
decodeSbrData(hSbrHeader, hFrameDataLeft, &pSbrChannel[0]->prevFrameData,
|
|
(stereo) ? hFrameDataRight : NULL,
|
|
(stereo) ? &pSbrChannel[1]->prevFrameData : NULL);
|
|
|
|
/* Now we have a full parameter set and can do parameter
|
|
based concealment instead of plain upsampling. */
|
|
hSbrHeader->syncState = SBR_ACTIVE;
|
|
}
|
|
|
|
if (timeDataSize <
|
|
hSbrHeader->numberTimeSlots * hSbrHeader->timeStep *
|
|
self->pQmfDomain->globalConf.nBandsSynthesis *
|
|
(psPossible ? fMax(2, numInChannels) : numInChannels)) {
|
|
return SBRDEC_OUTPUT_BUFFER_TOO_SMALL;
|
|
}
|
|
|
|
{
|
|
self->flags &= ~SBRDEC_PS_DECODED;
|
|
C_ALLOC_SCRATCH_START(pPsScratch, struct PS_DEC_COEFFICIENTS, 1)
|
|
|
|
/* decode PS data if available */
|
|
if (h_ps_d != NULL && psPossible && (hSbrHeader->syncState == SBR_ACTIVE)) {
|
|
int applyPs = 1;
|
|
|
|
/* define which frame delay line slot to process */
|
|
h_ps_d->processSlot = hSbrElement->useFrameSlot;
|
|
|
|
applyPs = DecodePs(h_ps_d, hSbrHeader->frameErrorFlag, pPsScratch);
|
|
self->flags |= (applyPs) ? SBRDEC_PS_DECODED : 0;
|
|
}
|
|
|
|
offset0 = FDK_chMapDescr_getMapValue(mapDescr, channelIndex, mapIdx);
|
|
offset0_block = offset0 * codecFrameSize;
|
|
if (stereo || psPossible) {
|
|
/* the value of offset1 only matters if the condition is true, however if
|
|
it is not true channelIndex+1 may exceed the channel map resutling in an
|
|
error, though the value of offset1 is actually meaningless. This is
|
|
prevented here. */
|
|
offset1 = FDK_chMapDescr_getMapValue(mapDescr, channelIndex + 1, mapIdx);
|
|
offset1_block = offset1 * codecFrameSize;
|
|
}
|
|
/* Set strides for reading and writing */
|
|
if (psPossible)
|
|
strideOut = (numInChannels < 2) ? 2 : numInChannels;
|
|
else
|
|
strideOut = numInChannels;
|
|
|
|
/* use same buffers for left and right channel and apply PS per timeslot */
|
|
/* Process left channel */
|
|
sbr_dec(&pSbrChannel[0]->SbrDec, input + offset0_block, timeData + offset0,
|
|
(self->flags & SBRDEC_PS_DECODED) ? &pSbrChannel[1]->SbrDec : NULL,
|
|
timeData + offset1, strideOut, hSbrHeader, hFrameDataLeft,
|
|
&pSbrChannel[0]->prevFrameData,
|
|
(hSbrHeader->syncState == SBR_ACTIVE), h_ps_d, self->flags,
|
|
codecFrameSize, self->sbrInDataHeadroom);
|
|
|
|
if (stereo) {
|
|
/* Process right channel */
|
|
sbr_dec(&pSbrChannel[1]->SbrDec, input + offset1_block,
|
|
timeData + offset1, NULL, NULL, strideOut, hSbrHeader,
|
|
hFrameDataRight, &pSbrChannel[1]->prevFrameData,
|
|
(hSbrHeader->syncState == SBR_ACTIVE), NULL, self->flags,
|
|
codecFrameSize, self->sbrInDataHeadroom);
|
|
}
|
|
|
|
C_ALLOC_SCRATCH_END(pPsScratch, struct PS_DEC_COEFFICIENTS, 1)
|
|
}
|
|
|
|
if (h_ps_d != NULL) {
|
|
/* save PS status for next run */
|
|
h_ps_d->psDecodedPrv = (self->flags & SBRDEC_PS_DECODED) ? 1 : 0;
|
|
}
|
|
|
|
if (psPossible && !(self->flags & SBRDEC_SKIP_QMF_SYN)) {
|
|
FDK_ASSERT(strideOut > 1);
|
|
if (!(self->flags & SBRDEC_PS_DECODED)) {
|
|
/* A decoder which is able to decode PS has to produce a stereo output
|
|
* even if no PS data is available. */
|
|
/* So copy left channel to right channel. */
|
|
int copyFrameSize =
|
|
codecFrameSize * self->pQmfDomain->QmfDomainOut->fb.no_channels;
|
|
copyFrameSize /= self->pQmfDomain->QmfDomainIn->fb.no_channels;
|
|
LONG *ptr;
|
|
INT i;
|
|
FDK_ASSERT(strideOut == 2);
|
|
|
|
ptr = timeData;
|
|
for (i = copyFrameSize >> 1; i--;) {
|
|
LONG tmp; /* This temporal variable is required because some compilers
|
|
can't do *ptr++ = *ptr++ correctly. */
|
|
tmp = *ptr++;
|
|
*ptr++ = tmp;
|
|
tmp = *ptr++;
|
|
*ptr++ = tmp;
|
|
}
|
|
}
|
|
*numOutChannels = 2; /* Output minimum two channels when PS is enabled. */
|
|
}
|
|
|
|
return errorStatus;
|
|
}
|
|
|
|
SBR_ERROR sbrDecoder_Apply(HANDLE_SBRDECODER self, LONG *input, LONG *timeData,
|
|
const int timeDataSize, int *numChannels,
|
|
int *sampleRate,
|
|
const FDK_channelMapDescr *const mapDescr,
|
|
const int mapIdx, const int coreDecodedOk,
|
|
UCHAR *psDecoded, const INT inDataHeadroom,
|
|
INT *outDataHeadroom) {
|
|
SBR_ERROR errorStatus = SBRDEC_OK;
|
|
|
|
int psPossible;
|
|
int sbrElementNum;
|
|
int numCoreChannels;
|
|
int numSbrChannels = 0;
|
|
|
|
if ((self == NULL) || (timeData == NULL) || (numChannels == NULL) ||
|
|
(sampleRate == NULL) || (psDecoded == NULL) ||
|
|
!FDK_chMapDescr_isValid(mapDescr)) {
|
|
return SBRDEC_INVALID_ARGUMENT;
|
|
}
|
|
|
|
psPossible = *psDecoded;
|
|
numCoreChannels = *numChannels;
|
|
if (numCoreChannels <= 0) {
|
|
return SBRDEC_INVALID_ARGUMENT;
|
|
}
|
|
|
|
if (self->numSbrElements < 1) {
|
|
/* exit immediately to avoid access violations */
|
|
return SBRDEC_NOT_INITIALIZED;
|
|
}
|
|
|
|
/* Sanity check of allocated SBR elements. */
|
|
for (sbrElementNum = 0; sbrElementNum < self->numSbrElements;
|
|
sbrElementNum++) {
|
|
if (self->pSbrElement[sbrElementNum] == NULL) {
|
|
return SBRDEC_NOT_INITIALIZED;
|
|
}
|
|
}
|
|
|
|
if (self->numSbrElements != 1 || self->pSbrElement[0]->elementID != ID_SCE) {
|
|
psPossible = 0;
|
|
}
|
|
|
|
self->sbrInDataHeadroom = inDataHeadroom;
|
|
*outDataHeadroom = (INT)(8);
|
|
|
|
/* Make sure that even if no SBR data was found/parsed *psDecoded is returned
|
|
* 1 if psPossible was 0. */
|
|
if (psPossible == 0) {
|
|
self->flags &= ~SBRDEC_PS_DECODED;
|
|
}
|
|
|
|
/* replaces channel based reset inside sbr_dec() */
|
|
if (((self->flags & SBRDEC_LOW_POWER) ? 1 : 0) !=
|
|
((self->pQmfDomain->globalConf.flags & QMF_FLAG_LP) ? 1 : 0)) {
|
|
if (self->flags & SBRDEC_LOW_POWER) {
|
|
self->pQmfDomain->globalConf.flags |= QMF_FLAG_LP;
|
|
self->pQmfDomain->globalConf.flags_requested |= QMF_FLAG_LP;
|
|
} else {
|
|
self->pQmfDomain->globalConf.flags &= ~QMF_FLAG_LP;
|
|
self->pQmfDomain->globalConf.flags_requested &= ~QMF_FLAG_LP;
|
|
}
|
|
if (FDK_QmfDomain_InitFilterBank(self->pQmfDomain, QMF_FLAG_KEEP_STATES)) {
|
|
return SBRDEC_UNSUPPORTED_CONFIG;
|
|
}
|
|
}
|
|
if (self->numSbrChannels > self->pQmfDomain->globalConf.nInputChannels) {
|
|
return SBRDEC_UNSUPPORTED_CONFIG;
|
|
}
|
|
|
|
if (self->flags & SBRDEC_FLUSH) {
|
|
/* flushing is signalized, hence increment the flush frame counter */
|
|
self->numFlushedFrames++;
|
|
} else {
|
|
/* no flushing is signalized, hence reset the flush frame counter */
|
|
self->numFlushedFrames = 0;
|
|
}
|
|
|
|
/* Loop over SBR elements */
|
|
for (sbrElementNum = 0; sbrElementNum < self->numSbrElements;
|
|
sbrElementNum++) {
|
|
int numElementChan;
|
|
|
|
if (psPossible &&
|
|
self->pSbrElement[sbrElementNum]->pSbrChannel[1] == NULL) {
|
|
/* Disable PS and try decoding SBR mono. */
|
|
psPossible = 0;
|
|
}
|
|
|
|
numElementChan =
|
|
(self->pSbrElement[sbrElementNum]->elementID == ID_CPE) ? 2 : 1;
|
|
|
|
/* If core signal is bad then force upsampling */
|
|
if (!coreDecodedOk) {
|
|
setFrameErrorFlag(self->pSbrElement[sbrElementNum], FRAME_ERROR_ALLSLOTS);
|
|
}
|
|
|
|
errorStatus = sbrDecoder_DecodeElement(
|
|
self, input, timeData, timeDataSize, mapDescr, mapIdx, numSbrChannels,
|
|
sbrElementNum,
|
|
numCoreChannels, /* is correct even for USC SCI==2 case */
|
|
&numElementChan, psPossible);
|
|
|
|
if (errorStatus != SBRDEC_OK) {
|
|
goto bail;
|
|
}
|
|
|
|
numSbrChannels += numElementChan;
|
|
|
|
if (numSbrChannels >= numCoreChannels) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* Update numChannels and samplerate */
|
|
/* Do not mess with output channels in case of USAC. numSbrChannels !=
|
|
* numChannels for stereoConfigIndex == 2 */
|
|
if (!(self->flags & SBRDEC_SYNTAX_USAC)) {
|
|
*numChannels = numSbrChannels;
|
|
}
|
|
*sampleRate = self->sampleRateOut;
|
|
*psDecoded = (self->flags & SBRDEC_PS_DECODED) ? 1 : 0;
|
|
|
|
/* Clear reset and flush flag because everything seems to be done
|
|
* successfully. */
|
|
self->flags &= ~SBRDEC_FORCE_RESET;
|
|
self->flags &= ~SBRDEC_FLUSH;
|
|
|
|
bail:
|
|
|
|
return errorStatus;
|
|
}
|
|
|
|
SBR_ERROR sbrDecoder_Close(HANDLE_SBRDECODER *pSelf) {
|
|
HANDLE_SBRDECODER self = *pSelf;
|
|
int i;
|
|
|
|
if (self != NULL) {
|
|
if (self->hParametricStereoDec != NULL) {
|
|
DeletePsDec(&self->hParametricStereoDec);
|
|
}
|
|
|
|
for (i = 0; i < (8); i++) {
|
|
sbrDecoder_DestroyElement(self, i);
|
|
}
|
|
|
|
FreeRam_SbrDecoder(pSelf);
|
|
}
|
|
|
|
return SBRDEC_OK;
|
|
}
|
|
|
|
INT sbrDecoder_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_SBRDEC;
|
|
info->version =
|
|
LIB_VERSION(SBRDECODER_LIB_VL0, SBRDECODER_LIB_VL1, SBRDECODER_LIB_VL2);
|
|
LIB_VERSION_STRING(info);
|
|
info->build_date = SBRDECODER_LIB_BUILD_DATE;
|
|
info->build_time = SBRDECODER_LIB_BUILD_TIME;
|
|
info->title = SBRDECODER_LIB_TITLE;
|
|
|
|
/* Set flags */
|
|
info->flags = 0 | CAPF_SBR_HQ | CAPF_SBR_LP | CAPF_SBR_PS_MPEG |
|
|
CAPF_SBR_DRM_BS | CAPF_SBR_CONCEALMENT | CAPF_SBR_DRC |
|
|
CAPF_SBR_ELD_DOWNSCALE | CAPF_SBR_HBEHQ;
|
|
/* End of flags */
|
|
|
|
return 0;
|
|
}
|
|
|
|
UINT sbrDecoder_GetDelay(const HANDLE_SBRDECODER self) {
|
|
UINT outputDelay = 0;
|
|
|
|
if (self != NULL) {
|
|
UINT flags = self->flags;
|
|
|
|
/* See chapter 1.6.7.2 of ISO/IEC 14496-3 for the GA-SBR figures below. */
|
|
|
|
/* Are we initialized? */
|
|
if ((self->numSbrChannels > 0) && (self->numSbrElements > 0)) {
|
|
/* Add QMF synthesis delay */
|
|
if ((flags & SBRDEC_ELD_GRID) && IS_LOWDELAY(self->coreCodec)) {
|
|
/* Low delay SBR: */
|
|
if (!(flags & SBRDEC_SKIP_QMF_SYN)) {
|
|
outputDelay +=
|
|
(flags & SBRDEC_DOWNSAMPLE) ? 32 : 64; /* QMF synthesis */
|
|
if (flags & SBRDEC_LD_MPS_QMF) {
|
|
outputDelay += 32;
|
|
}
|
|
}
|
|
} else if (!IS_USAC(self->coreCodec)) {
|
|
/* By the method of elimination this is the GA (AAC-LC, HE-AAC, ...)
|
|
* branch: */
|
|
outputDelay += (flags & SBRDEC_DOWNSAMPLE) ? 481 : 962;
|
|
if (flags & SBRDEC_SKIP_QMF_SYN) {
|
|
outputDelay -= 257; /* QMF synthesis */
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return (outputDelay);
|
|
}
|