| |
| /* ----------------------------------------------------------------------------------------------------------- |
| Software License for The Fraunhofer FDK AAC Codec Library for Android |
| |
| © Copyright 1995 - 2015 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 |
| ----------------------------------------------------------------------------------------------------------- */ |
| |
| /*************************** Fraunhofer IIS FDK Tools *********************** |
| |
| Author(s): Andreas Ehret, Tobias Chalupka |
| Description: SBR encoder top level processing. |
| |
| ******************************************************************************/ |
| |
| #include "sbr_encoder.h" |
| |
| #include "sbr_ram.h" |
| #include "sbr_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 3 |
| #define SBRENCODER_LIB_VL1 3 |
| #define SBRENCODER_LIB_VL2 12 |
| |
| |
| |
| /***************************************************************************/ |
| /* |
| * 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 (2) /* NO_POLY/2=2.5, rounded down to 2 */ |
| #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) |
| #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) |
| #define DELAY_ELDSBR(fl,dwnsmp) ( ( ((fl)/2)*(dwnsmp) ) - 1 + DELAY_QMF_POSTPROC(dwnsmp) ) |
| |
| /* Delay differences for SBR and SBR+PS */ |
| #define MAX_DS_FILTER_DELAY (5) /* the additional max downsampler filter delay (source fs) */ |
| #define DELAY_AAC2SBR(fl,dwnsmp) ((DELAY_QMF_ANA(dwnsmp) + DELAY_DEC_QMF(dwnsmp) + DELAY_QMF_SYN) - DELAY_SBR((fl),(dwnsmp))) |
| #define DELAY_ELD2SBR(fl,dwnsmp) ((DELAY_QMF_POSTPROC(dwnsmp)) - DELAY_ELDSBR(fl,dwnsmp)) |
| #define DELAY_AAC2PS(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) - 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_SAMPLE_DELAY (DELAY_AAC2SBR(1024,2) + MAX_DS_FILTER_DELAY) /* maximum delay: frame length of 1024 and dual-rate sbr */ |
| |
| /***************************************************************************/ |
| |
| |
| |
| #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)) { |
| bitRateClosestLower = bitrate; |
| bitRateClosestUpper = bitrate; |
| //FDKprintf("entry %d\n", i); |
| 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 (pBitRateClosest != NULL) |
| { |
| /* If there was at least one matching tuning entry found then 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 (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 confifuration |
| 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 > QMF_CHANNELS*QMF_MAX_TIME_SLOTS) ) |
| 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 */ |
| 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 interleaved */ |
| UINT timeInStride, /*!< time buffer channel interleaving 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, QMF_CHANNELS*2) |
| |
| |
| /* Obtain pointers to QMF buffers. */ |
| pQmfReal = sbrExtrEnv->rBuffer; |
| pQmfImag = sbrExtrEnv->iBuffer; |
| |
| qmfAnalysisFiltering( hSbrElement->hQmfAnalysis[ch], |
| pQmfReal, |
| pQmfImag, |
| &tmpScale, |
| samples + hSbrElement->elInfo.ChannelIndex[ch], |
| timeInStride, |
| qmfWorkBuffer ); |
| |
| h_envChan->qmfScale = tmpScale.lb_scale + 7; |
| |
| |
| C_AALLOC_SCRATCH_END(qmfWorkBuffer, FIXP_DBL, QMF_CHANNELS*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],samples + hSbrElement->elInfo.ChannelIndex[1]}; |
| error = FDKsbrEnc_PSEnc_ParametricStereoProcessing( hEnvEncoder->hParametricStereo, |
| pSamples, |
| timeInStride, |
| hSbrElement->hQmfAnalysis, |
| sbrExtrEnv->rBuffer, |
| sbrExtrEnv->iBuffer, |
| samples + hSbrElement->elInfo.ChannelIndex[ch], |
| &hEnvEncoder->qmfSynthesisPS, |
| &qmfScale, |
| psHeaderActive ); |
| if (noError != error) |
| { |
| error = handBack(error); |
| } |
| 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->sbrChannel[1]->hEnvChannel, |
| &hSbrElement->CmonData, |
| eData, |
| fData, |
| clearOutput |
| ); |
| |
| /* |
| 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); |
| |
| |
| } |
| |
| |
| /*******************************/ |
| |
| if (hEnvEncoder->fTimeDomainDownsampling) |
| { |
| int ch; |
| int nChannels = hSbrElement->sbrConfigData.nChannels; |
| |
| for (ch=0; ch < nChannels; ch++) |
| { |
| INT nOutSamples; |
| |
| FDKaacEnc_Downsample(&hSbrElement->sbrChannel[ch]->downSampler, |
| samples + hSbrElement->elInfo.ChannelIndex[ch] + hEnvEncoder->bufferOffset, |
| hSbrElement->sbrConfigData.frameSize, |
| timeInStride, |
| samples + hSbrElement->elInfo.ChannelIndex[ch], |
| &nOutSamples, |
| hEnvEncoder->nChannels); |
| } |
| } /* downsample */ |
| |
| |
| 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)); |
| |
| hSbrEncoder->pSBRdynamic_RAM = (UCHAR*)GetRam_SbrDynamic_RAM(); |
| hSbrEncoder->dynamicRam = hSbrEncoder->pSBRdynamic_RAM; |
| |
| 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; |
| } |
| } |
| |
| 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; |
| } |
| |
| } |
| |
| 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; |
| } |
| } |
| |
| 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; |
| } /* coreEl */ |
| |
| 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 nBitstrDelay, |
| int nElement, |
| const int headerPeriod, |
| ULONG statesInitFlag, |
| int fTimeDomainDownsampling |
| ,UCHAR *dynamic_RAM |
| ) |
| { |
| UCHAR *bitstreamBuffer; |
| int ch, i; |
| |
| if ((params->codecSettings.nChannels < 1) || (params->codecSettings.nChannels > MAX_NUM_CHANNELS)){ |
| return(1); |
| } |
| |
| /* initialize the encoder handle and structs*/ |
| bitstreamBuffer = hSbrElement->payloadDelayLine[nBitstrDelay]; |
| |
| /* 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 = QMF_CHANNELS>>(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); |
| } |
| |
| FDKinitBitStream(&hSbrElement->CmonData.sbrBitbuf, bitstreamBuffer, MAX_PAYLOAD_SIZE*sizeof(UCHAR), 0, BS_WRITER); |
| |
| /* |
| now initialize sbrConfigData, sbrHeaderData and sbrBitstreamData, |
| */ |
| hSbrElement->sbrConfigData.nChannels = params->codecSettings.nChannels; |
| |
| if(params->codecSettings.nChannels == 2) |
| 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->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 |
| ) |
| { |
| 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->sbrElement[el]->sbrConfigData.nChannels, |
| NULL, |
| NULL, |
| 1 |
| )) |
| return -1; |
| } |
| sbrEncoder_UpdateBuffers(hEnvEnc, timeBuffer); |
| } |
| return 0; |
| } |
| |
| UINT sbrEncoder_LimitBitRate(UINT bitRate, UINT numChannels, UINT coreSampleRate, AUDIO_OBJECT_TYPE aot) |
| { |
| UINT newBitRate; |
| INT index; |
| |
| FDK_ASSERT(numChannels > 0 && numChannels <= 2); |
| if (aot == AOT_PS) { |
| if (numChannels == 2) { |
| index = getPsTuningTableIndex(bitRate, &newBitRate); |
| if (index == INVALID_TABLE_IDX) { |
| bitRate = newBitRate; |
| } |
| /* Set numChannels to 1 because for PS we need a SBR SCE (mono) element. */ |
| numChannels = 1; |
| } 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; |
| } |
| |
| INT sbrEncoder_Init( |
| HANDLE_SBR_ENCODER hSbrEncoder, |
| SBR_ELEMENT_INFO elInfo[(8)], |
| int noElements, |
| INT_PCM *inputBuffer, |
| INT *coreBandwidth, |
| INT *inputBufferOffset, |
| INT *numChannels, |
| 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; |
| |
| int downsampledOffset = 0; |
| int sbrOffset = 0; |
| int downsamplerDelay = 0; |
| int timeDomainDownsample = 0; |
| int nBitstrDelay = 0; |
| int highestSbrStartFreq, highestSbrStopFreq; |
| int lowDelay = 0; |
| int usePs = 0; |
| |
| /* check whether SBR setting is available for the current encoder configuration (bitrate, samplerate) */ |
| if (!sbrEncoder_IsSingleRatePossible(aot)) { |
| *downSampleFactor = 2; |
| } |
| |
| |
| |
| if ( aot==AOT_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; |
| break; |
| case 2: |
| *coreSampleRate = inputSampleRate>>1; |
| break; |
| default: |
| *coreSampleRate = inputSampleRate>>1; |
| return 0; /* return error */ |
| } |
| |
| /* check whether SBR setting is available for the current encoder configuration (bitrate, coreSampleRate) */ |
| { |
| int delayDiff = 0; |
| 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; |
| } |
| } |
| |
| /* Determine Delay balancing and new encoder delay */ |
| if (lowDelay) { |
| { |
| delayDiff = (*delay * *downSampleFactor) + DELAY_ELD2SBR(coreFrameLength,*downSampleFactor); |
| *delay = DELAY_ELDSBR(coreFrameLength,*downSampleFactor); |
| } |
| } |
| else if (usePs) { |
| delayDiff = (*delay * *downSampleFactor) + DELAY_AAC2PS(coreFrameLength,*downSampleFactor); |
| *delay = DELAY_PS(coreFrameLength,*downSampleFactor); |
| } |
| else { |
| delayDiff = DELAY_AAC2SBR(coreFrameLength,*downSampleFactor); |
| delayDiff += (*delay * *downSampleFactor); |
| *delay = DELAY_SBR(coreFrameLength,*downSampleFactor); |
| } |
| |
| if (!usePs) { |
| timeDomainDownsample = *downSampleFactor-1; /* activate time domain downsampler when downSampleFactor is != 1 */ |
| } |
| |
| |
| /* Take care about downsampled data bound to the SBR path */ |
| if (!timeDomainDownsample && delayDiff > 0) { |
| /* |
| * We must tweak the balancing into a situation where the downsampled path |
| * is the one to be delayed, because delaying the QMF domain input, also delays |
| * the downsampled audio, counteracting to the purpose of delay balancing. |
| */ |
| while ( delayDiff > 0 ) |
| { |
| /* Encoder delay increases */ |
| { |
| *delay += coreFrameLength * *downSampleFactor; |
| /* Add one frame delay to SBR path */ |
| delayDiff -= coreFrameLength * *downSampleFactor; |
| } |
| nBitstrDelay += 1; |
| } |
| } else |
| { |
| *delay += fixp_abs(delayDiff); |
| } |
| |
| if (delayDiff < 0) { |
| /* Delay AAC data */ |
| delayDiff = -delayDiff; |
| /* Multiply downsampled offset by AAC core channels. Divide by 2 because of half samplerate of downsampled data. */ |
| FDK_ASSERT(*downSampleFactor>0 && *downSampleFactor<=2); |
| downsampledOffset = (delayDiff*(*numChannels))>>(*downSampleFactor-1); |
| sbrOffset = 0; |
| } else { |
| /* Delay SBR input */ |
| if ( delayDiff > (int)coreFrameLength * (int)*downSampleFactor ) |
| { |
| /* Do bitstream frame-wise delay balancing if we have more than SBR framelength samples delay difference */ |
| delayDiff -= coreFrameLength * *downSampleFactor; |
| nBitstrDelay = 1; |
| } |
| /* Multiply input offset by input channels */ |
| sbrOffset = delayDiff*(*numChannels); |
| downsampledOffset = 0; |
| } |
| hSbrEncoder->nBitstrDelay = nBitstrDelay; |
| hSbrEncoder->nChannels = *numChannels; |
| hSbrEncoder->frameSize = coreFrameLength * *downSampleFactor; |
| hSbrEncoder->fTimeDomainDownsampling = timeDomainDownsample; |
| hSbrEncoder->downSampleFactor = *downSampleFactor; |
| hSbrEncoder->estimateBitrate = 0; |
| hSbrEncoder->inputDataDelay = 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, |
| nBitstrDelay, |
| el, |
| headerPeriod, |
| statesInitFlag, |
| hSbrEncoder->fTimeDomainDownsampling |
| ,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->fTimeDomainDownsampling) |
| { |
| for (el=0; el<hSbrEncoder->noElements; el++) |
| { |
| HANDLE_SBR_ELEMENT hSbrEl = hSbrEncoder->sbrElement[el]; |
| INT Wc, ch; |
| |
| /* Calculated required normalized cutoff frequency (Wc = 1.0 -> lowestBandwidth = inputSampleRate/2) */ |
| Wc = (2*lowestBandwidth)*1000 / inputSampleRate; |
| |
| 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); |
| } |
| |
| downsamplerDelay = hSbrEl->sbrChannel[0]->downSampler.delay; |
| } /* third element loop */ |
| |
| /* lfe */ |
| FDKaacEnc_InitDownsampler (&hSbrEncoder->lfeDownSampler, 0, *downSampleFactor); |
| |
| /* Add the resampler additional delay to get the final delay and buffer offset values. */ |
| if (sbrOffset > 0 || downsampledOffset <= ((downsamplerDelay * (*numChannels))>>(*downSampleFactor-1))) { |
| sbrOffset += (downsamplerDelay - downsampledOffset) * (*numChannels) ; |
| *delay += downsamplerDelay - downsampledOffset; |
| downsampledOffset = 0; |
| } else { |
| downsampledOffset -= (downsamplerDelay * (*numChannels))>>(*downSampleFactor-1); |
| sbrOffset = 0; |
| } |
| |
| hSbrEncoder->inputDataDelay = downsamplerDelay; |
| } |
| |
| /* Assign core encoder Bandwidth */ |
| *coreBandwidth = lowestBandwidth; |
| |
| /* Estimate sbr bitrate, 2.5 kBit/s per sbr channel */ |
| hSbrEncoder->estimateBitrate += 2500 * (*numChannels); |
| |
| /* 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); |
| |
| if(noError != (errorInfo = PSEnc_Init( hSbrEncoder->hParametricStereo, |
| &psEncConfig, |
| hSbrEncoder->sbrElement[0]->sbrConfigData.noQmfSlots, |
| hSbrEncoder->sbrElement[0]->sbrConfigData.noQmfBands |
| ,hSbrEncoder->dynamicRam |
| ))) |
| { |
| errorInfo = handBack(errorInfo); |
| } |
| } |
| |
| /* QMF analysis + Hybrid analysis + Hybrid synthesis + QMF synthesis + downsampled input buffer delay */ |
| hSbrEncoder->inputDataDelay = (64*10/2) + (6*64) + (0) + (64*10/2-64+1) + ((*downSampleFactor)*downsampledOffset); |
| } |
| |
| hSbrEncoder->downsampledOffset = downsampledOffset; |
| { |
| hSbrEncoder->downmixSize = coreFrameLength*(*numChannels); |
| } |
| |
| hSbrEncoder->bufferOffset = sbrOffset; |
| /* Delay Compensation: fill bitstream delay buffer with zero input signal */ |
| if ( hSbrEncoder->nBitstrDelay > 0 ) |
| { |
| error = FDKsbrEnc_DelayCompensation (hSbrEncoder, inputBuffer); |
| if (error != 0) |
| goto bail; |
| } |
| |
| /* Set Output frame length */ |
| *frameLength = coreFrameLength * *downSampleFactor; |
| /* Input buffer offset */ |
| *inputBufferOffset = fixMax(sbrOffset, downsampledOffset); |
| |
| |
| } |
| |
| 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 timeInStride, |
| 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, |
| timeInStride, |
| &sbrDataBits[el], |
| sbrData[el], |
| 0 |
| ); |
| if (error) |
| return error; |
| } |
| } |
| |
| if ( ( hSbrEncoder->lfeChIdx!=-1) && (hSbrEncoder->downSampleFactor > 1) ) |
| { /* lfe downsampler */ |
| INT nOutSamples; |
| |
| FDKaacEnc_Downsample(&hSbrEncoder->lfeDownSampler, |
| samples + hSbrEncoder->downsampledOffset + hSbrEncoder->bufferOffset + hSbrEncoder->lfeChIdx, |
| hSbrEncoder->frameSize, |
| timeInStride, |
| samples + hSbrEncoder->downsampledOffset + hSbrEncoder->lfeChIdx, |
| &nOutSamples, |
| hSbrEncoder->nChannels); |
| |
| |
| } |
| |
| return 0; |
| } |
| |
| |
| INT sbrEncoder_UpdateBuffers( |
| HANDLE_SBR_ENCODER hSbrEncoder, |
| INT_PCM *timeBuffer |
| ) |
| { |
| if ( hSbrEncoder->downsampledOffset > 0 ) { |
| /* Move delayed downsampled data */ |
| FDKmemcpy ( timeBuffer, |
| timeBuffer + hSbrEncoder->downmixSize, |
| sizeof(INT_PCM) * (hSbrEncoder->downsampledOffset) ); |
| } else { |
| /* Move delayed input data */ |
| FDKmemcpy ( timeBuffer, |
| timeBuffer + hSbrEncoder->nChannels * hSbrEncoder->frameSize, |
| sizeof(INT_PCM) * hSbrEncoder->bufferOffset ); |
| } |
| 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_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_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; |
| } |