From 0e5af65c467b2423a0b857ae3ad98c91acc1e190 Mon Sep 17 00:00:00 2001 From: "Matthias P. Braendli" Date: Mon, 11 Nov 2019 11:38:02 +0100 Subject: Include patched FDK-AAC in the repository The initial idea was to get the DAB+ patch into upstream, but since that follows the android source releases, there is no place for a custom DAB+ patch there. So instead of having to maintain a patched fdk-aac that has to have the same .so version as the distribution package on which it is installed, we prefer having a separate fdk-aac-dab library to avoid collision. At that point, there's no reason to keep fdk-aac in a separate repository, as odr-audioenc is the only tool that needs DAB+ encoding support. Including it here simplifies installation, and makes it consistent with toolame-dab, also shipped in this repository. DAB+ decoding support (needed by ODR-SourceCompanion, dablin, etisnoop, welle.io and others) can be done using upstream FDK-AAC. --- fdk-aac/libAACenc/src/qc_main.cpp | 1555 +++++++++++++++++++++++++++++++++++++ 1 file changed, 1555 insertions(+) create mode 100644 fdk-aac/libAACenc/src/qc_main.cpp (limited to 'fdk-aac/libAACenc/src/qc_main.cpp') diff --git a/fdk-aac/libAACenc/src/qc_main.cpp b/fdk-aac/libAACenc/src/qc_main.cpp new file mode 100644 index 0000000..0bf234c --- /dev/null +++ b/fdk-aac/libAACenc/src/qc_main.cpp @@ -0,0 +1,1555 @@ +/* ----------------------------------------------------------------------------- +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. Werner + + Description: Quantizing & coding + +*******************************************************************************/ + +#include "qc_main.h" +#include "quantize.h" +#include "interface.h" +#include "adj_thr.h" +#include "sf_estim.h" +#include "bit_cnt.h" +#include "dyn_bits.h" +#include "channel_map.h" +#include "aacEnc_ram.h" + +#include "genericStds.h" + +#define AACENC_DZQ_BR_THR 32000 /* Dead zone quantizer bitrate threshold */ + +typedef struct { + QCDATA_BR_MODE bitrateMode; + LONG vbrQualFactor; +} TAB_VBR_QUAL_FACTOR; + +static const TAB_VBR_QUAL_FACTOR tableVbrQualFactor[] = { + {QCDATA_BR_MODE_VBR_1, + FL2FXCONST_DBL(0.160f)}, /* Approx. 32 - 48 (AC-LC), 32 - 56 + (AAC-LD/ELD) kbps/channel */ + {QCDATA_BR_MODE_VBR_2, + FL2FXCONST_DBL(0.148f)}, /* Approx. 40 - 56 (AC-LC), 40 - 64 + (AAC-LD/ELD) kbps/channel */ + {QCDATA_BR_MODE_VBR_3, + FL2FXCONST_DBL(0.135f)}, /* Approx. 48 - 64 (AC-LC), 48 - 72 + (AAC-LD/ELD) kbps/channel */ + {QCDATA_BR_MODE_VBR_4, + FL2FXCONST_DBL(0.111f)}, /* Approx. 64 - 80 (AC-LC), 64 - 88 + (AAC-LD/ELD) kbps/channel */ + {QCDATA_BR_MODE_VBR_5, + FL2FXCONST_DBL(0.070f)} /* Approx. 96 - 120 (AC-LC), 112 - 144 + (AAC-LD/ELD) kbps/channel */ +}; + +static INT isConstantBitrateMode(const QCDATA_BR_MODE bitrateMode) { + return (((bitrateMode == QCDATA_BR_MODE_CBR) || + (bitrateMode == QCDATA_BR_MODE_SFR) || + (bitrateMode == QCDATA_BR_MODE_FF)) + ? 1 + : 0); +} + +typedef enum { + FRAME_LEN_BYTES_MODULO = 1, + FRAME_LEN_BYTES_INT = 2 +} FRAME_LEN_RESULT_MODE; + +/* forward declarations */ + +static INT FDKaacEnc_calcMaxValueInSfb(INT sfbCnt, INT maxSfbPerGroup, + INT sfbPerGroup, INT* RESTRICT sfbOffset, + SHORT* RESTRICT quantSpectrum, + UINT* RESTRICT maxValue); + +static void FDKaacEnc_crashRecovery(INT nChannels, + PSY_OUT_ELEMENT* psyOutElement, + QC_OUT* qcOut, QC_OUT_ELEMENT* qcElement, + INT bitsToSave, AUDIO_OBJECT_TYPE aot, + UINT syntaxFlags, SCHAR epConfig); + +static AAC_ENCODER_ERROR FDKaacEnc_reduceBitConsumption( + int* iterations, const int maxIterations, int gainAdjustment, + int* chConstraintsFulfilled, int* calculateQuant, int nChannels, + PSY_OUT_ELEMENT* psyOutElement, QC_OUT* qcOut, QC_OUT_ELEMENT* qcOutElement, + ELEMENT_BITS* elBits, AUDIO_OBJECT_TYPE aot, UINT syntaxFlags, + SCHAR epConfig); + +void FDKaacEnc_QCClose(QC_STATE** phQCstate, QC_OUT** phQC); + +/***************************************************************************** + + functionname: FDKaacEnc_calcFrameLen + description: + returns: + input: + output: + +*****************************************************************************/ +static INT FDKaacEnc_calcFrameLen(INT bitRate, INT sampleRate, + INT granuleLength, + FRAME_LEN_RESULT_MODE mode) { + INT result; + + result = ((granuleLength) >> 3) * (bitRate); + + switch (mode) { + case FRAME_LEN_BYTES_MODULO: + result %= sampleRate; + break; + case FRAME_LEN_BYTES_INT: + result /= sampleRate; + break; + } + return (result); +} + +/***************************************************************************** + + functionname:FDKaacEnc_framePadding + description: Calculates if padding is needed for actual frame + returns: + input: + output: + +*****************************************************************************/ +static INT FDKaacEnc_framePadding(INT bitRate, INT sampleRate, + INT granuleLength, INT* paddingRest) { + INT paddingOn; + INT difference; + + paddingOn = 0; + + difference = FDKaacEnc_calcFrameLen(bitRate, sampleRate, granuleLength, + FRAME_LEN_BYTES_MODULO); + *paddingRest -= difference; + + if (*paddingRest <= 0) { + paddingOn = 1; + *paddingRest += sampleRate; + } + + return (paddingOn); +} + +/********************************************************************************* + + functionname: FDKaacEnc_QCOutNew + description: + return: + +**********************************************************************************/ +AAC_ENCODER_ERROR FDKaacEnc_QCOutNew(QC_OUT** phQC, const INT nElements, + const INT nChannels, const INT nSubFrames, + UCHAR* dynamic_RAM) { + AAC_ENCODER_ERROR ErrorStatus; + int n, i; + int elInc = 0, chInc = 0; + + for (n = 0; n < nSubFrames; n++) { + phQC[n] = GetRam_aacEnc_QCout(n); + if (phQC[n] == NULL) { + ErrorStatus = AAC_ENC_NO_MEMORY; + goto QCOutNew_bail; + } + + for (i = 0; i < nChannels; i++) { + phQC[n]->pQcOutChannels[i] = GetRam_aacEnc_QCchannel(chInc, dynamic_RAM); + if (phQC[n]->pQcOutChannels[i] == NULL) { + ErrorStatus = AAC_ENC_NO_MEMORY; + goto QCOutNew_bail; + } + + chInc++; + } /* nChannels */ + + for (i = 0; i < nElements; i++) { + phQC[n]->qcElement[i] = GetRam_aacEnc_QCelement(elInc); + if (phQC[n]->qcElement[i] == NULL) { + ErrorStatus = AAC_ENC_NO_MEMORY; + goto QCOutNew_bail; + } + elInc++; + + /* initialize pointer to dynamic buffer which are used in adjust + * thresholds */ + phQC[n]->qcElement[i]->dynMem_Ah_Flag = dynamic_RAM + (P_BUF_1); + phQC[n]->qcElement[i]->dynMem_Thr_Exp = + dynamic_RAM + (P_BUF_1) + ADJ_THR_AH_FLAG_SIZE; + phQC[n]->qcElement[i]->dynMem_SfbNActiveLinesLdData = + dynamic_RAM + (P_BUF_1) + ADJ_THR_AH_FLAG_SIZE + ADJ_THR_THR_EXP_SIZE; + + } /* nElements */ + + } /* nSubFrames */ + + return AAC_ENC_OK; + +QCOutNew_bail: + return ErrorStatus; +} + +/********************************************************************************* + + functionname: FDKaacEnc_QCOutInit + description: + return: + +**********************************************************************************/ +AAC_ENCODER_ERROR FDKaacEnc_QCOutInit(QC_OUT* phQC[(1)], const INT nSubFrames, + const CHANNEL_MAPPING* cm) { + INT n, i, ch; + + for (n = 0; n < nSubFrames; n++) { + INT chInc = 0; + for (i = 0; i < cm->nElements; i++) { + for (ch = 0; ch < cm->elInfo[i].nChannelsInEl; ch++) { + phQC[n]->qcElement[i]->qcOutChannel[ch] = + phQC[n]->pQcOutChannels[chInc]; + chInc++; + } /* chInEl */ + } /* nElements */ + } /* nSubFrames */ + + return AAC_ENC_OK; +} + +/********************************************************************************* + + functionname: FDKaacEnc_QCNew + description: + return: + +**********************************************************************************/ +AAC_ENCODER_ERROR FDKaacEnc_QCNew(QC_STATE** phQC, INT nElements, + UCHAR* dynamic_RAM) { + AAC_ENCODER_ERROR ErrorStatus; + int i; + + QC_STATE* hQC = GetRam_aacEnc_QCstate(); + *phQC = hQC; + if (hQC == NULL) { + ErrorStatus = AAC_ENC_NO_MEMORY; + goto QCNew_bail; + } + + if (FDKaacEnc_AdjThrNew(&hQC->hAdjThr, nElements)) { + ErrorStatus = AAC_ENC_NO_MEMORY; + goto QCNew_bail; + } + + if (FDKaacEnc_BCNew(&(hQC->hBitCounter), dynamic_RAM)) { + ErrorStatus = AAC_ENC_NO_MEMORY; + goto QCNew_bail; + } + + for (i = 0; i < nElements; i++) { + hQC->elementBits[i] = GetRam_aacEnc_ElementBits(i); + if (hQC->elementBits[i] == NULL) { + ErrorStatus = AAC_ENC_NO_MEMORY; + goto QCNew_bail; + } + } + + return AAC_ENC_OK; + +QCNew_bail: + FDKaacEnc_QCClose(phQC, NULL); + return ErrorStatus; +} + +/********************************************************************************* + + functionname: FDKaacEnc_QCInit + description: + return: + +**********************************************************************************/ +AAC_ENCODER_ERROR FDKaacEnc_QCInit(QC_STATE* hQC, struct QC_INIT* init, + const ULONG initFlags) { + AAC_ENCODER_ERROR err = AAC_ENC_OK; + + int i; + hQC->maxBitsPerFrame = init->maxBits; + hQC->minBitsPerFrame = init->minBits; + hQC->nElements = init->channelMapping->nElements; + if ((initFlags != 0) || ((init->bitrateMode != QCDATA_BR_MODE_FF) && + (hQC->bitResTotMax != init->bitRes))) { + hQC->bitResTot = init->bitRes; + } + hQC->bitResTotMax = init->bitRes; + hQC->maxBitFac = init->maxBitFac; + hQC->bitrateMode = init->bitrateMode; + hQC->invQuant = init->invQuant; + hQC->maxIterations = init->maxIterations; + + if (isConstantBitrateMode(hQC->bitrateMode)) { + /* 0: full bitreservoir, 1: reduced bitreservoir, 2: disabled bitreservoir + */ + hQC->bitResMode = init->bitResMode; + } else { + hQC->bitResMode = AACENC_BR_MODE_FULL; /* full bitreservoir */ + } + + hQC->padding.paddingRest = init->padding.paddingRest; + + hQC->globHdrBits = init->staticBits; /* Bit overhead due to transport */ + + err = FDKaacEnc_InitElementBits( + hQC, init->channelMapping, init->bitrate, + (init->averageBits / init->nSubFrames) - hQC->globHdrBits, + hQC->maxBitsPerFrame / init->channelMapping->nChannelsEff); + if (err != AAC_ENC_OK) goto bail; + + hQC->vbrQualFactor = FL2FXCONST_DBL(0.f); + for (i = 0; + i < (int)(sizeof(tableVbrQualFactor) / sizeof(TAB_VBR_QUAL_FACTOR)); + i++) { + if (hQC->bitrateMode == tableVbrQualFactor[i].bitrateMode) { + hQC->vbrQualFactor = (FIXP_DBL)tableVbrQualFactor[i].vbrQualFactor; + break; + } + } + + if (init->channelMapping->nChannelsEff == 1 && + (init->bitrate / init->channelMapping->nChannelsEff) < + AACENC_DZQ_BR_THR && + init->isLowDelay != + 0) /* watch out here: init->bitrate is the bitrate "minus" the + standard SBR bitrate (=2500kbps) --> for the FDK the OFFSTE + tuning should start somewhere below 32000kbps-2500kbps ... so + everything is fine here */ + { + hQC->dZoneQuantEnable = 1; + } else { + hQC->dZoneQuantEnable = 0; + } + + FDKaacEnc_AdjThrInit( + hQC->hAdjThr, init->meanPe, hQC->invQuant, init->channelMapping, + init->sampleRate, /* output sample rate */ + init->bitrate, /* total bitrate */ + init->isLowDelay, /* if set, calc bits2PE factor + depending on samplerate */ + init->bitResMode /* for a small bitreservoir, the pe + correction is calc'd differently */ + , + hQC->dZoneQuantEnable, init->bitDistributionMode, hQC->vbrQualFactor); + +bail: + return err; +} + +/********************************************************************************* + + functionname: FDKaacEnc_QCMainPrepare + description: + return: + +**********************************************************************************/ +AAC_ENCODER_ERROR FDKaacEnc_QCMainPrepare( + ELEMENT_INFO* elInfo, ATS_ELEMENT* RESTRICT adjThrStateElement, + PSY_OUT_ELEMENT* RESTRICT psyOutElement, + QC_OUT_ELEMENT* RESTRICT qcOutElement, AUDIO_OBJECT_TYPE aot, + UINT syntaxFlags, SCHAR epConfig) { + AAC_ENCODER_ERROR ErrorStatus = AAC_ENC_OK; + INT nChannels = elInfo->nChannelsInEl; + + PSY_OUT_CHANNEL** RESTRICT psyOutChannel = + psyOutElement->psyOutChannel; /* may be modified in-place */ + + FDKaacEnc_CalcFormFactor(qcOutElement->qcOutChannel, psyOutChannel, + nChannels); + + /* prepare and calculate PE without reduction */ + FDKaacEnc_peCalculation(&qcOutElement->peData, psyOutChannel, + qcOutElement->qcOutChannel, &psyOutElement->toolsInfo, + adjThrStateElement, nChannels); + + ErrorStatus = FDKaacEnc_ChannelElementWrite( + NULL, elInfo, NULL, psyOutElement, psyOutElement->psyOutChannel, + syntaxFlags, aot, epConfig, &qcOutElement->staticBitsUsed, 0); + + return ErrorStatus; +} + +/********************************************************************************* + + functionname: FDKaacEnc_AdjustBitrate + description: adjusts framelength via padding on a frame to frame +basis, to achieve a bitrate that demands a non byte aligned framelength return: +errorcode + +**********************************************************************************/ +AAC_ENCODER_ERROR FDKaacEnc_AdjustBitrate( + QC_STATE* RESTRICT hQC, CHANNEL_MAPPING* RESTRICT cm, INT* avgTotalBits, + INT bitRate, /* total bitrate */ + INT sampleRate, /* output sampling rate */ + INT granuleLength) /* frame length */ +{ + INT paddingOn; + INT frameLen; + //fprintf(stderr, "hQC->padding.paddingRest=%d bytes! (before)\n", hQC->padding.paddingRest); + + /* Do we need an extra padding byte? */ + paddingOn = FDKaacEnc_framePadding(bitRate, sampleRate, granuleLength, + &hQC->padding.paddingRest); + + frameLen = + paddingOn + FDKaacEnc_calcFrameLen(bitRate, sampleRate, granuleLength, + FRAME_LEN_BYTES_INT); + + *avgTotalBits = frameLen << 3; + + return AAC_ENC_OK; +} + +#define isAudioElement(elType) \ + ((elType == ID_SCE) || (elType == ID_CPE) || (elType == ID_LFE)) + +/********************************************************************************* + + functionname: FDKaacEnc_distributeElementDynBits + description: distributes all bits over all elements. The relative bit + distibution is described in the ELEMENT_INFO of the + appropriate element. The bit distribution table is + initialized in FDKaacEnc_InitChannelMapping(). + return: errorcode + +**********************************************************************************/ +static AAC_ENCODER_ERROR FDKaacEnc_distributeElementDynBits( + QC_STATE* hQC, QC_OUT_ELEMENT* qcElement[((8))], CHANNEL_MAPPING* cm, + INT codeBits) { + INT i; /* counter variable */ + INT totalBits = 0; /* sum of bits over all elements */ + + for (i = (cm->nElements - 1); i >= 0; i--) { + if (isAudioElement(cm->elInfo[i].elType)) { + qcElement[i]->grantedDynBits = + fMax(0, fMultI(hQC->elementBits[i]->relativeBitsEl, codeBits)); + totalBits += qcElement[i]->grantedDynBits; + } + } + + /* Due to inaccuracies with the multiplication, codeBits may differ from + totalBits. For that case, the difference must be added/substracted again + to/from one element, i.e: + Negative differences are substracted from the element with the most bits. + Positive differences are added to the element with the least bits. + */ + if (codeBits != totalBits) { + INT elMaxBits = cm->nElements - 1; /* element with the most bits */ + INT elMinBits = cm->nElements - 1; /* element with the least bits */ + + /* Search for biggest and smallest audio element */ + for (i = (cm->nElements - 1); i >= 0; i--) { + if (isAudioElement(cm->elInfo[i].elType)) { + if (qcElement[i]->grantedDynBits > + qcElement[elMaxBits]->grantedDynBits) { + elMaxBits = i; + } + if (qcElement[i]->grantedDynBits < + qcElement[elMinBits]->grantedDynBits) { + elMinBits = i; + } + } + } + /* Compensate for bit distibution difference */ + if (codeBits - totalBits > 0) { + qcElement[elMinBits]->grantedDynBits += codeBits - totalBits; + } else { + qcElement[elMaxBits]->grantedDynBits += codeBits - totalBits; + } + } + + return AAC_ENC_OK; +} + +/** + * \brief Verify whether minBitsPerFrame criterion can be satisfied. + * + * This function evaluates the bit consumption only if minBitsPerFrame parameter + * is not 0. In hyperframing mode the difference between grantedDynBits and + * usedDynBits of all sub frames results the number of fillbits to be written. + * This bits can be distrubitued in superframe to reach minBitsPerFrame bit + * consumption in single AU's. The return value denotes if enough desired fill + * bits are available to achieve minBitsPerFrame in all frames. This check can + * only be used within superframes. + * + * \param qcOut Pointer to coding data struct. + * \param minBitsPerFrame Minimal number of bits to be consumed in each frame. + * \param nSubFrames Number of frames in superframe + * + * \return + * - 1: all fine + * - 0: criterion not fulfilled + */ +static int checkMinFrameBitsDemand(QC_OUT** qcOut, const INT minBitsPerFrame, + const INT nSubFrames) { + int result = 1; /* all fine*/ + return result; +} + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/********************************************************************************* + + functionname: FDKaacEnc_getMinimalStaticBitdemand + description: calculate minmal size of static bits by reduction , + to zero spectrum and deactivating tns and MS + return: number of static bits + +**********************************************************************************/ +static int FDKaacEnc_getMinimalStaticBitdemand(CHANNEL_MAPPING* cm, + PSY_OUT** psyOut) { + AUDIO_OBJECT_TYPE aot = AOT_AAC_LC; + UINT syntaxFlags = 0; + SCHAR epConfig = -1; + int i, bitcount = 0; + + for (i = 0; i < cm->nElements; i++) { + ELEMENT_INFO elInfo = cm->elInfo[i]; + + if ((elInfo.elType == ID_SCE) || (elInfo.elType == ID_CPE) || + (elInfo.elType == ID_LFE)) { + INT minElBits = 0; + + FDKaacEnc_ChannelElementWrite(NULL, &elInfo, NULL, + psyOut[0]->psyOutElement[i], + psyOut[0]->psyOutElement[i]->psyOutChannel, + syntaxFlags, aot, epConfig, &minElBits, 1); + bitcount += minElBits; + } + } + + return bitcount; +} + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +static AAC_ENCODER_ERROR FDKaacEnc_prepareBitDistribution( + QC_STATE* hQC, PSY_OUT** psyOut, QC_OUT** qcOut, CHANNEL_MAPPING* cm, + QC_OUT_ELEMENT* qcElement[(1)][((8))], INT avgTotalBits, + INT* totalAvailableBits, INT* avgTotalDynBits) { + int i; + /* get maximal allowed dynamic bits */ + qcOut[0]->grantedDynBits = + (fixMin(hQC->maxBitsPerFrame, avgTotalBits) - hQC->globHdrBits) & ~7; + qcOut[0]->grantedDynBits -= (qcOut[0]->globalExtBits + qcOut[0]->staticBits + + qcOut[0]->elementExtBits); + qcOut[0]->maxDynBits = ((hQC->maxBitsPerFrame) & ~7) - + (qcOut[0]->globalExtBits + qcOut[0]->staticBits + + qcOut[0]->elementExtBits); + /* assure that enough bits are available */ + if ((qcOut[0]->grantedDynBits + hQC->bitResTot) < 0) { + /* crash recovery allows to reduce static bits to a minimum */ + if ((qcOut[0]->grantedDynBits + hQC->bitResTot) < + (FDKaacEnc_getMinimalStaticBitdemand(cm, psyOut) - + qcOut[0]->staticBits)) + return AAC_ENC_BITRES_TOO_LOW; + } + + /* distribute dynamic bits to each element */ + FDKaacEnc_distributeElementDynBits(hQC, qcElement[0], cm, + qcOut[0]->grantedDynBits); + + *avgTotalDynBits = 0; /*frameDynBits;*/ + + *totalAvailableBits = avgTotalBits; + + /* sum up corrected granted PE */ + qcOut[0]->totalGrantedPeCorr = 0; + + for (i = 0; i < cm->nElements; i++) { + ELEMENT_INFO elInfo = cm->elInfo[i]; + int nChannels = elInfo.nChannelsInEl; + + if ((elInfo.elType == ID_SCE) || (elInfo.elType == ID_CPE) || + (elInfo.elType == ID_LFE)) { + /* for ( all sub frames ) ... */ + FDKaacEnc_DistributeBits( + hQC->hAdjThr, hQC->hAdjThr->adjThrStateElem[i], + psyOut[0]->psyOutElement[i]->psyOutChannel, &qcElement[0][i]->peData, + &qcElement[0][i]->grantedPe, &qcElement[0][i]->grantedPeCorr, + nChannels, psyOut[0]->psyOutElement[i]->commonWindow, + qcElement[0][i]->grantedDynBits, hQC->elementBits[i]->bitResLevelEl, + hQC->elementBits[i]->maxBitResBitsEl, hQC->maxBitFac, + hQC->bitResMode); + + *totalAvailableBits += hQC->elementBits[i]->bitResLevelEl; + /* get total corrected granted PE */ + qcOut[0]->totalGrantedPeCorr += qcElement[0][i]->grantedPeCorr; + } /* -end- if(ID_SCE || ID_CPE || ID_LFE) */ + + } /* -end- element loop */ + + *totalAvailableBits = fMin(hQC->maxBitsPerFrame, (*totalAvailableBits)); + + return AAC_ENC_OK; +} + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +static AAC_ENCODER_ERROR FDKaacEnc_updateUsedDynBits( + INT* sumDynBitsConsumed, QC_OUT_ELEMENT* qcElement[((8))], + CHANNEL_MAPPING* cm) { + INT i; + + *sumDynBitsConsumed = 0; + + for (i = 0; i < cm->nElements; i++) { + ELEMENT_INFO elInfo = cm->elInfo[i]; + + if ((elInfo.elType == ID_SCE) || (elInfo.elType == ID_CPE) || + (elInfo.elType == ID_LFE)) { + /* sum up bits consumed */ + *sumDynBitsConsumed += qcElement[i]->dynBitsUsed; + } /* -end- if(ID_SCE || ID_CPE || ID_LFE) */ + + } /* -end- element loop */ + + return AAC_ENC_OK; +} + +static INT FDKaacEnc_getTotalConsumedDynBits(QC_OUT** qcOut, INT nSubFrames) { + INT c, totalBits = 0; + + /* sum up bit consumption for all sub frames */ + for (c = 0; c < nSubFrames; c++) { + /* bit consumption not valid if dynamic bits + not available in one sub frame */ + if (qcOut[c]->usedDynBits == -1) return -1; + totalBits += qcOut[c]->usedDynBits; + } + + return totalBits; +} + +static INT FDKaacEnc_getTotalConsumedBits(QC_OUT** qcOut, + QC_OUT_ELEMENT* qcElement[(1)][((8))], + CHANNEL_MAPPING* cm, INT globHdrBits, + INT nSubFrames) { + int c, i; + int totalUsedBits = 0; + + for (c = 0; c < nSubFrames; c++) { + int dataBits = 0; + for (i = 0; i < cm->nElements; i++) { + if ((cm->elInfo[i].elType == ID_SCE) || + (cm->elInfo[i].elType == ID_CPE) || + (cm->elInfo[i].elType == ID_LFE)) { + dataBits += qcElement[c][i]->dynBitsUsed + + qcElement[c][i]->staticBitsUsed + + qcElement[c][i]->extBitsUsed; + } + } + dataBits += qcOut[c]->globalExtBits; + + totalUsedBits += (8 - (dataBits) % 8) % 8; + totalUsedBits += dataBits + globHdrBits; /* header bits for every frame */ + } + return totalUsedBits; +} + +static AAC_ENCODER_ERROR FDKaacEnc_BitResRedistribution( + QC_STATE* const hQC, const CHANNEL_MAPPING* const cm, + const INT avgTotalBits) { + /* check bitreservoir fill level */ + if (hQC->bitResTot < 0) { + return AAC_ENC_BITRES_TOO_LOW; + } else if (hQC->bitResTot > hQC->bitResTotMax) { + return AAC_ENC_BITRES_TOO_HIGH; + } else { + INT i; + INT totalBits = 0, totalBits_max = 0; + + const int totalBitreservoir = + fMin(hQC->bitResTot, (hQC->maxBitsPerFrame - avgTotalBits)); + const int totalBitreservoirMax = + fMin(hQC->bitResTotMax, (hQC->maxBitsPerFrame - avgTotalBits)); + + for (i = (cm->nElements - 1); i >= 0; i--) { + if ((cm->elInfo[i].elType == ID_SCE) || + (cm->elInfo[i].elType == ID_CPE) || + (cm->elInfo[i].elType == ID_LFE)) { + hQC->elementBits[i]->bitResLevelEl = + fMultI(hQC->elementBits[i]->relativeBitsEl, totalBitreservoir); + totalBits += hQC->elementBits[i]->bitResLevelEl; + + hQC->elementBits[i]->maxBitResBitsEl = + fMultI(hQC->elementBits[i]->relativeBitsEl, totalBitreservoirMax); + totalBits_max += hQC->elementBits[i]->maxBitResBitsEl; + } + } + for (i = 0; i < cm->nElements; i++) { + if ((cm->elInfo[i].elType == ID_SCE) || + (cm->elInfo[i].elType == ID_CPE) || + (cm->elInfo[i].elType == ID_LFE)) { + int deltaBits = fMax(totalBitreservoir - totalBits, + -hQC->elementBits[i]->bitResLevelEl); + hQC->elementBits[i]->bitResLevelEl += deltaBits; + totalBits += deltaBits; + + deltaBits = fMax(totalBitreservoirMax - totalBits_max, + -hQC->elementBits[i]->maxBitResBitsEl); + hQC->elementBits[i]->maxBitResBitsEl += deltaBits; + totalBits_max += deltaBits; + } + } + } + + return AAC_ENC_OK; +} + +AAC_ENCODER_ERROR FDKaacEnc_QCMain(QC_STATE* RESTRICT hQC, PSY_OUT** psyOut, + QC_OUT** qcOut, INT avgTotalBits, + CHANNEL_MAPPING* cm, + const AUDIO_OBJECT_TYPE aot, + UINT syntaxFlags, SCHAR epConfig) { + int i, c; + AAC_ENCODER_ERROR ErrorStatus = AAC_ENC_OK; + INT avgTotalDynBits = 0; /* maximal allowed dynamic bits for all frames */ + INT totalAvailableBits = 0; + INT nSubFrames = 1; + + /*-------------------------------------------- */ + /* redistribute total bitreservoir to elements */ + ErrorStatus = FDKaacEnc_BitResRedistribution(hQC, cm, avgTotalBits); + if (ErrorStatus != AAC_ENC_OK) { + return ErrorStatus; + } + + /*-------------------------------------------- */ + /* fastenc needs one time threshold simulation, + in case of multiple frames, one more guess has to be calculated */ + + /*-------------------------------------------- */ + /* helper pointer */ + QC_OUT_ELEMENT* qcElement[(1)][((8))]; + + /* work on a copy of qcChannel and qcElement */ + for (i = 0; i < cm->nElements; i++) { + ELEMENT_INFO elInfo = cm->elInfo[i]; + + if ((elInfo.elType == ID_SCE) || (elInfo.elType == ID_CPE) || + (elInfo.elType == ID_LFE)) { + /* for ( all sub frames ) ... */ + for (c = 0; c < nSubFrames; c++) { + { qcElement[c][i] = qcOut[c]->qcElement[i]; } + } + } + } + + /*-------------------------------------------- */ + /*-------------------------------------------- */ + if (isConstantBitrateMode(hQC->bitrateMode)) { + /* calc granted dynamic bits for sub frame and + distribute it to each element */ + ErrorStatus = FDKaacEnc_prepareBitDistribution( + hQC, psyOut, qcOut, cm, qcElement, avgTotalBits, &totalAvailableBits, + &avgTotalDynBits); + + if (ErrorStatus != AAC_ENC_OK) { + return ErrorStatus; + } + } else { + qcOut[0]->grantedDynBits = + ((hQC->maxBitsPerFrame - (hQC->globHdrBits)) & ~7) - + (qcOut[0]->globalExtBits + qcOut[0]->staticBits + + qcOut[0]->elementExtBits); + qcOut[0]->maxDynBits = qcOut[0]->grantedDynBits; + + totalAvailableBits = hQC->maxBitsPerFrame; + avgTotalDynBits = 0; + } + + /* for ( all sub frames ) ... */ + for (c = 0; c < nSubFrames; c++) { + /* for CBR and VBR mode */ + FDKaacEnc_AdjustThresholds(hQC->hAdjThr, qcElement[c], qcOut[c], + psyOut[c]->psyOutElement, + isConstantBitrateMode(hQC->bitrateMode), cm); + + } /* -end- sub frame counter */ + + /*-------------------------------------------- */ + INT iterations[(1)][((8))]; + INT chConstraintsFulfilled[(1)][((8))][(2)]; + INT calculateQuant[(1)][((8))][(2)]; + INT constraintsFulfilled[(1)][((8))]; + /*-------------------------------------------- */ + + /* for ( all sub frames ) ... */ + for (c = 0; c < nSubFrames; c++) { + for (i = 0; i < cm->nElements; i++) { + ELEMENT_INFO elInfo = cm->elInfo[i]; + INT ch, nChannels = elInfo.nChannelsInEl; + + if ((elInfo.elType == ID_SCE) || (elInfo.elType == ID_CPE) || + (elInfo.elType == ID_LFE)) { + /* Turn thresholds into scalefactors, optimize bit consumption and + * verify conformance */ + FDKaacEnc_EstimateScaleFactors( + psyOut[c]->psyOutElement[i]->psyOutChannel, + qcElement[c][i]->qcOutChannel, hQC->invQuant, hQC->dZoneQuantEnable, + cm->elInfo[i].nChannelsInEl); + + /*-------------------------------------------- */ + constraintsFulfilled[c][i] = 1; + iterations[c][i] = 0; + + for (ch = 0; ch < nChannels; ch++) { + chConstraintsFulfilled[c][i][ch] = 1; + calculateQuant[c][i][ch] = 1; + } + + /*-------------------------------------------- */ + + } /* -end- if(ID_SCE || ID_CPE || ID_LFE) */ + + } /* -end- element loop */ + + qcOut[c]->usedDynBits = -1; + + } /* -end- sub frame counter */ + + INT quantizationDone = 0; + INT sumDynBitsConsumedTotal = 0; + INT decreaseBitConsumption = -1; /* no direction yet! */ + + /*-------------------------------------------- */ + /* -start- Quantization loop ... */ + /*-------------------------------------------- */ + do /* until max allowed bits per frame and maxDynBits!=-1*/ + { + quantizationDone = 0; + + c = 0; /* get frame to process */ + + for (i = 0; i < cm->nElements; i++) { + ELEMENT_INFO elInfo = cm->elInfo[i]; + INT ch, nChannels = elInfo.nChannelsInEl; + + if ((elInfo.elType == ID_SCE) || (elInfo.elType == ID_CPE) || + (elInfo.elType == ID_LFE)) { + do /* until element bits < nChannels*MIN_BUFSIZE_PER_EFF_CHAN */ + { + do /* until spectral values < MAX_QUANT */ + { + /*-------------------------------------------- */ + if (!constraintsFulfilled[c][i]) { + if ((ErrorStatus = FDKaacEnc_reduceBitConsumption( + &iterations[c][i], hQC->maxIterations, + (decreaseBitConsumption) ? 1 : -1, + chConstraintsFulfilled[c][i], calculateQuant[c][i], + nChannels, psyOut[c]->psyOutElement[i], qcOut[c], + qcElement[c][i], hQC->elementBits[i], aot, syntaxFlags, + epConfig)) != AAC_ENC_OK) { + return ErrorStatus; + } + } + + /*-------------------------------------------- */ + /*-------------------------------------------- */ + constraintsFulfilled[c][i] = 1; + + /*-------------------------------------------- */ + /* quantize spectrum (per each channel) */ + for (ch = 0; ch < nChannels; ch++) { + /*-------------------------------------------- */ + chConstraintsFulfilled[c][i][ch] = 1; + + /*-------------------------------------------- */ + + if (calculateQuant[c][i][ch]) { + QC_OUT_CHANNEL* qcOutCh = qcElement[c][i]->qcOutChannel[ch]; + PSY_OUT_CHANNEL* psyOutCh = + psyOut[c]->psyOutElement[i]->psyOutChannel[ch]; + + calculateQuant[c][i][ch] = + 0; /* calculate quantization only if necessary */ + + /*-------------------------------------------- */ + FDKaacEnc_QuantizeSpectrum( + psyOutCh->sfbCnt, psyOutCh->maxSfbPerGroup, + psyOutCh->sfbPerGroup, psyOutCh->sfbOffsets, + qcOutCh->mdctSpectrum, qcOutCh->globalGain, qcOutCh->scf, + qcOutCh->quantSpec, hQC->dZoneQuantEnable); + + /*-------------------------------------------- */ + if (FDKaacEnc_calcMaxValueInSfb( + psyOutCh->sfbCnt, psyOutCh->maxSfbPerGroup, + psyOutCh->sfbPerGroup, psyOutCh->sfbOffsets, + qcOutCh->quantSpec, + qcOutCh->maxValueInSfb) > MAX_QUANT) { + chConstraintsFulfilled[c][i][ch] = 0; + constraintsFulfilled[c][i] = 0; + /* if quanizted value out of range; increase global gain! */ + decreaseBitConsumption = 1; + } + + /*-------------------------------------------- */ + + } /* if calculateQuant[c][i][ch] */ + + } /* channel loop */ + + /*-------------------------------------------- */ + /* quantize spectrum (per each channel) */ + + /*-------------------------------------------- */ + + } while (!constraintsFulfilled[c][i]); /* does not regard bit + consumption */ + + /*-------------------------------------------- */ + /*-------------------------------------------- */ + qcElement[c][i]->dynBitsUsed = 0; /* reset dynamic bits */ + + /* quantization valid in current channel! */ + for (ch = 0; ch < nChannels; ch++) { + QC_OUT_CHANNEL* qcOutCh = qcElement[c][i]->qcOutChannel[ch]; + PSY_OUT_CHANNEL* psyOutCh = + psyOut[c]->psyOutElement[i]->psyOutChannel[ch]; + + /* count dynamic bits */ + INT chDynBits = FDKaacEnc_dynBitCount( + hQC->hBitCounter, qcOutCh->quantSpec, qcOutCh->maxValueInSfb, + qcOutCh->scf, psyOutCh->lastWindowSequence, psyOutCh->sfbCnt, + psyOutCh->maxSfbPerGroup, psyOutCh->sfbPerGroup, + psyOutCh->sfbOffsets, &qcOutCh->sectionData, psyOutCh->noiseNrg, + psyOutCh->isBook, psyOutCh->isScale, syntaxFlags); + + /* sum up dynamic channel bits */ + qcElement[c][i]->dynBitsUsed += chDynBits; + } + + /* save dynBitsUsed for correction of bits2pe relation */ + if (hQC->hAdjThr->adjThrStateElem[i]->dynBitsLast == -1) { + hQC->hAdjThr->adjThrStateElem[i]->dynBitsLast = + qcElement[c][i]->dynBitsUsed; + } + + /* hold total bit consumption in present element below maximum allowed + */ + if (qcElement[c][i]->dynBitsUsed > + ((nChannels * MIN_BUFSIZE_PER_EFF_CHAN) - + qcElement[c][i]->staticBitsUsed - + qcElement[c][i]->extBitsUsed)) { + constraintsFulfilled[c][i] = 0; + } + + } while (!constraintsFulfilled[c][i]); + + } /* -end- if(ID_SCE || ID_CPE || ID_LFE) */ + + } /* -end- element loop */ + + /* update dynBits of current subFrame */ + FDKaacEnc_updateUsedDynBits(&qcOut[c]->usedDynBits, qcElement[c], cm); + + /* get total consumed bits, dyn bits in all sub frames have to be valid */ + sumDynBitsConsumedTotal = + FDKaacEnc_getTotalConsumedDynBits(qcOut, nSubFrames); + + if (sumDynBitsConsumedTotal == -1) { + quantizationDone = 0; /* bit consumption not valid in all sub frames */ + } else { + int sumBitsConsumedTotal = FDKaacEnc_getTotalConsumedBits( + qcOut, qcElement, cm, hQC->globHdrBits, nSubFrames); + + /* in all frames are valid dynamic bits */ + if (((sumBitsConsumedTotal < totalAvailableBits) || + sumDynBitsConsumedTotal == 0) && + (decreaseBitConsumption == 1) && + checkMinFrameBitsDemand(qcOut, hQC->minBitsPerFrame, nSubFrames) + /*()*/) { + quantizationDone = 1; /* exit bit adjustment */ + } + if (sumBitsConsumedTotal > totalAvailableBits && + (decreaseBitConsumption == 0)) { + quantizationDone = 0; /* reset! */ + } + } + + /*-------------------------------------------- */ + + int emergencyIterations = 1; + int dynBitsOvershoot = 0; + + for (c = 0; c < nSubFrames; c++) { + for (i = 0; i < cm->nElements; i++) { + ELEMENT_INFO elInfo = cm->elInfo[i]; + + if ((elInfo.elType == ID_SCE) || (elInfo.elType == ID_CPE) || + (elInfo.elType == ID_LFE)) { + /* iteration limitation */ + emergencyIterations &= + ((iterations[c][i] < hQC->maxIterations) ? 0 : 1); + } + } + /* detection if used dyn bits exceeds the maximal allowed criterion */ + dynBitsOvershoot |= + ((qcOut[c]->usedDynBits > qcOut[c]->maxDynBits) ? 1 : 0); + } + + if (quantizationDone == 0 || dynBitsOvershoot) { + int sumBitsConsumedTotal = FDKaacEnc_getTotalConsumedBits( + qcOut, qcElement, cm, hQC->globHdrBits, nSubFrames); + + if ((sumDynBitsConsumedTotal >= avgTotalDynBits) || + (sumDynBitsConsumedTotal == 0)) { + quantizationDone = 1; + } + if (emergencyIterations && (sumBitsConsumedTotal < totalAvailableBits)) { + quantizationDone = 1; + } + if ((sumBitsConsumedTotal > totalAvailableBits) || + !checkMinFrameBitsDemand(qcOut, hQC->minBitsPerFrame, nSubFrames)) { + quantizationDone = 0; + } + if ((sumBitsConsumedTotal < totalAvailableBits) && + checkMinFrameBitsDemand(qcOut, hQC->minBitsPerFrame, nSubFrames)) { + decreaseBitConsumption = 0; + } else { + decreaseBitConsumption = 1; + } + + if (dynBitsOvershoot) { + quantizationDone = 0; + decreaseBitConsumption = 1; + } + + /* reset constraints fullfilled flags */ + FDKmemclear(constraintsFulfilled, sizeof(constraintsFulfilled)); + FDKmemclear(chConstraintsFulfilled, sizeof(chConstraintsFulfilled)); + + } /* quantizationDone */ + + } while (!quantizationDone); + + /*-------------------------------------------- */ + /* ... -end- Quantization loop */ + /*-------------------------------------------- */ + + /*-------------------------------------------- */ + /*-------------------------------------------- */ + + return AAC_ENC_OK; +} + +static AAC_ENCODER_ERROR FDKaacEnc_reduceBitConsumption( + int* iterations, const int maxIterations, int gainAdjustment, + int* chConstraintsFulfilled, int* calculateQuant, int nChannels, + PSY_OUT_ELEMENT* psyOutElement, QC_OUT* qcOut, QC_OUT_ELEMENT* qcOutElement, + ELEMENT_BITS* elBits, AUDIO_OBJECT_TYPE aot, UINT syntaxFlags, + SCHAR epConfig) { + int ch; + + /** SOLVING PROBLEM **/ + if ((*iterations) < maxIterations) { + /* increase gain (+ next iteration) */ + for (ch = 0; ch < nChannels; ch++) { + if (!chConstraintsFulfilled[ch]) { + qcOutElement->qcOutChannel[ch]->globalGain += gainAdjustment; + calculateQuant[ch] = 1; /* global gain has changed, recalculate + quantization in next iteration! */ + } + } + } else if ((*iterations) == maxIterations) { + if (qcOutElement->dynBitsUsed == 0) { + return AAC_ENC_QUANT_ERROR; + } else { + /* crash recovery */ + INT bitsToSave = 0; + if ((bitsToSave = fixMax( + (qcOutElement->dynBitsUsed + 8) - + (elBits->bitResLevelEl + qcOutElement->grantedDynBits), + (qcOutElement->dynBitsUsed + qcOutElement->staticBitsUsed + 8) - + (elBits->maxBitsEl))) > 0) { + FDKaacEnc_crashRecovery(nChannels, psyOutElement, qcOut, qcOutElement, + bitsToSave, aot, syntaxFlags, epConfig); + } else { + for (ch = 0; ch < nChannels; ch++) { + qcOutElement->qcOutChannel[ch]->globalGain += 1; + } + } + for (ch = 0; ch < nChannels; ch++) { + calculateQuant[ch] = 1; + } + } + } else { + /* (*iterations) > maxIterations */ + return AAC_ENC_QUANT_ERROR; + } + (*iterations)++; + + return AAC_ENC_OK; +} + +AAC_ENCODER_ERROR FDKaacEnc_updateFillBits(CHANNEL_MAPPING* cm, + QC_STATE* qcKernel, + ELEMENT_BITS* RESTRICT elBits[((8))], + QC_OUT** qcOut) { + switch (qcKernel->bitrateMode) { + case QCDATA_BR_MODE_SFR: + break; + + case QCDATA_BR_MODE_FF: + break; + case QCDATA_BR_MODE_VBR_1: + case QCDATA_BR_MODE_VBR_2: + case QCDATA_BR_MODE_VBR_3: + case QCDATA_BR_MODE_VBR_4: + case QCDATA_BR_MODE_VBR_5: + qcOut[0]->totFillBits = + (qcOut[0]->grantedDynBits - qcOut[0]->usedDynBits) & + 7; /* precalculate alignment bits */ + qcOut[0]->totalBits = qcOut[0]->staticBits + qcOut[0]->usedDynBits + + qcOut[0]->totFillBits + qcOut[0]->elementExtBits + + qcOut[0]->globalExtBits; + qcOut[0]->totFillBits += + (fixMax(0, qcKernel->minBitsPerFrame - qcOut[0]->totalBits) + 7) & ~7; + break; + case QCDATA_BR_MODE_CBR: + case QCDATA_BR_MODE_INVALID: + default: + INT bitResSpace = qcKernel->bitResTotMax - qcKernel->bitResTot; + /* processing fill-bits */ + INT deltaBitRes = qcOut[0]->grantedDynBits - qcOut[0]->usedDynBits; + qcOut[0]->totFillBits = fixMax( + (deltaBitRes & 7), (deltaBitRes - (fixMax(0, bitResSpace - 7) & ~7))); + qcOut[0]->totalBits = qcOut[0]->staticBits + qcOut[0]->usedDynBits + + qcOut[0]->totFillBits + qcOut[0]->elementExtBits + + qcOut[0]->globalExtBits; + qcOut[0]->totFillBits += + (fixMax(0, qcKernel->minBitsPerFrame - qcOut[0]->totalBits) + 7) & ~7; + break; + } /* switch (qcKernel->bitrateMode) */ + + return AAC_ENC_OK; +} + +/********************************************************************************* + + functionname: FDKaacEnc_calcMaxValueInSfb + description: + return: + +**********************************************************************************/ + +static INT FDKaacEnc_calcMaxValueInSfb(INT sfbCnt, INT maxSfbPerGroup, + INT sfbPerGroup, INT* RESTRICT sfbOffset, + SHORT* RESTRICT quantSpectrum, + UINT* RESTRICT maxValue) { + INT sfbOffs, sfb; + INT maxValueAll = 0; + + for (sfbOffs = 0; sfbOffs < sfbCnt; sfbOffs += sfbPerGroup) + for (sfb = 0; sfb < maxSfbPerGroup; sfb++) { + INT line; + INT maxThisSfb = 0; + for (line = sfbOffset[sfbOffs + sfb]; line < sfbOffset[sfbOffs + sfb + 1]; + line++) { + INT tmp = fixp_abs(quantSpectrum[line]); + maxThisSfb = fixMax(tmp, maxThisSfb); + } + + maxValue[sfbOffs + sfb] = maxThisSfb; + maxValueAll = fixMax(maxThisSfb, maxValueAll); + } + return maxValueAll; +} + +/********************************************************************************* + + functionname: FDKaacEnc_updateBitres + description: + return: + +**********************************************************************************/ +void FDKaacEnc_updateBitres(CHANNEL_MAPPING* cm, QC_STATE* qcKernel, + QC_OUT** qcOut) { + switch (qcKernel->bitrateMode) { + case QCDATA_BR_MODE_VBR_1: + case QCDATA_BR_MODE_VBR_2: + case QCDATA_BR_MODE_VBR_3: + case QCDATA_BR_MODE_VBR_4: + case QCDATA_BR_MODE_VBR_5: + /* variable bitrate */ + qcKernel->bitResTot = + fMin(qcKernel->maxBitsPerFrame, qcKernel->bitResTotMax); + break; + case QCDATA_BR_MODE_CBR: + case QCDATA_BR_MODE_SFR: + case QCDATA_BR_MODE_INVALID: + default: + int c = 0; + /* constant bitrate */ + { + qcKernel->bitResTot += qcOut[c]->grantedDynBits - + (qcOut[c]->usedDynBits + qcOut[c]->totFillBits + + qcOut[c]->alignBits); + } + break; + } +} + +/********************************************************************************* + + functionname: FDKaacEnc_FinalizeBitConsumption + description: + return: + +**********************************************************************************/ +AAC_ENCODER_ERROR FDKaacEnc_FinalizeBitConsumption( + CHANNEL_MAPPING* cm, QC_STATE* qcKernel, QC_OUT* qcOut, + QC_OUT_ELEMENT** qcElement, HANDLE_TRANSPORTENC hTpEnc, + AUDIO_OBJECT_TYPE aot, UINT syntaxFlags, SCHAR epConfig) { + QC_OUT_EXTENSION fillExtPayload; + INT totFillBits, alignBits; + + /* Get total consumed bits in AU */ + qcOut->totalBits = qcOut->staticBits + qcOut->usedDynBits + + qcOut->totFillBits + qcOut->elementExtBits + + qcOut->globalExtBits; + + if (qcKernel->bitrateMode == QCDATA_BR_MODE_CBR) { + /* Now we can get the exact transport bit amount, and hopefully it is equal + * to the estimated value */ + INT exactTpBits = transportEnc_GetStaticBits(hTpEnc, qcOut->totalBits); + + if (exactTpBits != qcKernel->globHdrBits) { + INT diffFillBits = 0; + + /* How many bits can be take by bitreservoir */ + const INT bitresSpace = + qcKernel->bitResTotMax - + (qcKernel->bitResTot + + (qcOut->grantedDynBits - (qcOut->usedDynBits + qcOut->totFillBits))); + + /* Number of bits which can be moved to bitreservoir. */ + const INT bitsToBitres = qcKernel->globHdrBits - exactTpBits; + FDK_ASSERT(bitsToBitres >= 0); /* is always positive */ + + /* If bitreservoir can not take all bits, move ramaining bits to fillbits + */ + diffFillBits = fMax(0, bitsToBitres - bitresSpace); + + /* Assure previous alignment */ + diffFillBits = (diffFillBits + 7) & ~7; + + /* Move as many bits as possible to bitreservoir */ + qcKernel->bitResTot += (bitsToBitres - diffFillBits); + + /* Write remaing bits as fill bits */ + qcOut->totFillBits += diffFillBits; + qcOut->totalBits += diffFillBits; + qcOut->grantedDynBits += diffFillBits; + + /* Get new header bits */ + qcKernel->globHdrBits = + transportEnc_GetStaticBits(hTpEnc, qcOut->totalBits); + + if (qcKernel->globHdrBits != exactTpBits) { + /* In previous step, fill bits and corresponding total bits were changed + when bitreservoir was completely filled. Now we can take the too much + taken bits caused by header overhead from bitreservoir. + */ + qcKernel->bitResTot -= (qcKernel->globHdrBits - exactTpBits); + } + } + + } /* MODE_CBR */ + + /* Update exact number of consumed header bits. */ + qcKernel->globHdrBits = transportEnc_GetStaticBits(hTpEnc, qcOut->totalBits); + + /* Save total fill bits and distribut to alignment and fill bits */ + totFillBits = qcOut->totFillBits; + + /* fake a fill extension payload */ + FDKmemclear(&fillExtPayload, sizeof(QC_OUT_EXTENSION)); + + fillExtPayload.type = EXT_FILL_DATA; + fillExtPayload.nPayloadBits = totFillBits; + + /* ask bitstream encoder how many of that bits can be written in a fill + * extension data entity */ + qcOut->totFillBits = FDKaacEnc_writeExtensionData(NULL, &fillExtPayload, 0, 0, + syntaxFlags, aot, epConfig); + + //fprintf(stderr, "FinalizeBitConsumption(): totFillBits=%d, qcOut->totFillBits=%d \n", totFillBits, qcOut->totFillBits); + + /* now distribute extra fillbits and alignbits */ + alignBits = + 7 - (qcOut->staticBits + qcOut->usedDynBits + qcOut->elementExtBits + + qcOut->totFillBits + qcOut->globalExtBits - 1) % + 8; + + /* Maybe we could remove this */ + if (((alignBits + qcOut->totFillBits - totFillBits) == 8) && + (qcOut->totFillBits > 8)) + qcOut->totFillBits -= 8; + + qcOut->totalBits = qcOut->staticBits + qcOut->usedDynBits + + qcOut->totFillBits + alignBits + qcOut->elementExtBits + + qcOut->globalExtBits; + + if ((qcOut->totalBits > qcKernel->maxBitsPerFrame) || + (qcOut->totalBits < qcKernel->minBitsPerFrame)) { + return AAC_ENC_QUANT_ERROR; + } + + qcOut->alignBits = alignBits; + + return AAC_ENC_OK; +} + +/********************************************************************************* + + functionname: FDKaacEnc_crashRecovery + description: fulfills constraints by means of brute force... + => bits are saved by cancelling out spectral lines!! + (beginning at the highest frequencies) + return: errorcode + +**********************************************************************************/ + +static void FDKaacEnc_crashRecovery(INT nChannels, + PSY_OUT_ELEMENT* psyOutElement, + QC_OUT* qcOut, QC_OUT_ELEMENT* qcElement, + INT bitsToSave, AUDIO_OBJECT_TYPE aot, + UINT syntaxFlags, SCHAR epConfig) { + INT ch; + INT savedBits = 0; + INT sfb, sfbGrp; + INT bitsPerScf[(2)][MAX_GROUPED_SFB]; + INT sectionToScf[(2)][MAX_GROUPED_SFB]; + INT* sfbOffset; + INT sect, statBitsNew; + QC_OUT_CHANNEL** qcChannel = qcElement->qcOutChannel; + PSY_OUT_CHANNEL** psyChannel = psyOutElement->psyOutChannel; + + /* create a table which converts frq-bins to bit-demand... [bitsPerScf] */ + /* ...and another one which holds the corresponding sections [sectionToScf] */ + for (ch = 0; ch < nChannels; ch++) { + sfbOffset = psyChannel[ch]->sfbOffsets; + + for (sect = 0; sect < qcChannel[ch]->sectionData.noOfSections; sect++) { + INT codeBook = qcChannel[ch]->sectionData.huffsection[sect].codeBook; + + for (sfb = qcChannel[ch]->sectionData.huffsection[sect].sfbStart; + sfb < qcChannel[ch]->sectionData.huffsection[sect].sfbStart + + qcChannel[ch]->sectionData.huffsection[sect].sfbCnt; + sfb++) { + bitsPerScf[ch][sfb] = 0; + if ((codeBook != CODE_BOOK_PNS_NO) /*&& + (sfb < (qcChannel[ch]->sectionData.noOfGroups*qcChannel[ch]->sectionData.maxSfbPerGroup))*/) { + INT sfbStartLine = sfbOffset[sfb]; + INT noOfLines = sfbOffset[sfb + 1] - sfbStartLine; + bitsPerScf[ch][sfb] = FDKaacEnc_countValues( + &(qcChannel[ch]->quantSpec[sfbStartLine]), noOfLines, codeBook); + } + sectionToScf[ch][sfb] = sect; + } + } + } + + /* LOWER [maxSfb] IN BOTH CHANNELS!! */ + /* Attention: in case of stereo: maxSfbL == maxSfbR, GroupingL == GroupingR ; + */ + + for (sfb = qcChannel[0]->sectionData.maxSfbPerGroup - 1; sfb >= 0; sfb--) { + for (sfbGrp = 0; sfbGrp < psyChannel[0]->sfbCnt; + sfbGrp += psyChannel[0]->sfbPerGroup) { + for (ch = 0; ch < nChannels; ch++) { + sect = sectionToScf[ch][sfbGrp + sfb]; + qcChannel[ch]->sectionData.huffsection[sect].sfbCnt--; + savedBits += bitsPerScf[ch][sfbGrp + sfb]; + + if (qcChannel[ch]->sectionData.huffsection[sect].sfbCnt == 0) { + savedBits += (psyChannel[ch]->lastWindowSequence != SHORT_WINDOW) + ? FDKaacEnc_sideInfoTabLong[0] + : FDKaacEnc_sideInfoTabShort[0]; + } + } + } + + /* ...have enough bits been saved? */ + if (savedBits >= bitsToSave) break; + + } /* sfb loop */ + + /* if not enough bits saved, + clean whole spectrum and remove side info overhead */ + if (sfb == -1) { + sfb = 0; + } + + for (ch = 0; ch < nChannels; ch++) { + qcChannel[ch]->sectionData.maxSfbPerGroup = sfb; + psyChannel[ch]->maxSfbPerGroup = sfb; + /* when no spectrum is coded save tools info in bitstream */ + if (sfb == 0) { + FDKmemclear(&psyChannel[ch]->tnsInfo, sizeof(TNS_INFO)); + FDKmemclear(&psyOutElement->toolsInfo, sizeof(TOOLSINFO)); + } + } + /* dynamic bits will be updated in iteration loop */ + + { /* if stop sfb has changed save bits in side info, e.g. MS or TNS coding */ + ELEMENT_INFO elInfo; + + FDKmemclear(&elInfo, sizeof(ELEMENT_INFO)); + elInfo.nChannelsInEl = nChannels; + elInfo.elType = (nChannels == 2) ? ID_CPE : ID_SCE; + + FDKaacEnc_ChannelElementWrite(NULL, &elInfo, NULL, psyOutElement, + psyChannel, syntaxFlags, aot, epConfig, + &statBitsNew, 0); + } + + savedBits = qcElement->staticBitsUsed - statBitsNew; + + /* update static and dynamic bits */ + qcElement->staticBitsUsed -= savedBits; + qcElement->grantedDynBits += savedBits; + + qcOut->staticBits -= savedBits; + qcOut->grantedDynBits += savedBits; + qcOut->maxDynBits += savedBits; +} + +void FDKaacEnc_QCClose(QC_STATE** phQCstate, QC_OUT** phQC) { + int n, i; + + if (phQC != NULL) { + for (n = 0; n < (1); n++) { + if (phQC[n] != NULL) { + QC_OUT* hQC = phQC[n]; + for (i = 0; i < (8); i++) { + } + + for (i = 0; i < ((8)); i++) { + if (hQC->qcElement[i]) FreeRam_aacEnc_QCelement(&hQC->qcElement[i]); + } + + FreeRam_aacEnc_QCout(&phQC[n]); + } + } + } + + if (phQCstate != NULL) { + if (*phQCstate != NULL) { + QC_STATE* hQCstate = *phQCstate; + + if (hQCstate->hAdjThr != NULL) FDKaacEnc_AdjThrClose(&hQCstate->hAdjThr); + + if (hQCstate->hBitCounter != NULL) + FDKaacEnc_BCClose(&hQCstate->hBitCounter); + + for (i = 0; i < ((8)); i++) { + if (hQCstate->elementBits[i] != NULL) { + FreeRam_aacEnc_ElementBits(&hQCstate->elementBits[i]); + } + } + FreeRam_aacEnc_QCstate(phQCstate); + } + } +} -- cgit v1.2.3