| /* ----------------------------------------------------------------------------- |
| 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 |
| ----------------------------------------------------------------------------- */ |
| |
| /**************************** AAC encoder library ****************************** |
| |
| Author(s): M. Schug / A. Groeschel |
| |
| 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 BITRES_MAX_LD 4000 |
| #define BITRES_MIN_LD 500 |
| #define BITRATE_MAX_LD 70000 /* Max assumed bitrate for bitres calculation */ |
| #define BITRATE_MIN_LD 12000 /* Min assumed bitrate for bitres calculation */ |
| |
| INT FDKaacEnc_CalcBitsPerFrame(const INT bitRate, const INT frameLength, |
| const INT samplingRate) { |
| int shift = 0; |
| while ((frameLength & ~((1 << (shift + 1)) - 1)) == frameLength && |
| (samplingRate & ~((1 << (shift + 1)) - 1)) == samplingRate) { |
| shift++; |
| } |
| |
| return (bitRate * (frameLength >> shift)) / (samplingRate >> shift); |
| } |
| |
| INT FDKaacEnc_CalcBitrate(const INT bitsPerFrame, const INT frameLength, |
| const INT samplingRate) { |
| int shift = 0; |
| while ((frameLength & ~((1 << (shift + 1)) - 1)) == frameLength && |
| (samplingRate & ~((1 << (shift + 1)) - 1)) == samplingRate) { |
| shift++; |
| } |
| |
| return (bitsPerFrame * (samplingRate >> shift)) / (frameLength >> shift); |
| } |
| |
| static AAC_ENCODER_ERROR FDKaacEnc_InitCheckAncillary( |
| INT bitRate, INT framelength, INT ancillaryRate, INT *ancillaryBitsPerFrame, |
| INT sampleRate); |
| |
| INT FDKaacEnc_LimitBitrate(HANDLE_TRANSPORTENC hTpEnc, AUDIO_OBJECT_TYPE aot, |
| INT coreSamplingRate, INT frameLength, INT nChannels, |
| INT nChannelsEff, INT bitRate, INT averageBits, |
| INT *pAverageBitsPerFrame, |
| AACENC_BITRATE_MODE bitrateMode, INT nSubFrames) { |
| INT transportBits, prevBitRate, averageBitsPerFrame, minBitrate = 0, iter = 0; |
| INT minBitsPerFrame = 40 * nChannels; |
| if (isLowDelay(aot)) { |
| minBitrate = 8000 * nChannelsEff; |
| } |
| |
| do { |
| prevBitRate = bitRate; |
| averageBitsPerFrame = |
| FDKaacEnc_CalcBitsPerFrame(bitRate, frameLength, coreSamplingRate) / |
| nSubFrames; |
| |
| if (pAverageBitsPerFrame != NULL) { |
| *pAverageBitsPerFrame = averageBitsPerFrame; |
| } |
| |
| if (hTpEnc != NULL) { |
| transportBits = transportEnc_GetStaticBits(hTpEnc, averageBitsPerFrame); |
| } else { |
| /* Assume some worst case */ |
| transportBits = 208; |
| } |
| |
| bitRate = fMax(bitRate, |
| fMax(minBitrate, |
| FDKaacEnc_CalcBitrate((minBitsPerFrame + transportBits), |
| frameLength, coreSamplingRate))); |
| FDK_ASSERT(bitRate >= 0); |
| |
| bitRate = fMin(bitRate, FDKaacEnc_CalcBitrate( |
| (nChannelsEff * MIN_BUFSIZE_PER_EFF_CHAN), |
| frameLength, coreSamplingRate)); |
| 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(AACENC_BITRATE_MODE bitrateMode, |
| CHANNEL_MODE channelMode) { |
| INT bitrate = 0; |
| INT monoStereoMode = 0; /* default mono */ |
| |
| if (FDKaacEnc_GetMonoStereoMode(channelMode) == EL_MODE_STEREO) { |
| monoStereoMode = 1; |
| } |
| |
| switch (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 hAacEnc Encoder handle |
| * |
| * \return Corrected bitreservoir level used in transport library. |
| */ |
| static INT FDKaacEnc_EncBitresToTpBitres(const HANDLE_AAC_ENC hAacEnc) { |
| INT transportBitreservoir = 0; |
| |
| switch (hAacEnc->bitrateMode) { |
| case AACENC_BR_MODE_CBR: |
| transportBitreservoir = |
| hAacEnc->qcKernel->bitResTot; /* 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: |
| transportBitreservoir = FDK_INT_MAX; /* signal variable bitrate */ |
| break; |
| case AACENC_BR_MODE_SFR: |
| transportBitreservoir = 0; /* super framing and fixed framing */ |
| break; /* without bitreservoir signaling */ |
| default: |
| case AACENC_BR_MODE_INVALID: |
| transportBitreservoir = 0; /* invalid configuration*/ |
| } |
| |
| if (hAacEnc->config->audioMuxVersion == 2) { |
| transportBitreservoir = |
| MIN_BUFSIZE_PER_EFF_CHAN * hAacEnc->channelMapping.nChannelsEff; |
| } |
| |
| return transportBitreservoir; |
| } |
| |
| INT FDKaacEnc_GetBitReservoirState(const HANDLE_AAC_ENC hAacEncoder) { |
| return FDKaacEnc_EncBitresToTpBitres(hAacEncoder); |
| } |
| |
| /*----------------------------------------------------------------------------- |
| |
| functionname: FDKaacEnc_AacInitDefaultConfig |
| description: gives reasonable default configuration |
| returns: --- |
| |
| ------------------------------------------------------------------------------*/ |
| void FDKaacEnc_AacInitDefaultConfig(AACENC_CONFIG *config) { |
| /* make the preinitialization 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 = |
| AACENC_BR_MODE_CBR; /* set bitrate mode to constant bitrate */ |
| 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->useMS = 1; /* MS Stereo tool */ |
| config->framelength = -1; /* Framesize not configured */ |
| 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->audioMuxVersion = -1; /* audio mux version not configured */ |
| config->downscaleFactor = |
| 1; /* downscale factor for ELD reduced delay mode, 1 is normal ELD */ |
| } |
| |
| /*--------------------------------------------------------------------------- |
| |
| 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)); |
| |
| if (NULL == (hAacEnc->dynamic_RAM = GetAACdynamic_RAM())) { |
| ErrorStatus = AAC_ENC_NO_MEMORY; |
| goto bail; |
| } |
| 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 mbfac_e, qbw; |
| FIXP_DBL mbfac, bw_ratio; |
| QC_INIT qcInit; |
| INT averageBitsPerFrame = 0; |
| int bitresMin = 0; /* the bitreservoir is always big for AAC-LC */ |
| const CHANNEL_MODE prevChannelMode = hAacEnc->encoderMode; |
| |
| if (config == NULL) return AAC_ENC_INVALID_HANDLE; |
| |
| /******************* sanity checks *******************/ |
| |
| /* check config structure */ |
| if (config->nChannels < 1 || config->nChannels > (8)) { |
| 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->audioObjectType, config->sampleRate, |
| config->framelength, config->nChannels, |
| FDKaacEnc_GetChannelModeConfiguration(config->channelMode) |
| ->nChannelsEff, |
| config->bitRate, config->averageBits, &averageBitsPerFrame, |
| config->bitrateMode, config->nSubFrames) != config->bitRate && |
| !(AACENC_BR_MODE_IS_VBR(config->bitrateMode))) { |
| 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 (isLowDelay(config->audioObjectType)) { |
| return AAC_ENC_INVALID_FRAME_LENGTH; |
| } |
| break; |
| case 128: |
| case 256: |
| case 512: |
| case 120: |
| case 240: |
| case 480: |
| if (!isLowDelay(config->audioObjectType)) { |
| 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 += |
| FDKaacEnc_CalcBitrate(hAacEnc->ancillaryBitsPerFrame, |
| config->framelength, config->sampleRate); |
| } |
| |
| /* maximal allowed DSE bytes in frame */ |
| config->maxAncBytesPerAU = |
| fMin((256), fMax(0, FDKaacEnc_CalcBitsPerFrame( |
| (config->bitRate - (config->nChannels * 8000)), |
| config->framelength, config->sampleRate) >> |
| 3)); |
| |
| /* bind config to hAacEnc->config */ |
| hAacEnc->config = config; |
| |
| /* set hAacEnc->bitrateMode */ |
| hAacEnc->bitrateMode = 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( |
| config->bandWidth, config->bitRate - config->ancDataBitRate, |
| hAacEnc->bitrateMode, config->sampleRate, config->framelength, cm, |
| hAacEnc->encoderMode, &hAacEnc->config->bandWidth); |
| 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; |
| |
| if ((hAacEnc->encoderMode != prevChannelMode) || (initFlags != 0)) { |
| /* Reinitialize psych states in case of channel configuration change ore if |
| * full reset requested. */ |
| 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->useMS, 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; |
| |
| if (AACENC_BR_MODE_IS_VBR(config->bitrateMode)) { |
| qcInit.averageBits = (averageBitsPerFrame + 7) & ~7; |
| qcInit.bitRes = MIN_BUFSIZE_PER_EFF_CHAN * cm->nChannelsEff; |
| qcInit.maxBits = MIN_BUFSIZE_PER_EFF_CHAN * cm->nChannelsEff; |
| qcInit.maxBits = (config->maxBitsPerFrame != -1) |
| ? fixMin(qcInit.maxBits, config->maxBitsPerFrame) |
| : qcInit.maxBits; |
| qcInit.maxBits = fixMax(qcInit.maxBits, (averageBitsPerFrame + 7) & ~7); |
| qcInit.minBits = |
| (config->minBitsPerFrame != -1) ? config->minBitsPerFrame : 0; |
| qcInit.minBits = fixMin(qcInit.minBits, averageBitsPerFrame & ~7); |
| } else { |
| INT bitreservoir = -1; /* default bitrservoir size*/ |
| if (isLowDelay(config->audioObjectType)) { |
| INT brPerChannel = config->bitRate / config->nChannels; |
| brPerChannel = fMin(BITRATE_MAX_LD, fMax(BITRATE_MIN_LD, brPerChannel)); |
| |
| /* bitreservoir = |
| * (maxBitRes-minBitRes)/(maxBitRate-minBitrate)*(bitRate-minBitrate)+minBitRes; |
| */ |
| FIXP_DBL slope = fDivNorm( |
| (brPerChannel - BITRATE_MIN_LD), |
| BITRATE_MAX_LD - BITRATE_MIN_LD); /* calc slope for interpolation */ |
| bitreservoir = fMultI(slope, (INT)(BITRES_MAX_LD - BITRES_MIN_LD)) + |
| BITRES_MIN_LD; /* interpolate */ |
| bitreservoir = bitreservoir & ~7; /* align to bytes */ |
| bitresMin = BITRES_MIN_LD; |
| } |
| |
| int maxBitres; |
| qcInit.averageBits = (averageBitsPerFrame + 7) & ~7; |
| maxBitres = |
| (MIN_BUFSIZE_PER_EFF_CHAN * cm->nChannelsEff) - qcInit.averageBits; |
| qcInit.bitRes = |
| (bitreservoir != -1) ? fMin(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.maxBits = |
| fixMin(MIN_BUFSIZE_PER_EFF_CHAN * cm->nChannelsEff, |
| fixMax(qcInit.maxBits, (averageBitsPerFrame + 7 + 8) & ~7)); |
| |
| 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.minBits = fixMin( |
| qcInit.minBits, (averageBitsPerFrame - |
| transportEnc_GetStaticBits(hTpEnc, qcInit.maxBits)) & |
| ~7); |
| } |
| |
| qcInit.sampleRate = config->sampleRate; |
| qcInit.isLowDelay = isLowDelay(config->audioObjectType) ? 1 : 0; |
| qcInit.nSubFrames = config->nSubFrames; |
| qcInit.padding.paddingRest = config->sampleRate; |
| |
| if (qcInit.bitRes >= bitresMin * config->nChannels) { |
| qcInit.bitResMode = AACENC_BR_MODE_FULL; /* full bitreservoir */ |
| } else if (qcInit.bitRes > 0) { |
| qcInit.bitResMode = AACENC_BR_MODE_REDUCED; /* reduced bitreservoir */ |
| } else { |
| qcInit.bitResMode = AACENC_BR_MODE_DISABLED; /* disabled bitreservoir */ |
| } |
| |
| /* Configure bitrate distribution strategy. */ |
| switch (config->channelMode) { |
| case MODE_1_2: |
| case MODE_1_2_1: |
| case MODE_1_2_2: |
| case MODE_1_2_2_1: |
| case MODE_6_1: |
| case MODE_1_2_2_2_1: |
| case MODE_7_1_BACK: |
| case MODE_7_1_TOP_FRONT: |
| case MODE_7_1_REAR_SURROUND: |
| case MODE_7_1_FRONT_CENTER: |
| qcInit.bitDistributionMode = 0; /* over all elements bitrate estimation */ |
| break; |
| case MODE_1: |
| case MODE_2: |
| default: /* all non mpeg defined channel modes */ |
| qcInit.bitDistributionMode = 1; /* element-wise bit bitrate estimation */ |
| } /* config->channelMode */ |
| |
| /* Calc meanPe: qcInit.meanPe = 10.0f * FRAME_LEN_LONG * |
| * hAacEnc->bandwidth90dB/(config->sampleRate/2.0f); */ |
| bw_ratio = |
| fDivNorm((FIXP_DBL)(10 * config->framelength * hAacEnc->bandwidth90dB), |
| (FIXP_DBL)(config->sampleRate), &qbw); |
| qcInit.meanPe = |
| fMax((INT)scaleValue(bw_ratio, qbw + 1 - (DFRACT_BITS - 1)), 1); |
| |
| /* Calc maxBitFac, scale it to 24 bit accuracy */ |
| mbfac = fDivNorm(qcInit.maxBits, qcInit.averageBits / qcInit.nSubFrames, |
| &mbfac_e); |
| qcInit.maxBitFac = scaleValue(mbfac, -(DFRACT_BITS - 1 - 24 - mbfac_e)); |
| |
| 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 (isLowDelay(config->audioObjectType)) { |
| 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, initFlags); |
| 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: |
| hAacEnc->aot = AOT_AAC_LC; |
| break; |
| case AOT_MP2_SBR: |
| hAacEnc->aot = AOT_SBR; |
| 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, |
| const UINT inputBufferBufSize, 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; |
| } |
| |
| ErrorStatus = FDKaacEnc_psyMain( |
| elInfo.nChannelsInEl, hAacEnc->psyKernel->psyElement[el], |
| hAacEnc->psyKernel->psyDynamic, hAacEnc->psyKernel->psyConf, |
| psyOut->psyOutElement[el], inputBuffer, inputBufferBufSize, |
| cm->elInfo[el].ChannelIndex, cm->nChannels); |
| |
| if (ErrorStatus != AAC_ENC_OK) return ErrorStatus; |
| |
| /* 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 */ |
| if (TRANSPORTENC_OK != |
| transportEnc_WriteAccessUnit(hTpEnc, totalBits, |
| FDKaacEnc_EncBitresToTpBitres(hAacEnc), |
| cm->nChannelsEff)) { |
| return AAC_ENC_UNKNOWN; |
| } |
| |
| /* 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() */ |
| if (TRANSPORTENC_OK != transportEnc_GetFrame(hTpEnc, nOutBytes)) { |
| return AAC_ENC_UNKNOWN; |
| } |
| |
| } /* -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) { |
| /* 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 = |
| FDKaacEnc_CalcBitsPerFrame(ancillaryRate, framelength, sampleRate) & ~0x7; |
| |
| return AAC_ENC_OK; |
| } |