diff options
author | Fraunhofer IIS FDK <audio-fdk@iis.fraunhofer.de> | 2018-02-26 20:17:00 +0100 |
---|---|---|
committer | Jean-Michel Trivi <jmtrivi@google.com> | 2018-04-19 11:21:15 -0700 |
commit | 6cfabd35363c3ef5e3b209b867169a500b3ccc3c (patch) | |
tree | 01c0a19f2735e8b5d2407555fe992d4230d089eb /libSACenc/src/sacenc_lib.cpp | |
parent | 6288a1e34c4dede4c2806beb1736ece6580558c7 (diff) | |
download | fdk-aac-6cfabd35363c3ef5e3b209b867169a500b3ccc3c.tar.gz fdk-aac-6cfabd35363c3ef5e3b209b867169a500b3ccc3c.tar.bz2 fdk-aac-6cfabd35363c3ef5e3b209b867169a500b3ccc3c.zip |
Upgrade to FDKv2
Bug: 71430241
Test: CTS DecoderTest and DecoderTestAacDrc
original-Change-Id: Iaa20f749b8a04d553b20247cfe1a8930ebbabe30
Apply clang-format also on header files.
original-Change-Id: I14de1ef16bbc79ec0283e745f98356a10efeb2e4
Fixes for MPEG-D DRC
original-Change-Id: If1de2d74bbbac84b3f67de3b88b83f6a23b8a15c
Catch unsupported tw_mdct at an early stage
original-Change-Id: Ied9dd00d754162a0e3ca1ae3e6b854315d818afe
Fixing PVC transition frames
original-Change-Id: Ib75725abe39252806c32d71176308f2c03547a4e
Move qmf bands sanity check
original-Change-Id: Iab540c3013c174d9490d2ae100a4576f51d8dbc4
Initialize scaling variable
original-Change-Id: I3c4087101b70e998c71c1689b122b0d7762e0f9e
Add 16 qmf band configuration to getSlotNrgHQ()
original-Change-Id: I49a5d30f703a1b126ff163df9656db2540df21f1
Always apply byte alignment at the end of the AudioMuxElement
original-Change-Id: I42d560287506d65d4c3de8bfe3eb9a4ebeb4efc7
Setup SBR element only if no parse error exists
original-Change-Id: I1915b73704bc80ab882b9173d6bec59cbd073676
Additional array index check in HCR
original-Change-Id: I18cc6e501ea683b5009f1bbee26de8ddd04d8267
Fix fade-in index selection in concealment module
original-Change-Id: Ibf802ed6ed8c05e9257e1f3b6d0ac1162e9b81c1
Enable explicit backward compatible parser for AAC_LD
original-Change-Id: I27e9c678dcb5d40ed760a6d1e06609563d02482d
Skip spatial specific config in explicit backward compatible ASC
original-Change-Id: Iff7cc365561319e886090cedf30533f562ea4d6e
Update flags description in decoder API
original-Change-Id: I9a5b4f8da76bb652f5580cbd3ba9760425c43830
Add QMF domain reset function
original-Change-Id: I4f89a8a2c0277d18103380134e4ed86996e9d8d6
DRC upgrade v2.1.0
original-Change-Id: I5731c0540139dab220094cd978ef42099fc45b74
Fix integer overflow in sqrtFixp_lookup()
original-Change-Id: I429a6f0d19aa2cc957e0f181066f0ca73968c914
Fix integer overflow in invSqrtNorm2()
original-Change-Id: I84de5cbf9fb3adeb611db203fe492fabf4eb6155
Fix integer overflow in GenerateRandomVector()
original-Change-Id: I3118a641008bd9484d479e5b0b1ee2b5d7d44d74
Fix integer overflow in adjustTimeSlot_EldGrid()
original-Change-Id: I29d503c247c5c8282349b79df940416a512fb9d5
Fix integer overflow in FDKsbrEnc_codeEnvelope()
original-Change-Id: I6b34b61ebb9d525b0c651ed08de2befc1f801449
Follow-up on: Fix integer overflow in adjustTimeSlot_EldGrid()
original-Change-Id: I6f8f578cc7089e5eb7c7b93e580b72ca35ad689a
Fix integer overflow in get_pk_v2()
original-Change-Id: I63375bed40d45867f6eeaa72b20b1f33e815938c
Fix integer overflow in Syn_filt_zero()
original-Change-Id: Ie0c02fdfbe03988f9d3b20d10cd9fe4c002d1279
Fix integer overflow in CFac_CalcFacSignal()
original-Change-Id: Id2d767c40066c591b51768e978eb8af3b803f0c5
Fix integer overflow in FDKaacEnc_FDKaacEnc_calcPeNoAH()
original-Change-Id: Idcbd0f4a51ae2550ed106aa6f3d678d1f9724841
Fix integer overflow in sbrDecoder_calculateGainVec()
original-Change-Id: I7081bcbe29c5cede9821b38d93de07c7add2d507
Fix integer overflow in CLpc_SynthesisLattice()
original-Change-Id: I4a95ddc18de150102352d4a1845f06094764c881
Fix integer overflow in Pred_Lt4()
original-Change-Id: I4dbd012b2de7d07c3e70a47b92e3bfae8dbc750a
Fix integer overflow in FDKsbrEnc_InitSbrFastTransientDetector()
original-Change-Id: I788cbec1a4a00f44c2f3a72ad7a4afa219807d04
Fix unsigned integer overflow in FDKaacEnc_WriteBitstream()
original-Change-Id: I68fc75166e7d2cd5cd45b18dbe3d8c2a92f1822a
Fix unsigned integer overflow in FDK_MetadataEnc_Init()
original-Change-Id: Ie8d025f9bcdb2442c704bd196e61065c03c10af4
Fix overflow in pseudo random number generators
original-Change-Id: I3e2551ee01356297ca14e3788436ede80bd5513c
Fix unsigned integer overflow in sbrDecoder_Parse()
original-Change-Id: I3f231b2f437e9c37db4d5b964164686710eee971
Fix unsigned integer overflow in longsub()
original-Change-Id: I73c2bc50415cac26f1f5a29e125bbe75f9180a6e
Fix unsigned integer overflow in CAacDecoder_DecodeFrame()
original-Change-Id: Ifce2db4b1454b46fa5f887e9d383f1cc43b291e4
Fix overflow at CLpdChannelStream_Read()
original-Change-Id: Idb9d822ce3a4272e4794b643644f5434e2d4bf3f
Fix unsigned integer overflow in Hcr_State_BODY_SIGN_ESC__ESC_WORD()
original-Change-Id: I1ccf77c0015684b85534c5eb97162740a870b71c
Fix unsigned integer overflow in UsacConfig_Parse()
original-Change-Id: Ie6d27f84b6ae7eef092ecbff4447941c77864d9f
Fix unsigned integer overflow in aacDecoder_drcParse()
original-Change-Id: I713f28e883eea3d70b6fa56a7b8f8c22bcf66ca0
Fix unsigned integer overflow in aacDecoder_drcReadCompression()
original-Change-Id: Ia34dfeb88c4705c558bce34314f584965cafcf7a
Fix unsigned integer overflow in CDataStreamElement_Read()
original-Change-Id: Iae896cc1d11f0a893d21be6aa90bd3e60a2c25f0
Fix unsigned integer overflow in transportDec_AdjustEndOfAccessUnit()
original-Change-Id: I64cf29a153ee784bb4a16fdc088baabebc0007dc
Fix unsigned integer overflow in transportDec_GetAuBitsRemaining()
original-Change-Id: I975b3420faa9c16a041874ba0db82e92035962e4
Fix unsigned integer overflow in extractExtendedData()
original-Change-Id: I2a59eb09e2053cfb58dfb75fcecfad6b85a80a8f
Fix signed integer overflow in CAacDecoder_ExtPayloadParse()
original-Change-Id: I4ad5ca4e3b83b5d964f1c2f8c5e7b17c477c7929
Fix unsigned integer overflow in CAacDecoder_DecodeFrame()
original-Change-Id: I29a39df77d45c52a0c9c5c83c1ba81f8d0f25090
Follow-up on: Fix integer overflow in CLpc_SynthesisLattice()
original-Change-Id: I8fb194ffc073a3432a380845be71036a272d388f
Fix signed integer overflow in _interpolateDrcGain()
original-Change-Id: I879ec9ab14005069a7c47faf80e8bc6e03d22e60
Fix unsigned integer overflow in FDKreadBits()
original-Change-Id: I1f47a6a8037ff70375aa8844947d5681bb4287ad
Fix unsigned integer overflow in FDKbyteAlign()
original-Change-Id: Id5f3a11a0c9e50fc6f76ed6c572dbd4e9f2af766
Fix unsigned integer overflow in FDK_get32()
original-Change-Id: I9d33b8e97e3d38cbb80629cb859266ca0acdce96
Fix unsigned integer overflow in FDK_pushBack()
original-Change-Id: Ic87f899bc8c6acf7a377a8ca7f3ba74c3a1e1c19
Fix unsigned integer overflow in FDK_pushForward()
original-Change-Id: I3b754382f6776a34be1602e66694ede8e0b8effc
Fix unsigned integer overflow in ReadPsData()
original-Change-Id: I25361664ba8139e32bbbef2ca8c106a606ce9c37
Fix signed integer overflow in E_UTIL_residu()
original-Change-Id: I8c3abd1f437ee869caa8fb5903ce7d3d641b6aad
REVERT: Follow-up on: Integer overflow in CLpc_SynthesisLattice().
original-Change-Id: I3d340099acb0414795c8dfbe6362bc0a8f045f9b
Follow-up on: Fix integer overflow in CLpc_SynthesisLattice()
original-Change-Id: I4aedb8b3a187064e9f4d985175aa55bb99cc7590
Follow-up on: Fix unsigned integer overflow in aacDecoder_drcParse()
original-Change-Id: I2aa2e13916213bf52a67e8b0518e7bf7e57fb37d
Fix integer overflow in acelp
original-Change-Id: Ie6390c136d84055f8b728aefbe4ebef6e029dc77
Fix unsigned integer overflow in aacDecoder_UpdateBitStreamCounters()
original-Change-Id: I391ffd97ddb0b2c184cba76139bfb356a3b4d2e2
Adjust concealment default settings
original-Change-Id: I6a95db935a327c47df348030bcceafcb29f54b21
Saturate estimatedStartPos
original-Change-Id: I27be2085e0ae83ec9501409f65e003f6bcba1ab6
Negative shift exponent in _interpolateDrcGain()
original-Change-Id: I18edb26b26d002aafd5e633d4914960f7a359c29
Negative shift exponent in calculateICC()
original-Change-Id: I3dcd2ae98d2eb70ee0d59750863cbb2a6f4f8aba
Too large shift exponent in FDK_put()
original-Change-Id: Ib7d9aaa434d2d8de4a13b720ca0464b31ca9b671
Too large shift exponent in CalcInvLdData()
original-Change-Id: I43e6e78d4cd12daeb1dcd5d82d1798bdc2550262
Member access within null pointer of type SBR_CHANNEL
original-Change-Id: Idc5e4ea8997810376d2f36bbdf628923b135b097
Member access within null pointer of type CpePersistentData
original-Change-Id: Ib6c91cb0d37882768e5baf63324e429589de0d9d
Member access within null pointer FDKaacEnc_psyMain()
original-Change-Id: I7729b7f4479970531d9dc823abff63ca52e01997
Member access within null pointer FDKaacEnc_GetPnsParam()
original-Change-Id: I9aa3b9f3456ae2e0f7483dbd5b3dde95fc62da39
Member access within null pointer FDKsbrEnc_EnvEncodeFrame()
original-Change-Id: I67936f90ea714e90b3e81bc0dd1472cc713eb23a
Add HCR sanity check
original-Change-Id: I6c1d9732ebcf6af12f50b7641400752f74be39f7
Fix memory issue for HBE edge case with 8:3 SBR
original-Change-Id: I11ea58a61e69fbe8bf75034b640baee3011e63e9
Additional SBR parametrization sanity check for ELD
original-Change-Id: Ie26026fbfe174c2c7b3691f6218b5ce63e322140
Add MPEG-D DRC channel layout check
original-Change-Id: Iea70a74f171b227cce636a9eac4ba662777a2f72
Additional out-of-bounds checks in MPEG-D DRC
original-Change-Id: Ife4a8c3452c6fde8a0a09e941154a39a769777d4
Change-Id: Ic63cb2f628720f54fe9b572b0cb528e2599c624e
Diffstat (limited to 'libSACenc/src/sacenc_lib.cpp')
-rw-r--r-- | libSACenc/src/sacenc_lib.cpp | 2042 |
1 files changed, 2042 insertions, 0 deletions
diff --git a/libSACenc/src/sacenc_lib.cpp b/libSACenc/src/sacenc_lib.cpp new file mode 100644 index 0000000..d6a1658 --- /dev/null +++ b/libSACenc/src/sacenc_lib.cpp @@ -0,0 +1,2042 @@ +/* ----------------------------------------------------------------------------- +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 +----------------------------------------------------------------------------- */ + +/*********************** MPEG surround encoder library ************************* + + Author(s): Max Neuendorf + + Description: Encoder Library Interface + Interface to Spacial Audio Coding Encoder lib + +*******************************************************************************/ + +/**************************************************************************** +\file +Description of file contents +******************************************************************************/ + +/* Includes ******************************************************************/ +#include "sacenc_lib.h" +#include "sacenc_const.h" +#include "genericStds.h" +#include "FDK_core.h" +#include "sacenc_tree.h" +#include "sacenc_bitstream.h" +#include "sacenc_onsetdetect.h" +#include "sacenc_framewindowing.h" +#include "sacenc_filter.h" +#include "sacenc_paramextract.h" +#include "sacenc_staticgain.h" +#include "sacenc_delay.h" +#include "sacenc_dmx_tdom_enh.h" +#include "sacenc_vectorfunctions.h" +#include "qmf.h" + +/* Defines *******************************************************************/ + +/* Encoder library info */ +#define SACENC_LIB_VL0 2 +#define SACENC_LIB_VL1 0 +#define SACENC_LIB_VL2 0 +#define SACENC_LIB_TITLE "MPEG Surround Encoder" +#ifdef __ANDROID__ +#define SACENC_LIB_BUILD_DATE "" +#define SACENC_LIB_BUILD_TIME "" +#else +#define SACENC_LIB_BUILD_DATE __DATE__ +#define SACENC_LIB_BUILD_TIME __TIME__ +#endif + +#define MAX_MPEGS_BYTES (1 << 14) +#define MAX_SSC_BYTES (1 << 6) + +#define MAX_SPACE_TREE_CHANNELS 2 +#define NUM_KEEP_WINDOWS 3 + +/* Data Types ****************************************************************/ +typedef struct { + MP4SPACEENC_MODE encMode; + MP4SPACEENC_BANDS_CONFIG nParamBands; + MP4SPACEENC_QUANTMODE quantMode; + UCHAR bUseCoarseQuant; + UCHAR bLdMode; + UCHAR bTimeDomainDmx; + UINT sampleRate; + UINT frameTimeSlots; /* e.g. 32 when used with HE-AAC */ + UINT independencyFactor; /* how often should we set the independency flag */ + INT timeAlignment; /* additional delay for downmix */ + +} MP4SPACEENC_SETUP, *HANDLE_MP4SPACEENC_SETUP; + +struct ENC_CONFIG_SETUP { + UCHAR bEncMode_212; + UCHAR maxHybridInStaticSlots; + LONG maxSamplingrate; + INT maxAnalysisLengthTimeSlots; + INT maxHybridBands; + INT maxQmfBands; + INT maxChIn; + INT maxFrameTimeSlots; + INT maxFrameLength; + INT maxChOut; + INT maxChTotOut; +}; + +struct MP4SPACE_ENCODER { + MP4SPACEENC_SETUP user; + + ENC_CONFIG_SETUP setup; /* describe allocated instance */ + + HANDLE_FRAMEWINDOW + hFrameWindow; /* Windowing, only created+updated, but not used */ + INT nSamplesValid; /* Input Buffer Handling */ + + /* Routing Sensible Switches/Variables */ + MP4SPACEENC_BANDS_CONFIG nParamBands; + UCHAR useTimeDomDownmix; + + /* not Routing Sensible Switches/Varibles - must be contained in Check */ + MP4SPACEENC_MODE encMode; + UCHAR bEncMode_212_only; + + /* not Routing Sensible Switches/Varibles + lower Classes */ + UCHAR useFrameKeep; + UINT independencyFactor; + UINT nSampleRate; + UCHAR nInputChannels; + UCHAR nOutputChannels; + UCHAR nFrameTimeSlots; /* e.g. 32 when used with HE-AAC */ + UCHAR nQmfBands; + UCHAR nHybridBands; + UINT nFrameLength; /* number of output waveform samples/channel/frame */ + + /* not Routing Sensible Switches/Varibles + lower Classes, secondary computed + */ + INT nSamplesNext; + INT nAnalysisLengthTimeSlots; + INT nAnalysisLookaheadTimeSlots; + INT nUpdateHybridPositionTimeSlots; + INT *pnOutputBits; + INT nInputDelay; + INT nOutputBufferDelay; + INT nSurroundAnalysisBufferDelay; + INT nBitstreamDelayBuffer; + INT nBitstreamBufferRead; + INT nBitstreamBufferWrite; + INT nDiscardOutFrames; + INT avoid_keep; + + /* not Routing Sensible Switches/Varibles -> moved to lower Classes */ + UCHAR useCoarseQuantCld; /* Only Used in SpaceTreeSetup */ + UCHAR useCoarseQuantIcc; /* Only Used in SpaceTreeSetup */ + UCHAR useCoarseQuantCpc; /* Only Used in SpaceTreeSetup */ + UCHAR useCoarseQuantArbDmx; /* ArbitraryDmx,... not available yet */ + MP4SPACEENC_QUANTMODE + quantMode; /* Used for quanitzation and in bitstream writer */ + INT coreCoderDelay; /* Used in delay compensation */ + INT timeAlignment; /* Used in delay compensation */ + + /* Local Processing Variables */ + INT independencyCount; + INT independencyFlag; + INT **ppTrCurrPos; /* belongs somehow to Onset Detection */ + INT trPrevPos[2 * MAX_NUM_TRANS]; /* belongs somehow to Onset Detection */ + + FRAMEWIN_LIST frameWinList; + SPATIALFRAME saveFrame; + + /* Module-Handles */ + SPACE_TREE_SETUP spaceTreeSetup; + MPEG4SPACEENC_SSCBUF sscBuf; + FIXP_WIN *pFrameWindowAna__FDK[MAX_NUM_PARAMS]; + HANDLE_QMF_FILTER_BANK *phQmfFiltIn__FDK; + HANDLE_DC_FILTER phDCFilterSigIn[SACENC_MAX_INPUT_CHANNELS]; + HANDLE_ONSET_DETECT phOnset[SACENC_MAX_INPUT_CHANNELS]; + HANDLE_SPACE_TREE hSpaceTree; + HANDLE_BSF_INSTANCE hBitstreamFormatter; + HANDLE_STATIC_GAIN_CONFIG hStaticGainConfig; + HANDLE_STATIC_GAIN hStaticGain; + HANDLE_DELAY hDelay; + + /* enhanced time domain downmix (for stereo input) */ + HANDLE_ENHANCED_TIME_DOMAIN_DMX hEnhancedTimeDmx; + + /* Data Buffers */ + INT_PCM **ppTimeSigIn__FDK; + INT_PCM **ppTimeSigDelayIn__FDK; + INT_PCM **ppTimeSigOut__FDK; + FIXP_DPK ***pppHybridIn__FDK; + FIXP_DPK ***pppHybridInStatic__FDK; + FIXP_DPK ***pppProcDataIn__FDK; + INT_PCM *pOutputDelayBuffer__FDK; + + UCHAR **ppBitstreamDelayBuffer; + + UCHAR *pParameterBand2HybridBandOffset; + INT staticGainScale; + + INT *pEncoderInputChScale; + INT *staticTimeDomainDmxInScale; +}; + +/* Constants *****************************************************************/ +static const UCHAR pValidBands_Ld[8] = {4, 5, 7, 9, 12, 15, 23, 40}; + +static const UCHAR qmf2qmf[] = /* Bypass the HybridAnylyis/Synthesis*/ + {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, + 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, + 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, + 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, + 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, + 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, + 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, + 120, 121, 122, 123, 124, 125, 126, 127}; + +/* Function / Class Declarations *********************************************/ +static FDK_SACENC_ERROR mp4SpaceEnc_create( + HANDLE_MP4SPACE_ENCODER *phMp4SpaceEnc); + +static FDK_SACENC_ERROR FillSpatialSpecificConfig( + const HANDLE_MP4SPACE_ENCODER hEnc, SPATIALSPECIFICCONFIG *const hSsc); + +static FDK_SACENC_ERROR mp4SpaceEnc_FillSpaceTreeSetup( + const HANDLE_MP4SPACE_ENCODER hEnc, + SPACE_TREE_SETUP *const hSpaceTreeSetup); + +static FDK_SACENC_ERROR mp4SpaceEnc_InitDelayCompensation( + HANDLE_MP4SPACE_ENCODER hMp4SpaceEnc, const INT coreCoderDelay); + +static FDK_SACENC_ERROR mp4SpaceEnc_InitDefault( + HANDLE_MP4SPACE_ENCODER hMp4SpaceEnc); + +static DECORRCONFIG mp4SpaceEnc_GetDecorrConfig(const MP4SPACEENC_MODE encMode); + +static FDK_SACENC_ERROR mp4SpaceEnc_InitNumParamBands( + HANDLE_MP4SPACE_ENCODER hEnc, const MP4SPACEENC_BANDS_CONFIG nParamBands); + +/* Function / Class Definition ***********************************************/ +static UINT mp4SpaceEnc_GetNumQmfBands(const UINT nSampleRate) { + UINT nQmfBands = 0; + + if (nSampleRate < 27713) + nQmfBands = 32; + else if (nSampleRate < 55426) + nQmfBands = 64; + + return nQmfBands; +} + +static UINT updateQmfFlags(const UINT flags, const INT keepStates) { + UINT qmfFlags = flags; + + qmfFlags = (qmfFlags & (~(UINT)QMF_FLAG_LP)); + qmfFlags = (qmfFlags | QMF_FLAG_MPSLDFB); + qmfFlags = (keepStates) ? (qmfFlags | QMF_FLAG_KEEP_STATES) + : (qmfFlags & (~(UINT)QMF_FLAG_KEEP_STATES)); + + return qmfFlags; +} + +static INT freq2HybridBand(const UINT nFrequency, const UINT nSampleRate, + const UINT nQmfBands) { + /* + nQmfSlotWidth = (nSampleRate/2) / nQmfBands; + nQmfBand = nFrequency / nQmfSlotWidth; + */ + int nHybridBand = -1; + int scale = 0; + const FIXP_DBL temp = fDivNorm((FIXP_DBL)(2 * nFrequency * nQmfBands), + (FIXP_DBL)nSampleRate, &scale); + const int nQmfBand = scaleValue(temp, scale - (DFRACT_BITS - 1)); + + if ((nQmfBand > -1) && (nQmfBand < (int)nQmfBands)) { + nHybridBand = qmf2qmf[nQmfBand]; + } + + return nHybridBand; +} + +/* + * Examine buffer descriptor regarding choosen type. + * + * \param pBufDesc Pointer to buffer descriptor + * \param type Buffer type to look for. + + * \return - Buffer descriptor index. + * -1, if there is no entry available. + */ +static INT getBufDescIdx(const FDK_bufDescr *pBufDesc, const UINT type) { + INT i, idx = -1; + + for (i = 0; i < (int)pBufDesc->numBufs; i++) { + if (pBufDesc->pBufType[i] == type) { + idx = i; + break; + } + } + return idx; +} + +FDK_SACENC_ERROR FDK_sacenc_open(HANDLE_MP4SPACE_ENCODER *phMp4SpaceEnc) { + return mp4SpaceEnc_create(phMp4SpaceEnc); +} + +static FDK_SACENC_ERROR mp4SpaceEnc_create( + HANDLE_MP4SPACE_ENCODER *phMp4SpaceEnc) { + FDK_SACENC_ERROR error = SACENC_OK; + HANDLE_MP4SPACE_ENCODER hEnc = NULL; + ENC_CONFIG_SETUP setup; + + if (NULL == phMp4SpaceEnc) { + error = SACENC_INVALID_HANDLE; + } else { + int i, ch; + FDKmemclear(&setup, sizeof(ENC_CONFIG_SETUP)); + + /* Allocate Encoder Instance */ + FDK_ALLOCATE_MEMORY_1D(hEnc, 1, struct MP4SPACE_ENCODER); + + /* Clear everything, also pointers. */ + if (NULL != hEnc) { + FDKmemclear(hEnc, sizeof(struct MP4SPACE_ENCODER)); + } + + setup.maxSamplingrate = 48000; + setup.maxFrameTimeSlots = 16; + + setup.maxAnalysisLengthTimeSlots = 3 * setup.maxFrameTimeSlots; + setup.maxQmfBands = mp4SpaceEnc_GetNumQmfBands(setup.maxSamplingrate); + ; + setup.maxHybridBands = setup.maxQmfBands; + setup.maxFrameLength = setup.maxQmfBands * setup.maxFrameTimeSlots; + + setup.maxChIn = 2; + setup.maxChOut = 1; + setup.maxChTotOut = setup.maxChOut; + setup.bEncMode_212 = 1; + setup.maxHybridInStaticSlots = 24; + + /* Open Static Gain*/ + if (SACENC_OK != + (error = fdk_sacenc_staticGain_OpenConfig(&hEnc->hStaticGainConfig))) { + goto bail; + } + + /* enhanced time domain downmix (for stereo input) */ + if (SACENC_OK != (error = fdk_sacenc_open_enhancedTimeDomainDmx( + &hEnc->hEnhancedTimeDmx, setup.maxFrameLength))) { + goto bail; + } + + FDK_ALLOCATE_MEMORY_1D(hEnc->pParameterBand2HybridBandOffset, + MAX_NUM_PARAM_BANDS, UCHAR); + + /* Create Space Tree first, to get number of in-/output channels */ + if (SACENC_OK != (error = fdk_sacenc_spaceTree_Open(&hEnc->hSpaceTree))) { + goto bail; + } + + FDK_ALLOCATE_MEMORY_1D(hEnc->pEncoderInputChScale, setup.maxChIn, INT); + FDK_ALLOCATE_MEMORY_1D(hEnc->staticTimeDomainDmxInScale, setup.maxChIn, + INT); + + FDK_ALLOCATE_MEMORY_1D(hEnc->phQmfFiltIn__FDK, setup.maxChIn, + HANDLE_QMF_FILTER_BANK); + + /* Allocate Analysis Filterbank Structs */ + for (ch = 0; ch < setup.maxChIn; ch++) { + FDK_ALLOCATE_MEMORY_1D_INT(hEnc->phQmfFiltIn__FDK[ch], 1, + struct QMF_FILTER_BANK, SECT_DATA_L2) + FDK_ALLOCATE_MEMORY_1D_INT(hEnc->phQmfFiltIn__FDK[ch]->FilterStates, + 2 * 5 * setup.maxQmfBands, FIXP_QAS, + SECT_DATA_L2) + } + + /* Allocate Synthesis Filterbank Structs for arbitrary downmix */ + + /* Allocate DC Filter Struct for normal signal input */ + for (ch = 0; ch < setup.maxChIn; ch++) { + if (SACENC_OK != + (error = fdk_sacenc_createDCFilter(&hEnc->phDCFilterSigIn[ch]))) { + goto bail; + } + } + + /* Open Onset Detection */ + for (ch = 0; ch < setup.maxChIn; ch++) { + if (SACENC_OK != (error = fdk_sacenc_onsetDetect_Open( + &hEnc->phOnset[ch], setup.maxFrameTimeSlots))) { + goto bail; + } + } + + FDK_ALLOCATE_MEMORY_2D(hEnc->ppTrCurrPos, setup.maxChIn, MAX_NUM_TRANS, + INT); + + /* Create Windowing */ + if (SACENC_OK != + (error = fdk_sacenc_frameWindow_Create(&hEnc->hFrameWindow))) { + goto bail; + } + + /* Open static gain */ + if (SACENC_OK != (error = fdk_sacenc_staticGain_Open(&hEnc->hStaticGain))) { + goto bail; + } + + /* create bitstream encoder */ + if (SACENC_OK != (error = fdk_sacenc_createSpatialBitstreamEncoder( + &hEnc->hBitstreamFormatter))) { + goto bail; + } + + FDK_ALLOCATE_MEMORY_1D(hEnc->sscBuf.pSsc, MAX_SSC_BYTES, UCHAR); + + { + FDK_ALLOCATE_MEMORY_2D(hEnc->ppTimeSigIn__FDK, setup.maxChIn, + setup.maxFrameLength + MAX_DELAY_SURROUND_ANALYSIS, + INT_PCM); + } + FDK_ALLOCATE_MEMORY_2D(hEnc->ppTimeSigDelayIn__FDK, setup.maxChIn, + MAX_DELAY_SURROUND_ANALYSIS, INT_PCM); + + /* Create new buffers for several signals (including arbitrary downmix) */ + if (setup.bEncMode_212 == 0) { + /* pOutputDelayBuffer__FDK buffer is not needed for SACENC_212 mode */ + FDK_ALLOCATE_MEMORY_1D( + hEnc->pOutputDelayBuffer__FDK, + (setup.maxFrameLength + MAX_DELAY_OUTPUT) * setup.maxChOut, INT_PCM); + } + + /* allocate buffers */ + if (setup.bEncMode_212 == 0) { + /* ppTimeSigOut__FDK buffer is not needed for SACENC_212 mode */ + FDK_ALLOCATE_MEMORY_2D(hEnc->ppTimeSigOut__FDK, setup.maxChTotOut, + setup.maxFrameLength, INT_PCM); + } + + if (setup.bEncMode_212 == 1) { + /* pppHybridIn__FDK buffer can be reduced by maxFrameTimeSlots/2 slots for + * SACENC_212 mode */ + FDK_ALLOCATE_MEMORY_3D( + hEnc->pppHybridIn__FDK, setup.maxChIn, + setup.maxAnalysisLengthTimeSlots - (setup.maxFrameTimeSlots >> 1), + setup.maxHybridBands, FIXP_DPK); + FDK_ALLOCATE_MEMORY_3D(hEnc->pppHybridInStatic__FDK, setup.maxChIn, + setup.maxHybridInStaticSlots, setup.maxHybridBands, + FIXP_DPK); + } else { + FDK_ALLOCATE_MEMORY_3D(hEnc->pppHybridIn__FDK, setup.maxChIn, + setup.maxAnalysisLengthTimeSlots, + setup.maxHybridBands, FIXP_DPK); + } + + if (setup.bEncMode_212 == 0) { + /* pppProcDataIn__FDK buffer is not needed for SACENC_212 mode */ + FDK_ALLOCATE_MEMORY_3D(hEnc->pppProcDataIn__FDK, MAX_SPACE_TREE_CHANNELS, + setup.maxAnalysisLengthTimeSlots, + setup.maxHybridBands, FIXP_DPK); + } + for (i = 0; i < MAX_NUM_PARAMS; i++) { + FDK_ALLOCATE_MEMORY_1D(hEnc->pFrameWindowAna__FDK[i], + setup.maxAnalysisLengthTimeSlots, FIXP_WIN); + } /* for i */ + + if (SACENC_OK != (error = fdk_sacenc_delay_Open(&hEnc->hDelay))) { + goto bail; + } + + if (setup.bEncMode_212 == 0) { + /* ppBitstreamDelayBuffer buffer is not needed for SACENC_212 mode */ + FDK_ALLOCATE_MEMORY_2D(hEnc->ppBitstreamDelayBuffer, MAX_BITSTREAM_DELAY, + MAX_MPEGS_BYTES, UCHAR); + } + FDK_ALLOCATE_MEMORY_1D(hEnc->pnOutputBits, MAX_BITSTREAM_DELAY, INT); + + hEnc->setup = setup; /* save configuration used while encoder allocation. */ + mp4SpaceEnc_InitDefault(hEnc); + + if (NULL != phMp4SpaceEnc) { + *phMp4SpaceEnc = hEnc; /* return encoder handle */ + } + + } /* valid handle */ + + return error; + +bail: + if (NULL != hEnc) { + hEnc->setup = setup; + FDK_sacenc_close(&hEnc); + } + return ((SACENC_OK == error) ? SACENC_MEMORY_ERROR : error); +} + +static FDK_SACENC_ERROR mp4SpaceEnc_InitDefault(HANDLE_MP4SPACE_ENCODER hEnc) { + FDK_SACENC_ERROR err = SACENC_OK; + + /* Get default static gain configuration. */ + if (SACENC_OK != (err = fdk_sacenc_staticGain_InitDefaultConfig( + hEnc->hStaticGainConfig))) { + goto bail; + } + +bail: + return err; +} + +static FDK_SACENC_ERROR FDK_sacenc_configure( + HANDLE_MP4SPACE_ENCODER hEnc, const HANDLE_MP4SPACEENC_SETUP hSetup) { + FDK_SACENC_ERROR error = SACENC_OK; + + hEnc->nSampleRate = hSetup->sampleRate; + hEnc->encMode = hSetup->encMode; + hEnc->nQmfBands = mp4SpaceEnc_GetNumQmfBands(hEnc->nSampleRate); + + /* Make sure that we have set time domain downmix for 212 */ + if (hSetup->encMode == SACENC_212 && hSetup->bTimeDomainDmx == 0) { + error = SACENC_INVALID_CONFIG; + } else { + hEnc->useTimeDomDownmix = hSetup->bTimeDomainDmx; + } + + hEnc->timeAlignment = hSetup->timeAlignment; + hEnc->quantMode = hSetup->quantMode; + + hEnc->useCoarseQuantCld = hSetup->bUseCoarseQuant; + hEnc->useCoarseQuantCpc = hSetup->bUseCoarseQuant; + hEnc->useFrameKeep = (hSetup->bLdMode == 2); + hEnc->useCoarseQuantIcc = 0; /* not available */ + hEnc->useCoarseQuantArbDmx = 0; /* not available for user right now */ + hEnc->independencyFactor = hSetup->independencyFactor; + hEnc->independencyCount = 0; + hEnc->independencyFlag = 1; + + /* set number of Hybrid bands */ + hEnc->nHybridBands = hEnc->nQmfBands; + hEnc->nFrameTimeSlots = hSetup->frameTimeSlots; + mp4SpaceEnc_InitNumParamBands(hEnc, hSetup->nParamBands); + + return error; +} + +FDK_SACENC_ERROR FDK_sacenc_init(HANDLE_MP4SPACE_ENCODER hEnc, + const INT dmxDelay) { + FDK_SACENC_ERROR error = SACENC_OK; + + /* Sanity Checks */ + if (NULL == hEnc) { + error = SACENC_INVALID_HANDLE; + } else { + const int initStatesFlag = 1; + + int ch; /* loop counter */ + int nChInArbDmx; + + if (SACENC_OK != (error = FDK_sacenc_configure(hEnc, &hEnc->user))) { + goto bail; + } + + hEnc->bEncMode_212_only = hEnc->setup.bEncMode_212; + + /* Slots per Frame and Frame Length */ + if (hEnc->nFrameTimeSlots < 1) { + error = SACENC_INVALID_CONFIG; + goto bail; + } + hEnc->nFrameLength = hEnc->nQmfBands * hEnc->nFrameTimeSlots; + + if (hEnc->useFrameKeep == 1) { + hEnc->nAnalysisLengthTimeSlots = 3 * hEnc->nFrameTimeSlots; + hEnc->nUpdateHybridPositionTimeSlots = hEnc->nFrameTimeSlots; + } else { + hEnc->nAnalysisLengthTimeSlots = 2 * hEnc->nFrameTimeSlots; + hEnc->nUpdateHybridPositionTimeSlots = 0; + } + + { + hEnc->nAnalysisLookaheadTimeSlots = + hEnc->nAnalysisLengthTimeSlots - 3 * hEnc->nFrameTimeSlots / 2; + } + + /* init parameterBand2hybridBandOffset table */ + fdk_sacenc_calcParameterBand2HybridBandOffset( + (BOX_SUBBAND_CONFIG)hEnc->nParamBands, hEnc->nHybridBands, + hEnc->pParameterBand2HybridBandOffset); + + /* Fill Setup structure for Space Tree */ + if (SACENC_OK != + (error = mp4SpaceEnc_FillSpaceTreeSetup(hEnc, &hEnc->spaceTreeSetup))) { + goto bail; + } + + /* Init space tree configuration */ + if (SACENC_OK != + (error = fdk_sacenc_spaceTree_Init( + hEnc->hSpaceTree, &hEnc->spaceTreeSetup, + hEnc->pParameterBand2HybridBandOffset, hEnc->useFrameKeep))) { + goto bail; + } + + /* Get space tree description and resulting number of input/output channels + */ + { + SPACE_TREE_DESCRIPTION spaceTreeDescription; + + if (SACENC_OK != (error = fdk_sacenc_spaceTree_GetDescription( + hEnc->hSpaceTree, &spaceTreeDescription))) { + goto bail; + } + + hEnc->nInputChannels = + spaceTreeDescription.nOutChannels; /* space tree description + describes decoder + configuration */ + hEnc->nOutputChannels = + spaceTreeDescription.nInChannels; /* space tree description + describes decoder + configuration */ + } + + nChInArbDmx = 0; + + /* INITIALIZATION */ + for (ch = 0; ch < hEnc->nInputChannels; ch++) { + /* scaling in analysis qmf filterbank (7) */ + hEnc->pEncoderInputChScale[ch] = 7; + + { + /* additional scaling in qmf prototype filter for low delay */ + hEnc->pEncoderInputChScale[ch] += 1; + } + + { hEnc->pEncoderInputChScale[ch] += DC_FILTER_SF; } + } /* nInputChannels */ + + /* Init analysis filterbank */ + for (ch = 0; ch < hEnc->nInputChannels; ch++) { + hEnc->phQmfFiltIn__FDK[ch]->flags = + updateQmfFlags(hEnc->phQmfFiltIn__FDK[ch]->flags, !initStatesFlag); + + if (0 != qmfInitAnalysisFilterBank( + hEnc->phQmfFiltIn__FDK[ch], + (FIXP_QAS *)hEnc->phQmfFiltIn__FDK[ch]->FilterStates, 1, + hEnc->nQmfBands, hEnc->nQmfBands, hEnc->nQmfBands, + hEnc->phQmfFiltIn__FDK[ch]->flags)) { + error = SACENC_INIT_ERROR; + goto bail; + } + } + + /* Initialize DC Filter. */ + { + for (ch = 0; ch < hEnc->nInputChannels; ch++) { + if (SACENC_OK != (error = fdk_sacenc_initDCFilter( + hEnc->phDCFilterSigIn[ch], hEnc->nSampleRate))) { + goto bail; + } + } + } + + /* Init onset detect. */ + { + /* init onset detect configuration struct */ + ONSET_DETECT_CONFIG onsetDetectConfig; + onsetDetectConfig.maxTimeSlots = hEnc->nFrameTimeSlots; + onsetDetectConfig.lowerBoundOnsetDetection = + freq2HybridBand(1725, hEnc->nSampleRate, hEnc->nQmfBands); + onsetDetectConfig.upperBoundOnsetDetection = hEnc->nHybridBands; + + for (ch = 0; ch < hEnc->nInputChannels; ch++) { + if (SACENC_OK != (error = fdk_sacenc_onsetDetect_Init( + hEnc->phOnset[ch], &onsetDetectConfig, 1))) { + goto bail; + } + } + } + + { + /* init windowing */ + FRAMEWINDOW_CONFIG framewindowConfig; + framewindowConfig.nTimeSlotsMax = hEnc->nFrameTimeSlots; + framewindowConfig.bFrameKeep = hEnc->useFrameKeep; + + if (SACENC_OK != (error = fdk_sacenc_frameWindow_Init( + hEnc->hFrameWindow, &framewindowConfig))) { + goto bail; + } + } + + /* Set encoder mode for static gain initialization. */ + if (SACENC_OK != (error = fdk_sacenc_staticGain_SetEncMode( + hEnc->hStaticGainConfig, hEnc->encMode))) { + goto bail; + } + + /* Init static gain. */ + if (SACENC_OK != (error = fdk_sacenc_staticGain_Init( + hEnc->hStaticGain, hEnc->hStaticGainConfig, + &(hEnc->staticGainScale)))) { + goto bail; + } + + for (ch = 0; ch < hEnc->nInputChannels; ch++) { + hEnc->pEncoderInputChScale[ch] += hEnc->staticGainScale; + } + + /* enhanced downmix for stereo input*/ + if (hEnc->useTimeDomDownmix != 0) { + if (SACENC_OK != (error = fdk_sacenc_init_enhancedTimeDomainDmx( + hEnc->hEnhancedTimeDmx, + fdk_sacenc_getPreGainPtrFDK(hEnc->hStaticGain), + hEnc->staticGainScale, + fdk_sacenc_getPostGainFDK(hEnc->hStaticGain), + hEnc->staticGainScale, hEnc->nFrameLength))) { + goto bail; + } + } + + /* Create config structure for bitstream formatter including arbitrary + * downmix residual */ + if (SACENC_OK != (error = fdk_sacenc_initSpatialBitstreamEncoder( + hEnc->hBitstreamFormatter))) { + goto bail; + } + + if (SACENC_OK != (error = FillSpatialSpecificConfig( + hEnc, fdk_sacenc_getSpatialSpecificConfig( + hEnc->hBitstreamFormatter)))) { + goto bail; + } + + if (SACENC_OK != + (error = fdk_sacenc_writeSpatialSpecificConfig( + fdk_sacenc_getSpatialSpecificConfig(hEnc->hBitstreamFormatter), + hEnc->sscBuf.pSsc, MAX_SSC_BYTES, &hEnc->sscBuf.nSscSizeBits))) { + goto bail; + } + + /* init delay compensation with dmx core coder delay; if no core coder is + * used, many other buffers are initialized nevertheless */ + if (SACENC_OK != + (error = mp4SpaceEnc_InitDelayCompensation(hEnc, dmxDelay))) { + goto bail; + } + + /* How much input do we need? */ + hEnc->nSamplesNext = + hEnc->nFrameLength * (hEnc->nInputChannels + nChInArbDmx); + hEnc->nSamplesValid = 0; + } /* valid handle */ + +bail: + return error; +} + +static INT getAnalysisLengthTimeSlots(FIXP_WIN *pFrameWindowAna, + INT nTimeSlots) { + int i; + for (i = nTimeSlots - 1; i >= 0; i--) { + if (pFrameWindowAna[i] != (FIXP_WIN)0) { + break; + } + } + nTimeSlots = i + 1; + return nTimeSlots; +} + +static INT getAnalysisStartTimeSlot(FIXP_WIN *pFrameWindowAna, INT nTimeSlots) { + int startTimeSlot = 0; + int i; + for (i = 0; i < nTimeSlots; i++) { + if (pFrameWindowAna[i] != (FIXP_WIN)0) { + break; + } + } + startTimeSlot = i; + return startTimeSlot; +} + +static FDK_SACENC_ERROR __FeedDeinterPreScale( + HANDLE_MP4SPACE_ENCODER hEnc, INT_PCM const *const pSamples, + INT_PCM *const pOutputSamples, INT const nSamples, + UINT const isInputInterleaved, UINT const inputBufferSizePerChannel, + UINT *const pnSamplesFed) { + FDK_SACENC_ERROR error = SACENC_OK; + + if ((hEnc == NULL) || (pSamples == NULL) || (pnSamplesFed == NULL)) { + error = SACENC_INVALID_HANDLE; + } else if (nSamples == 0) { + error = SACENC_INVALID_CONFIG; /* Flushing not implemented */ + } else { + int ch; + const INT nChIn = hEnc->nInputChannels; + const INT nChInWithDmx = nChIn; + const INT samplesToFeed = + FDKmin(nSamples, hEnc->nSamplesNext - hEnc->nSamplesValid); + const INT nSamplesPerChannel = samplesToFeed / nChInWithDmx; + + if ((samplesToFeed < 0) || (samplesToFeed % nChInWithDmx != 0) || + (samplesToFeed > nChInWithDmx * (INT)hEnc->nFrameLength)) { + error = SACENC_INVALID_CONFIG; + goto bail; + } + int i; + + const INT_PCM *pInput__FDK; + const INT_PCM *pInput2__FDK; + + { /* no dmx align = default*/ + pInput__FDK = pSamples; + pInput2__FDK = pSamples + (hEnc->nInputDelay * nChInWithDmx); + } + + for (i = 0; i < hEnc->nInputChannels; i++) { + hEnc->staticTimeDomainDmxInScale[i] = hEnc->staticGainScale; + } + + /***** N-channel-input *****/ + for (ch = 0; ch < nChIn; ch++) { + /* Write delayed time signal into time signal buffer */ + FDKmemcpy(&(hEnc->ppTimeSigIn__FDK[ch][0]), + &(hEnc->ppTimeSigDelayIn__FDK[ch][0]), + hEnc->nSurroundAnalysisBufferDelay * sizeof(INT_PCM)); + + if (isInputInterleaved) { + /* Add the new frame de-interleaved. Apply nSurroundAnalysisBufferDelay. + */ + FDKmemcpy_flex( + &(hEnc->ppTimeSigIn__FDK[ch][hEnc->nSurroundAnalysisBufferDelay]), + 1, pInput__FDK + ch, nChInWithDmx, hEnc->nInputDelay); + FDKmemcpy_flex( + &(hEnc->ppTimeSigIn__FDK[ch][hEnc->nSurroundAnalysisBufferDelay + + hEnc->nInputDelay]), + 1, pInput2__FDK + ch, nChInWithDmx, + nSamplesPerChannel - hEnc->nInputDelay); + } else { + /* Input is already deinterleaved, just copy */ + FDKmemcpy( + &(hEnc->ppTimeSigIn__FDK[ch][hEnc->nSurroundAnalysisBufferDelay]), + pInput__FDK + ch * inputBufferSizePerChannel, + hEnc->nInputDelay * sizeof(INT_PCM)); + FDKmemcpy( + &(hEnc->ppTimeSigIn__FDK[ch][hEnc->nSurroundAnalysisBufferDelay + + hEnc->nInputDelay]), + pInput2__FDK + ch * inputBufferSizePerChannel, + (nSamplesPerChannel - hEnc->nInputDelay) * sizeof(INT_PCM)); + } + + /* Update time signal delay buffer */ + FDKmemcpy(&(hEnc->ppTimeSigDelayIn__FDK[ch][0]), + &(hEnc->ppTimeSigIn__FDK[ch][hEnc->nFrameLength]), + hEnc->nSurroundAnalysisBufferDelay * sizeof(INT_PCM)); + } /* for ch */ + + /***** No Arbitrary Downmix *****/ + /* "Crude TD Dmx": Time DomainDownmix + NO Arbitrary Downmix, Delay Added at + * pOutputBuffer */ + if ((hEnc->useTimeDomDownmix > 0)) { + if ((hEnc->useTimeDomDownmix == 1) || (hEnc->nInputChannels != 2)) { + error = SACENC_INVALID_CONFIG; + goto bail; + } else { + /* enhanced time domain downmix (for stereo input) */ + if (hEnc->encMode == SACENC_212) { + if (pOutputSamples == NULL) { + error = SACENC_INVALID_HANDLE; + goto bail; + } + + fdk_sacenc_apply_enhancedTimeDomainDmx( + hEnc->hEnhancedTimeDmx, hEnc->ppTimeSigIn__FDK, pOutputSamples, + hEnc->nSurroundAnalysisBufferDelay); + } else { + if (&hEnc->ppTimeSigOut__FDK[0][0] == NULL) { + error = SACENC_INVALID_HANDLE; + goto bail; + } + + fdk_sacenc_apply_enhancedTimeDomainDmx( + hEnc->hEnhancedTimeDmx, hEnc->ppTimeSigIn__FDK, + &hEnc->ppTimeSigOut__FDK[0][0], + hEnc->nSurroundAnalysisBufferDelay); + } + } + } + + /* update number of samples still to process */ + hEnc->nSamplesValid += samplesToFeed; + + /*return number of fed samples */ + *pnSamplesFed = samplesToFeed; + } +bail: + return error; +} + +FDK_SACENC_ERROR FDK_sacenc_encode(const HANDLE_MP4SPACE_ENCODER hMp4SpaceEnc, + const FDK_bufDescr *inBufDesc, + const FDK_bufDescr *outBufDesc, + const SACENC_InArgs *inargs, + SACENC_OutArgs *outargs) { + FDK_SACENC_ERROR error = SACENC_OK; + + const INT_PCM *pInputSamples = + (const INT_PCM *)inBufDesc->ppBase[getBufDescIdx( + inBufDesc, (FDK_BUF_TYPE_INPUT | FDK_BUF_TYPE_PCM_DATA))]; + + INT_PCM *const pOutputSamples = (INT_PCM *)outBufDesc->ppBase[getBufDescIdx( + outBufDesc, (FDK_BUF_TYPE_OUTPUT | FDK_BUF_TYPE_PCM_DATA))]; + + const int nOutputSamplesBufferSize = + outBufDesc->pBufSize[getBufDescIdx( + outBufDesc, (FDK_BUF_TYPE_OUTPUT | FDK_BUF_TYPE_PCM_DATA))] / + outBufDesc->pEleSize[getBufDescIdx( + outBufDesc, (FDK_BUF_TYPE_OUTPUT | FDK_BUF_TYPE_PCM_DATA))]; + + if ((hMp4SpaceEnc == NULL) || (pInputSamples == NULL)) { + error = SACENC_INVALID_HANDLE; + } else { + int nOutputSamples; + int i, ch, ps, winCnt, ts, slot; + INT currTransPos = -1; + SPATIALFRAME *pFrameData = NULL; + + /* Improve Code Readability */ + const int nChIn = hMp4SpaceEnc->nInputChannels; + const int nChInWithDmx = nChIn; + const int nChOut = hMp4SpaceEnc->nOutputChannels; + const int nSamplesPerChannel = inargs->nInputSamples / nChInWithDmx; + const int nOutputSamplesMax = nSamplesPerChannel * nChOut; + const int nFrameTimeSlots = hMp4SpaceEnc->nFrameTimeSlots; + + INT encoderInputChScale[SACENC_MAX_INPUT_CHANNELS]; + INT nFrameTimeSlotsReduction = 0; + + if (hMp4SpaceEnc->encMode == SACENC_212) { + nFrameTimeSlotsReduction = hMp4SpaceEnc->nFrameTimeSlots >> 1; + } + + for (i = 0; i < nChIn; i++) + encoderInputChScale[i] = hMp4SpaceEnc->pEncoderInputChScale[i]; + + /* Sanity Check */ + if ((0 != inargs->nInputSamples % nChInWithDmx)) { + error = SACENC_INVALID_CONFIG; + goto bail; + } + + /* + * Get Frame Data Handle. + */ + + /* get bitstream handle (for storage of cld's, icc's and so on) + * get spatialframe 2 frames in the future; NOTE: this is necessary to + * synchronise spatial data and audio data */ + if (NULL == (pFrameData = fdk_sacenc_getSpatialFrame( + hMp4SpaceEnc->hBitstreamFormatter, WRITE_SPATIALFRAME))) { + error = SACENC_INVALID_HANDLE; + goto bail; + } + + /* Independent Frames Counters*/ + if (hMp4SpaceEnc->nDiscardOutFrames > + 0) { /* Independent Frames if they should be discarded, Reset Counter*/ + hMp4SpaceEnc->independencyCount = + 0; /* Reset the counter, first valid frame is an independent one*/ + hMp4SpaceEnc->independencyFlag = 1; + } else { /*hMp4SpaceEnc->nDiscardOutFrames == 0*/ + hMp4SpaceEnc->independencyFlag = + (hMp4SpaceEnc->independencyCount == 0) ? 1 : 0; + if (hMp4SpaceEnc->independencyFactor > 0) { + hMp4SpaceEnc->independencyCount++; + hMp4SpaceEnc->independencyCount = + hMp4SpaceEnc->independencyCount % + ((int)hMp4SpaceEnc->independencyFactor); + } else { /* independencyFactor == 0 */ + hMp4SpaceEnc->independencyCount = -1; + } + } + + /* + * Time signal preprocessing: + * - Feed input buffer + * - Prescale time signal + * - Apply DC filter on input signal + */ + + /* Feed, Deinterleave, Pre-Scale the input time signals */ + if (SACENC_OK != + (error = __FeedDeinterPreScale( + hMp4SpaceEnc, pInputSamples, pOutputSamples, inargs->nInputSamples, + inargs->isInputInterleaved, inargs->inputBufferSizePerChannel, + &outargs->nSamplesConsumed))) { + goto bail; + } + + if (hMp4SpaceEnc->nSamplesNext != hMp4SpaceEnc->nSamplesValid) { + error = SACENC_INVALID_CONFIG; + goto bail; + } + + if (hMp4SpaceEnc->encMode == SACENC_212 && + hMp4SpaceEnc->bEncMode_212_only) { + for (ch = 0; ch < nChIn; ch++) { + for (slot = 0; slot < nFrameTimeSlots; slot++) { + setCplxVec( + hMp4SpaceEnc->pppHybridIn__FDK + [ch][hMp4SpaceEnc->nUpdateHybridPositionTimeSlots + + nFrameTimeSlots - nFrameTimeSlotsReduction + slot], + (FIXP_DBL)0, hMp4SpaceEnc->nHybridBands); + } + } + } + + /* + * Time / Frequency: + * - T/F audio input channels + * - T/F arbitrary downmix input channels + */ + for (ch = 0; ch < nChIn; ch++) { + C_AALLOC_SCRATCH_START(pQmfInReal, FIXP_DBL, MAX_QMF_BANDS) + C_AALLOC_SCRATCH_START(pQmfInImag, FIXP_DBL, MAX_QMF_BANDS) + FIXP_GAIN *pPreGain = + fdk_sacenc_getPreGainPtrFDK(hMp4SpaceEnc->hStaticGain); + + for (ts = 0; ts < nFrameTimeSlots; ts++) { + FIXP_DBL *pSpecReal; + FIXP_DBL *pSpecImag; + + INT_PCM *pTimeIn = + &hMp4SpaceEnc->ppTimeSigIn__FDK[ch][(ts * hMp4SpaceEnc->nQmfBands)]; + + { + /* Apply DC filter on input channels */ + if (SACENC_OK != (error = fdk_sacenc_applyDCFilter( + hMp4SpaceEnc->phDCFilterSigIn[ch], pTimeIn, + pTimeIn, hMp4SpaceEnc->nQmfBands))) { + goto bail; + } + } + + /* QMF filterbank */ + C_ALLOC_SCRATCH_START(pWorkBuffer, FIXP_DBL, (MAX_QMF_BANDS << 1)); + + qmfAnalysisFilteringSlot(hMp4SpaceEnc->phQmfFiltIn__FDK[ch], pQmfInReal, + pQmfInImag, pTimeIn, 1, pWorkBuffer); + + C_ALLOC_SCRATCH_END(pWorkBuffer, FIXP_DBL, (MAX_QMF_BANDS << 1)); + + pSpecReal = pQmfInReal; + pSpecImag = pQmfInImag; + + /* Apply pre-scale after filterbank */ + if (MAXVAL_GAIN != pPreGain[ch]) { + for (i = 0; i < hMp4SpaceEnc->nHybridBands; i++) { + hMp4SpaceEnc + ->pppHybridIn__FDK[ch] + [hMp4SpaceEnc->nAnalysisLookaheadTimeSlots + + ts][i] + .v.re = fMult(pSpecReal[i], pPreGain[ch]); + hMp4SpaceEnc + ->pppHybridIn__FDK[ch] + [hMp4SpaceEnc->nAnalysisLookaheadTimeSlots + + ts][i] + .v.im = fMult(pSpecImag[i], pPreGain[ch]); + } + } else { + for (i = 0; i < hMp4SpaceEnc->nHybridBands; i++) { + hMp4SpaceEnc + ->pppHybridIn__FDK[ch] + [hMp4SpaceEnc->nAnalysisLookaheadTimeSlots + + ts][i] + .v.re = pSpecReal[i]; + hMp4SpaceEnc + ->pppHybridIn__FDK[ch] + [hMp4SpaceEnc->nAnalysisLookaheadTimeSlots + + ts][i] + .v.im = pSpecImag[i]; + } + } + } /* ts */ + C_AALLOC_SCRATCH_END(pQmfInImag, FIXP_DBL, MAX_QMF_BANDS) + C_AALLOC_SCRATCH_END(pQmfInReal, FIXP_DBL, MAX_QMF_BANDS) + + if (SACENC_OK != error) { + goto bail; + } + } /* ch */ + + if (hMp4SpaceEnc->encMode == SACENC_212 && + hMp4SpaceEnc->bEncMode_212_only) { + for (ch = 0; ch < nChIn; ch++) { + for (slot = 0; + slot < (int)(hMp4SpaceEnc->nUpdateHybridPositionTimeSlots + + nFrameTimeSlots - nFrameTimeSlotsReduction); + slot++) { + copyCplxVec(hMp4SpaceEnc->pppHybridIn__FDK[ch][slot], + hMp4SpaceEnc->pppHybridInStatic__FDK[ch][slot], + hMp4SpaceEnc->nHybridBands); + } + } + for (ch = 0; ch < nChIn; ch++) { + for (slot = 0; + slot < (int)(hMp4SpaceEnc->nUpdateHybridPositionTimeSlots + + nFrameTimeSlots - nFrameTimeSlotsReduction); + slot++) { + copyCplxVec( + hMp4SpaceEnc->pppHybridInStatic__FDK[ch][slot], + hMp4SpaceEnc->pppHybridIn__FDK[ch][nFrameTimeSlots + slot], + hMp4SpaceEnc->nHybridBands); + } + } + } + + /* + * Onset Detection: + * - detection of transients + * - build framing + */ + for (ch = 0; ch < nChIn; ch++) { + if (ch != 3) { /* !LFE */ + if (SACENC_OK != + (error = fdk_sacenc_onsetDetect_Apply( + hMp4SpaceEnc->phOnset[ch], nFrameTimeSlots, + hMp4SpaceEnc->nHybridBands, + &hMp4SpaceEnc->pppHybridIn__FDK + [ch][hMp4SpaceEnc->nAnalysisLookaheadTimeSlots], + encoderInputChScale[ch], + hMp4SpaceEnc->trPrevPos[1], /* contains previous Transient */ + hMp4SpaceEnc->ppTrCurrPos[ch]))) { + goto bail; + } + + if ((1) && (hMp4SpaceEnc->useFrameKeep == 0)) { + hMp4SpaceEnc->ppTrCurrPos[ch][0] = -1; + } + + /* Find first Transient Position */ + if ((hMp4SpaceEnc->ppTrCurrPos[ch][0] >= 0) && + ((currTransPos < 0) || + (hMp4SpaceEnc->ppTrCurrPos[ch][0] < currTransPos))) { + currTransPos = hMp4SpaceEnc->ppTrCurrPos[ch][0]; + } + } /* !LFE */ + } /* ch */ + + if (hMp4SpaceEnc->useFrameKeep == 1) { + if ((currTransPos != -1) || (hMp4SpaceEnc->independencyFlag == 1)) { + hMp4SpaceEnc->avoid_keep = NUM_KEEP_WINDOWS; + currTransPos = -1; + } + } + + /* Save previous Transient Position */ + hMp4SpaceEnc->trPrevPos[0] = + FDKmax(-1, hMp4SpaceEnc->trPrevPos[1] - (INT)nFrameTimeSlots); + hMp4SpaceEnc->trPrevPos[1] = currTransPos; + + /* Update Onset Detection Energy Buffer */ + for (ch = 0; ch < nChIn; ch++) { + if (SACENC_OK != (error = fdk_sacenc_onsetDetect_Update( + hMp4SpaceEnc->phOnset[ch], nFrameTimeSlots))) { + goto bail; + } + } + + /* Framing */ + if (SACENC_OK != + (error = fdk_sacenc_frameWindow_GetWindow( + hMp4SpaceEnc->hFrameWindow, hMp4SpaceEnc->trPrevPos, + nFrameTimeSlots, &pFrameData->framingInfo, + hMp4SpaceEnc->pFrameWindowAna__FDK, &hMp4SpaceEnc->frameWinList, + hMp4SpaceEnc->avoid_keep))) { + goto bail; + } + + /* + * MPS Processing: + */ + for (ps = 0, winCnt = 0; ps < hMp4SpaceEnc->frameWinList.n; ++ps) { + /* Analysis Windowing */ + if (hMp4SpaceEnc->frameWinList.dat[ps].hold == FW_HOLD) { + /* ************************************** */ + /* ONLY COPY AND HOLD PREVIOUS PARAMETERS */ + if (SACENC_OK != (error = fdk_sacenc_duplicateParameterSet( + &hMp4SpaceEnc->saveFrame, 0, pFrameData, ps))) { + goto bail; + } + + } else { /* !FW_HOLD */ + /* ************************************** */ + /* NEW WINDOW */ + + INT nAnalysisLengthTimeSlots, analysisStartTimeSlot; + + nAnalysisLengthTimeSlots = getAnalysisLengthTimeSlots( + hMp4SpaceEnc->pFrameWindowAna__FDK[winCnt], + hMp4SpaceEnc->nAnalysisLengthTimeSlots); + + analysisStartTimeSlot = + getAnalysisStartTimeSlot(hMp4SpaceEnc->pFrameWindowAna__FDK[winCnt], + hMp4SpaceEnc->nAnalysisLengthTimeSlots); + + /* perform main signal analysis windowing in + * fdk_sacenc_spaceTree_Apply() */ + FIXP_WIN *pFrameWindowAna__FDK = + hMp4SpaceEnc->pFrameWindowAna__FDK[winCnt]; + FIXP_DPK ***pppHybridIn__FDK = hMp4SpaceEnc->pppHybridIn__FDK; + FIXP_DPK ***pppProcDataIn__FDK = hMp4SpaceEnc->pppProcDataIn__FDK; + + if (hMp4SpaceEnc->encMode == SACENC_212 && + hMp4SpaceEnc->bEncMode_212_only) { + pppProcDataIn__FDK = pppHybridIn__FDK; + } + + if (SACENC_OK != + (error = fdk_sacenc_spaceTree_Apply( + hMp4SpaceEnc->hSpaceTree, ps, nChIn, nAnalysisLengthTimeSlots, + analysisStartTimeSlot, hMp4SpaceEnc->nHybridBands, + pFrameWindowAna__FDK, pppHybridIn__FDK, + pppProcDataIn__FDK, /* multi-channel input */ + pFrameData, hMp4SpaceEnc->avoid_keep, encoderInputChScale))) { + goto bail; + } + + /* Save spatial frame for potential hold parameter set */ + if (SACENC_OK != (error = fdk_sacenc_duplicateParameterSet( + pFrameData, ps, &hMp4SpaceEnc->saveFrame, 0))) { + goto bail; + } + + ++winCnt; + } + if (hMp4SpaceEnc->avoid_keep > 0) { + hMp4SpaceEnc->avoid_keep--; + } + } /* Loop over Parameter Sets */ + /* ---- End of Processing Loop ---- */ + + /* + * Update hybridInReal/Imag buffer and do the same for arbDmx + * this means to move the hybrid data of the current frame to the beginning + * of the 2*nFrameLength-long buffer + */ + if (!(hMp4SpaceEnc->encMode == SACENC_212 && + hMp4SpaceEnc->bEncMode_212_only)) { + for (ch = 0; ch < nChIn; ch++) { /* for automatic downmix */ + for (slot = 0; + slot < (int)(hMp4SpaceEnc->nUpdateHybridPositionTimeSlots + + nFrameTimeSlots - nFrameTimeSlotsReduction); + slot++) { + copyCplxVec( + hMp4SpaceEnc->pppHybridIn__FDK[ch][slot], + hMp4SpaceEnc->pppHybridIn__FDK[ch][nFrameTimeSlots + slot], + hMp4SpaceEnc->nHybridBands); + } + for (slot = 0; slot < nFrameTimeSlots; slot++) { + setCplxVec( + hMp4SpaceEnc->pppHybridIn__FDK + [ch][hMp4SpaceEnc->nUpdateHybridPositionTimeSlots + + nFrameTimeSlots - nFrameTimeSlotsReduction + slot], + (FIXP_DBL)0, hMp4SpaceEnc->nHybridBands); + } + } + } + /* + * Spatial Tonality: + */ + { + /* Smooth config off. */ + FDKmemclear(&pFrameData->smgData, sizeof(pFrameData->smgData)); + } + + /* + * Create bitstream + * - control independecy flag + * - write spatial frame + * - return bitstream + */ + UCHAR *pBitstreamDelayBuffer; + + if (hMp4SpaceEnc->encMode == SACENC_212) { + /* no bitstream delay buffer for SACENC_212 mode, write bitstream directly + * into the sacOutBuffer buffer which is provided by the core routine */ + pBitstreamDelayBuffer = (UCHAR *)outBufDesc->ppBase[1]; + } else { + /* bitstream delay is handled in ppBitstreamDelayBuffer buffer */ + pBitstreamDelayBuffer = + hMp4SpaceEnc + ->ppBitstreamDelayBuffer[hMp4SpaceEnc->nBitstreamBufferWrite]; + } + if (pBitstreamDelayBuffer == NULL) { + error = SACENC_INVALID_HANDLE; + goto bail; + } + + pFrameData->bsIndependencyFlag = hMp4SpaceEnc->independencyFlag; + + if (SACENC_OK != + (error = fdk_sacenc_writeSpatialFrame( + pBitstreamDelayBuffer, MAX_MPEGS_BYTES, + &hMp4SpaceEnc->pnOutputBits[hMp4SpaceEnc->nBitstreamBufferWrite], + hMp4SpaceEnc->hBitstreamFormatter))) { + goto bail; + } + + /* return bitstream info */ + if ((hMp4SpaceEnc->nDiscardOutFrames == 0) && + (getBufDescIdx(outBufDesc, + (FDK_BUF_TYPE_OUTPUT | FDK_BUF_TYPE_BS_DATA)) != -1)) { + const INT idx = getBufDescIdx( + outBufDesc, (FDK_BUF_TYPE_OUTPUT | FDK_BUF_TYPE_BS_DATA)); + const INT outBits = + hMp4SpaceEnc->pnOutputBits[hMp4SpaceEnc->nBitstreamBufferRead]; + + if (((outBits + 7) / 8) > + (INT)(outBufDesc->pBufSize[idx] / outBufDesc->pEleSize[idx])) { + outargs->nOutputBits = 0; + error = SACENC_ENCODE_ERROR; + goto bail; + } + + /* return bitstream buffer, copy delayed bitstream for all configurations + * except for the SACENC_212 mode */ + if (hMp4SpaceEnc->encMode != SACENC_212) { + FDKmemcpy( + outBufDesc->ppBase[idx], + hMp4SpaceEnc + ->ppBitstreamDelayBuffer[hMp4SpaceEnc->nBitstreamBufferRead], + (outBits + 7) / 8); + } + + /* return number of valid bits */ + outargs->nOutputBits = outBits; + } else { /* No spatial data should be returned if the current frame is to be + discarded. */ + outargs->nOutputBits = 0; + } + + /* update pointers */ + hMp4SpaceEnc->nBitstreamBufferRead = + (hMp4SpaceEnc->nBitstreamBufferRead + 1) % + hMp4SpaceEnc->nBitstreamDelayBuffer; + hMp4SpaceEnc->nBitstreamBufferWrite = + (hMp4SpaceEnc->nBitstreamBufferWrite + 1) % + hMp4SpaceEnc->nBitstreamDelayBuffer; + + /* Set Output Parameters */ + nOutputSamples = + (hMp4SpaceEnc->nDiscardOutFrames == 0) + ? (nOutputSamplesMax) + : 0; /* don't output samples in case frames to be discarded */ + if (nOutputSamples > nOutputSamplesBufferSize) { + error = SACENC_INVALID_CONFIG; + goto bail; + } + outargs->nOutputSamples = nOutputSamples; + + { /* !bQmfOutput */ + + if (hMp4SpaceEnc->encMode != SACENC_212) { + /* delay output samples and interleave them */ + /* note: in case of arbitrary downmix this will always be processed, + * because nOutputSamples != 0, even if bDMXAlign is switched on */ + /* always run copy-func, so nOutputSamplesMax instead of nOutputSamples + */ + for (ch = 0; ch < nChOut; ch++) { + FDKmemcpy_flex( + &hMp4SpaceEnc->pOutputDelayBuffer__FDK + [ch + (hMp4SpaceEnc->nOutputBufferDelay) * nChOut], + nChOut, hMp4SpaceEnc->ppTimeSigOut__FDK[ch], 1, + nOutputSamplesMax / nChOut); + } + + /* write delayed data in output pcm stream */ + /* always calculate, limiter must have a lookahead!!! */ + FDKmemcpy(pOutputSamples, hMp4SpaceEnc->pOutputDelayBuffer__FDK, + nOutputSamplesMax * sizeof(INT_PCM)); + + /* update delay buffer (move back end to the beginning of the buffer) */ + FDKmemmove( + hMp4SpaceEnc->pOutputDelayBuffer__FDK, + &hMp4SpaceEnc->pOutputDelayBuffer__FDK[nOutputSamplesMax], + nChOut * (hMp4SpaceEnc->nOutputBufferDelay) * sizeof(INT_PCM)); + } + + if (hMp4SpaceEnc->useTimeDomDownmix <= 0) { + if (SACENC_OK != (error = fdk_sacenc_staticPostGain_ApplyFDK( + hMp4SpaceEnc->hStaticGain, pOutputSamples, + nOutputSamplesMax, 0))) { + goto bail; + } + } + + } /* !bQmfOutput */ + + if (hMp4SpaceEnc->nDiscardOutFrames > 0) { + hMp4SpaceEnc->nDiscardOutFrames--; + } + + /* Invalidate Input Buffer */ + hMp4SpaceEnc->nSamplesValid = 0; + + } /* valid handle */ +bail: + return error; +} + +FDK_SACENC_ERROR FDK_sacenc_close(HANDLE_MP4SPACE_ENCODER *phMp4SpaceEnc) { + FDK_SACENC_ERROR error = SACENC_OK; + + if (NULL != phMp4SpaceEnc) { + if (NULL != *phMp4SpaceEnc) { + int ch, i; + HANDLE_MP4SPACE_ENCODER const hEnc = *phMp4SpaceEnc; + + if (hEnc->pParameterBand2HybridBandOffset != NULL) { + FDK_FREE_MEMORY_1D(hEnc->pParameterBand2HybridBandOffset); + } + /* Free Analysis Filterbank Structs */ + if (hEnc->pEncoderInputChScale != NULL) { + FDK_FREE_MEMORY_1D(hEnc->pEncoderInputChScale); + } + if (hEnc->staticTimeDomainDmxInScale != NULL) { + FDK_FREE_MEMORY_1D(hEnc->staticTimeDomainDmxInScale); + } + if (hEnc->phQmfFiltIn__FDK != NULL) { + for (ch = 0; ch < hEnc->setup.maxChIn; ch++) { + if (hEnc->phQmfFiltIn__FDK[ch] != NULL) { + if (hEnc->phQmfFiltIn__FDK[ch]->FilterStates != NULL) { + FDK_FREE_MEMORY_1D(hEnc->phQmfFiltIn__FDK[ch]->FilterStates); + } + FDK_FREE_MEMORY_1D(hEnc->phQmfFiltIn__FDK[ch]); + } + } + FDK_FREE_MEMORY_1D(hEnc->phQmfFiltIn__FDK); + } + for (ch = 0; ch < hEnc->setup.maxChIn; ch++) { + if (NULL != hEnc->phDCFilterSigIn[ch]) { + fdk_sacenc_destroyDCFilter(&hEnc->phDCFilterSigIn[ch]); + } + } + /* Close Onset Detection */ + for (ch = 0; ch < hEnc->setup.maxChIn; ch++) { + if (NULL != hEnc->phOnset[ch]) { + fdk_sacenc_onsetDetect_Close(&hEnc->phOnset[ch]); + } + } + if (hEnc->ppTrCurrPos) { + FDK_FREE_MEMORY_2D(hEnc->ppTrCurrPos); + } + if (hEnc->hFrameWindow) { + fdk_sacenc_frameWindow_Destroy(&hEnc->hFrameWindow); + } + /* Close Space Tree */ + if (NULL != hEnc->hSpaceTree) { + fdk_sacenc_spaceTree_Close(&hEnc->hSpaceTree); + } + if (NULL != hEnc->hEnhancedTimeDmx) { + fdk_sacenc_close_enhancedTimeDomainDmx(&hEnc->hEnhancedTimeDmx); + } + /* Close Static Gain */ + if (NULL != hEnc->hStaticGain) { + fdk_sacenc_staticGain_Close(&hEnc->hStaticGain); + } + if (NULL != hEnc->hStaticGainConfig) { + fdk_sacenc_staticGain_CloseConfig(&hEnc->hStaticGainConfig); + } + /* Close Delay*/ + if (NULL != hEnc->hDelay) { + fdk_sacenc_delay_Close(&hEnc->hDelay); + } + /* Delete Bitstream Stuff */ + if (NULL != hEnc->hBitstreamFormatter) { + fdk_sacenc_destroySpatialBitstreamEncoder(&(hEnc->hBitstreamFormatter)); + } + if (hEnc->pppHybridIn__FDK != NULL) { + if (hEnc->setup.bEncMode_212 == 1) { + FDK_FREE_MEMORY_3D(hEnc->pppHybridIn__FDK); + FDK_FREE_MEMORY_3D(hEnc->pppHybridInStatic__FDK); + } else { + FDK_FREE_MEMORY_3D(hEnc->pppHybridIn__FDK); + } + } + if (hEnc->pppProcDataIn__FDK != NULL) { + FDK_FREE_MEMORY_3D(hEnc->pppProcDataIn__FDK); + } + if (hEnc->pOutputDelayBuffer__FDK != NULL) { + FDK_FREE_MEMORY_1D(hEnc->pOutputDelayBuffer__FDK); + } + if (hEnc->ppTimeSigIn__FDK != NULL) { + { FDK_FREE_MEMORY_2D(hEnc->ppTimeSigIn__FDK); } + } + if (hEnc->ppTimeSigDelayIn__FDK != NULL) { + FDK_FREE_MEMORY_2D(hEnc->ppTimeSigDelayIn__FDK); + } + if (hEnc->ppTimeSigOut__FDK != NULL) { + FDK_FREE_MEMORY_2D(hEnc->ppTimeSigOut__FDK); + } + for (i = 0; i < MAX_NUM_PARAMS; i++) { + if (hEnc->pFrameWindowAna__FDK[i] != NULL) { + FDK_FREE_MEMORY_1D(hEnc->pFrameWindowAna__FDK[i]); + } + } + if (hEnc->pnOutputBits != NULL) { + FDK_FREE_MEMORY_1D(hEnc->pnOutputBits); + } + if (hEnc->ppBitstreamDelayBuffer != NULL) { + FDK_FREE_MEMORY_2D(hEnc->ppBitstreamDelayBuffer); + } + if (hEnc->sscBuf.pSsc != NULL) { + FDK_FREE_MEMORY_1D(hEnc->sscBuf.pSsc); + } + FDK_FREE_MEMORY_1D(*phMp4SpaceEnc); + } + } + + return error; +} + +/*----------------------------------------------------------------------------- + functionname: mp4SpaceEnc_InitDelayCompensation() + description: initialzes delay compensation + returns: noError on success, an apropriate error code else + -----------------------------------------------------------------------------*/ +static FDK_SACENC_ERROR mp4SpaceEnc_InitDelayCompensation( + HANDLE_MP4SPACE_ENCODER hMp4SpaceEnc, const INT coreCoderDelay) { + FDK_SACENC_ERROR error = SACENC_OK; + + /* Sanity Check */ + if (hMp4SpaceEnc == NULL) { + error = SACENC_INVALID_HANDLE; + } else { + hMp4SpaceEnc->coreCoderDelay = coreCoderDelay; + + if (SACENC_OK != (error = fdk_sacenc_delay_Init( + hMp4SpaceEnc->hDelay, hMp4SpaceEnc->nQmfBands, + hMp4SpaceEnc->nFrameLength, coreCoderDelay, + hMp4SpaceEnc->timeAlignment))) { + goto bail; + } + + fdk_sacenc_delay_SetDmxAlign(hMp4SpaceEnc->hDelay, 0); + fdk_sacenc_delay_SetTimeDomDmx( + hMp4SpaceEnc->hDelay, (hMp4SpaceEnc->useTimeDomDownmix >= 1) ? 1 : 0); + fdk_sacenc_delay_SetMinimizeDelay(hMp4SpaceEnc->hDelay, 1); + + if (SACENC_OK != (error = fdk_sacenc_delay_SubCalulateBufferDelays( + hMp4SpaceEnc->hDelay))) { + goto bail; + } + + /* init output delay compensation */ + hMp4SpaceEnc->nBitstreamDelayBuffer = + fdk_sacenc_delay_GetBitstreamFrameBufferSize(hMp4SpaceEnc->hDelay); + hMp4SpaceEnc->nOutputBufferDelay = + fdk_sacenc_delay_GetOutputAudioBufferDelay(hMp4SpaceEnc->hDelay); + hMp4SpaceEnc->nSurroundAnalysisBufferDelay = + fdk_sacenc_delay_GetSurroundAnalysisBufferDelay(hMp4SpaceEnc->hDelay); + hMp4SpaceEnc->nBitstreamBufferRead = 0; + hMp4SpaceEnc->nBitstreamBufferWrite = + hMp4SpaceEnc->nBitstreamDelayBuffer - 1; + + if (hMp4SpaceEnc->encMode == SACENC_212) { + /* mode 212 expects no bitstream delay */ + if (hMp4SpaceEnc->nBitstreamBufferWrite != + hMp4SpaceEnc->nBitstreamBufferRead) { + error = SACENC_PARAM_ERROR; + goto bail; + } + + /* mode 212 expects no output buffer delay */ + if (hMp4SpaceEnc->nOutputBufferDelay != 0) { + error = SACENC_PARAM_ERROR; + goto bail; + } + } + + /*** Input delay to obtain a net encoder delay that is a multiple + of the used framelength to ensure synchronization of framing + in artistic down-mix with the corresponding spatial data. ***/ + hMp4SpaceEnc->nDiscardOutFrames = + fdk_sacenc_delay_GetDiscardOutFrames(hMp4SpaceEnc->hDelay); + hMp4SpaceEnc->nInputDelay = + fdk_sacenc_delay_GetDmxAlignBufferDelay(hMp4SpaceEnc->hDelay); + + /* reset independency Flag counter */ + hMp4SpaceEnc->independencyCount = 0; + hMp4SpaceEnc->independencyFlag = 1; + + int i; + + /* write some parameters to bitstream */ + for (i = 0; i < hMp4SpaceEnc->nBitstreamDelayBuffer - 1; i++) { + SPATIALFRAME *pFrameData = NULL; + + if (NULL == (pFrameData = fdk_sacenc_getSpatialFrame( + hMp4SpaceEnc->hBitstreamFormatter, READ_SPATIALFRAME))) { + error = SACENC_INVALID_HANDLE; + goto bail; + } + + pFrameData->bsIndependencyFlag = 1; + pFrameData->framingInfo.numParamSets = 1; + pFrameData->framingInfo.bsFramingType = 0; + + fdk_sacenc_writeSpatialFrame( + hMp4SpaceEnc->ppBitstreamDelayBuffer[i], MAX_MPEGS_BYTES, + &hMp4SpaceEnc->pnOutputBits[i], hMp4SpaceEnc->hBitstreamFormatter); + } + + if ((hMp4SpaceEnc->nInputDelay > MAX_DELAY_INPUT) || + (hMp4SpaceEnc->nOutputBufferDelay > MAX_DELAY_OUTPUT) || + (hMp4SpaceEnc->nSurroundAnalysisBufferDelay > + MAX_DELAY_SURROUND_ANALYSIS) || + (hMp4SpaceEnc->nBitstreamDelayBuffer > MAX_BITSTREAM_DELAY)) { + error = SACENC_INIT_ERROR; + goto bail; + } + } + +bail: + + return error; +} + +static QUANTMODE __mapQuantMode(const MP4SPACEENC_QUANTMODE quantMode) { + QUANTMODE bsQuantMode = QUANTMODE_INVALID; + + switch (quantMode) { + case SACENC_QUANTMODE_FINE: + bsQuantMode = QUANTMODE_FINE; + break; + case SACENC_QUANTMODE_EBQ1: + bsQuantMode = QUANTMODE_EBQ1; + break; + case SACENC_QUANTMODE_EBQ2: + bsQuantMode = QUANTMODE_EBQ2; + break; + case SACENC_QUANTMODE_RSVD3: + case SACENC_QUANTMODE_INVALID: + default: + bsQuantMode = QUANTMODE_INVALID; + } /* switch hEnc->quantMode */ + + return bsQuantMode; +} + +static FDK_SACENC_ERROR FillSpatialSpecificConfig( + const HANDLE_MP4SPACE_ENCODER hEnc, SPATIALSPECIFICCONFIG *const hSsc) { + FDK_SACENC_ERROR error = SACENC_OK; + + if ((NULL == hEnc) || (NULL == hSsc)) { + error = SACENC_INVALID_HANDLE; + } else { + SPACE_TREE_DESCRIPTION spaceTreeDescription; + int i; + + /* Get tree description */ + if (SACENC_OK != (error = fdk_sacenc_spaceTree_GetDescription( + hEnc->hSpaceTree, &spaceTreeDescription))) { + goto bail; + } + + /* Fill SSC */ + FDKmemclear(hSsc, sizeof(SPATIALSPECIFICCONFIG)); /* reset */ + + hSsc->numBands = hEnc->spaceTreeSetup.nParamBands; /* for bsFreqRes */ + + /* Fill tree configuration */ + hSsc->treeDescription.numOttBoxes = spaceTreeDescription.nOttBoxes; + hSsc->treeDescription.numInChan = spaceTreeDescription.nInChannels; + hSsc->treeDescription.numOutChan = spaceTreeDescription.nOutChannels; + + for (i = 0; i < SACENC_MAX_NUM_BOXES; i++) { + hSsc->ottConfig[i].bsOttBands = hSsc->numBands; + } + + switch (hEnc->encMode) { + case SACENC_212: + hSsc->bsTreeConfig = TREE_212; + break; + case SACENC_INVALID_MODE: + default: + error = SACENC_INVALID_CONFIG; + goto bail; + } + + hSsc->bsSamplingFrequency = + hEnc->nSampleRate; /* for bsSamplingFrequencyIndex */ + hSsc->bsFrameLength = hEnc->nFrameTimeSlots - 1; + + /* map decorr type */ + if (DECORR_INVALID == + (hSsc->bsDecorrConfig = mp4SpaceEnc_GetDecorrConfig(hEnc->encMode))) { + error = SACENC_INVALID_CONFIG; + goto bail; + } + + /* map quantMode */ + if (QUANTMODE_INVALID == + (hSsc->bsQuantMode = __mapQuantMode(hEnc->quantMode))) { + error = SACENC_INVALID_CONFIG; + goto bail; + } + + /* Configure Gains*/ + hSsc->bsFixedGainDMX = fdk_sacenc_staticGain_GetDmxGain(hEnc->hStaticGain); + hSsc->bsEnvQuantMode = 0; + + } /* valid handle */ + +bail: + return error; +} + +static FDK_SACENC_ERROR mp4SpaceEnc_FillSpaceTreeSetup( + const HANDLE_MP4SPACE_ENCODER hEnc, + SPACE_TREE_SETUP *const hSpaceTreeSetup) { + FDK_SACENC_ERROR error = SACENC_OK; + + /* Sanity Check */ + if (NULL == hEnc || NULL == hSpaceTreeSetup) { + error = SACENC_INVALID_HANDLE; + } else { + QUANTMODE tmpQuantmode = QUANTMODE_INVALID; + + /* map quantMode */ + if (QUANTMODE_INVALID == (tmpQuantmode = __mapQuantMode(hEnc->quantMode))) { + error = SACENC_INVALID_CONFIG; + goto bail; + } + + hSpaceTreeSetup->nParamBands = hEnc->nParamBands; + hSpaceTreeSetup->bUseCoarseQuantTtoCld = hEnc->useCoarseQuantCld; + hSpaceTreeSetup->bUseCoarseQuantTtoIcc = hEnc->useCoarseQuantIcc; + hSpaceTreeSetup->quantMode = tmpQuantmode; + hSpaceTreeSetup->nHybridBandsMax = hEnc->nHybridBands; + + switch (hEnc->encMode) { + case SACENC_212: + hSpaceTreeSetup->mode = SPACETREE_212; + hSpaceTreeSetup->nChannelsInMax = 2; + break; + case SACENC_INVALID_MODE: + default: + error = SACENC_INVALID_CONFIG; + goto bail; + } /* switch hEnc->encMode */ + + } /* valid handle */ +bail: + return error; +} + +FDK_SACENC_ERROR FDK_sacenc_getInfo(const HANDLE_MP4SPACE_ENCODER hMp4SpaceEnc, + MP4SPACEENC_INFO *const pInfo) { + FDK_SACENC_ERROR error = SACENC_OK; + + if ((NULL == hMp4SpaceEnc) || (NULL == pInfo)) { + error = SACENC_INVALID_HANDLE; + } else { + pInfo->nSampleRate = hMp4SpaceEnc->nSampleRate; + pInfo->nSamplesFrame = hMp4SpaceEnc->nFrameLength; + pInfo->nTotalInputChannels = hMp4SpaceEnc->nInputChannels; + pInfo->nDmxDelay = fdk_sacenc_delay_GetInfoDmxDelay(hMp4SpaceEnc->hDelay); + pInfo->nCodecDelay = + fdk_sacenc_delay_GetInfoCodecDelay(hMp4SpaceEnc->hDelay); + pInfo->nDecoderDelay = + fdk_sacenc_delay_GetInfoDecoderDelay(hMp4SpaceEnc->hDelay); + pInfo->nPayloadDelay = + fdk_sacenc_delay_GetBitstreamFrameBufferSize(hMp4SpaceEnc->hDelay) - 1; + pInfo->nDiscardOutFrames = hMp4SpaceEnc->nDiscardOutFrames; + + pInfo->pSscBuf = &hMp4SpaceEnc->sscBuf; + } + return error; +} + +FDK_SACENC_ERROR FDK_sacenc_setParam(HANDLE_MP4SPACE_ENCODER hMp4SpaceEnc, + const SPACEENC_PARAM param, + const UINT value) { + FDK_SACENC_ERROR error = SACENC_OK; + + /* check encoder handle */ + if (hMp4SpaceEnc == NULL) { + error = SACENC_INVALID_HANDLE; + goto bail; + } + + /* apply param value */ + switch (param) { + case SACENC_LOWDELAY: + if (!((value == 0) || (value == 1) || (value == 2))) { + error = SACENC_INVALID_CONFIG; + break; + } + hMp4SpaceEnc->user.bLdMode = value; + break; + + case SACENC_ENC_MODE: + switch ((MP4SPACEENC_MODE)value) { + case SACENC_212: + hMp4SpaceEnc->user.encMode = (MP4SPACEENC_MODE)value; + break; + default: + error = SACENC_INVALID_CONFIG; + } + break; + + case SACENC_SAMPLERATE: + if (((int)value < 0) || + ((int)value > hMp4SpaceEnc->setup.maxSamplingrate)) { + error = SACENC_INVALID_CONFIG; + break; + } + hMp4SpaceEnc->user.sampleRate = value; + break; + + case SACENC_FRAME_TIME_SLOTS: + if (((int)value < 0) || + ((int)value > hMp4SpaceEnc->setup.maxFrameTimeSlots)) { + error = SACENC_INVALID_CONFIG; + break; + } + hMp4SpaceEnc->user.frameTimeSlots = value; + break; + + case SACENC_PARAM_BANDS: + switch ((MP4SPACEENC_BANDS_CONFIG)value) { + case SACENC_BANDS_4: + case SACENC_BANDS_5: + case SACENC_BANDS_7: + case SACENC_BANDS_9: + case SACENC_BANDS_12: + case SACENC_BANDS_15: + case SACENC_BANDS_23: + hMp4SpaceEnc->user.nParamBands = (MP4SPACEENC_BANDS_CONFIG)value; + break; + default: + error = SACENC_INVALID_CONFIG; + } + break; + + case SACENC_TIME_DOM_DMX: + if (!((value == 0) || (value == 2))) { + error = SACENC_INVALID_CONFIG; + break; + } + hMp4SpaceEnc->user.bTimeDomainDmx = value; + break; + + case SACENC_DMX_GAIN: + if (!((value == 0) || (value == 1) || (value == 2) || (value == 3) || + (value == 4) || (value == 5) || (value == 6) || (value == 7))) { + error = SACENC_INVALID_CONFIG; + break; + } + error = fdk_sacenc_staticGain_SetDmxGain(hMp4SpaceEnc->hStaticGainConfig, + (MP4SPACEENC_DMX_GAIN)value); + break; + + case SACENC_COARSE_QUANT: + if (!((value == 0) || (value == 1))) { + error = SACENC_INVALID_CONFIG; + break; + } + hMp4SpaceEnc->user.bUseCoarseQuant = value; + break; + + case SACENC_QUANT_MODE: + switch ((MP4SPACEENC_QUANTMODE)value) { + case SACENC_QUANTMODE_FINE: + case SACENC_QUANTMODE_EBQ1: + case SACENC_QUANTMODE_EBQ2: + hMp4SpaceEnc->user.quantMode = (MP4SPACEENC_QUANTMODE)value; + break; + default: + error = SACENC_INVALID_CONFIG; + } + break; + + case SACENC_TIME_ALIGNMENT: + if ((INT)value < -32768 || (INT)value > 32767) { + error = SACENC_INVALID_CONFIG; + break; + } + hMp4SpaceEnc->user.timeAlignment = value; + break; + + case SACENC_INDEPENDENCY_COUNT: + hMp4SpaceEnc->independencyCount = value; + break; + + case SACENC_INDEPENDENCY_FACTOR: + hMp4SpaceEnc->user.independencyFactor = value; + break; + + default: + error = SACENC_UNSUPPORTED_PARAMETER; + break; + } /* switch(param) */ +bail: + return error; +} + +FDK_SACENC_ERROR FDK_sacenc_getLibInfo(LIB_INFO *info) { + int i = 0; + + if (info == NULL) { + return SACENC_INVALID_HANDLE; + } + + FDK_toolsGetLibInfo(info); + + /* search for next free tab */ + for (i = 0; i < FDK_MODULE_LAST; i++) { + if (info[i].module_id == FDK_NONE) break; + } + if (i == FDK_MODULE_LAST) { + return SACENC_INIT_ERROR; + } + + info[i].module_id = FDK_MPSENC; + info[i].build_date = SACENC_LIB_BUILD_DATE; + info[i].build_time = SACENC_LIB_BUILD_TIME; + info[i].title = SACENC_LIB_TITLE; + info[i].version = LIB_VERSION(SACENC_LIB_VL0, SACENC_LIB_VL1, SACENC_LIB_VL2); + LIB_VERSION_STRING(&info[i]); + + /* Capability flags */ + info[i].flags = 0; + /* End of flags */ + + return SACENC_OK; +} + +static DECORRCONFIG mp4SpaceEnc_GetDecorrConfig( + const MP4SPACEENC_MODE encMode) { + DECORRCONFIG decorrConfig = DECORR_INVALID; + + /* set decorrConfig dependent on tree mode */ + switch (encMode) { + case SACENC_212: + decorrConfig = DECORR_QMFSPLIT0; + break; + case SACENC_INVALID_MODE: + default: + decorrConfig = DECORR_INVALID; + } + return decorrConfig; +} + +static FDK_SACENC_ERROR mp4SpaceEnc_InitNumParamBands( + HANDLE_MP4SPACE_ENCODER hEnc, const MP4SPACEENC_BANDS_CONFIG nParamBands) { + FDK_SACENC_ERROR error = SACENC_OK; + + /* Set/Check nParamBands */ + int k = 0; + const int n = sizeof(pValidBands_Ld) / sizeof(UCHAR); + const UCHAR *pBands = pValidBands_Ld; + + while (k < n && pBands[k] != (UCHAR)nParamBands) ++k; + if (k == n) { + hEnc->nParamBands = SACENC_BANDS_INVALID; + } else { + hEnc->nParamBands = nParamBands; + } + return error; +} |