aboutsummaryrefslogtreecommitdiffstats
path: root/fdk-aac/libAACenc/src/qc_main.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'fdk-aac/libAACenc/src/qc_main.cpp')
-rw-r--r--fdk-aac/libAACenc/src/qc_main.cpp1555
1 files changed, 1555 insertions, 0 deletions
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);
+ }
+ }
+}