diff options
author | Matthias P. Braendli <matthias.braendli@mpb.li> | 2019-11-11 11:38:02 +0100 |
---|---|---|
committer | Matthias P. Braendli <matthias.braendli@mpb.li> | 2019-11-11 11:38:02 +0100 |
commit | 0e5af65c467b2423a0b857ae3ad98c91acc1e190 (patch) | |
tree | d07f69550d8886271e44fe79c4dcfb299cafbd38 /fdk-aac/libSBRenc/src/sbr_encoder.cpp | |
parent | efe406d9724f959c8bc2a31802559ca6d41fd897 (diff) | |
download | ODR-AudioEnc-0e5af65c467b2423a0b857ae3ad98c91acc1e190.tar.gz ODR-AudioEnc-0e5af65c467b2423a0b857ae3ad98c91acc1e190.tar.bz2 ODR-AudioEnc-0e5af65c467b2423a0b857ae3ad98c91acc1e190.zip |
Include patched FDK-AAC in the repository
The initial idea was to get the DAB+ patch into upstream, but since
that follows the android source releases, there is no place for a custom
DAB+ patch there.
So instead of having to maintain a patched fdk-aac that has to have the
same .so version as the distribution package on which it is installed,
we prefer having a separate fdk-aac-dab library to avoid collision.
At that point, there's no reason to keep fdk-aac in a separate
repository, as odr-audioenc is the only tool that needs DAB+ encoding
support. Including it here simplifies installation, and makes it
consistent with toolame-dab, also shipped in this repository.
DAB+ decoding support (needed by ODR-SourceCompanion, dablin, etisnoop,
welle.io and others) can be done using upstream FDK-AAC.
Diffstat (limited to 'fdk-aac/libSBRenc/src/sbr_encoder.cpp')
-rw-r--r-- | fdk-aac/libSBRenc/src/sbr_encoder.cpp | 2577 |
1 files changed, 2577 insertions, 0 deletions
diff --git a/fdk-aac/libSBRenc/src/sbr_encoder.cpp b/fdk-aac/libSBRenc/src/sbr_encoder.cpp new file mode 100644 index 0000000..26257a1 --- /dev/null +++ b/fdk-aac/libSBRenc/src/sbr_encoder.cpp @@ -0,0 +1,2577 @@ +/* ----------------------------------------------------------------------------- +Software License for The Fraunhofer FDK AAC Codec Library for Android + +© Copyright 1995 - 2018 Fraunhofer-Gesellschaft zur Förderung der angewandten +Forschung e.V. All rights reserved. + + 1. INTRODUCTION +The Fraunhofer FDK AAC Codec Library for Android ("FDK AAC Codec") is software +that implements the MPEG Advanced Audio Coding ("AAC") encoding and decoding +scheme for digital audio. This FDK AAC Codec software is intended to be used on +a wide variety of Android devices. + +AAC's HE-AAC and HE-AAC v2 versions are regarded as today's most efficient +general perceptual audio codecs. AAC-ELD is considered the best-performing +full-bandwidth communications codec by independent studies and is widely +deployed. AAC has been standardized by ISO and IEC as part of the MPEG +specifications. + +Patent licenses for necessary patent claims for the FDK AAC Codec (including +those of Fraunhofer) may be obtained through Via Licensing +(www.vialicensing.com) or through the respective patent owners individually for +the purpose of encoding or decoding bit streams in products that are compliant +with the ISO/IEC MPEG audio standards. Please note that most manufacturers of +Android devices already license these patent claims through Via Licensing or +directly from the patent owners, and therefore FDK AAC Codec software may +already be covered under those patent licenses when it is used for those +licensed purposes only. + +Commercially-licensed AAC software libraries, including floating-point versions +with enhanced sound quality, are also available from Fraunhofer. Users are +encouraged to check the Fraunhofer website for additional applications +information and documentation. + +2. COPYRIGHT LICENSE + +Redistribution and use in source and binary forms, with or without modification, +are permitted without payment of copyright license fees provided that you +satisfy the following conditions: + +You must retain the complete text of this software license in redistributions of +the FDK AAC Codec or your modifications thereto in source code form. + +You must retain the complete text of this software license in the documentation +and/or other materials provided with redistributions of the FDK AAC Codec or +your modifications thereto in binary form. You must make available free of +charge copies of the complete source code of the FDK AAC Codec and your +modifications thereto to recipients of copies in binary form. + +The name of Fraunhofer may not be used to endorse or promote products derived +from this library without prior written permission. + +You may not charge copyright license fees for anyone to use, copy or distribute +the FDK AAC Codec software or your modifications thereto. + +Your modified versions of the FDK AAC Codec must carry prominent notices stating +that you changed the software and the date of any change. For modified versions +of the FDK AAC Codec, the term "Fraunhofer FDK AAC Codec Library for Android" +must be replaced by the term "Third-Party Modified Version of the Fraunhofer FDK +AAC Codec Library for Android." + +3. NO PATENT LICENSE + +NO EXPRESS OR IMPLIED LICENSES TO ANY PATENT CLAIMS, including without +limitation the patents of Fraunhofer, ARE GRANTED BY THIS SOFTWARE LICENSE. +Fraunhofer provides no warranty of patent non-infringement with respect to this +software. + +You may use this FDK AAC Codec software or modifications thereto only for +purposes that are authorized by appropriate patent licenses. + +4. DISCLAIMER + +This FDK AAC Codec software is provided by Fraunhofer on behalf of the copyright +holders and contributors "AS IS" and WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, +including but not limited to the implied warranties of merchantability and +fitness for a particular purpose. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR +CONTRIBUTORS BE LIABLE for any direct, indirect, incidental, special, exemplary, +or consequential damages, including but not limited to procurement of substitute +goods or services; loss of use, data, or profits, or business interruption, +however caused and on any theory of liability, whether in contract, strict +liability, or tort (including negligence), arising in any way out of the use of +this software, even if advised of the possibility of such damage. + +5. CONTACT INFORMATION + +Fraunhofer Institute for Integrated Circuits IIS +Attention: Audio and Multimedia Departments - FDK AAC LL +Am Wolfsmantel 33 +91058 Erlangen, Germany + +www.iis.fraunhofer.de/amm +amm-info@iis.fraunhofer.de +----------------------------------------------------------------------------- */ + +/**************************** SBR encoder library ****************************** + + Author(s): Andreas Ehret, Tobias Chalupka + + Description: SBR encoder top level processing. + +*******************************************************************************/ + +#include "sbr_encoder.h" + +#include "sbrenc_ram.h" +#include "sbrenc_rom.h" +#include "sbrenc_freq_sca.h" +#include "env_bit.h" +#include "cmondata.h" +#include "sbr_misc.h" +#include "sbr.h" +#include "qmf.h" + +#include "ps_main.h" + +#define SBRENCODER_LIB_VL0 4 +#define SBRENCODER_LIB_VL1 0 +#define SBRENCODER_LIB_VL2 0 + +/***************************************************************************/ +/* + * SBR Delay balancing definitions. + */ + +/* + input buffer (1ch) + + |------------ 1537 -------------|-----|---------- 2048 -------------| + (core2sbr delay ) ds (read, core and ds area) +*/ + +#define SFB(dwnsmp) \ + (32 << (dwnsmp - \ + 1)) /* SBR Frequency bands: 64 for dual-rate, 32 for single-rate */ +#define STS(fl) \ + (((fl) == 1024) ? 32 \ + : 30) /* SBR Time Slots: 32 for core frame length 1024, 30 \ + for core frame length 960 */ + +#define DELAY_QMF_ANA(dwnsmp) \ + ((320 << ((dwnsmp)-1)) - (32 << ((dwnsmp)-1))) /* Full bandwidth */ +#define DELAY_HYB_ANA (10 * 64) /* + 0.5 */ /* */ +#define DELAY_HYB_SYN (6 * 64 - 32) /* */ +#define DELAY_QMF_POSTPROC(dwnsmp) \ + (32 * (dwnsmp)) /* QMF postprocessing delay */ +#define DELAY_DEC_QMF(dwnsmp) (6 * SFB(dwnsmp)) /* Decoder QMF overlap */ +#define DELAY_QMF_SYN(dwnsmp) \ + (1 << (dwnsmp - \ + 1)) /* QMF_NO_POLY/2=2.5, rounded down to 2, half for single-rate */ +#define DELAY_QMF_DS (32) /* QMF synthesis for downsampled time signal */ + +/* Delay in QMF paths */ +#define DELAY_SBR(fl, dwnsmp) \ + (DELAY_QMF_ANA(dwnsmp) + (SFB(dwnsmp) * STS(fl) - 1) + DELAY_QMF_SYN(dwnsmp)) +#define DELAY_PS(fl, dwnsmp) \ + (DELAY_QMF_ANA(dwnsmp) + DELAY_HYB_ANA + DELAY_DEC_QMF(dwnsmp) + \ + (SFB(dwnsmp) * STS(fl) - 1) + DELAY_HYB_SYN + DELAY_QMF_SYN(dwnsmp)) +#define DELAY_ELDSBR(fl, dwnsmp) \ + ((((fl) / 2) * (dwnsmp)) - 1 + DELAY_QMF_POSTPROC(dwnsmp)) +#define DELAY_ELDv2SBR(fl, dwnsmp) \ + ((((fl) / 2) * (dwnsmp)) - 1 + 80 * (dwnsmp)) /* 80 is the delay caused \ + by the sum of the CLD \ + analysis and the MPSLD \ + synthesis filterbank */ + +/* Delay in core path (core and downsampler not taken into account) */ +#define DELAY_COREPATH_SBR(fl, dwnsmp) \ + ((DELAY_QMF_ANA(dwnsmp) + DELAY_DEC_QMF(dwnsmp) + DELAY_QMF_SYN(dwnsmp))) +#define DELAY_COREPATH_ELDSBR(fl, dwnsmp) ((DELAY_QMF_POSTPROC(dwnsmp))) +#define DELAY_COREPATH_ELDv2SBR(fl, dwnsmp) (128 * (dwnsmp)) /* 4 slots */ +#define DELAY_COREPATH_PS(fl, dwnsmp) \ + ((DELAY_QMF_ANA(dwnsmp) + DELAY_QMF_DS + \ + /*(DELAY_AAC(fl)*2) + */ DELAY_QMF_ANA(dwnsmp) + DELAY_DEC_QMF(dwnsmp) + \ + DELAY_HYB_SYN + DELAY_QMF_SYN(dwnsmp))) /* 2048 - 463*2 */ + +/* Delay differences between SBR- and downsampled path for SBR and SBR+PS */ +#define DELAY_AAC2SBR(fl, dwnsmp) \ + ((DELAY_COREPATH_SBR(fl, dwnsmp)) - DELAY_SBR((fl), (dwnsmp))) +#define DELAY_ELD2SBR(fl, dwnsmp) \ + ((DELAY_COREPATH_ELDSBR(fl, dwnsmp)) - DELAY_ELDSBR(fl, dwnsmp)) +#define DELAY_AAC2PS(fl, dwnsmp) \ + ((DELAY_COREPATH_PS(fl, dwnsmp)) - DELAY_PS(fl, dwnsmp)) /* 2048 - 463*2 */ + +/* Assumption: The sample delay resulting of of DELAY_AAC2PS is always smaller + * than the sample delay implied by DELAY_AAC2SBR */ +#define MAX_DS_FILTER_DELAY \ + (5) /* the additional max downsampler filter delay (source fs) */ +#define MAX_SAMPLE_DELAY \ + (DELAY_AAC2SBR(1024, 2) + MAX_DS_FILTER_DELAY) /* maximum delay: frame \ + length of 1024 and \ + dual-rate sbr */ + +/***************************************************************************/ + +/*************** Delay parameters for sbrEncoder_Init_delay() **************/ +typedef struct { + int dsDelay; /* the delay of the (time-domain) downsampler itself */ + int delay; /* overall delay / samples */ + int sbrDecDelay; /* SBR decoder's delay */ + int corePathOffset; /* core path offset / samples; added by + sbrEncoder_Init_delay() */ + int sbrPathOffset; /* SBR path offset / samples; added by + sbrEncoder_Init_delay() */ + int bitstrDelay; /* bitstream delay / frames; added by sbrEncoder_Init_delay() + */ + int delayInput2Core; /* delay of the input to the core / samples */ +} DELAY_PARAM; +/***************************************************************************/ + +#define INVALID_TABLE_IDX -1 + +/***************************************************************************/ +/*! + + \brief Selects the SBR tuning settings to use dependent on number of + channels, bitrate, sample rate and core coder + + \return Index to the appropriate table + +****************************************************************************/ +#define DISTANCE_CEIL_VALUE 5000000 +static INT getSbrTuningTableIndex( + UINT bitrate, /*! the total bitrate in bits/sec */ + UINT numChannels, /*! the number of channels for the core coder */ + UINT sampleRate, /*! the sampling rate of the core coder */ + AUDIO_OBJECT_TYPE core, UINT *pBitRateClosest) { + int i, bitRateClosestLowerIndex = -1, bitRateClosestUpperIndex = -1, + found = 0; + UINT bitRateClosestUpper = 0, bitRateClosestLower = DISTANCE_CEIL_VALUE; + +#define isForThisCore(i) \ + ((sbrTuningTable[i].coreCoder == CODEC_AACLD && core == AOT_ER_AAC_ELD) || \ + (sbrTuningTable[i].coreCoder == CODEC_AAC && core != AOT_ER_AAC_ELD)) + + for (i = 0; i < sbrTuningTableSize; i++) { + if (isForThisCore(i)) /* tuning table is for this core codec */ + { + if (numChannels == sbrTuningTable[i].numChannels && + sampleRate == sbrTuningTable[i].sampleRate) { + found = 1; + if ((bitrate >= sbrTuningTable[i].bitrateFrom) && + (bitrate < sbrTuningTable[i].bitrateTo)) { + return i; + } else { + if (sbrTuningTable[i].bitrateFrom > bitrate) { + if (sbrTuningTable[i].bitrateFrom < bitRateClosestLower) { + bitRateClosestLower = sbrTuningTable[i].bitrateFrom; + bitRateClosestLowerIndex = i; + } + } + if (sbrTuningTable[i].bitrateTo <= bitrate) { + if (sbrTuningTable[i].bitrateTo > bitRateClosestUpper) { + bitRateClosestUpper = sbrTuningTable[i].bitrateTo - 1; + bitRateClosestUpperIndex = i; + } + } + } + } + } + } + + if (bitRateClosestUpperIndex >= 0) { + return bitRateClosestUpperIndex; + } + + if (pBitRateClosest != NULL) { + /* If there was at least one matching tuning entry pick the least distance + * bit rate */ + if (found) { + int distanceUpper = DISTANCE_CEIL_VALUE, + distanceLower = DISTANCE_CEIL_VALUE; + if (bitRateClosestLowerIndex >= 0) { + distanceLower = + sbrTuningTable[bitRateClosestLowerIndex].bitrateFrom - bitrate; + } + if (bitRateClosestUpperIndex >= 0) { + distanceUpper = + bitrate - sbrTuningTable[bitRateClosestUpperIndex].bitrateTo; + } + if (distanceUpper < distanceLower) { + *pBitRateClosest = bitRateClosestUpper; + } else { + *pBitRateClosest = bitRateClosestLower; + } + } else { + *pBitRateClosest = 0; + } + } + + return INVALID_TABLE_IDX; +} + +/***************************************************************************/ +/*! + + \brief Selects the PS tuning settings to use dependent on bitrate + and core coder + + \return Index to the appropriate table + +****************************************************************************/ +static INT getPsTuningTableIndex(UINT bitrate, UINT *pBitRateClosest) { + INT i, paramSets = sizeof(psTuningTable) / sizeof(psTuningTable[0]); + int bitRateClosestLowerIndex = -1, bitRateClosestUpperIndex = -1; + UINT bitRateClosestUpper = 0, bitRateClosestLower = DISTANCE_CEIL_VALUE; + + for (i = 0; i < paramSets; i++) { + if ((bitrate >= psTuningTable[i].bitrateFrom) && + (bitrate < psTuningTable[i].bitrateTo)) { + return i; + } else { + if (psTuningTable[i].bitrateFrom > bitrate) { + if (psTuningTable[i].bitrateFrom < bitRateClosestLower) { + bitRateClosestLower = psTuningTable[i].bitrateFrom; + bitRateClosestLowerIndex = i; + } + } + if (psTuningTable[i].bitrateTo <= bitrate) { + if (psTuningTable[i].bitrateTo > bitRateClosestUpper) { + bitRateClosestUpper = psTuningTable[i].bitrateTo - 1; + bitRateClosestUpperIndex = i; + } + } + } + } + + if (bitRateClosestUpperIndex >= 0) { + return bitRateClosestUpperIndex; + } + + if (pBitRateClosest != NULL) { + int distanceUpper = DISTANCE_CEIL_VALUE, + distanceLower = DISTANCE_CEIL_VALUE; + if (bitRateClosestLowerIndex >= 0) { + distanceLower = + sbrTuningTable[bitRateClosestLowerIndex].bitrateFrom - bitrate; + } + if (bitRateClosestUpperIndex >= 0) { + distanceUpper = + bitrate - sbrTuningTable[bitRateClosestUpperIndex].bitrateTo; + } + if (distanceUpper < distanceLower) { + *pBitRateClosest = bitRateClosestUpper; + } else { + *pBitRateClosest = bitRateClosestLower; + } + } + + return INVALID_TABLE_IDX; +} + +/***************************************************************************/ +/*! + + \brief In case of downsampled SBR we may need to lower the stop freq + of a tuning setting to fit into the lower half of the + spectrum ( which is sampleRate/4 ) + + \return the adapted stop frequency index (-1 -> error) + + \ingroup SbrEncCfg + +****************************************************************************/ +static INT FDKsbrEnc_GetDownsampledStopFreq(const INT sampleRateCore, + const INT startFreq, INT stopFreq, + const INT downSampleFactor) { + INT maxStopFreqRaw = sampleRateCore / 2; + INT startBand, stopBand; + HANDLE_ERROR_INFO err; + + while (stopFreq > 0 && FDKsbrEnc_getSbrStopFreqRAW(stopFreq, sampleRateCore) > + maxStopFreqRaw) { + stopFreq--; + } + + if (FDKsbrEnc_getSbrStopFreqRAW(stopFreq, sampleRateCore) > maxStopFreqRaw) + return -1; + + err = FDKsbrEnc_FindStartAndStopBand( + sampleRateCore << (downSampleFactor - 1), sampleRateCore, + 32 << (downSampleFactor - 1), startFreq, stopFreq, &startBand, &stopBand); + if (err) return -1; + + return stopFreq; +} + +/***************************************************************************/ +/*! + + \brief tells us, if for the given coreCoder, bitrate, number of channels + and input sampling rate an SBR setting is available. If yes, it + tells us also the core sampling rate we would need to run with + + \return a flag indicating success: yes (1) or no (0) + +****************************************************************************/ +static UINT FDKsbrEnc_IsSbrSettingAvail( + UINT bitrate, /*! the total bitrate in bits/sec */ + UINT vbrMode, /*! the vbr paramter, 0 means constant bitrate */ + UINT numOutputChannels, /*! the number of channels for the core coder */ + UINT sampleRateInput, /*! the input sample rate [in Hz] */ + UINT sampleRateCore, /*! the core's sampling rate */ + AUDIO_OBJECT_TYPE core) { + INT idx = INVALID_TABLE_IDX; + + if (sampleRateInput < 16000) return 0; + + if (bitrate == 0) { + /* map vbr quality to bitrate */ + if (vbrMode < 30) + bitrate = 24000; + else if (vbrMode < 40) + bitrate = 28000; + else if (vbrMode < 60) + bitrate = 32000; + else if (vbrMode < 75) + bitrate = 40000; + else + bitrate = 48000; + bitrate *= numOutputChannels; + } + + idx = getSbrTuningTableIndex(bitrate, numOutputChannels, sampleRateCore, core, + NULL); + + return (idx == INVALID_TABLE_IDX ? 0 : 1); +} + +/***************************************************************************/ +/*! + + \brief Adjusts the SBR settings according to the chosen core coder + settings which are accessible via config->codecSettings + + \return A flag indicating success: yes (1) or no (0) + +****************************************************************************/ +static UINT FDKsbrEnc_AdjustSbrSettings( + const sbrConfigurationPtr config, /*! output, modified */ + UINT bitRate, /*! the total bitrate in bits/sec */ + UINT numChannels, /*! the core coder number of channels */ + UINT sampleRateCore, /*! the core coder sampling rate in Hz */ + UINT sampleRateSbr, /*! the sbr coder sampling rate in Hz */ + UINT transFac, /*! the short block to long block ratio */ + UINT standardBitrate, /*! the standard bitrate per channel in bits/sec */ + UINT vbrMode, /*! the vbr paramter, 0 poor quality .. 100 high quality*/ + UINT useSpeechConfig, /*!< adapt tuning parameters for speech ? */ + UINT lcsMode, /*! the low complexity stereo mode */ + UINT bParametricStereo, /*!< use parametric stereo */ + AUDIO_OBJECT_TYPE core) /* Core audio codec object type */ +{ + INT idx = INVALID_TABLE_IDX; + /* set the core codec settings */ + config->codecSettings.bitRate = bitRate; + config->codecSettings.nChannels = numChannels; + config->codecSettings.sampleFreq = sampleRateCore; + config->codecSettings.transFac = transFac; + config->codecSettings.standardBitrate = standardBitrate; + + if (bitRate < 28000) { + config->threshold_AmpRes_FF_m = (FIXP_DBL)MAXVAL_DBL; + config->threshold_AmpRes_FF_e = 7; + } else if (bitRate >= 28000 && bitRate <= 48000) { + /* The float threshold is 75 + 0.524288f is fractional part of RELAXATION, the quotaMatrix and therefore + tonality are scaled by this 2/3 is because the original implementation + divides the tonality values by 3, here it's divided by 2 128 compensates + the necessary shiftfactor of 7 */ + config->threshold_AmpRes_FF_m = + FL2FXCONST_DBL(75.0f * 0.524288f / (2.0f / 3.0f) / 128.0f); + config->threshold_AmpRes_FF_e = 7; + } else if (bitRate > 48000) { + config->threshold_AmpRes_FF_m = FL2FXCONST_DBL(0); + config->threshold_AmpRes_FF_e = 0; + } + + if (bitRate == 0) { + /* map vbr quality to bitrate */ + if (vbrMode < 30) + bitRate = 24000; + else if (vbrMode < 40) + bitRate = 28000; + else if (vbrMode < 60) + bitRate = 32000; + else if (vbrMode < 75) + bitRate = 40000; + else + bitRate = 48000; + bitRate *= numChannels; + /* fix to enable mono vbrMode<40 @ 44.1 of 48kHz */ + if (numChannels == 1) { + if (sampleRateSbr == 44100 || sampleRateSbr == 48000) { + if (vbrMode < 40) bitRate = 32000; + } + } + } + + idx = + getSbrTuningTableIndex(bitRate, numChannels, sampleRateCore, core, NULL); + + if (idx != INVALID_TABLE_IDX) { + config->startFreq = sbrTuningTable[idx].startFreq; + config->stopFreq = sbrTuningTable[idx].stopFreq; + if (useSpeechConfig) { + config->startFreq = sbrTuningTable[idx].startFreqSpeech; + config->stopFreq = sbrTuningTable[idx].stopFreqSpeech; + } + + /* Adapt stop frequency in case of downsampled SBR - only 32 bands then */ + if (1 == config->downSampleFactor) { + INT dsStopFreq = FDKsbrEnc_GetDownsampledStopFreq( + sampleRateCore, config->startFreq, config->stopFreq, + config->downSampleFactor); + if (dsStopFreq < 0) { + return 0; + } + + config->stopFreq = dsStopFreq; + } + + config->sbr_noise_bands = sbrTuningTable[idx].numNoiseBands; + if (core == AOT_ER_AAC_ELD) config->init_amp_res_FF = SBR_AMP_RES_1_5; + config->noiseFloorOffset = sbrTuningTable[idx].noiseFloorOffset; + + config->ana_max_level = sbrTuningTable[idx].noiseMaxLevel; + config->stereoMode = sbrTuningTable[idx].stereoMode; + config->freqScale = sbrTuningTable[idx].freqScale; + + if (numChannels == 1) { + /* stereo case */ + switch (core) { + case AOT_AAC_LC: + if (bitRate <= (useSpeechConfig ? 24000U : 20000U)) { + config->freq_res_fixfix[0] = FREQ_RES_LOW; /* set low frequency + resolution for + non-split frames */ + config->freq_res_fixfix[1] = FREQ_RES_LOW; /* set low frequency + resolution for split + frames */ + } + break; + case AOT_ER_AAC_ELD: + if (bitRate < 36000) + config->freq_res_fixfix[1] = FREQ_RES_LOW; /* set low frequency + resolution for split + frames */ + if (bitRate < 26000) { + config->freq_res_fixfix[0] = FREQ_RES_LOW; /* set low frequency + resolution for + non-split frames */ + config->fResTransIsLow = + 1; /* for transient frames, set low frequency resolution */ + } + break; + default: + break; + } + } else { + /* stereo case */ + switch (core) { + case AOT_AAC_LC: + if (bitRate <= 28000) { + config->freq_res_fixfix[0] = FREQ_RES_LOW; /* set low frequency + resolution for + non-split frames */ + config->freq_res_fixfix[1] = FREQ_RES_LOW; /* set low frequency + resolution for split + frames */ + } + break; + case AOT_ER_AAC_ELD: + if (bitRate < 72000) { + config->freq_res_fixfix[1] = FREQ_RES_LOW; /* set low frequency + resolution for split + frames */ + } + if (bitRate < 52000) { + config->freq_res_fixfix[0] = FREQ_RES_LOW; /* set low frequency + resolution for + non-split frames */ + config->fResTransIsLow = + 1; /* for transient frames, set low frequency resolution */ + } + break; + default: + break; + } + if (bitRate <= 28000) { + /* + additionally restrict frequency resolution in FIXFIX frames + to further reduce SBR payload size */ + config->freq_res_fixfix[0] = FREQ_RES_LOW; + config->freq_res_fixfix[1] = FREQ_RES_LOW; + } + } + + /* adjust usage of parametric coding dependent on bitrate and speech config + * flag */ + if (useSpeechConfig) config->parametricCoding = 0; + + if (core == AOT_ER_AAC_ELD) { + if (bitRate < 28000) config->init_amp_res_FF = SBR_AMP_RES_3_0; + config->SendHeaderDataTime = -1; + } + + if (numChannels == 1) { + if (bitRate < 16000) { + config->parametricCoding = 0; + } + } else { + if (bitRate < 20000) { + config->parametricCoding = 0; + } + } + + config->useSpeechConfig = useSpeechConfig; + + /* PS settings */ + config->bParametricStereo = bParametricStereo; + + return 1; + } else { + return 0; + } +} + +/***************************************************************************** + + functionname: FDKsbrEnc_InitializeSbrDefaults + description: initializes the SBR configuration + returns: error status + input: - core codec type, + - factor of SBR to core frame length, + - core frame length + output: initialized SBR configuration + +*****************************************************************************/ +static UINT FDKsbrEnc_InitializeSbrDefaults(sbrConfigurationPtr config, + INT downSampleFactor, + UINT codecGranuleLen, + const INT isLowDelay) { + if ((downSampleFactor < 1 || downSampleFactor > 2) || + (codecGranuleLen * downSampleFactor > 64 * 32)) + return (0); /* error */ + + config->SendHeaderDataTime = 1000; + config->useWaveCoding = 0; + config->crcSbr = 0; + config->dynBwSupported = 1; + if (isLowDelay) + config->tran_thr = 6000; + else + config->tran_thr = 13000; + + config->parametricCoding = 1; + + config->sbrFrameSize = codecGranuleLen * downSampleFactor; + config->downSampleFactor = downSampleFactor; + + /* sbr default parameters */ + config->sbr_data_extra = 0; + config->amp_res = SBR_AMP_RES_3_0; + config->tran_fc = 0; + config->tran_det_mode = 1; + config->spread = 1; + config->stat = 0; + config->e = 1; + config->deltaTAcrossFrames = 1; + config->dF_edge_1stEnv = FL2FXCONST_DBL(0.3f); + config->dF_edge_incr = FL2FXCONST_DBL(0.3f); + + config->sbr_invf_mode = INVF_SWITCHED; + config->sbr_xpos_mode = XPOS_LC; + config->sbr_xpos_ctrl = SBR_XPOS_CTRL_DEFAULT; + config->sbr_xpos_level = 0; + config->useSaPan = 0; + config->dynBwEnabled = 0; + + /* the following parameters are overwritten by the + FDKsbrEnc_AdjustSbrSettings() function since they are included in the + tuning table */ + config->stereoMode = SBR_SWITCH_LRC; + config->ana_max_level = 6; + config->noiseFloorOffset = 0; + config->startFreq = 5; /* 5.9 respectively 6.0 kHz at fs = 44.1/48 kHz */ + config->stopFreq = 9; /* 16.2 respectively 16.8 kHz at fs = 44.1/48 kHz */ + config->freq_res_fixfix[0] = FREQ_RES_HIGH; /* non-split case */ + config->freq_res_fixfix[1] = FREQ_RES_HIGH; /* split case */ + config->fResTransIsLow = 0; /* for transient frames, set variable frequency + resolution according to freqResTable */ + + /* header_extra_1 */ + config->freqScale = SBR_FREQ_SCALE_DEFAULT; + config->alterScale = SBR_ALTER_SCALE_DEFAULT; + config->sbr_noise_bands = SBR_NOISE_BANDS_DEFAULT; + + /* header_extra_2 */ + config->sbr_limiter_bands = SBR_LIMITER_BANDS_DEFAULT; + config->sbr_limiter_gains = SBR_LIMITER_GAINS_DEFAULT; + config->sbr_interpol_freq = SBR_INTERPOL_FREQ_DEFAULT; + config->sbr_smoothing_length = SBR_SMOOTHING_LENGTH_DEFAULT; + + return 1; +} + +/***************************************************************************** + + functionname: DeleteEnvChannel + description: frees memory of one SBR channel + returns: - + input: handle of channel + output: released handle + +*****************************************************************************/ +static void deleteEnvChannel(HANDLE_ENV_CHANNEL hEnvCut) { + if (hEnvCut) { + FDKsbrEnc_DeleteTonCorrParamExtr(&hEnvCut->TonCorr); + + FDKsbrEnc_deleteExtractSbrEnvelope(&hEnvCut->sbrExtractEnvelope); + } +} + +/***************************************************************************** + + functionname: sbrEncoder_ChannelClose + description: close the channel coding handle + returns: + input: phSbrChannel + output: + +*****************************************************************************/ +static void sbrEncoder_ChannelClose(HANDLE_SBR_CHANNEL hSbrChannel) { + if (hSbrChannel != NULL) { + deleteEnvChannel(&hSbrChannel->hEnvChannel); + } +} + +/***************************************************************************** + + functionname: sbrEncoder_ElementClose + description: close the channel coding handle + returns: + input: phSbrChannel + output: + +*****************************************************************************/ +static void sbrEncoder_ElementClose(HANDLE_SBR_ELEMENT *phSbrElement) { + HANDLE_SBR_ELEMENT hSbrElement = *phSbrElement; + + if (hSbrElement != NULL) { + if (hSbrElement->sbrConfigData.v_k_master) + FreeRam_Sbr_v_k_master(&hSbrElement->sbrConfigData.v_k_master); + if (hSbrElement->sbrConfigData.freqBandTable[LO]) + FreeRam_Sbr_freqBandTableLO( + &hSbrElement->sbrConfigData.freqBandTable[LO]); + if (hSbrElement->sbrConfigData.freqBandTable[HI]) + FreeRam_Sbr_freqBandTableHI( + &hSbrElement->sbrConfigData.freqBandTable[HI]); + + FreeRam_SbrElement(phSbrElement); + } + return; +} + +void sbrEncoder_Close(HANDLE_SBR_ENCODER *phSbrEncoder) { + HANDLE_SBR_ENCODER hSbrEncoder = *phSbrEncoder; + + if (hSbrEncoder != NULL) { + int el, ch; + + for (el = 0; el < (8); el++) { + if (hSbrEncoder->sbrElement[el] != NULL) { + sbrEncoder_ElementClose(&hSbrEncoder->sbrElement[el]); + } + } + + /* Close sbr Channels */ + for (ch = 0; ch < (8); ch++) { + if (hSbrEncoder->pSbrChannel[ch]) { + sbrEncoder_ChannelClose(hSbrEncoder->pSbrChannel[ch]); + FreeRam_SbrChannel(&hSbrEncoder->pSbrChannel[ch]); + } + + if (hSbrEncoder->QmfAnalysis[ch].FilterStates) + FreeRam_Sbr_QmfStatesAnalysis( + (FIXP_QAS **)&hSbrEncoder->QmfAnalysis[ch].FilterStates); + } + + if (hSbrEncoder->hParametricStereo) + PSEnc_Destroy(&hSbrEncoder->hParametricStereo); + if (hSbrEncoder->qmfSynthesisPS.FilterStates) + FreeRam_PsQmfStatesSynthesis( + (FIXP_DBL **)&hSbrEncoder->qmfSynthesisPS.FilterStates); + + /* Release Overlay */ + if (hSbrEncoder->pSBRdynamic_RAM) + FreeRam_SbrDynamic_RAM((FIXP_DBL **)&hSbrEncoder->pSBRdynamic_RAM); + + FreeRam_SbrEncoder(phSbrEncoder); + } +} + +/***************************************************************************** + + functionname: updateFreqBandTable + description: updates vk_master + returns: - + input: config handle + output: error info + +*****************************************************************************/ +static INT updateFreqBandTable(HANDLE_SBR_CONFIG_DATA sbrConfigData, + HANDLE_SBR_HEADER_DATA sbrHeaderData, + const INT downSampleFactor) { + INT k0, k2; + + if (FDKsbrEnc_FindStartAndStopBand( + sbrConfigData->sampleFreq, + sbrConfigData->sampleFreq >> (downSampleFactor - 1), + sbrConfigData->noQmfBands, sbrHeaderData->sbr_start_frequency, + sbrHeaderData->sbr_stop_frequency, &k0, &k2)) + return (1); + + if (FDKsbrEnc_UpdateFreqScale( + sbrConfigData->v_k_master, &sbrConfigData->num_Master, k0, k2, + sbrHeaderData->freqScale, sbrHeaderData->alterScale)) + return (1); + + sbrHeaderData->sbr_xover_band = 0; + + if (FDKsbrEnc_UpdateHiRes(sbrConfigData->freqBandTable[HI], + &sbrConfigData->nSfb[HI], sbrConfigData->v_k_master, + sbrConfigData->num_Master, + &sbrHeaderData->sbr_xover_band)) + return (1); + + FDKsbrEnc_UpdateLoRes( + sbrConfigData->freqBandTable[LO], &sbrConfigData->nSfb[LO], + sbrConfigData->freqBandTable[HI], sbrConfigData->nSfb[HI]); + + sbrConfigData->xOverFreq = + (sbrConfigData->freqBandTable[LOW_RES][0] * sbrConfigData->sampleFreq / + sbrConfigData->noQmfBands + + 1) >> + 1; + + return (0); +} + +/***************************************************************************** + + functionname: resetEnvChannel + description: resets parameters and allocates memory + returns: error status + input: + output: hEnv + +*****************************************************************************/ +static INT resetEnvChannel(HANDLE_SBR_CONFIG_DATA sbrConfigData, + HANDLE_SBR_HEADER_DATA sbrHeaderData, + HANDLE_ENV_CHANNEL hEnv) { + /* note !!! hEnv->encEnvData.noOfnoisebands will be updated later in function + * FDKsbrEnc_extractSbrEnvelope !!!*/ + hEnv->TonCorr.sbrNoiseFloorEstimate.noiseBands = + sbrHeaderData->sbr_noise_bands; + + if (FDKsbrEnc_ResetTonCorrParamExtr( + &hEnv->TonCorr, sbrConfigData->xposCtrlSwitch, + sbrConfigData->freqBandTable[HI][0], sbrConfigData->v_k_master, + sbrConfigData->num_Master, sbrConfigData->sampleFreq, + sbrConfigData->freqBandTable, sbrConfigData->nSfb, + sbrConfigData->noQmfBands)) + return (1); + + hEnv->sbrCodeNoiseFloor.nSfb[LO] = + hEnv->TonCorr.sbrNoiseFloorEstimate.noNoiseBands; + hEnv->sbrCodeNoiseFloor.nSfb[HI] = + hEnv->TonCorr.sbrNoiseFloorEstimate.noNoiseBands; + + hEnv->sbrCodeEnvelope.nSfb[LO] = sbrConfigData->nSfb[LO]; + hEnv->sbrCodeEnvelope.nSfb[HI] = sbrConfigData->nSfb[HI]; + + hEnv->encEnvData.noHarmonics = sbrConfigData->nSfb[HI]; + + hEnv->sbrCodeEnvelope.upDate = 0; + hEnv->sbrCodeNoiseFloor.upDate = 0; + + return (0); +} + +/* ****************************** FDKsbrEnc_SbrGetXOverFreq + * ******************************/ +/** + * @fn + * @brief calculates the closest possible crossover frequency + * @return the crossover frequency SBR accepts + * + */ +static INT FDKsbrEnc_SbrGetXOverFreq( + HANDLE_SBR_ELEMENT hEnv, /*!< handle to SBR encoder instance */ + INT xoverFreq) /*!< from core coder suggested crossover frequency */ +{ + INT band; + INT lastDiff, newDiff; + INT cutoffSb; + + UCHAR *RESTRICT pVKMaster = hEnv->sbrConfigData.v_k_master; + + /* Check if there is a matching cutoff frequency in the master table */ + cutoffSb = (4 * xoverFreq * hEnv->sbrConfigData.noQmfBands / + hEnv->sbrConfigData.sampleFreq + + 1) >> + 1; + lastDiff = cutoffSb; + for (band = 0; band < hEnv->sbrConfigData.num_Master; band++) { + newDiff = fixp_abs((INT)pVKMaster[band] - cutoffSb); + + if (newDiff >= lastDiff) { + band--; + break; + } + + lastDiff = newDiff; + } + + return ((pVKMaster[band] * hEnv->sbrConfigData.sampleFreq / + hEnv->sbrConfigData.noQmfBands + + 1) >> + 1); +} + +/***************************************************************************** + + functionname: FDKsbrEnc_EnvEncodeFrame + description: performs the sbr envelope calculation for one element + returns: + input: + output: + +*****************************************************************************/ +INT FDKsbrEnc_EnvEncodeFrame( + HANDLE_SBR_ENCODER hEnvEncoder, int iElement, + INT_PCM *samples, /*!< time samples, always deinterleaved */ + UINT samplesBufSize, /*!< time buffer channel stride */ + UINT *sbrDataBits, /*!< Size of SBR payload */ + UCHAR *sbrData, /*!< SBR payload */ + int clearOutput /*!< Do not consider any input signal */ +) { + HANDLE_SBR_ELEMENT hSbrElement = NULL; + FDK_CRCINFO crcInfo; + INT crcReg; + INT ch; + INT band; + INT cutoffSb; + INT newXOver; + + if (hEnvEncoder == NULL) return -1; + + hSbrElement = hEnvEncoder->sbrElement[iElement]; + + if (hSbrElement == NULL) return -1; + + /* header bitstream handling */ + HANDLE_SBR_BITSTREAM_DATA sbrBitstreamData = &hSbrElement->sbrBitstreamData; + + INT psHeaderActive = 0; + sbrBitstreamData->HeaderActive = 0; + + /* Anticipate PS header because of internal PS bitstream delay in order to be + * in sync with SBR header. */ + if (sbrBitstreamData->CountSendHeaderData == + (sbrBitstreamData->NrSendHeaderData - 1)) { + psHeaderActive = 1; + } + + /* Signal SBR header to be written into bitstream */ + if (sbrBitstreamData->CountSendHeaderData == 0) { + sbrBitstreamData->HeaderActive = 1; + } + + /* Increment header interval counter */ + if (sbrBitstreamData->NrSendHeaderData == 0) { + sbrBitstreamData->CountSendHeaderData = 1; + } else { + if (sbrBitstreamData->CountSendHeaderData >= 0) { + sbrBitstreamData->CountSendHeaderData++; + sbrBitstreamData->CountSendHeaderData %= + sbrBitstreamData->NrSendHeaderData; + } + } + + if (hSbrElement->CmonData.dynBwEnabled) { + INT i; + for (i = 4; i > 0; i--) + hSbrElement->dynXOverFreqDelay[i] = hSbrElement->dynXOverFreqDelay[i - 1]; + + hSbrElement->dynXOverFreqDelay[0] = hSbrElement->CmonData.dynXOverFreqEnc; + if (hSbrElement->dynXOverFreqDelay[1] > hSbrElement->dynXOverFreqDelay[2]) + newXOver = hSbrElement->dynXOverFreqDelay[2]; + else + newXOver = hSbrElement->dynXOverFreqDelay[1]; + + /* has the crossover frequency changed? */ + if (hSbrElement->sbrConfigData.dynXOverFreq != newXOver) { + /* get corresponding master band */ + cutoffSb = ((4 * newXOver * hSbrElement->sbrConfigData.noQmfBands / + hSbrElement->sbrConfigData.sampleFreq) + + 1) >> + 1; + + for (band = 0; band < hSbrElement->sbrConfigData.num_Master; band++) { + if (cutoffSb == hSbrElement->sbrConfigData.v_k_master[band]) break; + } + FDK_ASSERT(band < hSbrElement->sbrConfigData.num_Master); + + hSbrElement->sbrConfigData.dynXOverFreq = newXOver; + hSbrElement->sbrHeaderData.sbr_xover_band = band; + hSbrElement->sbrBitstreamData.HeaderActive = 1; + psHeaderActive = 1; /* ps header is one frame delayed */ + + /* + update vk_master table + */ + if (updateFreqBandTable(&hSbrElement->sbrConfigData, + &hSbrElement->sbrHeaderData, + hEnvEncoder->downSampleFactor)) + return (1); + + /* reset SBR channels */ + INT nEnvCh = hSbrElement->sbrConfigData.nChannels; + for (ch = 0; ch < nEnvCh; ch++) { + if (resetEnvChannel(&hSbrElement->sbrConfigData, + &hSbrElement->sbrHeaderData, + &hSbrElement->sbrChannel[ch]->hEnvChannel)) + return (1); + } + } + } + + /* + allocate space for dummy header and crc + */ + crcReg = FDKsbrEnc_InitSbrBitstream( + &hSbrElement->CmonData, + hSbrElement->payloadDelayLine[hEnvEncoder->nBitstrDelay], + MAX_PAYLOAD_SIZE * sizeof(UCHAR), &crcInfo, + hSbrElement->sbrConfigData.sbrSyntaxFlags); + + /* Temporal Envelope Data */ + SBR_FRAME_TEMP_DATA _fData; + SBR_FRAME_TEMP_DATA *fData = &_fData; + SBR_ENV_TEMP_DATA eData[MAX_NUM_CHANNELS]; + + /* Init Temporal Envelope Data */ + { + int i; + + FDKmemclear(&eData[0], sizeof(SBR_ENV_TEMP_DATA)); + FDKmemclear(&eData[1], sizeof(SBR_ENV_TEMP_DATA)); + FDKmemclear(fData, sizeof(SBR_FRAME_TEMP_DATA)); + + for (i = 0; i < MAX_NUM_NOISE_VALUES; i++) fData->res[i] = FREQ_RES_HIGH; + } + + if (!clearOutput) { + /* + * Transform audio data into QMF domain + */ + for (ch = 0; ch < hSbrElement->sbrConfigData.nChannels; ch++) { + HANDLE_ENV_CHANNEL h_envChan = &hSbrElement->sbrChannel[ch]->hEnvChannel; + HANDLE_SBR_EXTRACT_ENVELOPE sbrExtrEnv = &h_envChan->sbrExtractEnvelope; + + if (hSbrElement->elInfo.fParametricStereo == 0) { + QMF_SCALE_FACTOR tmpScale; + FIXP_DBL **pQmfReal, **pQmfImag; + C_AALLOC_SCRATCH_START(qmfWorkBuffer, FIXP_DBL, 64 * 2) + + /* Obtain pointers to QMF buffers. */ + pQmfReal = sbrExtrEnv->rBuffer; + pQmfImag = sbrExtrEnv->iBuffer; + + qmfAnalysisFiltering( + hSbrElement->hQmfAnalysis[ch], pQmfReal, pQmfImag, &tmpScale, + samples + hSbrElement->elInfo.ChannelIndex[ch] * samplesBufSize, 0, + 1, qmfWorkBuffer); + + h_envChan->qmfScale = tmpScale.lb_scale + 7; + + C_AALLOC_SCRATCH_END(qmfWorkBuffer, FIXP_DBL, 64 * 2) + + } /* fParametricStereo == 0 */ + + /* + Parametric Stereo processing + */ + if (hSbrElement->elInfo.fParametricStereo) { + INT error = noError; + + /* Limit Parametric Stereo to one instance */ + FDK_ASSERT(ch == 0); + + if (error == noError) { + /* parametric stereo processing: + - input: + o left and right time domain samples + - processing: + o stereo qmf analysis + o stereo hybrid analysis + o ps parameter extraction + o downmix + hybrid synthesis + - output: + o downmixed qmf data is written to sbrExtrEnv->rBuffer and + sbrExtrEnv->iBuffer + */ + SCHAR qmfScale; + INT_PCM *pSamples[2] = { + samples + hSbrElement->elInfo.ChannelIndex[0] * samplesBufSize, + samples + hSbrElement->elInfo.ChannelIndex[1] * samplesBufSize}; + error = FDKsbrEnc_PSEnc_ParametricStereoProcessing( + hEnvEncoder->hParametricStereo, pSamples, samplesBufSize, + hSbrElement->hQmfAnalysis, sbrExtrEnv->rBuffer, + sbrExtrEnv->iBuffer, + samples + hSbrElement->elInfo.ChannelIndex[ch] * samplesBufSize, + &hEnvEncoder->qmfSynthesisPS, &qmfScale, psHeaderActive); + h_envChan->qmfScale = (int)qmfScale; + } + + } /* if (hEnvEncoder->hParametricStereo) */ + + /* + + Extract Envelope relevant things from QMF data + + */ + FDKsbrEnc_extractSbrEnvelope1(&hSbrElement->sbrConfigData, + &hSbrElement->sbrHeaderData, + &hSbrElement->sbrBitstreamData, h_envChan, + &hSbrElement->CmonData, &eData[ch], fData); + + } /* hEnvEncoder->sbrConfigData.nChannels */ + } + + /* + Process Envelope relevant things and calculate envelope data and write + payload + */ + FDKsbrEnc_extractSbrEnvelope2( + &hSbrElement->sbrConfigData, &hSbrElement->sbrHeaderData, + (hSbrElement->elInfo.fParametricStereo) ? hEnvEncoder->hParametricStereo + : NULL, + &hSbrElement->sbrBitstreamData, &hSbrElement->sbrChannel[0]->hEnvChannel, + (hSbrElement->sbrConfigData.stereoMode != SBR_MONO) + ? &hSbrElement->sbrChannel[1]->hEnvChannel + : NULL, + &hSbrElement->CmonData, eData, fData, clearOutput); + + hSbrElement->sbrBitstreamData.rightBorderFIX = 0; + + /* + format payload, calculate crc + */ + FDKsbrEnc_AssembleSbrBitstream(&hSbrElement->CmonData, &crcInfo, crcReg, + hSbrElement->sbrConfigData.sbrSyntaxFlags); + + /* + save new payload, set to zero length if greater than MAX_PAYLOAD_SIZE + */ + hSbrElement->payloadDelayLineSize[hEnvEncoder->nBitstrDelay] = + FDKgetValidBits(&hSbrElement->CmonData.sbrBitbuf); + + if (hSbrElement->payloadDelayLineSize[hEnvEncoder->nBitstrDelay] > + (MAX_PAYLOAD_SIZE << 3)) + hSbrElement->payloadDelayLineSize[hEnvEncoder->nBitstrDelay] = 0; + + /* While filling the Delay lines, sbrData is NULL */ + if (sbrData) { + *sbrDataBits = hSbrElement->payloadDelayLineSize[0]; + FDKmemcpy(sbrData, hSbrElement->payloadDelayLine[0], + (hSbrElement->payloadDelayLineSize[0] + 7) >> 3); + } + + /* delay header active flag */ + if (hSbrElement->sbrBitstreamData.HeaderActive == 1) { + hSbrElement->sbrBitstreamData.HeaderActiveDelay = + 1 + hEnvEncoder->nBitstrDelay; + } else { + if (hSbrElement->sbrBitstreamData.HeaderActiveDelay > 0) { + hSbrElement->sbrBitstreamData.HeaderActiveDelay--; + } + } + + return (0); +} + +/***************************************************************************** + + functionname: FDKsbrEnc_Downsample + description: performs downsampling and delay compensation of the core path + returns: + input: + output: + +*****************************************************************************/ +INT FDKsbrEnc_Downsample( + HANDLE_SBR_ENCODER hSbrEncoder, + INT_PCM *samples, /*!< time samples, always deinterleaved */ + UINT samplesBufSize, /*!< time buffer size per channel */ + UINT numChannels, /*!< number of channels */ + UINT *sbrDataBits, /*!< Size of SBR payload */ + UCHAR *sbrData, /*!< SBR payload */ + int clearOutput /*!< Do not consider any input signal */ +) { + HANDLE_SBR_ELEMENT hSbrElement = NULL; + INT nOutSamples; + int el; + if (hSbrEncoder->downSampleFactor > 1) { + /* Do downsampling */ + + /* Loop over elements (LFE is handled later) */ + for (el = 0; el < hSbrEncoder->noElements; el++) { + hSbrElement = hSbrEncoder->sbrElement[el]; + if (hSbrEncoder->sbrElement[el] != NULL) { + if (hSbrEncoder->downsamplingMethod == SBRENC_DS_TIME) { + int ch; + int nChannels = hSbrElement->sbrConfigData.nChannels; + + for (ch = 0; ch < nChannels; ch++) { + FDKaacEnc_Downsample( + &hSbrElement->sbrChannel[ch]->downSampler, + samples + + hSbrElement->elInfo.ChannelIndex[ch] * samplesBufSize + + hSbrEncoder->bufferOffset / numChannels, + hSbrElement->sbrConfigData.frameSize, + samples + hSbrElement->elInfo.ChannelIndex[ch] * samplesBufSize, + &nOutSamples); + } + } + } + } + + /* Handle LFE (if existing) */ + if (hSbrEncoder->lfeChIdx != -1) { /* lfe downsampler */ + FDKaacEnc_Downsample(&hSbrEncoder->lfeDownSampler, + samples + hSbrEncoder->lfeChIdx * samplesBufSize + + hSbrEncoder->bufferOffset / numChannels, + hSbrEncoder->frameSize, + samples + hSbrEncoder->lfeChIdx * samplesBufSize, + &nOutSamples); + } + } else { + /* No downsampling. Still, some buffer shifting for correct delay */ + int samples2Copy = hSbrEncoder->frameSize; + if (hSbrEncoder->bufferOffset / (int)numChannels < samples2Copy) { + for (int c = 0; c < (int)numChannels; c++) { + /* Do memmove while taking care of overlapping memory areas. (memcpy + does not necessarily take care) Distinguish between oeverlapping and + non overlapping version due to reasons of complexity. */ + FDKmemmove(samples + c * samplesBufSize, + samples + c * samplesBufSize + + hSbrEncoder->bufferOffset / numChannels, + samples2Copy * sizeof(INT_PCM)); + } + } else { + for (int c = 0; c < (int)numChannels; c++) { + /* Simple memcpy since the memory areas are not overlapping */ + FDKmemcpy(samples + c * samplesBufSize, + samples + c * samplesBufSize + + hSbrEncoder->bufferOffset / numChannels, + samples2Copy * sizeof(INT_PCM)); + } + } + } + + return 0; +} + +/***************************************************************************** + + functionname: createEnvChannel + description: initializes parameters and allocates memory + returns: error status + input: + output: hEnv + +*****************************************************************************/ + +static INT createEnvChannel(HANDLE_ENV_CHANNEL hEnv, INT channel, + UCHAR *dynamic_RAM) { + FDKmemclear(hEnv, sizeof(struct ENV_CHANNEL)); + + if (FDKsbrEnc_CreateTonCorrParamExtr(&hEnv->TonCorr, channel)) { + return (1); + } + + if (FDKsbrEnc_CreateExtractSbrEnvelope(&hEnv->sbrExtractEnvelope, channel, + /*chan*/ 0, dynamic_RAM)) { + return (1); + } + + return 0; +} + +/***************************************************************************** + + functionname: initEnvChannel + description: initializes parameters + returns: error status + input: + output: + +*****************************************************************************/ +static INT initEnvChannel(HANDLE_SBR_CONFIG_DATA sbrConfigData, + HANDLE_SBR_HEADER_DATA sbrHeaderData, + HANDLE_ENV_CHANNEL hEnv, sbrConfigurationPtr params, + ULONG statesInitFlag, INT chanInEl, + UCHAR *dynamic_RAM) { + int frameShift, tran_off = 0; + INT e; + INT tran_fc; + INT timeSlots, timeStep, startIndex; + INT noiseBands[2] = {3, 3}; + + e = 1 << params->e; + + FDK_ASSERT(params->e >= 0); + + hEnv->encEnvData.freq_res_fixfix[0] = params->freq_res_fixfix[0]; + hEnv->encEnvData.freq_res_fixfix[1] = params->freq_res_fixfix[1]; + hEnv->encEnvData.fResTransIsLow = params->fResTransIsLow; + + hEnv->fLevelProtect = 0; + + hEnv->encEnvData.ldGrid = + (sbrConfigData->sbrSyntaxFlags & SBR_SYNTAX_LOW_DELAY) ? 1 : 0; + + hEnv->encEnvData.sbr_xpos_mode = (XPOS_MODE)params->sbr_xpos_mode; + + if (hEnv->encEnvData.sbr_xpos_mode == XPOS_SWITCHED) { + /* + no other type than XPOS_MDCT or XPOS_SPEECH allowed, + but enable switching + */ + sbrConfigData->switchTransposers = TRUE; + hEnv->encEnvData.sbr_xpos_mode = XPOS_MDCT; + } else { + sbrConfigData->switchTransposers = FALSE; + } + + hEnv->encEnvData.sbr_xpos_ctrl = params->sbr_xpos_ctrl; + + /* extended data */ + if (params->parametricCoding) { + hEnv->encEnvData.extended_data = 1; + } else { + hEnv->encEnvData.extended_data = 0; + } + + hEnv->encEnvData.extension_size = 0; + + startIndex = QMF_FILTER_PROTOTYPE_SIZE - sbrConfigData->noQmfBands; + + switch (params->sbrFrameSize) { + case 2304: + timeSlots = 18; + break; + case 2048: + case 1024: + case 512: + timeSlots = 16; + break; + case 1920: + case 960: + case 480: + timeSlots = 15; + break; + case 1152: + timeSlots = 9; + break; + default: + return (1); /* Illegal frame size */ + } + + timeStep = sbrConfigData->noQmfSlots / timeSlots; + + if (FDKsbrEnc_InitTonCorrParamExtr( + params->sbrFrameSize, &hEnv->TonCorr, sbrConfigData, timeSlots, + params->sbr_xpos_ctrl, params->ana_max_level, + sbrHeaderData->sbr_noise_bands, params->noiseFloorOffset, + params->useSpeechConfig)) + return (1); + + hEnv->encEnvData.noOfnoisebands = + hEnv->TonCorr.sbrNoiseFloorEstimate.noNoiseBands; + + noiseBands[0] = hEnv->encEnvData.noOfnoisebands; + noiseBands[1] = hEnv->encEnvData.noOfnoisebands; + + hEnv->encEnvData.sbr_invf_mode = (INVF_MODE)params->sbr_invf_mode; + + if (hEnv->encEnvData.sbr_invf_mode == INVF_SWITCHED) { + hEnv->encEnvData.sbr_invf_mode = INVF_MID_LEVEL; + hEnv->TonCorr.switchInverseFilt = TRUE; + } else { + hEnv->TonCorr.switchInverseFilt = FALSE; + } + + tran_fc = params->tran_fc; + + if (tran_fc == 0) { + tran_fc = fixMin( + 5000, FDKsbrEnc_getSbrStartFreqRAW(sbrHeaderData->sbr_start_frequency, + params->codecSettings.sampleFreq)); + } + + tran_fc = + (tran_fc * 4 * sbrConfigData->noQmfBands / sbrConfigData->sampleFreq + + 1) >> + 1; + + if (sbrConfigData->sbrSyntaxFlags & SBR_SYNTAX_LOW_DELAY) { + frameShift = LD_PRETRAN_OFF; + tran_off = LD_PRETRAN_OFF + FRAME_MIDDLE_SLOT_512LD * timeStep; + } else { + frameShift = 0; + switch (timeSlots) { + /* The factor of 2 is by definition. */ + case NUMBER_TIME_SLOTS_2048: + tran_off = 8 + FRAME_MIDDLE_SLOT_2048 * timeStep; + break; + case NUMBER_TIME_SLOTS_1920: + tran_off = 7 + FRAME_MIDDLE_SLOT_1920 * timeStep; + break; + default: + return 1; + } + } + if (FDKsbrEnc_InitExtractSbrEnvelope( + &hEnv->sbrExtractEnvelope, sbrConfigData->noQmfSlots, + sbrConfigData->noQmfBands, startIndex, timeSlots, timeStep, tran_off, + statesInitFlag, chanInEl, dynamic_RAM, sbrConfigData->sbrSyntaxFlags)) + return (1); + + if (FDKsbrEnc_InitSbrCodeEnvelope(&hEnv->sbrCodeEnvelope, sbrConfigData->nSfb, + params->deltaTAcrossFrames, + params->dF_edge_1stEnv, + params->dF_edge_incr)) + return (1); + + if (FDKsbrEnc_InitSbrCodeEnvelope(&hEnv->sbrCodeNoiseFloor, noiseBands, + params->deltaTAcrossFrames, 0, 0)) + return (1); + + sbrConfigData->initAmpResFF = params->init_amp_res_FF; + + if (FDKsbrEnc_InitSbrHuffmanTables(&hEnv->encEnvData, &hEnv->sbrCodeEnvelope, + &hEnv->sbrCodeNoiseFloor, + sbrHeaderData->sbr_amp_res)) + return (1); + + FDKsbrEnc_initFrameInfoGenerator( + &hEnv->SbrEnvFrame, params->spread, e, params->stat, timeSlots, + hEnv->encEnvData.freq_res_fixfix, hEnv->encEnvData.fResTransIsLow, + hEnv->encEnvData.ldGrid); + + if (sbrConfigData->sbrSyntaxFlags & SBR_SYNTAX_LOW_DELAY) + + { + INT bandwidth_qmf_slot = + (sbrConfigData->sampleFreq >> 1) / (sbrConfigData->noQmfBands); + if (FDKsbrEnc_InitSbrFastTransientDetector( + &hEnv->sbrFastTransientDetector, sbrConfigData->noQmfSlots, + bandwidth_qmf_slot, sbrConfigData->noQmfBands, + sbrConfigData->freqBandTable[0][0])) + return (1); + } + + /* The transient detector has to be initialized also if the fast transient + detector was active, because the values from the transient detector + structure are used. */ + if (FDKsbrEnc_InitSbrTransientDetector( + &hEnv->sbrTransientDetector, sbrConfigData->sbrSyntaxFlags, + sbrConfigData->frameSize, sbrConfigData->sampleFreq, params, tran_fc, + sbrConfigData->noQmfSlots, sbrConfigData->noQmfBands, + hEnv->sbrExtractEnvelope.YBufferWriteOffset, + hEnv->sbrExtractEnvelope.YBufferSzShift, frameShift, tran_off)) + return (1); + + sbrConfigData->xposCtrlSwitch = params->sbr_xpos_ctrl; + + hEnv->encEnvData.noHarmonics = sbrConfigData->nSfb[HI]; + hEnv->encEnvData.addHarmonicFlag = 0; + + return (0); +} + +INT sbrEncoder_Open(HANDLE_SBR_ENCODER *phSbrEncoder, INT nElements, + INT nChannels, INT supportPS) { + INT i; + INT errorStatus = 1; + HANDLE_SBR_ENCODER hSbrEncoder = NULL; + + if (phSbrEncoder == NULL) { + goto bail; + } + + hSbrEncoder = GetRam_SbrEncoder(); + if (hSbrEncoder == NULL) { + goto bail; + } + FDKmemclear(hSbrEncoder, sizeof(SBR_ENCODER)); + + if (NULL == + (hSbrEncoder->pSBRdynamic_RAM = (UCHAR *)GetRam_SbrDynamic_RAM())) { + goto bail; + } + hSbrEncoder->dynamicRam = hSbrEncoder->pSBRdynamic_RAM; + + /* Create SBR elements */ + for (i = 0; i < nElements; i++) { + hSbrEncoder->sbrElement[i] = GetRam_SbrElement(i); + if (hSbrEncoder->sbrElement[i] == NULL) { + goto bail; + } + FDKmemclear(hSbrEncoder->sbrElement[i], sizeof(SBR_ELEMENT)); + hSbrEncoder->sbrElement[i]->sbrConfigData.freqBandTable[LO] = + GetRam_Sbr_freqBandTableLO(i); + hSbrEncoder->sbrElement[i]->sbrConfigData.freqBandTable[HI] = + GetRam_Sbr_freqBandTableHI(i); + hSbrEncoder->sbrElement[i]->sbrConfigData.v_k_master = + GetRam_Sbr_v_k_master(i); + if ((hSbrEncoder->sbrElement[i]->sbrConfigData.freqBandTable[LO] == NULL) || + (hSbrEncoder->sbrElement[i]->sbrConfigData.freqBandTable[HI] == NULL) || + (hSbrEncoder->sbrElement[i]->sbrConfigData.v_k_master == NULL)) { + goto bail; + } + } + + /* Create SBR channels */ + for (i = 0; i < nChannels; i++) { + hSbrEncoder->pSbrChannel[i] = GetRam_SbrChannel(i); + if (hSbrEncoder->pSbrChannel[i] == NULL) { + goto bail; + } + + if (createEnvChannel(&hSbrEncoder->pSbrChannel[i]->hEnvChannel, i, + hSbrEncoder->dynamicRam)) { + goto bail; + } + } + + /* Create QMF States */ + for (i = 0; i < fixMax(nChannels, (supportPS) ? 2 : 0); i++) { + hSbrEncoder->QmfAnalysis[i].FilterStates = GetRam_Sbr_QmfStatesAnalysis(i); + if (hSbrEncoder->QmfAnalysis[i].FilterStates == NULL) { + goto bail; + } + } + + /* Create Parametric Stereo handle */ + if (supportPS) { + if (PSEnc_Create(&hSbrEncoder->hParametricStereo)) { + goto bail; + } + + hSbrEncoder->qmfSynthesisPS.FilterStates = GetRam_PsQmfStatesSynthesis(); + if (hSbrEncoder->qmfSynthesisPS.FilterStates == NULL) { + goto bail; + } + } /* supportPS */ + + *phSbrEncoder = hSbrEncoder; + + errorStatus = 0; + return errorStatus; + +bail: + /* Close SBR encoder instance */ + sbrEncoder_Close(&hSbrEncoder); + return errorStatus; +} + +static INT FDKsbrEnc_Reallocate(HANDLE_SBR_ENCODER hSbrEncoder, + SBR_ELEMENT_INFO elInfo[(8)], + const INT noElements) { + INT totalCh = 0; + INT totalQmf = 0; + INT coreEl; + INT el = -1; + + hSbrEncoder->lfeChIdx = -1; /* default value, until lfe found */ + + for (coreEl = 0; coreEl < noElements; coreEl++) { + /* SBR only handles SCE and CPE's */ + if (elInfo[coreEl].elType == ID_SCE || elInfo[coreEl].elType == ID_CPE) { + el++; + } else { + if (elInfo[coreEl].elType == ID_LFE) { + hSbrEncoder->lfeChIdx = elInfo[coreEl].ChannelIndex[0]; + } + continue; + } + + SBR_ELEMENT_INFO *pelInfo = &elInfo[coreEl]; + HANDLE_SBR_ELEMENT hSbrElement = hSbrEncoder->sbrElement[el]; + + int ch; + for (ch = 0; ch < pelInfo->nChannelsInEl; ch++) { + hSbrElement->sbrChannel[ch] = hSbrEncoder->pSbrChannel[totalCh]; + totalCh++; + } + /* analysis QMF */ + for (ch = 0; + ch < ((pelInfo->fParametricStereo) ? 2 : pelInfo->nChannelsInEl); + ch++) { + hSbrElement->elInfo.ChannelIndex[ch] = pelInfo->ChannelIndex[ch]; + hSbrElement->hQmfAnalysis[ch] = &hSbrEncoder->QmfAnalysis[totalQmf++]; + } + + /* Copy Element info */ + hSbrElement->elInfo.elType = pelInfo->elType; + hSbrElement->elInfo.instanceTag = pelInfo->instanceTag; + hSbrElement->elInfo.nChannelsInEl = pelInfo->nChannelsInEl; + hSbrElement->elInfo.fParametricStereo = pelInfo->fParametricStereo; + hSbrElement->elInfo.fDualMono = pelInfo->fDualMono; + } /* coreEl */ + + return 0; +} + +/***************************************************************************** + + functionname: FDKsbrEnc_bsBufInit + description: initializes bitstream buffer + returns: initialized bitstream buffer in env encoder + input: + output: hEnv + +*****************************************************************************/ +static INT FDKsbrEnc_bsBufInit(HANDLE_SBR_ELEMENT hSbrElement, + int nBitstrDelay) { + UCHAR *bitstreamBuffer; + + /* initialize the bitstream buffer */ + bitstreamBuffer = hSbrElement->payloadDelayLine[nBitstrDelay]; + FDKinitBitStream(&hSbrElement->CmonData.sbrBitbuf, bitstreamBuffer, + MAX_PAYLOAD_SIZE * sizeof(UCHAR), 0, BS_WRITER); + + return (0); +} + +/***************************************************************************** + + functionname: FDKsbrEnc_EnvInit + description: initializes parameters + returns: error status + input: + output: hEnv + +*****************************************************************************/ +static INT FDKsbrEnc_EnvInit(HANDLE_SBR_ELEMENT hSbrElement, + sbrConfigurationPtr params, INT *coreBandWith, + AUDIO_OBJECT_TYPE aot, int nElement, + const int headerPeriod, ULONG statesInitFlag, + const SBRENC_DS_TYPE downsamplingMethod, + UCHAR *dynamic_RAM) { + int ch, i; + + if ((params->codecSettings.nChannels < 1) || + (params->codecSettings.nChannels > MAX_NUM_CHANNELS)) { + return (1); + } + + /* init and set syntax flags */ + hSbrElement->sbrConfigData.sbrSyntaxFlags = 0; + + switch (aot) { + case AOT_ER_AAC_ELD: + hSbrElement->sbrConfigData.sbrSyntaxFlags |= SBR_SYNTAX_LOW_DELAY; + break; + default: + break; + } + if (params->crcSbr) { + hSbrElement->sbrConfigData.sbrSyntaxFlags |= SBR_SYNTAX_CRC; + } + + hSbrElement->sbrConfigData.noQmfBands = 64 >> (2 - params->downSampleFactor); + switch (hSbrElement->sbrConfigData.noQmfBands) { + case 64: + hSbrElement->sbrConfigData.noQmfSlots = params->sbrFrameSize >> 6; + break; + case 32: + hSbrElement->sbrConfigData.noQmfSlots = params->sbrFrameSize >> 5; + break; + default: + hSbrElement->sbrConfigData.noQmfSlots = params->sbrFrameSize >> 6; + return (2); + } + + /* + now initialize sbrConfigData, sbrHeaderData and sbrBitstreamData, + */ + hSbrElement->sbrConfigData.nChannels = params->codecSettings.nChannels; + + if (params->codecSettings.nChannels == 2) { + if ((hSbrElement->elInfo.elType == ID_CPE) && + ((hSbrElement->elInfo.fDualMono == 1))) { + hSbrElement->sbrConfigData.stereoMode = SBR_LEFT_RIGHT; + } else { + hSbrElement->sbrConfigData.stereoMode = params->stereoMode; + } + } else { + hSbrElement->sbrConfigData.stereoMode = SBR_MONO; + } + + hSbrElement->sbrConfigData.frameSize = params->sbrFrameSize; + + hSbrElement->sbrConfigData.sampleFreq = + params->downSampleFactor * params->codecSettings.sampleFreq; + + hSbrElement->sbrBitstreamData.CountSendHeaderData = 0; + if (params->SendHeaderDataTime > 0) { + if (headerPeriod == -1) { + hSbrElement->sbrBitstreamData.NrSendHeaderData = (INT)( + params->SendHeaderDataTime * hSbrElement->sbrConfigData.sampleFreq / + (1000 * hSbrElement->sbrConfigData.frameSize)); + hSbrElement->sbrBitstreamData.NrSendHeaderData = + fixMax(hSbrElement->sbrBitstreamData.NrSendHeaderData, 1); + } else { + /* assure header period at least once per second */ + hSbrElement->sbrBitstreamData.NrSendHeaderData = fixMin( + fixMax(headerPeriod, 1), (hSbrElement->sbrConfigData.sampleFreq / + hSbrElement->sbrConfigData.frameSize)); + } + } else { + hSbrElement->sbrBitstreamData.NrSendHeaderData = 0; + } + + hSbrElement->sbrHeaderData.sbr_data_extra = params->sbr_data_extra; + hSbrElement->sbrBitstreamData.HeaderActive = 0; + hSbrElement->sbrBitstreamData.rightBorderFIX = 0; + hSbrElement->sbrHeaderData.sbr_start_frequency = params->startFreq; + hSbrElement->sbrHeaderData.sbr_stop_frequency = params->stopFreq; + hSbrElement->sbrHeaderData.sbr_xover_band = 0; + hSbrElement->sbrHeaderData.sbr_lc_stereo_mode = 0; + + /* data_extra */ + if (params->sbr_xpos_ctrl != SBR_XPOS_CTRL_DEFAULT) + hSbrElement->sbrHeaderData.sbr_data_extra = 1; + + hSbrElement->sbrHeaderData.sbr_amp_res = (AMP_RES)params->amp_res; + + /* header_extra_1 */ + hSbrElement->sbrHeaderData.freqScale = params->freqScale; + hSbrElement->sbrHeaderData.alterScale = params->alterScale; + hSbrElement->sbrHeaderData.sbr_noise_bands = params->sbr_noise_bands; + hSbrElement->sbrHeaderData.header_extra_1 = 0; + + if ((params->freqScale != SBR_FREQ_SCALE_DEFAULT) || + (params->alterScale != SBR_ALTER_SCALE_DEFAULT) || + (params->sbr_noise_bands != SBR_NOISE_BANDS_DEFAULT)) { + hSbrElement->sbrHeaderData.header_extra_1 = 1; + } + + /* header_extra_2 */ + hSbrElement->sbrHeaderData.sbr_limiter_bands = params->sbr_limiter_bands; + hSbrElement->sbrHeaderData.sbr_limiter_gains = params->sbr_limiter_gains; + + if ((hSbrElement->sbrConfigData.sampleFreq > 48000) && + (hSbrElement->sbrHeaderData.sbr_start_frequency >= 9)) { + hSbrElement->sbrHeaderData.sbr_limiter_gains = SBR_LIMITER_GAINS_INFINITE; + } + + hSbrElement->sbrHeaderData.sbr_interpol_freq = params->sbr_interpol_freq; + hSbrElement->sbrHeaderData.sbr_smoothing_length = + params->sbr_smoothing_length; + hSbrElement->sbrHeaderData.header_extra_2 = 0; + + if ((params->sbr_limiter_bands != SBR_LIMITER_BANDS_DEFAULT) || + (params->sbr_limiter_gains != SBR_LIMITER_GAINS_DEFAULT) || + (params->sbr_interpol_freq != SBR_INTERPOL_FREQ_DEFAULT) || + (params->sbr_smoothing_length != SBR_SMOOTHING_LENGTH_DEFAULT)) { + hSbrElement->sbrHeaderData.header_extra_2 = 1; + } + + /* other switches */ + hSbrElement->sbrConfigData.useWaveCoding = params->useWaveCoding; + hSbrElement->sbrConfigData.useParametricCoding = params->parametricCoding; + hSbrElement->sbrConfigData.thresholdAmpResFF_m = + params->threshold_AmpRes_FF_m; + hSbrElement->sbrConfigData.thresholdAmpResFF_e = + params->threshold_AmpRes_FF_e; + + /* init freq band table */ + if (updateFreqBandTable(&hSbrElement->sbrConfigData, + &hSbrElement->sbrHeaderData, + params->downSampleFactor)) { + return (1); + } + + /* now create envelope ext and QMF for each available channel */ + for (ch = 0; ch < hSbrElement->sbrConfigData.nChannels; ch++) { + if (initEnvChannel(&hSbrElement->sbrConfigData, &hSbrElement->sbrHeaderData, + &hSbrElement->sbrChannel[ch]->hEnvChannel, params, + statesInitFlag, ch, dynamic_RAM)) { + return (1); + } + + } /* nChannels */ + + /* reset and intialize analysis qmf */ + for (ch = 0; ch < ((hSbrElement->elInfo.fParametricStereo) + ? 2 + : hSbrElement->sbrConfigData.nChannels); + ch++) { + int err; + UINT qmfFlags = + (hSbrElement->sbrConfigData.sbrSyntaxFlags & SBR_SYNTAX_LOW_DELAY) + ? QMF_FLAG_CLDFB + : 0; + if (statesInitFlag) + qmfFlags &= ~QMF_FLAG_KEEP_STATES; + else + qmfFlags |= QMF_FLAG_KEEP_STATES; + + err = qmfInitAnalysisFilterBank( + hSbrElement->hQmfAnalysis[ch], + (FIXP_QAS *)hSbrElement->hQmfAnalysis[ch]->FilterStates, + hSbrElement->sbrConfigData.noQmfSlots, + hSbrElement->sbrConfigData.noQmfBands, + hSbrElement->sbrConfigData.noQmfBands, + hSbrElement->sbrConfigData.noQmfBands, qmfFlags); + if (0 != err) { + return err; + } + } + + /* */ + hSbrElement->CmonData.xOverFreq = hSbrElement->sbrConfigData.xOverFreq; + hSbrElement->CmonData.dynBwEnabled = + (params->dynBwSupported && params->dynBwEnabled); + hSbrElement->CmonData.dynXOverFreqEnc = + FDKsbrEnc_SbrGetXOverFreq(hSbrElement, hSbrElement->CmonData.xOverFreq); + for (i = 0; i < 5; i++) + hSbrElement->dynXOverFreqDelay[i] = hSbrElement->CmonData.dynXOverFreqEnc; + hSbrElement->CmonData.sbrNumChannels = hSbrElement->sbrConfigData.nChannels; + hSbrElement->sbrConfigData.dynXOverFreq = hSbrElement->CmonData.xOverFreq; + + /* Update Bandwith to be passed to the core encoder */ + *coreBandWith = hSbrElement->CmonData.xOverFreq; + + return (0); +} + +INT sbrEncoder_GetInBufferSize(int noChannels) { + INT temp; + + temp = (2048); + temp += 1024 + MAX_SAMPLE_DELAY; + temp *= noChannels; + temp *= sizeof(INT_PCM); + return temp; +} + +/* + * Encode Dummy SBR payload frames to fill the delay lines. + */ +static INT FDKsbrEnc_DelayCompensation(HANDLE_SBR_ENCODER hEnvEnc, + INT_PCM *timeBuffer, + UINT timeBufferBufSize) { + int n, el; + + for (n = hEnvEnc->nBitstrDelay; n > 0; n--) { + for (el = 0; el < hEnvEnc->noElements; el++) { + if (FDKsbrEnc_EnvEncodeFrame( + hEnvEnc, el, + timeBuffer + hEnvEnc->downsampledOffset / hEnvEnc->nChannels, + timeBufferBufSize, NULL, NULL, 1)) + return -1; + } + sbrEncoder_UpdateBuffers(hEnvEnc, timeBuffer, timeBufferBufSize); + } + return 0; +} + +UINT sbrEncoder_LimitBitRate(UINT bitRate, UINT numChannels, + UINT coreSampleRate, AUDIO_OBJECT_TYPE aot) { + UINT newBitRate = bitRate; + INT index; + + FDK_ASSERT(numChannels > 0 && numChannels <= 2); + if (aot == AOT_PS) { + if (numChannels == 1) { + index = getPsTuningTableIndex(bitRate, &newBitRate); + if (index == INVALID_TABLE_IDX) { + bitRate = newBitRate; + } + } else { + return 0; + } + } + index = getSbrTuningTableIndex(bitRate, numChannels, coreSampleRate, aot, + &newBitRate); + if (index != INVALID_TABLE_IDX) { + newBitRate = bitRate; + } + + return newBitRate; +} + +UINT sbrEncoder_IsSingleRatePossible(AUDIO_OBJECT_TYPE aot) { + UINT isPossible = (AOT_PS == aot) ? 0 : 1; + return isPossible; +} + +/*****************************************************************************/ +/* */ +/*functionname: sbrEncoder_Init_delay */ +/*description: Determine Delay balancing and new encoder delay */ +/* */ +/*returns: - error status */ +/*input: - frame length of the core (i.e. e.g. AAC) */ +/* - number of channels */ +/* - downsample factor (1 for downsampled, 2 for dual-rate SBR) */ +/* - low delay presence */ +/* - ps presence */ +/* - downsampling method: QMF-, time domain or no downsampling */ +/* - various delay values (see DELAY_PARAM struct description) */ +/* */ +/*Example: Delay balancing for a HE-AACv1 encoder (time-domain downsampling) */ +/*========================================================================== */ +/* */ +/* +--------+ +--------+ +--------+ +--------+ +--------+ */ +/* |core | |ds 2:1 | |AAC | |QMF | |QMF | */ +/* +-+path +------------+ +-+core +-+analysis+-+overlap +-+ */ +/* | |offset | | | | | |32 bands| | | | */ +/* | +--------+ +--------+ +--------+ +--------+ +--------+ | */ +/* | core path +-------++ */ +/* | |QMF | */ +/*->+ +synth. +-> */ +/* | |64 bands| */ +/* | +-------++ */ +/* | +--------+ +--------+ +--------+ +--------+ | */ +/* | |SBR path| |QMF | |subband | |bs delay| | */ +/* +-+offset +-+analysis+-+sample +-+(full +-----------------------+ */ +/* | | |64 bands| |buffer | | frames)| */ +/* +--------+ +--------+ +--------+ +--------+ */ +/* SBR path */ +/* */ +/*****************************************************************************/ +static INT sbrEncoder_Init_delay( + const int coreFrameLength, /* input */ + const int numChannels, /* input */ + const int downSampleFactor, /* input */ + const int lowDelay, /* input */ + const int usePs, /* input */ + const int is212, /* input */ + const SBRENC_DS_TYPE downsamplingMethod, /* input */ + DELAY_PARAM *hDelayParam /* input/output */ +) { + int delayCorePath = 0; /* delay in core path */ + int delaySbrPath = 0; /* delay difference in QMF aka SBR path */ + int delayInput2Core = 0; /* delay from the input to the core */ + int delaySbrDec = 0; /* delay of the decoder's SBR module */ + + int delayCore = hDelayParam->delay; /* delay of the core */ + + /* Added delay by the SBR delay initialization */ + int corePathOffset = 0; /* core path */ + int sbrPathOffset = 0; /* sbr path */ + int bitstreamDelay = 0; /* sbr path, framewise */ + + int flCore = coreFrameLength; /* core frame length */ + + int returnValue = 0; /* return value - 0 means: no error */ + + /* 1) Calculate actual delay for core and SBR path */ + if (is212) { + delayCorePath = DELAY_COREPATH_ELDv2SBR(flCore, downSampleFactor); + delaySbrPath = DELAY_ELDv2SBR(flCore, downSampleFactor); + delaySbrDec = ((flCore) / 2) * (downSampleFactor); + } else if (lowDelay) { + delayCorePath = DELAY_COREPATH_ELDSBR(flCore, downSampleFactor); + delaySbrPath = DELAY_ELDSBR(flCore, downSampleFactor); + delaySbrDec = DELAY_QMF_POSTPROC(downSampleFactor); + } else if (usePs) { + delayCorePath = DELAY_COREPATH_PS(flCore, downSampleFactor); + delaySbrPath = DELAY_PS(flCore, downSampleFactor); + delaySbrDec = DELAY_COREPATH_SBR(flCore, downSampleFactor); + } else { + delayCorePath = DELAY_COREPATH_SBR(flCore, downSampleFactor); + delaySbrPath = DELAY_SBR(flCore, downSampleFactor); + delaySbrDec = DELAY_COREPATH_SBR(flCore, downSampleFactor); + } + delayCorePath += delayCore * downSampleFactor; + delayCorePath += + (downsamplingMethod == SBRENC_DS_TIME) ? hDelayParam->dsDelay : 0; + + /* 2) Manage coupling of paths */ + if (downsamplingMethod == SBRENC_DS_QMF && delayCorePath > delaySbrPath) { + /* In case of QMF downsampling, both paths are coupled, i.e. the SBR path + offset would be added to both the SBR path and to the core path + as well, thus making it impossible to achieve delay balancing. + To overcome that problem, a framewise delay is added to the SBR path + first, until the overall delay of the core path is shorter than + the delay of the SBR path. When this is achieved, the missing delay + difference can be added as downsampled offset to the core path. + */ + while (delayCorePath > delaySbrPath) { + /* Add one frame delay to SBR path */ + delaySbrPath += flCore * downSampleFactor; + bitstreamDelay += 1; + } + } + + /* 3) Calculate necessary additional delay to balance the paths */ + if (delayCorePath > delaySbrPath) { + /* Delay QMF input */ + while (delayCorePath > delaySbrPath + (int)flCore * (int)downSampleFactor) { + /* Do bitstream frame-wise delay balancing if there are + more than SBR framelength samples delay difference */ + delaySbrPath += flCore * downSampleFactor; + bitstreamDelay += 1; + } + /* Multiply input offset by input channels */ + corePathOffset = 0; + sbrPathOffset = (delayCorePath - delaySbrPath) * numChannels; + } else { + /* Delay AAC data */ + /* Multiply downsampled offset by AAC core channels. Divide by 2 because of + half samplerate of downsampled data. */ + corePathOffset = ((delaySbrPath - delayCorePath) * numChannels) >> + (downSampleFactor - 1); + sbrPathOffset = 0; + } + + /* 4) Calculate delay from input to core */ + if (usePs) { + delayInput2Core = + (DELAY_QMF_ANA(downSampleFactor) + DELAY_QMF_DS + DELAY_HYB_SYN) + + (downSampleFactor * corePathOffset) + 1; + } else if (downsamplingMethod == SBRENC_DS_TIME) { + delayInput2Core = corePathOffset + hDelayParam->dsDelay; + } else { + delayInput2Core = corePathOffset; + } + + /* 6) Set output parameters */ + hDelayParam->delay = FDKmax(delayCorePath, delaySbrPath); /* overall delay */ + hDelayParam->sbrDecDelay = delaySbrDec; /* SBR decoder delay */ + hDelayParam->delayInput2Core = delayInput2Core; /* delay input - core */ + hDelayParam->bitstrDelay = bitstreamDelay; /* bitstream delay, in frames */ + hDelayParam->corePathOffset = corePathOffset; /* offset added to core path */ + hDelayParam->sbrPathOffset = sbrPathOffset; /* offset added to SBR path */ + + return returnValue; +} + +/***************************************************************************** + + functionname: sbrEncoder_Init + description: initializes the SBR encoder + returns: error status + +*****************************************************************************/ +INT sbrEncoder_Init(HANDLE_SBR_ENCODER hSbrEncoder, + SBR_ELEMENT_INFO elInfo[(8)], int noElements, + INT_PCM *inputBuffer, UINT inputBufferBufSize, + INT *coreBandwidth, INT *inputBufferOffset, + INT *numChannels, const UINT syntaxFlags, + INT *coreSampleRate, UINT *downSampleFactor, + INT *frameLength, AUDIO_OBJECT_TYPE aot, int *delay, + int transformFactor, const int headerPeriod, + ULONG statesInitFlag) { + HANDLE_ERROR_INFO errorInfo = noError; + sbrConfiguration sbrConfig[(8)]; + INT error = 0; + INT lowestBandwidth; + /* Save input parameters */ + INT inputSampleRate = *coreSampleRate; + int coreFrameLength = *frameLength; + int inputBandWidth = *coreBandwidth; + int inputChannels = *numChannels; + + SBRENC_DS_TYPE downsamplingMethod = SBRENC_DS_NONE; + int highestSbrStartFreq, highestSbrStopFreq; + int lowDelay = 0; + int usePs = 0; + int is212 = 0; + + DELAY_PARAM delayParam; + + /* check whether SBR setting is available for the current encoder + * configuration (bitrate, samplerate) */ + if (!sbrEncoder_IsSingleRatePossible(aot)) { + *downSampleFactor = 2; + } + + if (aot == AOT_PS || aot == AOT_DABPLUS_PS) { + usePs = 1; + } + if (aot == AOT_ER_AAC_ELD) { + lowDelay = 1; + } else if (aot == AOT_ER_AAC_LD) { + error = 1; + goto bail; + } + + /* Parametric Stereo */ + if (usePs) { + if (*numChannels == 2 && noElements == 1) { + /* Override Element type in case of Parametric stereo */ + elInfo[0].elType = ID_SCE; + elInfo[0].fParametricStereo = 1; + elInfo[0].nChannelsInEl = 1; + /* core encoder gets downmixed mono signal */ + *numChannels = 1; + } else { + error = 1; + goto bail; + } + } /* usePs */ + + /* set the core's sample rate */ + switch (*downSampleFactor) { + case 1: + *coreSampleRate = inputSampleRate; + downsamplingMethod = SBRENC_DS_NONE; + break; + case 2: + *coreSampleRate = inputSampleRate >> 1; + downsamplingMethod = usePs ? SBRENC_DS_QMF : SBRENC_DS_TIME; + break; + default: + *coreSampleRate = inputSampleRate >> 1; + return 0; /* return error */ + } + + /* check whether SBR setting is available for the current encoder + * configuration (bitrate, coreSampleRate) */ + { + int el, coreEl; + + /* Check if every element config is feasible */ + for (coreEl = 0; coreEl < noElements; coreEl++) { + /* SBR only handles SCE and CPE's */ + if (elInfo[coreEl].elType != ID_SCE && elInfo[coreEl].elType != ID_CPE) { + continue; + } + /* check if desired configuration is available */ + if (!FDKsbrEnc_IsSbrSettingAvail(elInfo[coreEl].bitRate, 0, + elInfo[coreEl].nChannelsInEl, + inputSampleRate, *coreSampleRate, aot)) { + error = 1; + goto bail; + } + } + + hSbrEncoder->nChannels = *numChannels; + hSbrEncoder->frameSize = coreFrameLength * *downSampleFactor; + hSbrEncoder->downsamplingMethod = downsamplingMethod; + hSbrEncoder->downSampleFactor = *downSampleFactor; + hSbrEncoder->estimateBitrate = 0; + hSbrEncoder->inputDataDelay = 0; + is212 = ((aot == AOT_ER_AAC_ELD) && (syntaxFlags & AC_LD_MPS)) ? 1 : 0; + + /* Open SBR elements */ + el = -1; + highestSbrStartFreq = highestSbrStopFreq = 0; + lowestBandwidth = 99999; + + /* Loop through each core encoder element and get a matching SBR element + * config */ + for (coreEl = 0; coreEl < noElements; coreEl++) { + /* SBR only handles SCE and CPE's */ + if (elInfo[coreEl].elType == ID_SCE || elInfo[coreEl].elType == ID_CPE) { + el++; + } else { + continue; + } + + /* Set parametric Stereo Flag. */ + if (usePs) { + elInfo[coreEl].fParametricStereo = 1; + } else { + elInfo[coreEl].fParametricStereo = 0; + } + + /* + * Init sbrConfig structure + */ + if (!FDKsbrEnc_InitializeSbrDefaults(&sbrConfig[el], *downSampleFactor, + coreFrameLength, IS_LOWDELAY(aot))) { + error = 1; + goto bail; + } + + /* + * Modify sbrConfig structure according to Element parameters + */ + if (!FDKsbrEnc_AdjustSbrSettings( + &sbrConfig[el], elInfo[coreEl].bitRate, + elInfo[coreEl].nChannelsInEl, *coreSampleRate, inputSampleRate, + transformFactor, 24000, 0, 0, /* useSpeechConfig */ + 0, /* lcsMode */ + usePs, /* bParametricStereo */ + aot)) { + error = 1; + goto bail; + } + + /* Find common frequency border for all SBR elements */ + highestSbrStartFreq = + fixMax(highestSbrStartFreq, sbrConfig[el].startFreq); + highestSbrStopFreq = fixMax(highestSbrStopFreq, sbrConfig[el].stopFreq); + + } /* first element loop */ + + /* Set element count (can be less than core encoder element count) */ + hSbrEncoder->noElements = el + 1; + + FDKsbrEnc_Reallocate(hSbrEncoder, elInfo, noElements); + + for (el = 0; el < hSbrEncoder->noElements; el++) { + int bandwidth = *coreBandwidth; + + /* Use lowest common bandwidth */ + sbrConfig[el].startFreq = highestSbrStartFreq; + sbrConfig[el].stopFreq = highestSbrStopFreq; + + /* initialize SBR element, and get core bandwidth */ + error = FDKsbrEnc_EnvInit(hSbrEncoder->sbrElement[el], &sbrConfig[el], + &bandwidth, aot, el, headerPeriod, + statesInitFlag, hSbrEncoder->downsamplingMethod, + hSbrEncoder->dynamicRam); + + if (error != 0) { + error = 2; + goto bail; + } + + /* Get lowest core encoder bandwidth to be returned later. */ + lowestBandwidth = fixMin(lowestBandwidth, bandwidth); + + } /* second element loop */ + + /* Initialize a downsampler for each channel in each SBR element */ + if (hSbrEncoder->downsamplingMethod == SBRENC_DS_TIME) { + for (el = 0; el < hSbrEncoder->noElements; el++) { + HANDLE_SBR_ELEMENT hSbrEl = hSbrEncoder->sbrElement[el]; + INT Wc, ch; + + Wc = 500; /* Cutoff frequency with full bandwidth */ + + for (ch = 0; ch < hSbrEl->elInfo.nChannelsInEl; ch++) { + FDKaacEnc_InitDownsampler(&hSbrEl->sbrChannel[ch]->downSampler, Wc, + *downSampleFactor); + FDK_ASSERT(hSbrEl->sbrChannel[ch]->downSampler.delay <= + MAX_DS_FILTER_DELAY); + } + } /* third element loop */ + + /* lfe */ + FDKaacEnc_InitDownsampler(&hSbrEncoder->lfeDownSampler, 0, + *downSampleFactor); + } + + /* Get delay information */ + delayParam.dsDelay = + hSbrEncoder->sbrElement[0]->sbrChannel[0]->downSampler.delay; + delayParam.delay = *delay; + + error = sbrEncoder_Init_delay(coreFrameLength, *numChannels, + *downSampleFactor, lowDelay, usePs, is212, + downsamplingMethod, &delayParam); + + if (error != 0) { + error = 3; + goto bail; + } + + hSbrEncoder->nBitstrDelay = delayParam.bitstrDelay; + hSbrEncoder->sbrDecDelay = delayParam.sbrDecDelay; + hSbrEncoder->inputDataDelay = delayParam.delayInput2Core; + + /* Assign core encoder Bandwidth */ + *coreBandwidth = lowestBandwidth; + + /* Estimate sbr bitrate, 2.5 kBit/s per sbr channel */ + hSbrEncoder->estimateBitrate += 2500 * (*numChannels); + + /* Initialize bitstream buffer for each element */ + for (el = 0; el < hSbrEncoder->noElements; el++) { + FDKsbrEnc_bsBufInit(hSbrEncoder->sbrElement[el], delayParam.bitstrDelay); + } + + /* initialize parametric stereo */ + if (usePs) { + PSENC_CONFIG psEncConfig; + FDK_ASSERT(hSbrEncoder->noElements == 1); + INT psTuningTableIdx = getPsTuningTableIndex(elInfo[0].bitRate, NULL); + + psEncConfig.frameSize = coreFrameLength; // sbrConfig.sbrFrameSize; + psEncConfig.qmfFilterMode = 0; + psEncConfig.sbrPsDelay = 0; + + /* tuning parameters */ + if (psTuningTableIdx != INVALID_TABLE_IDX) { + psEncConfig.nStereoBands = psTuningTable[psTuningTableIdx].nStereoBands; + psEncConfig.maxEnvelopes = psTuningTable[psTuningTableIdx].nEnvelopes; + psEncConfig.iidQuantErrorThreshold = + (FIXP_DBL)psTuningTable[psTuningTableIdx].iidQuantErrorThreshold; + + /* calculation is not quite linear, increased number of envelopes causes + * more bits */ + /* assume avg. 50 bits per frame for 10 stereo bands / 1 envelope + * configuration */ + hSbrEncoder->estimateBitrate += + ((((*coreSampleRate) * 5 * psEncConfig.nStereoBands * + psEncConfig.maxEnvelopes) / + hSbrEncoder->frameSize)); + + } else { + error = ERROR(CDI, "Invalid ps tuning table index."); + goto bail; + } + + qmfInitSynthesisFilterBank( + &hSbrEncoder->qmfSynthesisPS, + (FIXP_DBL *)hSbrEncoder->qmfSynthesisPS.FilterStates, + hSbrEncoder->sbrElement[0]->sbrConfigData.noQmfSlots, + hSbrEncoder->sbrElement[0]->sbrConfigData.noQmfBands >> 1, + hSbrEncoder->sbrElement[0]->sbrConfigData.noQmfBands >> 1, + hSbrEncoder->sbrElement[0]->sbrConfigData.noQmfBands >> 1, + (statesInitFlag) ? 0 : QMF_FLAG_KEEP_STATES); + + if (errorInfo == noError) { + /* update delay */ + psEncConfig.sbrPsDelay = + FDKsbrEnc_GetEnvEstDelay(&hSbrEncoder->sbrElement[0] + ->sbrChannel[0] + ->hEnvChannel.sbrExtractEnvelope); + + errorInfo = + PSEnc_Init(hSbrEncoder->hParametricStereo, &psEncConfig, + hSbrEncoder->sbrElement[0]->sbrConfigData.noQmfSlots, + hSbrEncoder->sbrElement[0]->sbrConfigData.noQmfBands, + hSbrEncoder->dynamicRam); + } + } + + hSbrEncoder->downsampledOffset = delayParam.corePathOffset; + hSbrEncoder->bufferOffset = delayParam.sbrPathOffset; + *delay = delayParam.delay; + + { hSbrEncoder->downmixSize = coreFrameLength * (*numChannels); } + + /* Delay Compensation: fill bitstream delay buffer with zero input signal */ + if (hSbrEncoder->nBitstrDelay > 0) { + error = FDKsbrEnc_DelayCompensation(hSbrEncoder, inputBuffer, + inputBufferBufSize); + if (error != 0) goto bail; + } + + /* Set Output frame length */ + *frameLength = coreFrameLength * *downSampleFactor; + /* Input buffer offset */ + *inputBufferOffset = + fixMax(delayParam.sbrPathOffset, delayParam.corePathOffset); + } + + return error; + +bail: + /* Restore input settings */ + *coreSampleRate = inputSampleRate; + *frameLength = coreFrameLength; + *numChannels = inputChannels; + *coreBandwidth = inputBandWidth; + + return error; +} + +INT sbrEncoder_EncodeFrame(HANDLE_SBR_ENCODER hSbrEncoder, INT_PCM *samples, + UINT samplesBufSize, UINT sbrDataBits[(8)], + UCHAR sbrData[(8)][MAX_PAYLOAD_SIZE]) { + INT error; + int el; + + for (el = 0; el < hSbrEncoder->noElements; el++) { + if (hSbrEncoder->sbrElement[el] != NULL) { + error = FDKsbrEnc_EnvEncodeFrame( + hSbrEncoder, el, + samples + hSbrEncoder->downsampledOffset / hSbrEncoder->nChannels, + samplesBufSize, &sbrDataBits[el], sbrData[el], 0); + if (error) return error; + } + } + + error = FDKsbrEnc_Downsample( + hSbrEncoder, + samples + hSbrEncoder->downsampledOffset / hSbrEncoder->nChannels, + samplesBufSize, hSbrEncoder->nChannels, &sbrDataBits[el], sbrData[el], 0); + if (error) return error; + + return 0; +} + +INT sbrEncoder_UpdateBuffers(HANDLE_SBR_ENCODER hSbrEncoder, + INT_PCM *timeBuffer, UINT timeBufferBufSize) { + if (hSbrEncoder->downsampledOffset > 0) { + int c; + int nd = hSbrEncoder->downmixSize / hSbrEncoder->nChannels; + + for (c = 0; c < hSbrEncoder->nChannels; c++) { + /* Move delayed downsampled data */ + FDKmemcpy(timeBuffer + timeBufferBufSize * c, + timeBuffer + timeBufferBufSize * c + nd, + sizeof(INT_PCM) * + (hSbrEncoder->downsampledOffset / hSbrEncoder->nChannels)); + } + } else { + int c; + + for (c = 0; c < hSbrEncoder->nChannels; c++) { + /* Move delayed input data */ + FDKmemcpy( + timeBuffer + timeBufferBufSize * c, + timeBuffer + timeBufferBufSize * c + hSbrEncoder->frameSize, + sizeof(INT_PCM) * hSbrEncoder->bufferOffset / hSbrEncoder->nChannels); + } + } + if (hSbrEncoder->nBitstrDelay > 0) { + int el; + + for (el = 0; el < hSbrEncoder->noElements; el++) { + FDKmemmove( + hSbrEncoder->sbrElement[el]->payloadDelayLine[0], + hSbrEncoder->sbrElement[el]->payloadDelayLine[1], + sizeof(UCHAR) * (hSbrEncoder->nBitstrDelay * MAX_PAYLOAD_SIZE)); + + FDKmemmove(&hSbrEncoder->sbrElement[el]->payloadDelayLineSize[0], + &hSbrEncoder->sbrElement[el]->payloadDelayLineSize[1], + sizeof(UINT) * (hSbrEncoder->nBitstrDelay)); + } + } + return 0; +} + +INT sbrEncoder_SendHeader(HANDLE_SBR_ENCODER hSbrEncoder) { + INT error = -1; + if (hSbrEncoder) { + int el; + for (el = 0; el < hSbrEncoder->noElements; el++) { + if ((hSbrEncoder->noElements == 1) && + (hSbrEncoder->sbrElement[0]->elInfo.fParametricStereo == 1)) { + hSbrEncoder->sbrElement[el]->sbrBitstreamData.CountSendHeaderData = + hSbrEncoder->sbrElement[el]->sbrBitstreamData.NrSendHeaderData - 1; + } else { + hSbrEncoder->sbrElement[el]->sbrBitstreamData.CountSendHeaderData = 0; + } + } + error = 0; + } + return error; +} + +INT sbrEncoder_ContainsHeader(HANDLE_SBR_ENCODER hSbrEncoder) { + INT sbrHeader = 1; + if (hSbrEncoder) { + int el; + for (el = 0; el < hSbrEncoder->noElements; el++) { + sbrHeader &= + (hSbrEncoder->sbrElement[el]->sbrBitstreamData.HeaderActiveDelay == 1) + ? 1 + : 0; + } + } + return sbrHeader; +} + +INT sbrEncoder_GetHeaderDelay(HANDLE_SBR_ENCODER hSbrEncoder) { + INT delay = -1; + + if (hSbrEncoder) { + if ((hSbrEncoder->noElements == 1) && + (hSbrEncoder->sbrElement[0]->elInfo.fParametricStereo == 1)) { + delay = hSbrEncoder->nBitstrDelay + 1; + } else { + delay = hSbrEncoder->nBitstrDelay; + } + } + return delay; +} +INT sbrEncoder_GetBsDelay(HANDLE_SBR_ENCODER hSbrEncoder) { + INT delay = -1; + + if (hSbrEncoder) { + delay = hSbrEncoder->nBitstrDelay; + } + return delay; +} + +INT sbrEncoder_SAPPrepare(HANDLE_SBR_ENCODER hSbrEncoder) { + INT error = -1; + if (hSbrEncoder) { + int el; + for (el = 0; el < hSbrEncoder->noElements; el++) { + hSbrEncoder->sbrElement[el]->sbrBitstreamData.rightBorderFIX = 1; + } + error = 0; + } + return error; +} + +INT sbrEncoder_GetEstimateBitrate(HANDLE_SBR_ENCODER hSbrEncoder) { + INT estimateBitrate = 0; + + if (hSbrEncoder) { + estimateBitrate += hSbrEncoder->estimateBitrate; + } + + return estimateBitrate; +} + +INT sbrEncoder_GetInputDataDelay(HANDLE_SBR_ENCODER hSbrEncoder) { + INT delay = -1; + + if (hSbrEncoder) { + delay = hSbrEncoder->inputDataDelay; + } + return delay; +} + +INT sbrEncoder_GetSbrDecDelay(HANDLE_SBR_ENCODER hSbrEncoder) { + INT delay = -1; + + if (hSbrEncoder) { + delay = hSbrEncoder->sbrDecDelay; + } + return delay; +} + +INT sbrEncoder_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_SBRENC; + info->version = + LIB_VERSION(SBRENCODER_LIB_VL0, SBRENCODER_LIB_VL1, SBRENCODER_LIB_VL2); + LIB_VERSION_STRING(info); +#ifdef __ANDROID__ + info->build_date = ""; + info->build_time = ""; +#else + info->build_date = __DATE__; + info->build_time = __TIME__; +#endif + info->title = "SBR Encoder"; + + /* Set flags */ + info->flags = 0 | CAPF_SBR_HQ | CAPF_SBR_PS_MPEG; + /* End of flags */ + + return 0; +} |