diff options
author | The Android Open Source Project <initial-contribution@android.com> | 2012-07-11 10:15:24 -0700 |
---|---|---|
committer | The Android Open Source Project <initial-contribution@android.com> | 2012-07-11 10:15:24 -0700 |
commit | 2228e360595641dd906bf1773307f43d304f5b2e (patch) | |
tree | 57f3d390ebb0782cc0de0fb984c8ea7e45b4f386 /libAACenc/src/aacenc.cpp | |
download | fdk-aac-dabplus-2228e360595641dd906bf1773307f43d304f5b2e.tar.gz fdk-aac-dabplus-2228e360595641dd906bf1773307f43d304f5b2e.tar.bz2 fdk-aac-dabplus-2228e360595641dd906bf1773307f43d304f5b2e.zip |
Snapshot 2bda038c163298531d47394bc2c09e1409c5d0db
Change-Id: If584e579464f28b97d50e51fc76ba654a5536c54
Diffstat (limited to 'libAACenc/src/aacenc.cpp')
-rw-r--r-- | libAACenc/src/aacenc.cpp | 1031 |
1 files changed, 1031 insertions, 0 deletions
diff --git a/libAACenc/src/aacenc.cpp b/libAACenc/src/aacenc.cpp new file mode 100644 index 0000000..85083cd --- /dev/null +++ b/libAACenc/src/aacenc.cpp @@ -0,0 +1,1031 @@ + +/* ----------------------------------------------------------------------------------------------------------- +Software License for The Fraunhofer FDK AAC Codec Library for Android + +© Copyright 1995 - 2012 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 +----------------------------------------------------------------------------------------------------------- */ + +/*************************** Fast MPEG AAC Audio Encoder ********************** + + Initial author: M. Schug / A. Groeschel + contents/description: fast aac coder functions + +******************************************************************************/ + +#include "aacenc.h" + +#include "bitenc.h" +#include "interface.h" +#include "psy_configuration.h" +#include "psy_main.h" +#include "qc_main.h" +#include "bandwidth.h" +#include "channel_map.h" +#include "tns_func.h" +#include "aacEnc_ram.h" + +#include "genericStds.h" + + + + +#define MIN_BUFSIZE_PER_EFF_CHAN 6144 + +static AAC_ENCODER_ERROR FDKaacEnc_InitCheckAncillary(INT bitRate, + INT framelength, + INT ancillaryRate, + INT *ancillaryBitsPerFrame, + INT sampleRate); + +INT FDKaacEnc_LimitBitrate( + HANDLE_TRANSPORTENC hTpEnc, + INT coreSamplingRate, + INT frameLength, + INT nChannels, + INT nChannelsEff, + INT bitRate, + INT averageBits, + INT *pAverageBitsPerFrame, + INT bitrateMode, + INT nSubFrames + ) +{ + INT transportBits, prevBitRate, averageBitsPerFrame, shift = 0, iter=0; + + while ( (frameLength & ~((1<<(shift+1))-1)) == frameLength + && (coreSamplingRate & ~((1<<(shift+1))-1)) == coreSamplingRate ) + { + shift ++; + } + + do { + prevBitRate = bitRate; + averageBitsPerFrame = (bitRate*(frameLength>>shift)) / (coreSamplingRate>>shift) / nSubFrames; + + if (pAverageBitsPerFrame != NULL) { + *pAverageBitsPerFrame = averageBitsPerFrame; + } + + if (hTpEnc != NULL) { + transportBits = transportEnc_GetStaticBits(hTpEnc, averageBitsPerFrame); + } else { + /* Assume some worst case */ + transportBits = 208; + } + + bitRate = FDKmax(bitRate, ((((40 * nChannels) + transportBits + frameLength) * (coreSamplingRate)) / frameLength) ); + FDK_ASSERT(bitRate >= 0); + + bitRate = FDKmin(bitRate, ((nChannelsEff * MIN_BUFSIZE_PER_EFF_CHAN)*(coreSamplingRate>>shift)) / (frameLength>>shift)) ; + FDK_ASSERT(bitRate >= 0); + + } while (prevBitRate != bitRate && iter++ < 3) ; + + return bitRate; +} + + +typedef struct +{ + AACENC_BITRATE_MODE bitrateMode; + int chanBitrate[2]; /* mono/stereo settings */ +} CONFIG_TAB_ENTRY_VBR; + +static const CONFIG_TAB_ENTRY_VBR configTabVBR[] = { + {AACENC_BR_MODE_CBR, { 0, 0}} , + {AACENC_BR_MODE_VBR_1, { 32000, 20000}} , + {AACENC_BR_MODE_VBR_2, { 40000, 32000}} , + {AACENC_BR_MODE_VBR_3, { 56000, 48000}} , + {AACENC_BR_MODE_VBR_4, { 72000, 64000}} , + {AACENC_BR_MODE_VBR_5, {112000, 96000}} +}; + +/*----------------------------------------------------------------------------- + + functionname: FDKaacEnc_GetVBRBitrate + description: Get VBR bitrate from vbr quality + input params: int vbrQuality (VBR0, VBR1, VBR2) + channelMode + returns: vbr bitrate + + ------------------------------------------------------------------------------*/ +INT FDKaacEnc_GetVBRBitrate(INT bitrateMode, CHANNEL_MODE channelMode) +{ + INT bitrate = 0; + INT monoStereoMode = 0; /* default mono */ + + if (FDKaacEnc_GetMonoStereoMode(channelMode)==EL_MODE_STEREO) { + monoStereoMode = 1; + } + + switch((AACENC_BITRATE_MODE)bitrateMode){ + case AACENC_BR_MODE_VBR_1: + case AACENC_BR_MODE_VBR_2: + case AACENC_BR_MODE_VBR_3: + case AACENC_BR_MODE_VBR_4: + case AACENC_BR_MODE_VBR_5: + bitrate = configTabVBR[bitrateMode].chanBitrate[monoStereoMode]; + break; + case AACENC_BR_MODE_INVALID: + case AACENC_BR_MODE_CBR: + case AACENC_BR_MODE_SFR: + case AACENC_BR_MODE_FF: + default: + bitrate = 0; + break; + } + + /* convert channel bitrate to overall bitrate*/ + bitrate *= FDKaacEnc_GetChannelModeConfiguration(channelMode)->nChannelsEff; + + return bitrate; +} + +/** + * \brief Convert encoder bitreservoir value for transport library. + * + * \param bitrateMode Bitratemode used in current encoder instance. Se ::AACENC_BITRATE_MODE + * \param bitresTotal Encoder bitreservoir level in bits. + * + * \return Corrected bitreservoir level used in transport library. + */ +static INT FDKaacEnc_EncBitresToTpBitres( + const AACENC_BITRATE_MODE bitrateMode, + const INT bitresTotal + ) +{ + INT transporBitreservoir = 0; + + switch (bitrateMode) { + case AACENC_BR_MODE_CBR: + transporBitreservoir = bitresTotal; /* encoder bitreservoir level */ + break; + case AACENC_BR_MODE_VBR_1: + case AACENC_BR_MODE_VBR_2: + case AACENC_BR_MODE_VBR_3: + case AACENC_BR_MODE_VBR_4: + case AACENC_BR_MODE_VBR_5: + transporBitreservoir = FDK_INT_MAX; /* signal variable bitrate */ + break; + case AACENC_BR_MODE_FF: + case AACENC_BR_MODE_SFR: + transporBitreservoir = 0; /* super framing and fixed framing */ + break; /* without bitreservoir signaling */ + default: + case AACENC_BR_MODE_INVALID: + transporBitreservoir = 0; /* invalid configuration*/ + FDK_ASSERT(0); + } + + return transporBitreservoir; +} + +/*----------------------------------------------------------------------------- + + functionname: FDKaacEnc_AacInitDefaultConfig + description: gives reasonable default configuration + returns: --- + + ------------------------------------------------------------------------------*/ +void FDKaacEnc_AacInitDefaultConfig(AACENC_CONFIG *config) +{ + /* make thepre initialization of the structs flexible */ + FDKmemclear(config, sizeof(AACENC_CONFIG)); + + /* default ancillary */ + config->anc_Rate = 0; /* no ancillary data */ + config->ancDataBitRate = 0; /* no additional consumed bitrate */ + + /* default configurations */ + config->bitRate = -1; /* bitrate must be set*/ + config->averageBits = -1; /* instead of bitrate/s we can configure bits/superframe */ + config->bitrateMode = 0; + config->bandWidth = 0; /* get bandwidth from table */ + config->useTns = TNS_ENABLE_MASK; /* tns enabled completly */ + config->usePns = 1; /* depending on channelBitrate this might be set to 0 later */ + config->useIS = 1; /* Intensity Stereo Configuration */ + config->framelength = DEFAULT_FRAMELENGTH; /* used frame size */ + config->syntaxFlags = 0; /* default syntax with no specialities */ + config->epConfig = -1; /* no ER syntax -> no additional error protection */ + config->nSubFrames = 1; /* default, no sub frames */ + config->channelOrder = CH_ORDER_MPEG; /* Use MPEG channel ordering. */ + config->channelMode = MODE_UNKNOWN; + config->minBitsPerFrame = -1; /* minum number of bits in each AU */ + config->maxBitsPerFrame = -1; /* minum number of bits in each AU */ + config->bitreservoir = -1; /* default, uninitialized value */ + + /* init tabs in fixpoint_math */ + InitLdInt(); + InitInvSqrtTab(); +} + + +/*--------------------------------------------------------------------------- + + functionname: FDKaacEnc_Open + description: allocate and initialize a new encoder instance + returns: error code + + ---------------------------------------------------------------------------*/ +AAC_ENCODER_ERROR FDKaacEnc_Open(HANDLE_AAC_ENC *phAacEnc, + const INT nElements, + const INT nChannels, + const INT nSubFrames) +{ + AAC_ENCODER_ERROR ErrorStatus; + AAC_ENC *hAacEnc = NULL; + UCHAR *dynamicRAM = NULL; + + if (phAacEnc==NULL) { + return AAC_ENC_INVALID_HANDLE; + } + + /* allocate encoder structure */ + hAacEnc = GetRam_aacEnc_AacEncoder(); + if (hAacEnc == NULL) { + ErrorStatus = AAC_ENC_NO_MEMORY; + goto bail; + } + FDKmemclear(hAacEnc, sizeof(AAC_ENC)); + + hAacEnc->dynamic_RAM = GetAACdynamic_RAM(); + dynamicRAM = (UCHAR*)hAacEnc->dynamic_RAM; + + /* allocate the Psy aud Psy Out structure */ + ErrorStatus = FDKaacEnc_PsyNew(&hAacEnc->psyKernel, + nElements, + nChannels + ,dynamicRAM + ); + if (ErrorStatus != AAC_ENC_OK) + goto bail; + + ErrorStatus = FDKaacEnc_PsyOutNew(hAacEnc->psyOut, + nElements, + nChannels, + nSubFrames + ,dynamicRAM + ); + if (ErrorStatus != AAC_ENC_OK) + goto bail; + + /* allocate the Q&C Out structure */ + ErrorStatus = FDKaacEnc_QCOutNew(hAacEnc->qcOut, + nElements, + nChannels, + nSubFrames + ,dynamicRAM + ); + if (ErrorStatus != AAC_ENC_OK) + goto bail; + + /* allocate the Q&C kernel */ + ErrorStatus = FDKaacEnc_QCNew(&hAacEnc->qcKernel, + nElements + ,dynamicRAM + ); + if (ErrorStatus != AAC_ENC_OK) + goto bail; + + hAacEnc->maxChannels = nChannels; + hAacEnc->maxElements = nElements; + hAacEnc->maxFrames = nSubFrames; + +bail: + *phAacEnc = hAacEnc; + return ErrorStatus; +} + + +AAC_ENCODER_ERROR FDKaacEnc_Initialize(HANDLE_AAC_ENC hAacEnc, + AACENC_CONFIG *config, /* pre-initialized config struct */ + HANDLE_TRANSPORTENC hTpEnc, + ULONG initFlags) +{ + AAC_ENCODER_ERROR ErrorStatus; + INT psyBitrate, tnsMask; //INT profile = 1; + CHANNEL_MAPPING *cm = NULL; + + INT qmbfac, qbw; + FIXP_DBL mbfac, bw_ratio; + QC_INIT qcInit; + INT averageBitsPerFrame = 0; + + if (config==NULL) + return AAC_ENC_INVALID_HANDLE; + + /******************* sanity checks *******************/ + + /* check config structure */ + if (config->nChannels < 1 || config->nChannels > (6)) { + return AAC_ENC_UNSUPPORTED_CHANNELCONFIG; + } + + /* check sample rate */ + switch (config->sampleRate) + { + case 8000: + case 11025: + case 12000: + case 16000: + case 22050: + case 24000: + case 32000: + case 44100: + case 48000: + case 64000: + case 88200: + case 96000: + break; + default: + return AAC_ENC_UNSUPPORTED_SAMPLINGRATE; + } + + /* bitrate has to be set */ + if (config->bitRate==-1) { + return AAC_ENC_UNSUPPORTED_BITRATE; + } + + /* check bit rate */ + + if (FDKaacEnc_LimitBitrate( + hTpEnc, + config->sampleRate, + config->framelength, + config->nChannels, + FDKaacEnc_GetChannelModeConfiguration(config->channelMode)->nChannelsEff, + config->bitRate, + config->averageBits, + &averageBitsPerFrame, + config->bitrateMode, + config->nSubFrames + ) != config->bitRate ) + { + return AAC_ENC_UNSUPPORTED_BITRATE; + } + + if (config->syntaxFlags & AC_ER_VCB11) { + return AAC_ENC_UNSUPPORTED_ER_FORMAT; + } + if (config->syntaxFlags & AC_ER_HCR) { + return AAC_ENC_UNSUPPORTED_ER_FORMAT; + } + + /* check frame length */ + switch (config->framelength) + { + case 1024: + if ( config->audioObjectType != AOT_AAC_LC + && config->audioObjectType != AOT_SBR + && config->audioObjectType != AOT_PS + && config->audioObjectType != AOT_ER_AAC_LC + && config->audioObjectType != AOT_AAC_SCAL ) + { + return AAC_ENC_INVALID_FRAME_LENGTH; + } + break; + case 512: + case 480: + if ( config->audioObjectType != AOT_ER_AAC_LD + && config->audioObjectType != AOT_ER_AAC_ELD ) + { + return AAC_ENC_INVALID_FRAME_LENGTH; + } + break; + default: + return AAC_ENC_INVALID_FRAME_LENGTH; + } + + if (config->anc_Rate != 0) { + + ErrorStatus = FDKaacEnc_InitCheckAncillary(config->bitRate, + config->framelength, + config->anc_Rate, + &hAacEnc->ancillaryBitsPerFrame, + config->sampleRate); + if (ErrorStatus != AAC_ENC_OK) + goto bail; + + + /* update estimated consumed bitrate */ + config->ancDataBitRate += ( (hAacEnc->ancillaryBitsPerFrame * config->sampleRate) / config->framelength ); + + } + + /* maximal allowed DSE bytes in frame */ + { + /* fixpoint calculation*/ + INT q_res, encBitrate, sc; + FIXP_DBL tmp = fDivNorm(config->framelength, config->sampleRate, &q_res); + encBitrate = (config->bitRate/*-config->ancDataBitRate*/)- (INT)(config->nChannels*8000); + sc = CountLeadingBits(encBitrate); + config->maxAncBytesPerAU = FDKmin( (256), FDKmax(0,(INT)(fMultDiv2(tmp, (FIXP_DBL)(encBitrate<<sc))>>(-q_res+sc-1+3))) ); + } + + /* bind config to hAacEnc->config */ + hAacEnc->config = config; + + /* set hAacEnc->bitrateMode */ + hAacEnc->bitrateMode = (AACENC_BITRATE_MODE)config->bitrateMode; + + hAacEnc->encoderMode = config->channelMode; + + ErrorStatus = FDKaacEnc_InitChannelMapping(hAacEnc->encoderMode, config->channelOrder, &hAacEnc->channelMapping); + if (ErrorStatus != AAC_ENC_OK) + goto bail; + + cm = &hAacEnc->channelMapping; + + ErrorStatus = FDKaacEnc_DetermineBandWidth(&hAacEnc->config->bandWidth, + config->bandWidth, + config->bitRate - config->ancDataBitRate, + hAacEnc->bitrateMode, + config->sampleRate, + config->framelength, + cm, + hAacEnc->encoderMode); + if (ErrorStatus != AAC_ENC_OK) + goto bail; + + hAacEnc->bandwidth90dB = (INT)hAacEnc->config->bandWidth; + + tnsMask = config->useTns ? TNS_ENABLE_MASK : 0x0; + psyBitrate = config->bitRate - config->ancDataBitRate; + + ErrorStatus = FDKaacEnc_psyInit(hAacEnc->psyKernel, + hAacEnc->psyOut, + hAacEnc->maxFrames, + hAacEnc->maxChannels, + config->audioObjectType, + cm); + if (ErrorStatus != AAC_ENC_OK) + goto bail; + + ErrorStatus = FDKaacEnc_psyMainInit(hAacEnc->psyKernel, + config->audioObjectType, + cm, + config->sampleRate, + config->framelength, + psyBitrate, + tnsMask, + hAacEnc->bandwidth90dB, + config->usePns, + config->useIS, + config->syntaxFlags, + initFlags); + if (ErrorStatus != AAC_ENC_OK) + goto bail; + + ErrorStatus = FDKaacEnc_QCOutInit(hAacEnc->qcOut, hAacEnc->maxFrames, cm); + if (ErrorStatus != AAC_ENC_OK) + goto bail; + + + + qcInit.channelMapping = &hAacEnc->channelMapping; + qcInit.sceCpe = 0; + + { + int maxBitres; + qcInit.averageBits = (averageBitsPerFrame+7)&~7; + maxBitres = (MIN_BUFSIZE_PER_EFF_CHAN*cm->nChannelsEff) - qcInit.averageBits; + qcInit.bitRes = (config->bitreservoir!=-1) ? FDKmin(config->bitreservoir, maxBitres) : maxBitres; + + qcInit.maxBits = fixMin(MIN_BUFSIZE_PER_EFF_CHAN*cm->nChannelsEff, ((averageBitsPerFrame+7)&~7)+qcInit.bitRes); + qcInit.maxBits = (config->maxBitsPerFrame!=-1) ? fixMin(qcInit.maxBits, config->maxBitsPerFrame) : qcInit.maxBits; + + qcInit.minBits = fixMax(0, ((averageBitsPerFrame-1)&~7)-qcInit.bitRes-transportEnc_GetStaticBits(hTpEnc, ((averageBitsPerFrame+7)&~7)+qcInit.bitRes)); + qcInit.minBits = (config->minBitsPerFrame!=-1) ? fixMax(qcInit.minBits, config->minBitsPerFrame) : qcInit.minBits; + } + + qcInit.nSubFrames = config->nSubFrames; + qcInit.padding.paddingRest = config->sampleRate; + + /* Calc meanPe */ + bw_ratio = fDivNorm((FIXP_DBL)hAacEnc->bandwidth90dB, (FIXP_DBL)(config->sampleRate>>1), &qbw); + qbw = DFRACT_BITS-1-qbw; + /* qcInit.meanPe = 10.0f * FRAME_LEN_LONG * hAacEnc->bandwidth90dB/(config->sampleRate/2.0f); */ + qcInit.meanPe = fMult(bw_ratio, (FIXP_DBL)((10*config->framelength)<<16)) >> (qbw-15); + + /* Calc maxBitFac */ + mbfac = fDivNorm((MIN_BUFSIZE_PER_EFF_CHAN-744)*cm->nChannelsEff, qcInit.averageBits/qcInit.nSubFrames, &qmbfac); + qmbfac = DFRACT_BITS-1-qmbfac; + qcInit.maxBitFac = (qmbfac > 24) ? (mbfac >> (qmbfac - 24)):(mbfac << (24 - qmbfac)); + + switch(config->bitrateMode){ + case AACENC_BR_MODE_CBR: + qcInit.bitrateMode = QCDATA_BR_MODE_CBR; + break; + case AACENC_BR_MODE_VBR_1: + qcInit.bitrateMode = QCDATA_BR_MODE_VBR_1; + break; + case AACENC_BR_MODE_VBR_2: + qcInit.bitrateMode = QCDATA_BR_MODE_VBR_2; + break; + case AACENC_BR_MODE_VBR_3: + qcInit.bitrateMode = QCDATA_BR_MODE_VBR_3; + break; + case AACENC_BR_MODE_VBR_4: + qcInit.bitrateMode = QCDATA_BR_MODE_VBR_4; + break; + case AACENC_BR_MODE_VBR_5: + qcInit.bitrateMode = QCDATA_BR_MODE_VBR_5; + break; + case AACENC_BR_MODE_SFR: + qcInit.bitrateMode = QCDATA_BR_MODE_SFR; + break; + case AACENC_BR_MODE_FF: + qcInit.bitrateMode = QCDATA_BR_MODE_FF; + break; + default: + ErrorStatus = AAC_ENC_UNSUPPORTED_BITRATE_MODE; + goto bail; + } + + qcInit.invQuant = (config->useRequant)?2:0; + + /* maxIterations should be set to the maximum number of requantization iterations that are + * allowed before the crash recovery functionality is activated. This setting should be adjusted + * to the processing power available, i.e. to the processing power headroom in one frame that is + * still left after normal encoding without requantization. Please note that if activated this + * functionality is used most likely only in cases where the encoder is operating beyond + * recommended settings, i.e. the audio quality is suboptimal anyway. Activating the crash + * recovery does not further reduce audio quality significantly in these cases. */ + if ( (config->audioObjectType == AOT_ER_AAC_LD) || (config->audioObjectType == AOT_ER_AAC_ELD) ) { + qcInit.maxIterations = 2; + } + else + { + qcInit.maxIterations = 5; + } + + qcInit.bitrate = config->bitRate - config->ancDataBitRate; + + qcInit.staticBits = transportEnc_GetStaticBits(hTpEnc, qcInit.averageBits/qcInit.nSubFrames); + + ErrorStatus = FDKaacEnc_QCInit(hAacEnc->qcKernel, &qcInit); + if (ErrorStatus != AAC_ENC_OK) + goto bail; + + /* Map virtual aot's to intern aot used in bitstream writer. */ + switch (hAacEnc->config->audioObjectType) { + case AOT_MP2_AAC_LC: + case AOT_DABPLUS_AAC_LC: + hAacEnc->aot = AOT_AAC_LC; + break; + case AOT_MP2_SBR: + case AOT_DABPLUS_SBR: + hAacEnc->aot = AOT_SBR; + break; + case AOT_MP2_PS: + case AOT_DABPLUS_PS: + hAacEnc->aot = AOT_PS; + break; + default: + hAacEnc->aot = hAacEnc->config->audioObjectType; + } + + /* common things */ + + return AAC_ENC_OK; + +bail: + + return ErrorStatus; +} + + +/*--------------------------------------------------------------------------- + + functionname: FDKaacEnc_EncodeFrame + description: encodes one frame + returns: error code + + ---------------------------------------------------------------------------*/ +AAC_ENCODER_ERROR FDKaacEnc_EncodeFrame( HANDLE_AAC_ENC hAacEnc, /* encoder handle */ + HANDLE_TRANSPORTENC hTpEnc, + INT_PCM* RESTRICT inputBuffer, + INT* nOutBytes, + AACENC_EXT_PAYLOAD extPayload[MAX_TOTAL_EXT_PAYLOADS] + ) +{ + AAC_ENCODER_ERROR ErrorStatus; + int el, n, c=0; + UCHAR extPayloadUsed[MAX_TOTAL_EXT_PAYLOADS]; + + CHANNEL_MAPPING *cm = &hAacEnc->channelMapping; + + + + PSY_OUT *psyOut = hAacEnc->psyOut[c]; + QC_OUT *qcOut = hAacEnc->qcOut[c]; + + FDKmemclear(extPayloadUsed, MAX_TOTAL_EXT_PAYLOADS * sizeof(UCHAR)); + + qcOut->elementExtBits = 0; /* sum up all extended bit of each element */ + qcOut->staticBits = 0; /* sum up side info bits of each element */ + qcOut->totalNoRedPe = 0; /* sum up PE */ + + /* advance psychoacoustics */ + for (el=0; el<cm->nElements; el++) { + ELEMENT_INFO elInfo = cm->elInfo[el]; + + if ( (elInfo.elType == ID_SCE) + || (elInfo.elType == ID_CPE) + || (elInfo.elType == ID_LFE) ) + { + int ch; + + /* update pointer!*/ + for(ch=0;ch<elInfo.nChannelsInEl;ch++) { + PSY_OUT_CHANNEL *psyOutChan = psyOut->psyOutElement[el]->psyOutChannel[ch]; + QC_OUT_CHANNEL *qcOutChan = qcOut->qcElement[el]->qcOutChannel[ch]; + + psyOutChan->mdctSpectrum = qcOutChan->mdctSpectrum; + psyOutChan->sfbSpreadEnergy = qcOutChan->sfbSpreadEnergy; + psyOutChan->sfbEnergy = qcOutChan->sfbEnergy; + psyOutChan->sfbEnergyLdData = qcOutChan->sfbEnergyLdData; + psyOutChan->sfbMinSnrLdData = qcOutChan->sfbMinSnrLdData; + psyOutChan->sfbThresholdLdData = qcOutChan->sfbThresholdLdData; + + } + + FDKaacEnc_psyMain(elInfo.nChannelsInEl, + hAacEnc->psyKernel->psyElement[el], + hAacEnc->psyKernel->psyDynamic, + hAacEnc->psyKernel->psyConf, + psyOut->psyOutElement[el], + inputBuffer, + cm->elInfo[el].ChannelIndex, + cm->nChannels + + ); + + /* FormFactor, Pe and staticBitDemand calculation */ + ErrorStatus = FDKaacEnc_QCMainPrepare(&elInfo, + hAacEnc->qcKernel->hAdjThr->adjThrStateElem[el], + psyOut->psyOutElement[el], + qcOut->qcElement[el], + hAacEnc->aot, + hAacEnc->config->syntaxFlags, + hAacEnc->config->epConfig); + + if (ErrorStatus != AAC_ENC_OK) + return ErrorStatus; + + /*-------------------------------------------- */ + + qcOut->qcElement[el]->extBitsUsed = 0; + qcOut->qcElement[el]->nExtensions = 0; + /* reset extension payload */ + FDKmemclear(&qcOut->qcElement[el]->extension, (1)*sizeof(QC_OUT_EXTENSION)); + + for ( n = 0; n < MAX_TOTAL_EXT_PAYLOADS; n++ ) { + if ( !extPayloadUsed[n] + && (extPayload[n].associatedChElement == el) + && (extPayload[n].dataSize > 0) + && (extPayload[n].pData != NULL) ) + { + int idx = qcOut->qcElement[el]->nExtensions++; + + qcOut->qcElement[el]->extension[idx].type = extPayload[n].dataType; /* Perform a sanity check on the type? */ + qcOut->qcElement[el]->extension[idx].nPayloadBits = extPayload[n].dataSize; + qcOut->qcElement[el]->extension[idx].pPayload = extPayload[n].pData; + /* Now ask the bitstream encoder how many bits we need to encode the data with the current bitstream syntax: */ + qcOut->qcElement[el]->extBitsUsed += + FDKaacEnc_writeExtensionData( NULL, + &qcOut->qcElement[el]->extension[idx], + 0, 0, + hAacEnc->config->syntaxFlags, + hAacEnc->aot, + hAacEnc->config->epConfig ); + extPayloadUsed[n] = 1; + } + } + + /* sum up extension and static bits for all channel elements */ + qcOut->elementExtBits += qcOut->qcElement[el]->extBitsUsed; + qcOut->staticBits += qcOut->qcElement[el]->staticBitsUsed; + + /* sum up pe */ + qcOut->totalNoRedPe += qcOut->qcElement[el]->peData.pe; + } + } + + qcOut->nExtensions = 0; + qcOut->globalExtBits = 0; + + /* reset extension payload */ + FDKmemclear(&qcOut->extension, (2+2)*sizeof(QC_OUT_EXTENSION)); + + /* Add extension payload not assigned to an channel element + (Ancillary data is the only supported type up to now) */ + for ( n = 0; n < MAX_TOTAL_EXT_PAYLOADS; n++ ) { + if ( !extPayloadUsed[n] + && (extPayload[n].associatedChElement == -1) + && (extPayload[n].pData != NULL) ) + { + UINT payloadBits = 0; + + if (extPayload[n].dataType == EXT_DATA_ELEMENT) { + if (hAacEnc->ancillaryBitsPerFrame) { + /* granted frame dse bitrate */ + payloadBits = hAacEnc->ancillaryBitsPerFrame; + } + else { + /* write anc data if bitrate constraint fulfilled */ + if ((extPayload[n].dataSize>>3) <= hAacEnc->config->maxAncBytesPerAU) { + payloadBits = extPayload[n].dataSize; + } + } + payloadBits = fixMin( extPayload[n].dataSize, payloadBits ); + } else { + payloadBits = extPayload[n].dataSize; + } + + if (payloadBits > 0) + { + int idx = qcOut->nExtensions++; + + qcOut->extension[idx].type = extPayload[n].dataType; /* Perform a sanity check on the type? */ + qcOut->extension[idx].nPayloadBits = payloadBits; + qcOut->extension[idx].pPayload = extPayload[n].pData; + /* Now ask the bitstream encoder how many bits we need to encode the data with the current bitstream syntax: */ + qcOut->globalExtBits += FDKaacEnc_writeExtensionData( NULL, + &qcOut->extension[idx], + 0, 0, + hAacEnc->config->syntaxFlags, + hAacEnc->aot, + hAacEnc->config->epConfig ); + if (extPayload[n].dataType == EXT_DATA_ELEMENT) { + /* substract the processed bits */ + extPayload[n].dataSize -= payloadBits; + } + extPayloadUsed[n] = 1; + } + } + } + + if (!(hAacEnc->config->syntaxFlags & (AC_SCALABLE|AC_ER))) { + qcOut->globalExtBits += EL_ID_BITS; /* add bits for ID_END */ + } + + /* build bitstream all nSubFrames */ + { + INT totalBits = 0; /* Total AU bits */; + INT avgTotalBits = 0; + + /*-------------------------------------------- */ + /* Get average total bits */ + /*-------------------------------------------- */ + { + /* frame wise bitrate adaption */ + FDKaacEnc_AdjustBitrate(hAacEnc->qcKernel, + cm, + &avgTotalBits, + hAacEnc->config->bitRate, + hAacEnc->config->sampleRate, + hAacEnc->config->framelength); + + /* adjust super frame bitrate */ + avgTotalBits *= hAacEnc->config->nSubFrames; + } + + /* Make first estimate of transport header overhead. + Take maximum possible frame size into account to prevent bitreservoir underrun. */ + hAacEnc->qcKernel->globHdrBits = transportEnc_GetStaticBits(hTpEnc, avgTotalBits + hAacEnc->qcKernel->bitResTot); + + + /*-------------------------------------------- */ + /*-------------------------------------------- */ + /*-------------------------------------------- */ + + ErrorStatus = FDKaacEnc_QCMain(hAacEnc->qcKernel, + hAacEnc->psyOut, + hAacEnc->qcOut, + avgTotalBits, + cm + ,hAacEnc->aot, + hAacEnc->config->syntaxFlags, + hAacEnc->config->epConfig); + + if (ErrorStatus != AAC_ENC_OK) + return ErrorStatus; + /*-------------------------------------------- */ + + /*-------------------------------------------- */ + ErrorStatus = FDKaacEnc_updateFillBits(cm, + hAacEnc->qcKernel, + hAacEnc->qcKernel->elementBits, + hAacEnc->qcOut); + if (ErrorStatus != AAC_ENC_OK) + return ErrorStatus; + + /*-------------------------------------------- */ + ErrorStatus = FDKaacEnc_FinalizeBitConsumption(cm, + hAacEnc->qcKernel, + qcOut, + qcOut->qcElement, + hTpEnc, + hAacEnc->aot, + hAacEnc->config->syntaxFlags, + hAacEnc->config->epConfig); + if (ErrorStatus != AAC_ENC_OK) + return ErrorStatus; + /*-------------------------------------------- */ + totalBits += qcOut->totalBits; + + + /*-------------------------------------------- */ + FDKaacEnc_updateBitres(cm, + hAacEnc->qcKernel, + hAacEnc->qcOut); + + /*-------------------------------------------- */ + + /* for ( all sub frames ) ... */ + /* write bitstream header */ + transportEnc_WriteAccessUnit( + hTpEnc, + totalBits, + FDKaacEnc_EncBitresToTpBitres(hAacEnc->bitrateMode, hAacEnc->qcKernel->bitResTot), + cm->nChannelsEff); + + /* write bitstream */ + ErrorStatus = FDKaacEnc_WriteBitstream( + hTpEnc, + cm, + qcOut, + psyOut, + hAacEnc->qcKernel, + hAacEnc->aot, + hAacEnc->config->syntaxFlags, + hAacEnc->config->epConfig); + + if (ErrorStatus != AAC_ENC_OK) + return ErrorStatus; + + /* transportEnc_EndAccessUnit() is being called inside FDKaacEnc_WriteBitstream() */ + transportEnc_GetFrame(hTpEnc, nOutBytes); + + } /* -end- if (curFrame==hAacEnc->qcKernel->nSubFrames) */ + + + /*-------------------------------------------- */ + return AAC_ENC_OK; +} + +/*--------------------------------------------------------------------------- + + functionname:FDKaacEnc_Close + description: delete encoder instance + returns: + + ---------------------------------------------------------------------------*/ + +void FDKaacEnc_Close( HANDLE_AAC_ENC* phAacEnc) /* encoder handle */ +{ + if (*phAacEnc == NULL) { + return; + } + AAC_ENC *hAacEnc = (AAC_ENC*)*phAacEnc; + + if (hAacEnc->dynamic_RAM != NULL) + FreeAACdynamic_RAM(&hAacEnc->dynamic_RAM); + + FDKaacEnc_PsyClose(&hAacEnc->psyKernel,hAacEnc->psyOut); + + FDKaacEnc_QCClose(&hAacEnc->qcKernel, hAacEnc->qcOut); + + FreeRam_aacEnc_AacEncoder(phAacEnc); +} + + +/* The following functions are in this source file only for convenience and */ +/* need not be visible outside of a possible encoder library. */ + +/* basic defines for ancillary data */ +#define MAX_ANCRATE 19200 /* ancillary rate >= 19200 isn't valid */ + +/*--------------------------------------------------------------------------- + + functionname: FDKaacEnc_InitCheckAncillary + description: initialize and check ancillary data struct + return: if success or NULL if error + + ---------------------------------------------------------------------------*/ +static AAC_ENCODER_ERROR FDKaacEnc_InitCheckAncillary(INT bitRate, + INT framelength, + INT ancillaryRate, + INT *ancillaryBitsPerFrame, + INT sampleRate) +{ + INT diffToByteAlign; + + /* don't use negative ancillary rates */ + if ( ancillaryRate < -1 ) + return AAC_ENC_UNSUPPORTED_ANC_BITRATE; + + /* check if ancillary rate is ok */ + if ( (ancillaryRate != (-1)) && (ancillaryRate != 0) ) { + /* ancRate <= 15% of bitrate && ancRate < 19200 */ + if ( ( ancillaryRate >= MAX_ANCRATE ) || + ( (ancillaryRate * 20) > (bitRate * 3) ) ) { + return AAC_ENC_UNSUPPORTED_ANC_BITRATE; + } + } + else if (ancillaryRate == -1) { + /* if no special ancRate is requested but a ancillary file is + stated, then generate a ancillary rate matching to the bitrate */ + if (bitRate >= (MAX_ANCRATE * 10)) { + /* ancillary rate is 19199 */ + ancillaryRate = (MAX_ANCRATE - 1); + } + else { /* 10% of bitrate */ + ancillaryRate = bitRate / 10; + } + } + + /* make ancillaryBitsPerFrame byte align */ + *ancillaryBitsPerFrame = (ancillaryRate * framelength ) / sampleRate; + diffToByteAlign = *ancillaryBitsPerFrame % 8; + *ancillaryBitsPerFrame = *ancillaryBitsPerFrame - diffToByteAlign; + + return AAC_ENC_OK; +} |