mirror of
https://github.com/mstorsjo/fdk-aac.git
synced 2025-02-12 01:20:38 +01:00
Bug: 71430241 Test: CTS DecoderTest and DecoderTestAacDrc original-Change-Id: Iaa20f749b8a04d553b20247cfe1a8930ebbabe30 Apply clang-format also on header files. original-Change-Id: I14de1ef16bbc79ec0283e745f98356a10efeb2e4 Fixes for MPEG-D DRC original-Change-Id: If1de2d74bbbac84b3f67de3b88b83f6a23b8a15c Catch unsupported tw_mdct at an early stage original-Change-Id: Ied9dd00d754162a0e3ca1ae3e6b854315d818afe Fixing PVC transition frames original-Change-Id: Ib75725abe39252806c32d71176308f2c03547a4e Move qmf bands sanity check original-Change-Id: Iab540c3013c174d9490d2ae100a4576f51d8dbc4 Initialize scaling variable original-Change-Id: I3c4087101b70e998c71c1689b122b0d7762e0f9e Add 16 qmf band configuration to getSlotNrgHQ() original-Change-Id: I49a5d30f703a1b126ff163df9656db2540df21f1 Always apply byte alignment at the end of the AudioMuxElement original-Change-Id: I42d560287506d65d4c3de8bfe3eb9a4ebeb4efc7 Setup SBR element only if no parse error exists original-Change-Id: I1915b73704bc80ab882b9173d6bec59cbd073676 Additional array index check in HCR original-Change-Id: I18cc6e501ea683b5009f1bbee26de8ddd04d8267 Fix fade-in index selection in concealment module original-Change-Id: Ibf802ed6ed8c05e9257e1f3b6d0ac1162e9b81c1 Enable explicit backward compatible parser for AAC_LD original-Change-Id: I27e9c678dcb5d40ed760a6d1e06609563d02482d Skip spatial specific config in explicit backward compatible ASC original-Change-Id: Iff7cc365561319e886090cedf30533f562ea4d6e Update flags description in decoder API original-Change-Id: I9a5b4f8da76bb652f5580cbd3ba9760425c43830 Add QMF domain reset function original-Change-Id: I4f89a8a2c0277d18103380134e4ed86996e9d8d6 DRC upgrade v2.1.0 original-Change-Id: I5731c0540139dab220094cd978ef42099fc45b74 Fix integer overflow in sqrtFixp_lookup() original-Change-Id: I429a6f0d19aa2cc957e0f181066f0ca73968c914 Fix integer overflow in invSqrtNorm2() original-Change-Id: I84de5cbf9fb3adeb611db203fe492fabf4eb6155 Fix integer overflow in GenerateRandomVector() original-Change-Id: I3118a641008bd9484d479e5b0b1ee2b5d7d44d74 Fix integer overflow in adjustTimeSlot_EldGrid() original-Change-Id: I29d503c247c5c8282349b79df940416a512fb9d5 Fix integer overflow in FDKsbrEnc_codeEnvelope() original-Change-Id: I6b34b61ebb9d525b0c651ed08de2befc1f801449 Follow-up on: Fix integer overflow in adjustTimeSlot_EldGrid() original-Change-Id: I6f8f578cc7089e5eb7c7b93e580b72ca35ad689a Fix integer overflow in get_pk_v2() original-Change-Id: I63375bed40d45867f6eeaa72b20b1f33e815938c Fix integer overflow in Syn_filt_zero() original-Change-Id: Ie0c02fdfbe03988f9d3b20d10cd9fe4c002d1279 Fix integer overflow in CFac_CalcFacSignal() original-Change-Id: Id2d767c40066c591b51768e978eb8af3b803f0c5 Fix integer overflow in FDKaacEnc_FDKaacEnc_calcPeNoAH() original-Change-Id: Idcbd0f4a51ae2550ed106aa6f3d678d1f9724841 Fix integer overflow in sbrDecoder_calculateGainVec() original-Change-Id: I7081bcbe29c5cede9821b38d93de07c7add2d507 Fix integer overflow in CLpc_SynthesisLattice() original-Change-Id: I4a95ddc18de150102352d4a1845f06094764c881 Fix integer overflow in Pred_Lt4() original-Change-Id: I4dbd012b2de7d07c3e70a47b92e3bfae8dbc750a Fix integer overflow in FDKsbrEnc_InitSbrFastTransientDetector() original-Change-Id: I788cbec1a4a00f44c2f3a72ad7a4afa219807d04 Fix unsigned integer overflow in FDKaacEnc_WriteBitstream() original-Change-Id: I68fc75166e7d2cd5cd45b18dbe3d8c2a92f1822a Fix unsigned integer overflow in FDK_MetadataEnc_Init() original-Change-Id: Ie8d025f9bcdb2442c704bd196e61065c03c10af4 Fix overflow in pseudo random number generators original-Change-Id: I3e2551ee01356297ca14e3788436ede80bd5513c Fix unsigned integer overflow in sbrDecoder_Parse() original-Change-Id: I3f231b2f437e9c37db4d5b964164686710eee971 Fix unsigned integer overflow in longsub() original-Change-Id: I73c2bc50415cac26f1f5a29e125bbe75f9180a6e Fix unsigned integer overflow in CAacDecoder_DecodeFrame() original-Change-Id: Ifce2db4b1454b46fa5f887e9d383f1cc43b291e4 Fix overflow at CLpdChannelStream_Read() original-Change-Id: Idb9d822ce3a4272e4794b643644f5434e2d4bf3f Fix unsigned integer overflow in Hcr_State_BODY_SIGN_ESC__ESC_WORD() original-Change-Id: I1ccf77c0015684b85534c5eb97162740a870b71c Fix unsigned integer overflow in UsacConfig_Parse() original-Change-Id: Ie6d27f84b6ae7eef092ecbff4447941c77864d9f Fix unsigned integer overflow in aacDecoder_drcParse() original-Change-Id: I713f28e883eea3d70b6fa56a7b8f8c22bcf66ca0 Fix unsigned integer overflow in aacDecoder_drcReadCompression() original-Change-Id: Ia34dfeb88c4705c558bce34314f584965cafcf7a Fix unsigned integer overflow in CDataStreamElement_Read() original-Change-Id: Iae896cc1d11f0a893d21be6aa90bd3e60a2c25f0 Fix unsigned integer overflow in transportDec_AdjustEndOfAccessUnit() original-Change-Id: I64cf29a153ee784bb4a16fdc088baabebc0007dc Fix unsigned integer overflow in transportDec_GetAuBitsRemaining() original-Change-Id: I975b3420faa9c16a041874ba0db82e92035962e4 Fix unsigned integer overflow in extractExtendedData() original-Change-Id: I2a59eb09e2053cfb58dfb75fcecfad6b85a80a8f Fix signed integer overflow in CAacDecoder_ExtPayloadParse() original-Change-Id: I4ad5ca4e3b83b5d964f1c2f8c5e7b17c477c7929 Fix unsigned integer overflow in CAacDecoder_DecodeFrame() original-Change-Id: I29a39df77d45c52a0c9c5c83c1ba81f8d0f25090 Follow-up on: Fix integer overflow in CLpc_SynthesisLattice() original-Change-Id: I8fb194ffc073a3432a380845be71036a272d388f Fix signed integer overflow in _interpolateDrcGain() original-Change-Id: I879ec9ab14005069a7c47faf80e8bc6e03d22e60 Fix unsigned integer overflow in FDKreadBits() original-Change-Id: I1f47a6a8037ff70375aa8844947d5681bb4287ad Fix unsigned integer overflow in FDKbyteAlign() original-Change-Id: Id5f3a11a0c9e50fc6f76ed6c572dbd4e9f2af766 Fix unsigned integer overflow in FDK_get32() original-Change-Id: I9d33b8e97e3d38cbb80629cb859266ca0acdce96 Fix unsigned integer overflow in FDK_pushBack() original-Change-Id: Ic87f899bc8c6acf7a377a8ca7f3ba74c3a1e1c19 Fix unsigned integer overflow in FDK_pushForward() original-Change-Id: I3b754382f6776a34be1602e66694ede8e0b8effc Fix unsigned integer overflow in ReadPsData() original-Change-Id: I25361664ba8139e32bbbef2ca8c106a606ce9c37 Fix signed integer overflow in E_UTIL_residu() original-Change-Id: I8c3abd1f437ee869caa8fb5903ce7d3d641b6aad REVERT: Follow-up on: Integer overflow in CLpc_SynthesisLattice(). original-Change-Id: I3d340099acb0414795c8dfbe6362bc0a8f045f9b Follow-up on: Fix integer overflow in CLpc_SynthesisLattice() original-Change-Id: I4aedb8b3a187064e9f4d985175aa55bb99cc7590 Follow-up on: Fix unsigned integer overflow in aacDecoder_drcParse() original-Change-Id: I2aa2e13916213bf52a67e8b0518e7bf7e57fb37d Fix integer overflow in acelp original-Change-Id: Ie6390c136d84055f8b728aefbe4ebef6e029dc77 Fix unsigned integer overflow in aacDecoder_UpdateBitStreamCounters() original-Change-Id: I391ffd97ddb0b2c184cba76139bfb356a3b4d2e2 Adjust concealment default settings original-Change-Id: I6a95db935a327c47df348030bcceafcb29f54b21 Saturate estimatedStartPos original-Change-Id: I27be2085e0ae83ec9501409f65e003f6bcba1ab6 Negative shift exponent in _interpolateDrcGain() original-Change-Id: I18edb26b26d002aafd5e633d4914960f7a359c29 Negative shift exponent in calculateICC() original-Change-Id: I3dcd2ae98d2eb70ee0d59750863cbb2a6f4f8aba Too large shift exponent in FDK_put() original-Change-Id: Ib7d9aaa434d2d8de4a13b720ca0464b31ca9b671 Too large shift exponent in CalcInvLdData() original-Change-Id: I43e6e78d4cd12daeb1dcd5d82d1798bdc2550262 Member access within null pointer of type SBR_CHANNEL original-Change-Id: Idc5e4ea8997810376d2f36bbdf628923b135b097 Member access within null pointer of type CpePersistentData original-Change-Id: Ib6c91cb0d37882768e5baf63324e429589de0d9d Member access within null pointer FDKaacEnc_psyMain() original-Change-Id: I7729b7f4479970531d9dc823abff63ca52e01997 Member access within null pointer FDKaacEnc_GetPnsParam() original-Change-Id: I9aa3b9f3456ae2e0f7483dbd5b3dde95fc62da39 Member access within null pointer FDKsbrEnc_EnvEncodeFrame() original-Change-Id: I67936f90ea714e90b3e81bc0dd1472cc713eb23a Add HCR sanity check original-Change-Id: I6c1d9732ebcf6af12f50b7641400752f74be39f7 Fix memory issue for HBE edge case with 8:3 SBR original-Change-Id: I11ea58a61e69fbe8bf75034b640baee3011e63e9 Additional SBR parametrization sanity check for ELD original-Change-Id: Ie26026fbfe174c2c7b3691f6218b5ce63e322140 Add MPEG-D DRC channel layout check original-Change-Id: Iea70a74f171b227cce636a9eac4ba662777a2f72 Additional out-of-bounds checks in MPEG-D DRC original-Change-Id: Ife4a8c3452c6fde8a0a09e941154a39a769777d4 Change-Id: Ic63cb2f628720f54fe9b572b0cb528e2599c624e
1553 lines
56 KiB
C++
1553 lines
56 KiB
C++
/* -----------------------------------------------------------------------------
|
|
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;
|
|
|
|
/* 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);
|
|
|
|
/* 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);
|
|
}
|
|
}
|
|
}
|