aboutsummaryrefslogtreecommitdiffstats
path: root/libDRCdec/src/drcDec_reader.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'libDRCdec/src/drcDec_reader.cpp')
-rw-r--r--libDRCdec/src/drcDec_reader.cpp2029
1 files changed, 2029 insertions, 0 deletions
diff --git a/libDRCdec/src/drcDec_reader.cpp b/libDRCdec/src/drcDec_reader.cpp
new file mode 100644
index 0000000..6fe7a04
--- /dev/null
+++ b/libDRCdec/src/drcDec_reader.cpp
@@ -0,0 +1,2029 @@
+/* -----------------------------------------------------------------------------
+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
+----------------------------------------------------------------------------- */
+
+/************************* MPEG-D DRC decoder library **************************
+
+ Author(s):
+
+ Description:
+
+*******************************************************************************/
+
+#include "fixpoint_math.h"
+#include "drcDec_reader.h"
+#include "drcDec_tools.h"
+#include "drcDec_rom.h"
+#include "drcDecoder.h"
+
+/* MPEG-D DRC AMD 1 */
+
+#define UNIDRCCONFEXT_PARAM_DRC 0x1
+#define UNIDRCCONFEXT_V1 0x2
+#define UNIDRCLOUDEXT_EQ 0x1
+
+#define UNIDRCGAINEXT_TERM 0x0
+#define UNIDRCLOUDEXT_TERM 0x0
+#define UNIDRCCONFEXT_TERM 0x0
+
+static int _getZ(const int nNodesMax) {
+ /* Z is the minimum codeword length that is needed to encode all possible
+ * timeDelta values */
+ /* Z = ceil(log2(2*nNodesMax)) */
+ int Z = 1;
+ while ((1 << Z) < (2 * nNodesMax)) {
+ Z++;
+ }
+ return Z;
+}
+
+static int _getTimeDeltaMin(const GAIN_SET* pGset, const int deltaTminDefault) {
+ if (pGset->timeDeltaMinPresent) {
+ return pGset->timeDeltaMin;
+ } else {
+ return deltaTminDefault;
+ }
+}
+
+/* compare and assign */
+static inline int _compAssign(UCHAR* dest, const UCHAR src) {
+ int diff = 0;
+ if (*dest != src) diff = 1;
+ *dest = src;
+ return diff;
+}
+
+static inline int _compAssign(ULONG* dest, const ULONG src) {
+ int diff = 0;
+ if (*dest != src) diff = 1;
+ *dest = src;
+ return diff;
+}
+
+typedef const SCHAR (*Huffman)[2];
+
+int _decodeHuffmanCW(Huffman h, /*!< pointer to huffman codebook table */
+ HANDLE_FDK_BITSTREAM hBs) /*!< Handle to bitbuffer */
+{
+ SCHAR index = 0;
+ int value, bit;
+
+ while (index >= 0) {
+ bit = FDKreadBits(hBs, 1);
+ index = h[index][bit];
+ }
+
+ value = index + 64; /* Add offset */
+
+ return value;
+}
+
+/**********/
+/* uniDrc */
+/**********/
+
+DRC_ERROR
+drcDec_readUniDrc(HANDLE_FDK_BITSTREAM hBs, HANDLE_UNI_DRC_CONFIG hUniDrcConfig,
+ HANDLE_LOUDNESS_INFO_SET hLoudnessInfoSet,
+ const int frameSize, const int deltaTminDefault,
+ HANDLE_UNI_DRC_GAIN hUniDrcGain) {
+ DRC_ERROR err = DE_OK;
+ int loudnessInfoSetPresent, uniDrcConfigPresent;
+
+ loudnessInfoSetPresent = FDKreadBits(hBs, 1);
+ if (loudnessInfoSetPresent) {
+ uniDrcConfigPresent = FDKreadBits(hBs, 1);
+ if (uniDrcConfigPresent) {
+ err = drcDec_readUniDrcConfig(hBs, hUniDrcConfig);
+ if (err) return err;
+ }
+ err = drcDec_readLoudnessInfoSet(hBs, hLoudnessInfoSet);
+ if (err) return err;
+ }
+
+ if (hUniDrcGain != NULL) {
+ err = drcDec_readUniDrcGain(hBs, hUniDrcConfig, frameSize, deltaTminDefault,
+ hUniDrcGain);
+ if (err) return err;
+ }
+
+ return err;
+}
+
+/**************/
+/* uniDrcGain */
+/**************/
+
+static FIXP_SGL _decodeGainInitial(
+ HANDLE_FDK_BITSTREAM hBs, const GAIN_CODING_PROFILE gainCodingProfile) {
+ int sign, magn;
+ FIXP_SGL gainInitial = (FIXP_SGL)0;
+ switch (gainCodingProfile) {
+ case GCP_REGULAR:
+ sign = FDKreadBits(hBs, 1);
+ magn = FDKreadBits(hBs, 8);
+
+ gainInitial =
+ (FIXP_SGL)(magn << (FRACT_BITS - 1 - 3 - 7)); /* magn * 0.125; */
+ if (sign) gainInitial = -gainInitial;
+ break;
+ case GCP_FADING:
+ sign = FDKreadBits(hBs, 1);
+ if (sign == 0)
+ gainInitial = (FIXP_SGL)0;
+ else {
+ magn = FDKreadBits(hBs, 10);
+ gainInitial = -(FIXP_SGL)(
+ (magn + 1) << (FRACT_BITS - 1 - 3 - 7)); /* - (magn + 1) * 0.125; */
+ }
+ break;
+ case GCP_CLIPPING_DUCKING:
+ sign = FDKreadBits(hBs, 1);
+ if (sign == 0)
+ gainInitial = (FIXP_SGL)0;
+ else {
+ magn = FDKreadBits(hBs, 8);
+ gainInitial = -(FIXP_SGL)(
+ (magn + 1) << (FRACT_BITS - 1 - 3 - 7)); /* - (magn + 1) * 0.125; */
+ }
+ break;
+ case GCP_CONSTANT:
+ break;
+ }
+ return gainInitial;
+}
+
+static int _decodeNNodes(HANDLE_FDK_BITSTREAM hBs) {
+ int nNodes = 0, endMarker = 0;
+
+ /* decode number of nodes */
+ while (endMarker != 1) {
+ nNodes++;
+ if (nNodes >= 128) break;
+ endMarker = FDKreadBits(hBs, 1);
+ }
+ return nNodes;
+}
+
+static void _decodeGains(HANDLE_FDK_BITSTREAM hBs,
+ const GAIN_CODING_PROFILE gainCodingProfile,
+ const int nNodes, GAIN_NODE* pNodes) {
+ int k, deltaGain;
+ Huffman deltaGainCodebook;
+
+ pNodes[0].gainDb = _decodeGainInitial(hBs, gainCodingProfile);
+
+ if (gainCodingProfile == GCP_CLIPPING_DUCKING) {
+ deltaGainCodebook = (Huffman)&deltaGain_codingProfile_2_huffman;
+ } else {
+ deltaGainCodebook = (Huffman)&deltaGain_codingProfile_0_1_huffman;
+ }
+
+ for (k = 1; k < nNodes; k++) {
+ deltaGain = _decodeHuffmanCW(deltaGainCodebook, hBs);
+ if (k >= 16) continue;
+ /* gain_dB_e = 7 */
+ pNodes[k].gainDb =
+ pNodes[k - 1].gainDb +
+ (FIXP_SGL)(deltaGain << (FRACT_BITS - 1 - 7 -
+ 3)); /* pNodes[k-1].gainDb + 0.125*deltaGain */
+ }
+}
+
+static void _decodeSlopes(HANDLE_FDK_BITSTREAM hBs,
+ const GAIN_INTERPOLATION_TYPE gainInterpolationType,
+ const int nNodes, GAIN_NODE* pNodes) {
+ int k = 0;
+
+ if (gainInterpolationType == GIT_SPLINE) {
+ /* decode slope steepness */
+ for (k = 0; k < nNodes; k++) {
+ _decodeHuffmanCW((Huffman)&slopeSteepness_huffman, hBs);
+ }
+ }
+}
+
+static int _decodeTimeDelta(HANDLE_FDK_BITSTREAM hBs, const int Z) {
+ int prefix, mu;
+
+ prefix = FDKreadBits(hBs, 2);
+ switch (prefix) {
+ case 0x0:
+ return 1;
+ case 0x1:
+ mu = FDKreadBits(hBs, 2);
+ return mu + 2;
+ case 0x2:
+ mu = FDKreadBits(hBs, 3);
+ return mu + 6;
+ case 0x3:
+ mu = FDKreadBits(hBs, Z);
+ return mu + 14;
+ default:
+ return 0;
+ }
+}
+
+static void _decodeTimes(HANDLE_FDK_BITSTREAM hBs, const int deltaTmin,
+ const int frameSize, const int fullFrame,
+ const int timeOffset, const int Z, const int nNodes,
+ GAIN_NODE* pNodes) {
+ int timeDelta, k;
+ int timeOffs = timeOffset;
+ int frameEndFlag, nodeTimeTmp, nodeResFlag;
+
+ if (fullFrame == 0) {
+ frameEndFlag = FDKreadBits(hBs, 1);
+ } else {
+ frameEndFlag = 1;
+ }
+
+ if (frameEndFlag ==
+ 1) { /* frameEndFlag == 1 signals that the last node is at the end of the
+ DRC frame */
+ nodeResFlag = 0;
+ for (k = 0; k < nNodes - 1; k++) {
+ /* decode a delta time value */
+ timeDelta = _decodeTimeDelta(hBs, Z);
+ if (k >= (16 - 1)) continue;
+ /* frameEndFlag == 1 needs special handling for last node with node
+ * reservoir */
+ nodeTimeTmp = timeOffs + timeDelta * deltaTmin;
+ if (nodeTimeTmp > frameSize + timeOffset) {
+ if (nodeResFlag == 0) {
+ pNodes[k].time = frameSize + timeOffset;
+ nodeResFlag = 1;
+ }
+ pNodes[k + 1].time = nodeTimeTmp;
+ } else {
+ pNodes[k].time = nodeTimeTmp;
+ }
+ timeOffs = nodeTimeTmp;
+ }
+ if (nodeResFlag == 0) {
+ k = fMin(k, 16 - 1);
+ pNodes[k].time = frameSize + timeOffset;
+ }
+ } else {
+ for (k = 0; k < nNodes; k++) {
+ /* decode a delta time value */
+ timeDelta = _decodeTimeDelta(hBs, Z);
+ if (k >= 16) continue;
+ pNodes[k].time = timeOffs + timeDelta * deltaTmin;
+ timeOffs = pNodes[k].time;
+ }
+ }
+}
+
+static void _readNodes(HANDLE_FDK_BITSTREAM hBs, GAIN_SET* gainSet,
+ const int frameSize, const int timeDeltaMin,
+ UCHAR* pNNodes, GAIN_NODE* pNodes) {
+ int timeOffset, drcGainCodingMode, nNodes;
+ int Z = _getZ(frameSize / timeDeltaMin);
+ if (gainSet->timeAlignment == 0) {
+ timeOffset = -1;
+ } else {
+ timeOffset = -timeDeltaMin +
+ (timeDeltaMin - 1) /
+ 2; /* timeOffset = - deltaTmin + floor((deltaTmin-1)/2); */
+ }
+
+ drcGainCodingMode = FDKreadBits(hBs, 1);
+ if (drcGainCodingMode == 0) {
+ /* "simple" mode: only one node at the end of the frame with slope = 0 */
+ nNodes = 1;
+ pNodes[0].gainDb = _decodeGainInitial(
+ hBs, (GAIN_CODING_PROFILE)gainSet->gainCodingProfile);
+ pNodes[0].time = frameSize + timeOffset;
+ } else {
+ nNodes = _decodeNNodes(hBs);
+
+ _decodeSlopes(hBs, (GAIN_INTERPOLATION_TYPE)gainSet->gainInterpolationType,
+ nNodes, pNodes);
+
+ _decodeTimes(hBs, timeDeltaMin, frameSize, gainSet->fullFrame, timeOffset,
+ Z, nNodes, pNodes);
+
+ _decodeGains(hBs, (GAIN_CODING_PROFILE)gainSet->gainCodingProfile, nNodes,
+ pNodes);
+ }
+ *pNNodes = (UCHAR)nNodes;
+}
+
+static void _readDrcGainSequence(HANDLE_FDK_BITSTREAM hBs, GAIN_SET* gainSet,
+ const int frameSize, const int timeDeltaMin,
+ UCHAR* pNNodes, GAIN_NODE pNodes[16]) {
+ SHORT timeBufPrevFrame[16], timeBufCurFrame[16];
+ int nNodesNodeRes, nNodesCur, k, m;
+
+ if (gainSet->gainCodingProfile == GCP_CONSTANT) {
+ *pNNodes = 1;
+ pNodes[0].time = frameSize - 1;
+ pNodes[0].gainDb = (FIXP_SGL)0;
+ } else {
+ _readNodes(hBs, gainSet, frameSize, timeDeltaMin, pNNodes, pNodes);
+
+ /* count number of nodes in node reservoir */
+ nNodesNodeRes = 0;
+ nNodesCur = 0;
+ /* count and buffer nodes from node reservoir */
+ for (k = 0; k < *pNNodes; k++) {
+ if (k >= 16) continue;
+ if (pNodes[k].time >= frameSize) {
+ /* write node reservoir times into buffer */
+ timeBufPrevFrame[nNodesNodeRes] = pNodes[k].time;
+ nNodesNodeRes++;
+ } else { /* times from current frame */
+ timeBufCurFrame[nNodesCur] = pNodes[k].time;
+ nNodesCur++;
+ }
+ }
+ /* compose right time order (bit reservoir first) */
+ for (k = 0; k < nNodesNodeRes; k++) {
+ /* subtract two time frameSize: one to remove node reservoir offset and
+ * one to get the negative index relative to the current frame
+ */
+ pNodes[k].time = timeBufPrevFrame[k] - 2 * frameSize;
+ }
+ /* ...and times from current frame */
+ for (m = 0; m < nNodesCur; m++, k++) {
+ pNodes[k].time = timeBufCurFrame[m];
+ }
+ }
+}
+
+static DRC_ERROR _readUniDrcGainExtension(HANDLE_FDK_BITSTREAM hBs,
+ UNI_DRC_GAIN_EXTENSION* pExt) {
+ DRC_ERROR err = DE_OK;
+ int k, bitSizeLen, extSizeBits, bitSize;
+
+ k = 0;
+ pExt->uniDrcGainExtType[k] = FDKreadBits(hBs, 4);
+ while (pExt->uniDrcGainExtType[k] != UNIDRCGAINEXT_TERM) {
+ if (k >= (8 - 1)) return DE_MEMORY_ERROR;
+ bitSizeLen = FDKreadBits(hBs, 3);
+ extSizeBits = bitSizeLen + 4;
+
+ bitSize = FDKreadBits(hBs, extSizeBits);
+ pExt->extBitSize[k] = bitSize + 1;
+
+ switch (pExt->uniDrcGainExtType[k]) {
+ /* add future extensions here */
+ default:
+ FDKpushFor(hBs, pExt->extBitSize[k]);
+ break;
+ }
+ k++;
+ pExt->uniDrcGainExtType[k] = FDKreadBits(hBs, 4);
+ }
+
+ return err;
+}
+
+DRC_ERROR
+drcDec_readUniDrcGain(HANDLE_FDK_BITSTREAM hBs,
+ HANDLE_UNI_DRC_CONFIG hUniDrcConfig, const int frameSize,
+ const int deltaTminDefault,
+ HANDLE_UNI_DRC_GAIN hUniDrcGain) {
+ DRC_ERROR err = DE_OK;
+ int seq, gainSequenceCount;
+ DRC_COEFFICIENTS_UNI_DRC* pCoef =
+ selectDrcCoefficients(hUniDrcConfig, LOCATION_SELECTED);
+ if (pCoef == NULL) return DE_OK;
+ if (hUniDrcGain == NULL) return DE_OK; /* hUniDrcGain not initialized yet */
+
+ gainSequenceCount = fMin(pCoef->gainSequenceCount, (UCHAR)12);
+
+ for (seq = 0; seq < gainSequenceCount; seq++) {
+ UCHAR index = pCoef->gainSetIndexForGainSequence[seq];
+ GAIN_SET* gainSet;
+ int timeDeltaMin;
+ UCHAR tmpNNodes = 0;
+ GAIN_NODE tmpNodes[16];
+
+ if ((index >= pCoef->gainSetCount) || (index >= 12)) return DE_NOT_OK;
+ gainSet = &(pCoef->gainSet[index]);
+
+ timeDeltaMin = _getTimeDeltaMin(gainSet, deltaTminDefault);
+
+ _readDrcGainSequence(hBs, gainSet, frameSize, timeDeltaMin, &tmpNNodes,
+ tmpNodes);
+
+ hUniDrcGain->nNodes[seq] = tmpNNodes;
+ FDKmemcpy(hUniDrcGain->gainNode[seq], tmpNodes,
+ fMin(tmpNNodes, (UCHAR)16) * sizeof(GAIN_NODE));
+ }
+
+ hUniDrcGain->uniDrcGainExtPresent = FDKreadBits(hBs, 1);
+ if (hUniDrcGain->uniDrcGainExtPresent == 1) {
+ err = _readUniDrcGainExtension(hBs, &(hUniDrcGain->uniDrcGainExtension));
+ if (err) return err;
+ }
+
+ return err;
+}
+
+/****************/
+/* uniDrcConfig */
+/****************/
+
+static void _decodeDuckingModification(HANDLE_FDK_BITSTREAM hBs,
+ DUCKING_MODIFICATION* pDMod, int isBox) {
+ int bsDuckingScaling, sigma, mu;
+
+ if (isBox) FDKpushFor(hBs, 7); /* reserved */
+ pDMod->duckingScalingPresent = FDKreadBits(hBs, 1);
+
+ if (pDMod->duckingScalingPresent) {
+ if (isBox) FDKpushFor(hBs, 4); /* reserved */
+ bsDuckingScaling = FDKreadBits(hBs, 4);
+ sigma = bsDuckingScaling >> 3;
+ mu = bsDuckingScaling & 0x7;
+
+ if (sigma) {
+ pDMod->duckingScaling = (FIXP_SGL)(
+ (7 - mu) << (FRACT_BITS - 1 - 3 - 2)); /* 1.0 - 0.125 * (1 + mu); */
+ } else {
+ pDMod->duckingScaling = (FIXP_SGL)(
+ (9 + mu) << (FRACT_BITS - 1 - 3 - 2)); /* 1.0 + 0.125 * (1 + mu); */
+ }
+ } else {
+ pDMod->duckingScaling = (FIXP_SGL)(1 << (FRACT_BITS - 1 - 2)); /* 1.0 */
+ }
+}
+
+static void _decodeGainModification(HANDLE_FDK_BITSTREAM hBs, const int version,
+ int bandCount, GAIN_MODIFICATION* pGMod,
+ int isBox) {
+ int sign, bsGainOffset, bsAttenuationScaling, bsAmplificationScaling;
+
+ if (version > 0) {
+ int b, shapeFilterPresent;
+
+ if (isBox) {
+ FDKpushFor(hBs, 4); /* reserved */
+ bandCount = FDKreadBits(hBs, 4);
+ }
+
+ for (b = 0; b < bandCount; b++) {
+ if (isBox) {
+ FDKpushFor(hBs, 4); /* reserved */
+ pGMod[b].targetCharacteristicLeftPresent = FDKreadBits(hBs, 1);
+ pGMod[b].targetCharacteristicRightPresent = FDKreadBits(hBs, 1);
+ pGMod[b].gainScalingPresent = FDKreadBits(hBs, 1);
+ pGMod[b].gainOffsetPresent = FDKreadBits(hBs, 1);
+ }
+
+ if (!isBox)
+ pGMod[b].targetCharacteristicLeftPresent = FDKreadBits(hBs, 1);
+ if (pGMod[b].targetCharacteristicLeftPresent) {
+ if (isBox) FDKpushFor(hBs, 4); /* reserved */
+ pGMod[b].targetCharacteristicLeftIndex = FDKreadBits(hBs, 4);
+ }
+ if (!isBox)
+ pGMod[b].targetCharacteristicRightPresent = FDKreadBits(hBs, 1);
+ if (pGMod[b].targetCharacteristicRightPresent) {
+ if (isBox) FDKpushFor(hBs, 4); /* reserved */
+ pGMod[b].targetCharacteristicRightIndex = FDKreadBits(hBs, 4);
+ }
+ if (!isBox) pGMod[b].gainScalingPresent = FDKreadBits(hBs, 1);
+ if (pGMod[b].gainScalingPresent) {
+ bsAttenuationScaling = FDKreadBits(hBs, 4);
+ pGMod[b].attenuationScaling = (FIXP_SGL)(
+ bsAttenuationScaling
+ << (FRACT_BITS - 1 - 3 - 2)); /* bsAttenuationScaling * 0.125; */
+ bsAmplificationScaling = FDKreadBits(hBs, 4);
+ pGMod[b].amplificationScaling = (FIXP_SGL)(
+ bsAmplificationScaling
+ << (FRACT_BITS - 1 - 3 - 2)); /* bsAmplificationScaling * 0.125; */
+ }
+ if (!isBox) pGMod[b].gainOffsetPresent = FDKreadBits(hBs, 1);
+ if (pGMod[b].gainOffsetPresent) {
+ if (isBox) FDKpushFor(hBs, 2); /* reserved */
+ sign = FDKreadBits(hBs, 1);
+ bsGainOffset = FDKreadBits(hBs, 5);
+ pGMod[b].gainOffset = (FIXP_SGL)(
+ (1 + bsGainOffset)
+ << (FRACT_BITS - 1 - 2 - 4)); /* (1+bsGainOffset) * 0.25; */
+ if (sign) {
+ pGMod[b].gainOffset = -pGMod[b].gainOffset;
+ }
+ }
+ }
+ if (bandCount == 1) {
+ shapeFilterPresent = FDKreadBits(hBs, 1);
+ if (shapeFilterPresent) {
+ if (isBox) FDKpushFor(hBs, 3); /* reserved */
+ FDKpushFor(hBs, 4); /* pGMod->shapeFilterIndex */
+ } else {
+ if (isBox) FDKpushFor(hBs, 7); /* reserved */
+ }
+ }
+ } else {
+ int b, gainScalingPresent, gainOffsetPresent;
+ FIXP_SGL attenuationScaling = FL2FXCONST_SGL(1.0f / (float)(1 << 2)),
+ amplificationScaling = FL2FXCONST_SGL(1.0f / (float)(1 << 2)),
+ gainOffset = (FIXP_SGL)0;
+ if (isBox) FDKpushFor(hBs, 7); /* reserved */
+ gainScalingPresent = FDKreadBits(hBs, 1);
+ if (gainScalingPresent) {
+ bsAttenuationScaling = FDKreadBits(hBs, 4);
+ attenuationScaling = (FIXP_SGL)(
+ bsAttenuationScaling
+ << (FRACT_BITS - 1 - 3 - 2)); /* bsAttenuationScaling * 0.125; */
+ bsAmplificationScaling = FDKreadBits(hBs, 4);
+ amplificationScaling = (FIXP_SGL)(
+ bsAmplificationScaling
+ << (FRACT_BITS - 1 - 3 - 2)); /* bsAmplificationScaling * 0.125; */
+ }
+ if (isBox) FDKpushFor(hBs, 7); /* reserved */
+ gainOffsetPresent = FDKreadBits(hBs, 1);
+ if (gainOffsetPresent) {
+ if (isBox) FDKpushFor(hBs, 2); /* reserved */
+ sign = FDKreadBits(hBs, 1);
+ bsGainOffset = FDKreadBits(hBs, 5);
+ gainOffset =
+ (FIXP_SGL)((1 + bsGainOffset) << (FRACT_BITS - 1 - 2 -
+ 4)); /* (1+bsGainOffset) * 0.25; */
+ if (sign) {
+ gainOffset = -gainOffset;
+ }
+ }
+ for (b = 0; b < 4; b++) {
+ pGMod[b].targetCharacteristicLeftPresent = 0;
+ pGMod[b].targetCharacteristicRightPresent = 0;
+ pGMod[b].gainScalingPresent = gainScalingPresent;
+ pGMod[b].attenuationScaling = attenuationScaling;
+ pGMod[b].amplificationScaling = amplificationScaling;
+ pGMod[b].gainOffsetPresent = gainOffsetPresent;
+ pGMod[b].gainOffset = gainOffset;
+ }
+ }
+}
+
+static void _readDrcCharacteristic(HANDLE_FDK_BITSTREAM hBs, const int version,
+ DRC_CHARACTERISTIC* pDChar, int isBox) {
+ if (version == 0) {
+ if (isBox) FDKpushFor(hBs, 1); /* reserved */
+ pDChar->cicpIndex = FDKreadBits(hBs, 7);
+ if (pDChar->cicpIndex > 0) {
+ pDChar->present = 1;
+ pDChar->isCICP = 1;
+ } else {
+ pDChar->present = 0;
+ }
+ } else {
+ pDChar->present = FDKreadBits(hBs, 1);
+ if (isBox) pDChar->isCICP = FDKreadBits(hBs, 1);
+ if (pDChar->present) {
+ if (!isBox) pDChar->isCICP = FDKreadBits(hBs, 1);
+ if (pDChar->isCICP) {
+ if (isBox) FDKpushFor(hBs, 1); /* reserved */
+ pDChar->cicpIndex = FDKreadBits(hBs, 7);
+ } else {
+ pDChar->custom.left = FDKreadBits(hBs, 4);
+ pDChar->custom.right = FDKreadBits(hBs, 4);
+ }
+ }
+ }
+}
+
+static void _readBandBorder(HANDLE_FDK_BITSTREAM hBs, BAND_BORDER* pBBord,
+ int drcBandType, int isBox) {
+ if (drcBandType) {
+ if (isBox) FDKpushFor(hBs, 4); /* reserved */
+ pBBord->crossoverFreqIndex = FDKreadBits(hBs, 4);
+ } else {
+ if (isBox) FDKpushFor(hBs, 6); /* reserved */
+ pBBord->startSubBandIndex = FDKreadBits(hBs, 10);
+ }
+}
+
+static DRC_ERROR _readGainSet(HANDLE_FDK_BITSTREAM hBs, const int version,
+ int* gainSequenceIndex, GAIN_SET* pGSet,
+ int isBox) {
+ if (isBox) FDKpushFor(hBs, 2); /* reserved */
+ pGSet->gainCodingProfile = FDKreadBits(hBs, 2);
+ pGSet->gainInterpolationType = FDKreadBits(hBs, 1);
+ pGSet->fullFrame = FDKreadBits(hBs, 1);
+ pGSet->timeAlignment = FDKreadBits(hBs, 1);
+ pGSet->timeDeltaMinPresent = FDKreadBits(hBs, 1);
+
+ if (pGSet->timeDeltaMinPresent) {
+ int bsTimeDeltaMin;
+ if (isBox) FDKpushFor(hBs, 5); /* reserved */
+ bsTimeDeltaMin = FDKreadBits(hBs, 11);
+ pGSet->timeDeltaMin = bsTimeDeltaMin + 1;
+ }
+
+ if (pGSet->gainCodingProfile != GCP_CONSTANT) {
+ int i;
+ if (isBox) FDKpushFor(hBs, 3); /* reserved */
+ pGSet->bandCount = FDKreadBits(hBs, 4);
+ if (pGSet->bandCount > 4) return DE_MEMORY_ERROR;
+
+ if ((pGSet->bandCount > 1) || isBox) {
+ pGSet->drcBandType = FDKreadBits(hBs, 1);
+ }
+
+ for (i = 0; i < pGSet->bandCount; i++) {
+ if (version == 0) {
+ *gainSequenceIndex = (*gainSequenceIndex) + 1;
+ } else {
+ int indexPresent;
+ indexPresent = (isBox) ? 1 : FDKreadBits(hBs, 1);
+ if (indexPresent) {
+ int bsIndex;
+ bsIndex = FDKreadBits(hBs, 6);
+ *gainSequenceIndex = bsIndex;
+ } else {
+ *gainSequenceIndex = (*gainSequenceIndex) + 1;
+ }
+ }
+ pGSet->gainSequenceIndex[i] = *gainSequenceIndex;
+ _readDrcCharacteristic(hBs, version, &(pGSet->drcCharacteristic[i]),
+ isBox);
+ }
+ for (i = 1; i < pGSet->bandCount; i++) {
+ _readBandBorder(hBs, &(pGSet->bandBorder[i]), pGSet->drcBandType, isBox);
+ }
+ } else {
+ pGSet->bandCount = 1;
+ *gainSequenceIndex = (*gainSequenceIndex) + 1;
+ pGSet->gainSequenceIndex[0] = *gainSequenceIndex;
+ }
+
+ return DE_OK;
+}
+
+static DRC_ERROR _readCustomDrcCharacteristic(HANDLE_FDK_BITSTREAM hBs,
+ const CHARACTERISTIC_SIDE side,
+ UCHAR* pCharacteristicFormat,
+ CUSTOM_DRC_CHAR* pCChar,
+ int isBox) {
+ if (isBox) FDKpushFor(hBs, 7); /* reserved */
+ *pCharacteristicFormat = FDKreadBits(hBs, 1);
+ if (*pCharacteristicFormat == CF_SIGMOID) {
+ int bsGain, bsIoRatio, bsExp;
+ if (isBox) FDKpushFor(hBs, 1); /* reserved */
+ bsGain = FDKreadBits(hBs, 6);
+ if (side == CS_LEFT) {
+ pCChar->sigmoid.gain = (FIXP_SGL)(bsGain << (FRACT_BITS - 1 - 6));
+ } else {
+ pCChar->sigmoid.gain = (FIXP_SGL)(-bsGain << (FRACT_BITS - 1 - 6));
+ }
+ bsIoRatio = FDKreadBits(hBs, 4);
+ /* pCChar->sigmoid.ioRatio = 0.05 + 0.15 * bsIoRatio; */
+ pCChar->sigmoid.ioRatio =
+ FL2FXCONST_SGL(0.05f / (float)(1 << 2)) +
+ (FIXP_SGL)((((3 * bsIoRatio) << (FRACT_BITS - 1)) / 5) >> 4);
+ bsExp = FDKreadBits(hBs, 4);
+ if (bsExp < 15) {
+ pCChar->sigmoid.exp = (FIXP_SGL)((1 + 2 * bsExp) << (FRACT_BITS - 1 - 5));
+ } else {
+ pCChar->sigmoid.exp = (FIXP_SGL)MAXVAL_SGL; /* represents infinity */
+ }
+ pCChar->sigmoid.flipSign = FDKreadBits(hBs, 1);
+ } else { /* CF_NODES */
+ int i, bsCharacteristicNodeCount, bsNodeLevelDelta, bsNodeGain;
+ if (isBox) FDKpushFor(hBs, 6); /* reserved */
+ bsCharacteristicNodeCount = FDKreadBits(hBs, 2);
+ pCChar->nodes.characteristicNodeCount = bsCharacteristicNodeCount + 1;
+ if (pCChar->nodes.characteristicNodeCount > 4) return DE_MEMORY_ERROR;
+ pCChar->nodes.nodeLevel[0] = DRC_INPUT_LOUDNESS_TARGET_SGL;
+ pCChar->nodes.nodeGain[0] = (FIXP_SGL)0;
+ for (i = 0; i < pCChar->nodes.characteristicNodeCount; i++) {
+ if (isBox) FDKpushFor(hBs, 3); /* reserved */
+ bsNodeLevelDelta = FDKreadBits(hBs, 5);
+ if (side == CS_LEFT) {
+ pCChar->nodes.nodeLevel[i + 1] =
+ pCChar->nodes.nodeLevel[i] -
+ (FIXP_SGL)((1 + bsNodeLevelDelta) << (FRACT_BITS - 1 - 7));
+ } else {
+ pCChar->nodes.nodeLevel[i + 1] =
+ pCChar->nodes.nodeLevel[i] +
+ (FIXP_SGL)((1 + bsNodeLevelDelta) << (FRACT_BITS - 1 - 7));
+ }
+ bsNodeGain = FDKreadBits(hBs, 8);
+ pCChar->nodes.nodeGain[i + 1] = (FIXP_SGL)(
+ (bsNodeGain - 128)
+ << (FRACT_BITS - 1 - 1 - 7)); /* 0.5f * bsNodeGain - 64.0f; */
+ }
+ }
+ return DE_OK;
+}
+
+static void _skipLoudEqInstructions(HANDLE_FDK_BITSTREAM hBs) {
+ int i;
+ int downmixIdPresent, additionalDownmixIdPresent,
+ additionalDownmixIdCount = 0;
+ int drcSetIdPresent, additionalDrcSetIdPresent, additionalDrcSetIdCount = 0;
+ int eqSetIdPresent, additionalEqSetIdPresent, additionalEqSetIdCount = 0;
+ int loudEqGainSequenceCount, drcCharacteristicFormatIsCICP;
+
+ FDKpushFor(hBs, 4); /* loudEqSetId */
+ FDKpushFor(hBs, 4); /* drcLocation */
+ downmixIdPresent = FDKreadBits(hBs, 1);
+ if (downmixIdPresent) {
+ FDKpushFor(hBs, 7); /* downmixId */
+ additionalDownmixIdPresent = FDKreadBits(hBs, 1);
+ if (additionalDownmixIdPresent) {
+ additionalDownmixIdCount = FDKreadBits(hBs, 7);
+ for (i = 0; i < additionalDownmixIdCount; i++) {
+ FDKpushFor(hBs, 7); /* additionalDownmixId */
+ }
+ }
+ }
+
+ drcSetIdPresent = FDKreadBits(hBs, 1);
+ if (drcSetIdPresent) {
+ FDKpushFor(hBs, 6); /* drcSetId */
+ additionalDrcSetIdPresent = FDKreadBits(hBs, 1);
+ if (additionalDrcSetIdPresent) {
+ additionalDrcSetIdCount = FDKreadBits(hBs, 6);
+ for (i = 0; i < additionalDrcSetIdCount; i++) {
+ FDKpushFor(hBs, 6); /* additionalDrcSetId; */
+ }
+ }
+ }
+
+ eqSetIdPresent = FDKreadBits(hBs, 1);
+ if (eqSetIdPresent) {
+ FDKpushFor(hBs, 6); /* eqSetId */
+ additionalEqSetIdPresent = FDKreadBits(hBs, 1);
+ if (additionalEqSetIdPresent) {
+ additionalEqSetIdCount = FDKreadBits(hBs, 6);
+ for (i = 0; i < additionalEqSetIdCount; i++) {
+ FDKpushFor(hBs, 6); /* additionalEqSetId; */
+ }
+ }
+ }
+
+ FDKpushFor(hBs, 1); /* loudnessAfterDrc */
+ FDKpushFor(hBs, 1); /* loudnessAfterEq */
+ loudEqGainSequenceCount = FDKreadBits(hBs, 6);
+ for (i = 0; i < loudEqGainSequenceCount; i++) {
+ FDKpushFor(hBs, 6); /* gainSequenceIndex */
+ drcCharacteristicFormatIsCICP = FDKreadBits(hBs, 1);
+ if (drcCharacteristicFormatIsCICP) {
+ FDKpushFor(hBs, 7); /* drcCharacteristic */
+ } else {
+ FDKpushFor(hBs, 4); /* drcCharacteristicLeftIndex */
+ FDKpushFor(hBs, 4); /* drcCharacteristicRightIndex */
+ }
+ FDKpushFor(hBs, 6); /* frequencyRangeIndex */
+ FDKpushFor(hBs, 3); /* bsLoudEqScaling */
+ FDKpushFor(hBs, 5); /* bsLoudEqOffset */
+ }
+}
+
+static void _skipEqSubbandGainSpline(HANDLE_FDK_BITSTREAM hBs) {
+ int nEqNodes, k, bits;
+ nEqNodes = FDKreadBits(hBs, 5);
+ nEqNodes += 2;
+ for (k = 0; k < nEqNodes; k++) {
+ bits = FDKreadBits(hBs, 1);
+ if (!bits) {
+ FDKpushFor(hBs, 4);
+ }
+ }
+ FDKpushFor(hBs, 4 * (nEqNodes - 1));
+ bits = FDKreadBits(hBs, 2);
+ switch (bits) {
+ case 0:
+ FDKpushFor(hBs, 5);
+ break;
+ case 1:
+ case 2:
+ FDKpushFor(hBs, 4);
+ break;
+ case 3:
+ FDKpushFor(hBs, 3);
+ break;
+ }
+ FDKpushFor(hBs, 5 * (nEqNodes - 1));
+}
+
+static void _skipEqCoefficients(HANDLE_FDK_BITSTREAM hBs) {
+ int j, k;
+ int eqDelayMaxPresent;
+ int uniqueFilterBlockCount, filterElementCount, filterElementGainPresent;
+ int uniqueTdFilterElementCount, eqFilterFormat, bsRealZeroRadiusOneCount,
+ realZeroCount, genericZeroCount, realPoleCount, complexPoleCount,
+ firFilterOrder;
+ int uniqueEqSubbandGainsCount, eqSubbandGainRepresentation,
+ eqSubbandGainCount;
+ EQ_SUBBAND_GAIN_FORMAT eqSubbandGainFormat;
+
+ eqDelayMaxPresent = FDKreadBits(hBs, 1);
+ if (eqDelayMaxPresent) {
+ FDKpushFor(hBs, 8); /* bsEqDelayMax */
+ }
+
+ uniqueFilterBlockCount = FDKreadBits(hBs, 6);
+ for (j = 0; j < uniqueFilterBlockCount; j++) {
+ filterElementCount = FDKreadBits(hBs, 6);
+ for (k = 0; k < filterElementCount; k++) {
+ FDKpushFor(hBs, 6); /* filterElementIndex */
+ filterElementGainPresent = FDKreadBits(hBs, 1);
+ if (filterElementGainPresent) {
+ FDKpushFor(hBs, 10); /* bsFilterElementGain */
+ }
+ }
+ }
+ uniqueTdFilterElementCount = FDKreadBits(hBs, 6);
+ for (j = 0; j < uniqueTdFilterElementCount; j++) {
+ eqFilterFormat = FDKreadBits(hBs, 1);
+ if (eqFilterFormat == 0) { /* pole/zero */
+ bsRealZeroRadiusOneCount = FDKreadBits(hBs, 3);
+ realZeroCount = FDKreadBits(hBs, 6);
+ genericZeroCount = FDKreadBits(hBs, 6);
+ realPoleCount = FDKreadBits(hBs, 4);
+ complexPoleCount = FDKreadBits(hBs, 4);
+ FDKpushFor(hBs, 2 * bsRealZeroRadiusOneCount * 1);
+ FDKpushFor(hBs, realZeroCount * 8);
+ FDKpushFor(hBs, genericZeroCount * 14);
+ FDKpushFor(hBs, realPoleCount * 8);
+ FDKpushFor(hBs, complexPoleCount * 14);
+ } else { /* FIR coefficients */
+ firFilterOrder = FDKreadBits(hBs, 7);
+ FDKpushFor(hBs, 1);
+ FDKpushFor(hBs, (firFilterOrder / 2 + 1) * 11);
+ }
+ }
+ uniqueEqSubbandGainsCount = FDKreadBits(hBs, 6);
+ if (uniqueEqSubbandGainsCount > 0) {
+ eqSubbandGainRepresentation = FDKreadBits(hBs, 1);
+ eqSubbandGainFormat = (EQ_SUBBAND_GAIN_FORMAT)FDKreadBits(hBs, 4);
+ switch (eqSubbandGainFormat) {
+ case GF_QMF32:
+ eqSubbandGainCount = 32;
+ break;
+ case GF_QMFHYBRID39:
+ eqSubbandGainCount = 39;
+ break;
+ case GF_QMF64:
+ eqSubbandGainCount = 64;
+ break;
+ case GF_QMFHYBRID71:
+ eqSubbandGainCount = 71;
+ break;
+ case GF_QMF128:
+ eqSubbandGainCount = 128;
+ break;
+ case GF_QMFHYBRID135:
+ eqSubbandGainCount = 135;
+ break;
+ case GF_UNIFORM:
+ default:
+ eqSubbandGainCount = FDKreadBits(hBs, 8);
+ eqSubbandGainCount++;
+ break;
+ }
+ for (k = 0; k < uniqueEqSubbandGainsCount; k++) {
+ if (eqSubbandGainRepresentation == 1) {
+ _skipEqSubbandGainSpline(hBs);
+ } else {
+ FDKpushFor(hBs, eqSubbandGainCount * 9);
+ }
+ }
+ }
+}
+
+static void _skipTdFilterCascade(HANDLE_FDK_BITSTREAM hBs,
+ const int eqChannelGroupCount) {
+ int i, eqCascadeGainPresent, filterBlockCount, eqPhaseAlignmentPresent;
+ for (i = 0; i < eqChannelGroupCount; i++) {
+ eqCascadeGainPresent = FDKreadBits(hBs, 1);
+ if (eqCascadeGainPresent) {
+ FDKpushFor(hBs, 10); /* bsEqCascadeGain */
+ }
+ filterBlockCount = FDKreadBits(hBs, 4);
+ FDKpushFor(hBs, filterBlockCount * 7); /* filterBlockIndex */
+ }
+ eqPhaseAlignmentPresent = FDKreadBits(hBs, 1);
+ {
+ if (eqPhaseAlignmentPresent) {
+ for (i = 0; i < eqChannelGroupCount; i++) {
+ FDKpushFor(hBs, (eqChannelGroupCount - i - 1) * 1);
+ }
+ }
+ }
+}
+
+static DRC_ERROR _skipEqInstructions(HANDLE_FDK_BITSTREAM hBs,
+ HANDLE_UNI_DRC_CONFIG hUniDrcConfig) {
+ DRC_ERROR err = DE_OK;
+ int c, i, k, channelCount;
+ int downmixIdPresent, downmixId, eqApplyToDownmix, additionalDownmixIdPresent,
+ additionalDownmixIdCount = 0;
+ int additionalDrcSetIdPresent, additionalDrcSetIdCount;
+ int dependsOnEqSetPresent, eqChannelGroupCount, tdFilterCascadePresent,
+ subbandGainsPresent, eqTransitionDurationPresent;
+
+ FDKpushFor(hBs, 6); /* eqSetId */
+ FDKpushFor(hBs, 4); /* eqSetComplexityLevel */
+ downmixIdPresent = FDKreadBits(hBs, 1);
+ if (downmixIdPresent) {
+ downmixId = FDKreadBits(hBs, 7);
+ eqApplyToDownmix = FDKreadBits(hBs, 1);
+ additionalDownmixIdPresent = FDKreadBits(hBs, 1);
+ if (additionalDownmixIdPresent) {
+ additionalDownmixIdCount = FDKreadBits(hBs, 7);
+ FDKpushFor(hBs, additionalDownmixIdCount * 7); /* additionalDownmixId */
+ }
+ } else {
+ downmixId = 0;
+ eqApplyToDownmix = 0;
+ }
+ FDKpushFor(hBs, 6); /* drcSetId */
+ additionalDrcSetIdPresent = FDKreadBits(hBs, 1);
+ if (additionalDrcSetIdPresent) {
+ additionalDrcSetIdCount = FDKreadBits(hBs, 6);
+ for (i = 0; i < additionalDrcSetIdCount; i++) {
+ FDKpushFor(hBs, 6); /* additionalDrcSetId */
+ }
+ }
+ FDKpushFor(hBs, 16); /* eqSetPurpose */
+ dependsOnEqSetPresent = FDKreadBits(hBs, 1);
+ if (dependsOnEqSetPresent) {
+ FDKpushFor(hBs, 6); /* dependsOnEqSet */
+ } else {
+ FDKpushFor(hBs, 1); /* noIndependentEqUse */
+ }
+
+ channelCount = hUniDrcConfig->channelLayout.baseChannelCount;
+ if ((downmixIdPresent == 1) && (eqApplyToDownmix == 1) && (downmixId != 0) &&
+ (downmixId != DOWNMIX_ID_ANY_DOWNMIX) &&
+ (additionalDownmixIdCount == 0)) {
+ DOWNMIX_INSTRUCTIONS* pDown =
+ selectDownmixInstructions(hUniDrcConfig, downmixId);
+ if (pDown == NULL) return DE_NOT_OK;
+
+ channelCount =
+ pDown->targetChannelCount; /* targetChannelCountFromDownmixId*/
+ } else if ((downmixId == DOWNMIX_ID_ANY_DOWNMIX) ||
+ (additionalDownmixIdCount > 1)) {
+ channelCount = 1;
+ }
+
+ eqChannelGroupCount = 0;
+ for (c = 0; c < channelCount; c++) {
+ UCHAR eqChannelGroupForChannel[8];
+ int newGroup = 1;
+ if (c >= 8) return DE_MEMORY_ERROR;
+ eqChannelGroupForChannel[c] = FDKreadBits(hBs, 7);
+ for (k = 0; k < c; k++) {
+ if (eqChannelGroupForChannel[c] == eqChannelGroupForChannel[k]) {
+ newGroup = 0;
+ }
+ }
+ if (newGroup == 1) {
+ eqChannelGroupCount += 1;
+ }
+ }
+ tdFilterCascadePresent = FDKreadBits(hBs, 1);
+ if (tdFilterCascadePresent) {
+ _skipTdFilterCascade(hBs, eqChannelGroupCount);
+ }
+ subbandGainsPresent = FDKreadBits(hBs, 1);
+ if (subbandGainsPresent) {
+ FDKpushFor(hBs, eqChannelGroupCount * 6); /* subbandGainsIndex */
+ }
+ eqTransitionDurationPresent = FDKreadBits(hBs, 1);
+ if (eqTransitionDurationPresent) {
+ FDKpushFor(hBs, 5); /* bsEqTransitionDuration */
+ }
+ return err;
+}
+
+static void _skipDrcCoefficientsBasic(HANDLE_FDK_BITSTREAM hBs) {
+ FDKpushFor(hBs, 4); /* drcLocation */
+ FDKpushFor(hBs, 7); /* drcCharacteristic */
+}
+
+static DRC_ERROR _readDrcCoefficientsUniDrc(HANDLE_FDK_BITSTREAM hBs,
+ const int version,
+ DRC_COEFFICIENTS_UNI_DRC* pCoef) {
+ DRC_ERROR err = DE_OK;
+ int i, bsDrcFrameSize;
+ int gainSequenceIndex = -1;
+
+ pCoef->drcLocation = FDKreadBits(hBs, 4);
+ pCoef->drcFrameSizePresent = FDKreadBits(hBs, 1);
+
+ if (pCoef->drcFrameSizePresent == 1) {
+ bsDrcFrameSize = FDKreadBits(hBs, 15);
+ pCoef->drcFrameSize = bsDrcFrameSize + 1;
+ }
+ if (version == 0) {
+ int gainSequenceCount = 0, gainSetCount;
+ pCoef->characteristicLeftCount = 0;
+ pCoef->characteristicRightCount = 0;
+ gainSetCount = FDKreadBits(hBs, 6);
+ pCoef->gainSetCount = fMin(gainSetCount, 12);
+ for (i = 0; i < gainSetCount; i++) {
+ GAIN_SET tmpGset;
+ FDKmemclear(&tmpGset, sizeof(GAIN_SET));
+ err = _readGainSet(hBs, version, &gainSequenceIndex, &tmpGset, 0);
+ if (err) return err;
+ gainSequenceCount += tmpGset.bandCount;
+
+ if (i >= 12) continue;
+ pCoef->gainSet[i] = tmpGset;
+ }
+ pCoef->gainSequenceCount = gainSequenceCount;
+ } else { /* (version == 1) */
+ UCHAR drcCharacteristicLeftPresent, drcCharacteristicRightPresent;
+ UCHAR shapeFiltersPresent, shapeFilterCount, tmpPresent;
+ int gainSetCount;
+ drcCharacteristicLeftPresent = FDKreadBits(hBs, 1);
+ if (drcCharacteristicLeftPresent) {
+ pCoef->characteristicLeftCount = FDKreadBits(hBs, 4);
+ if ((pCoef->characteristicLeftCount + 1) > 8) return DE_MEMORY_ERROR;
+ for (i = 0; i < pCoef->characteristicLeftCount; i++) {
+ err = _readCustomDrcCharacteristic(
+ hBs, CS_LEFT, &(pCoef->characteristicLeftFormat[i + 1]),
+ &(pCoef->customCharacteristicLeft[i + 1]), 0);
+ if (err) return err;
+ }
+ }
+ drcCharacteristicRightPresent = FDKreadBits(hBs, 1);
+ if (drcCharacteristicRightPresent) {
+ pCoef->characteristicRightCount = FDKreadBits(hBs, 4);
+ if ((pCoef->characteristicRightCount + 1) > 8) return DE_MEMORY_ERROR;
+ for (i = 0; i < pCoef->characteristicRightCount; i++) {
+ err = _readCustomDrcCharacteristic(
+ hBs, CS_RIGHT, &(pCoef->characteristicRightFormat[i + 1]),
+ &(pCoef->customCharacteristicRight[i + 1]), 0);
+ if (err) return err;
+ }
+ }
+ shapeFiltersPresent = FDKreadBits(hBs, 1);
+ if (shapeFiltersPresent) {
+ shapeFilterCount = FDKreadBits(hBs, 4);
+ for (i = 0; i < shapeFilterCount; i++) {
+ tmpPresent = FDKreadBits(hBs, 1);
+ if (tmpPresent) /* lfCutParams */
+ FDKpushFor(hBs, 5);
+
+ tmpPresent = FDKreadBits(hBs, 1);
+ if (tmpPresent) /* lfBoostParams */
+ FDKpushFor(hBs, 5);
+
+ tmpPresent = FDKreadBits(hBs, 1);
+ if (tmpPresent) /* hfCutParams */
+ FDKpushFor(hBs, 5);
+
+ tmpPresent = FDKreadBits(hBs, 1);
+ if (tmpPresent) /* hfBoostParams */
+ FDKpushFor(hBs, 5);
+ }
+ }
+ pCoef->gainSequenceCount = FDKreadBits(hBs, 6);
+ gainSetCount = FDKreadBits(hBs, 6);
+ pCoef->gainSetCount = fMin(gainSetCount, 12);
+ for (i = 0; i < gainSetCount; i++) {
+ GAIN_SET tmpGset;
+ FDKmemclear(&tmpGset, sizeof(GAIN_SET));
+ err = _readGainSet(hBs, version, &gainSequenceIndex, &tmpGset, 0);
+ if (err) return err;
+
+ if (i >= 12) continue;
+ pCoef->gainSet[i] = tmpGset;
+ }
+ }
+ for (i = 0; i < 12; i++) {
+ pCoef->gainSetIndexForGainSequence[i] = 255;
+ }
+ for (i = 0; i < pCoef->gainSetCount; i++) {
+ int b;
+ for (b = 0; b < pCoef->gainSet[i].bandCount; b++) {
+ if (pCoef->gainSet[i].gainSequenceIndex[b] >= 12) continue;
+ pCoef->gainSetIndexForGainSequence[pCoef->gainSet[i]
+ .gainSequenceIndex[b]] = i;
+ }
+ }
+
+ return err;
+}
+
+static void _skipDrcInstructionsBasic(HANDLE_FDK_BITSTREAM hBs) {
+ int drcSetEffect;
+ int additionalDownmixIdPresent, additionalDownmixIdCount,
+ limiterPeakTargetPresent;
+ int drcSetTargetLoudnessPresent, drcSetTargetLoudnessValueLowerPresent;
+
+ FDKpushFor(hBs, 6); /* drcSetId */
+ FDKpushFor(hBs, 4); /* drcLocation */
+ FDKpushFor(hBs, 7); /* downmixId */
+ additionalDownmixIdPresent = FDKreadBits(hBs, 1);
+ if (additionalDownmixIdPresent) {
+ additionalDownmixIdCount = FDKreadBits(hBs, 3);
+ FDKpushFor(hBs, 7 * additionalDownmixIdCount); /* additionalDownmixId */
+ }
+
+ drcSetEffect = FDKreadBits(hBs, 16);
+ if (!(drcSetEffect & (EB_DUCK_OTHER | EB_DUCK_SELF))) {
+ limiterPeakTargetPresent = FDKreadBits(hBs, 1);
+ if (limiterPeakTargetPresent) {
+ FDKpushFor(hBs, 8); /* bsLimiterPeakTarget */
+ }
+ }
+
+ drcSetTargetLoudnessPresent = FDKreadBits(hBs, 1);
+ if (drcSetTargetLoudnessPresent) {
+ FDKpushFor(hBs, 6); /* bsDrcSetTargetLoudnessValueUpper */
+ drcSetTargetLoudnessValueLowerPresent = FDKreadBits(hBs, 1);
+ if (drcSetTargetLoudnessValueLowerPresent) {
+ FDKpushFor(hBs, 6); /* bsDrcSetTargetLoudnessValueLower */
+ }
+ }
+}
+
+static DRC_ERROR _readDrcInstructionsUniDrc(HANDLE_FDK_BITSTREAM hBs,
+ const int version,
+ HANDLE_UNI_DRC_CONFIG hUniDrcConfig,
+ DRC_INSTRUCTIONS_UNI_DRC* pInst) {
+ DRC_ERROR err = DE_OK;
+ int i, g, c;
+ int downmixIdPresent, additionalDownmixIdPresent, additionalDownmixIdCount;
+ int bsLimiterPeakTarget, channelCount;
+ DRC_COEFFICIENTS_UNI_DRC* pCoef = NULL;
+ int repeatParameters, bsRepeatParametersCount;
+ int repeatSequenceIndex, bsRepeatSequenceCount;
+ SCHAR* gainSetIndex = pInst->gainSetIndex;
+ SCHAR channelGroupForChannel[8];
+ DUCKING_MODIFICATION duckingModificationForChannelGroup[8];
+
+ pInst->drcSetId = FDKreadBits(hBs, 6);
+ if (version == 0) {
+ /* Assume all v0 DRC sets to be manageable in terms of complexity */
+ pInst->drcSetComplexityLevel = 2;
+ } else {
+ pInst->drcSetComplexityLevel = FDKreadBits(hBs, 4);
+ }
+ pInst->drcLocation = FDKreadBits(hBs, 4);
+ if (version == 0) {
+ downmixIdPresent = 1;
+ } else {
+ downmixIdPresent = FDKreadBits(hBs, 1);
+ }
+ if (downmixIdPresent) {
+ pInst->downmixId[0] = FDKreadBits(hBs, 7);
+ if (version == 0) {
+ if (pInst->downmixId[0] == 0)
+ pInst->drcApplyToDownmix = 0;
+ else
+ pInst->drcApplyToDownmix = 1;
+ } else {
+ pInst->drcApplyToDownmix = FDKreadBits(hBs, 1);
+ }
+
+ additionalDownmixIdPresent = FDKreadBits(hBs, 1);
+ if (additionalDownmixIdPresent) {
+ additionalDownmixIdCount = FDKreadBits(hBs, 3);
+ if ((1 + additionalDownmixIdCount) > 8) return DE_MEMORY_ERROR;
+ for (i = 0; i < additionalDownmixIdCount; i++) {
+ pInst->downmixId[i + 1] = FDKreadBits(hBs, 7);
+ }
+ pInst->downmixIdCount = 1 + additionalDownmixIdCount;
+ } else {
+ pInst->downmixIdCount = 1;
+ }
+ } else {
+ pInst->downmixId[0] = 0;
+ pInst->downmixIdCount = 1;
+ }
+
+ pInst->drcSetEffect = FDKreadBits(hBs, 16);
+
+ if ((pInst->drcSetEffect & (EB_DUCK_OTHER | EB_DUCK_SELF)) == 0) {
+ pInst->limiterPeakTargetPresent = FDKreadBits(hBs, 1);
+ if (pInst->limiterPeakTargetPresent) {
+ bsLimiterPeakTarget = FDKreadBits(hBs, 8);
+ pInst->limiterPeakTarget = -(FIXP_SGL)(
+ bsLimiterPeakTarget
+ << (FRACT_BITS - 1 - 3 - 5)); /* - bsLimiterPeakTarget * 0.125; */
+ }
+ }
+
+ pInst->drcSetTargetLoudnessPresent = FDKreadBits(hBs, 1);
+
+ /* set default values */
+ pInst->drcSetTargetLoudnessValueUpper = 0;
+ pInst->drcSetTargetLoudnessValueLower = -63;
+
+ if (pInst->drcSetTargetLoudnessPresent == 1) {
+ int bsDrcSetTargetLoudnessValueUpper, bsDrcSetTargetLoudnessValueLower;
+ int drcSetTargetLoudnessValueLowerPresent;
+ bsDrcSetTargetLoudnessValueUpper = FDKreadBits(hBs, 6);
+ pInst->drcSetTargetLoudnessValueUpper =
+ bsDrcSetTargetLoudnessValueUpper - 63;
+ drcSetTargetLoudnessValueLowerPresent = FDKreadBits(hBs, 1);
+ if (drcSetTargetLoudnessValueLowerPresent == 1) {
+ bsDrcSetTargetLoudnessValueLower = FDKreadBits(hBs, 6);
+ pInst->drcSetTargetLoudnessValueLower =
+ bsDrcSetTargetLoudnessValueLower - 63;
+ }
+ }
+
+ pInst->dependsOnDrcSetPresent = FDKreadBits(hBs, 1);
+
+ pInst->noIndependentUse = 0;
+ if (pInst->dependsOnDrcSetPresent) {
+ pInst->dependsOnDrcSet = FDKreadBits(hBs, 6);
+ } else {
+ pInst->noIndependentUse = FDKreadBits(hBs, 1);
+ }
+
+ if (version == 0) {
+ pInst->requiresEq = 0;
+ } else {
+ pInst->requiresEq = FDKreadBits(hBs, 1);
+ }
+
+ pCoef = selectDrcCoefficients(hUniDrcConfig, pInst->drcLocation);
+
+ pInst->drcChannelCount = channelCount =
+ hUniDrcConfig->channelLayout.baseChannelCount;
+
+ if (pInst->drcSetEffect & (EB_DUCK_OTHER | EB_DUCK_SELF)) {
+ DUCKING_MODIFICATION* pDModForChannel =
+ pInst->duckingModificationForChannel;
+ c = 0;
+ while (c < channelCount) {
+ int bsGainSetIndex;
+ bsGainSetIndex = FDKreadBits(hBs, 6);
+ if (c >= 8) return DE_MEMORY_ERROR;
+ gainSetIndex[c] = bsGainSetIndex - 1;
+ _decodeDuckingModification(hBs, &(pDModForChannel[c]), 0);
+
+ c++;
+ repeatParameters = FDKreadBits(hBs, 1);
+ if (repeatParameters == 1) {
+ bsRepeatParametersCount = FDKreadBits(hBs, 5);
+ bsRepeatParametersCount += 1;
+ for (i = 0; i < bsRepeatParametersCount; i++) {
+ if (c >= 8) return DE_MEMORY_ERROR;
+ gainSetIndex[c] = gainSetIndex[c - 1];
+ pDModForChannel[c] = pDModForChannel[c - 1];
+ c++;
+ }
+ }
+ }
+ if (c > channelCount) {
+ return DE_NOT_OK;
+ }
+
+ err = deriveDrcChannelGroups(
+ pInst->drcSetEffect, pInst->drcChannelCount, gainSetIndex,
+ pDModForChannel, &pInst->nDrcChannelGroups,
+ pInst->gainSetIndexForChannelGroup, channelGroupForChannel,
+ duckingModificationForChannelGroup);
+ if (err) return (err);
+ } else {
+ int deriveChannelCount = 0;
+ if (((version == 0) || (pInst->drcApplyToDownmix != 0)) &&
+ (pInst->downmixId[0] != DOWNMIX_ID_BASE_LAYOUT) &&
+ (pInst->downmixId[0] != DOWNMIX_ID_ANY_DOWNMIX) &&
+ (pInst->downmixIdCount == 1)) {
+ if (hUniDrcConfig->downmixInstructionsCount != 0) {
+ DOWNMIX_INSTRUCTIONS* pDown =
+ selectDownmixInstructions(hUniDrcConfig, pInst->downmixId[0]);
+ if (pDown == NULL) return DE_NOT_OK;
+ pInst->drcChannelCount = channelCount =
+ pDown->targetChannelCount; /* targetChannelCountFromDownmixId*/
+ } else {
+ deriveChannelCount = 1;
+ channelCount = 1;
+ }
+ } else if (((version == 0) || (pInst->drcApplyToDownmix != 0)) &&
+ ((pInst->downmixId[0] == DOWNMIX_ID_ANY_DOWNMIX) ||
+ (pInst->downmixIdCount > 1))) {
+ /* Set maximum channel count as upper border. The effective channel count
+ * is set at the process function. */
+ pInst->drcChannelCount = 8;
+ channelCount = 1;
+ }
+
+ c = 0;
+ while (c < channelCount) {
+ int bsGainSetIndex;
+ bsGainSetIndex = FDKreadBits(hBs, 6);
+ if (c >= 8) return DE_MEMORY_ERROR;
+ gainSetIndex[c] = bsGainSetIndex - 1;
+ c++;
+ repeatSequenceIndex = FDKreadBits(hBs, 1);
+
+ if (repeatSequenceIndex == 1) {
+ bsRepeatSequenceCount = FDKreadBits(hBs, 5);
+ bsRepeatSequenceCount += 1;
+ if (deriveChannelCount) {
+ channelCount = 1 + bsRepeatSequenceCount;
+ }
+ for (i = 0; i < bsRepeatSequenceCount; i++) {
+ if (c >= 8) return DE_MEMORY_ERROR;
+ gainSetIndex[c] = bsGainSetIndex - 1;
+ c++;
+ }
+ }
+ }
+ if (c > channelCount) {
+ return DE_NOT_OK;
+ }
+ if (deriveChannelCount) {
+ pInst->drcChannelCount = channelCount;
+ }
+
+ /* DOWNMIX_ID_ANY_DOWNMIX: channelCount is 1. Distribute gainSetIndex to all
+ * channels. */
+ if ((pInst->downmixId[0] == DOWNMIX_ID_ANY_DOWNMIX) ||
+ (pInst->downmixIdCount > 1)) {
+ for (c = 1; c < pInst->drcChannelCount; c++) {
+ gainSetIndex[c] = gainSetIndex[0];
+ }
+ }
+
+ err = deriveDrcChannelGroups(pInst->drcSetEffect, pInst->drcChannelCount,
+ gainSetIndex, NULL, &pInst->nDrcChannelGroups,
+ pInst->gainSetIndexForChannelGroup,
+ channelGroupForChannel, NULL);
+ if (err) return (err);
+
+ for (g = 0; g < pInst->nDrcChannelGroups; g++) {
+ int set, bandCount;
+ set = pInst->gainSetIndexForChannelGroup[g];
+
+ /* get bandCount */
+ if (pCoef != NULL && set < pCoef->gainSetCount) {
+ bandCount = pCoef->gainSet[set].bandCount;
+ } else {
+ bandCount = 1;
+ }
+
+ _decodeGainModification(hBs, version, bandCount,
+ pInst->gainModificationForChannelGroup[g], 0);
+ }
+ }
+
+ return err;
+}
+
+static DRC_ERROR _readChannelLayout(HANDLE_FDK_BITSTREAM hBs,
+ CHANNEL_LAYOUT* pChan) {
+ DRC_ERROR err = DE_OK;
+
+ pChan->baseChannelCount = FDKreadBits(hBs, 7);
+
+ if (pChan->baseChannelCount > 8) return DE_NOT_OK;
+
+ pChan->layoutSignalingPresent = FDKreadBits(hBs, 1);
+
+ if (pChan->layoutSignalingPresent) {
+ pChan->definedLayout = FDKreadBits(hBs, 8);
+
+ if (pChan->definedLayout == 0) {
+ int i;
+ for (i = 0; i < pChan->baseChannelCount; i++) {
+ if (i < 8) {
+ pChan->speakerPosition[i] = FDKreadBits(hBs, 7);
+ } else {
+ FDKpushFor(hBs, 7);
+ }
+ }
+ }
+ }
+ return err;
+}
+
+static DRC_ERROR _readDownmixInstructions(HANDLE_FDK_BITSTREAM hBs,
+ const int version,
+ CHANNEL_LAYOUT* pChan,
+ DOWNMIX_INSTRUCTIONS* pDown) {
+ DRC_ERROR err = DE_OK;
+
+ pDown->downmixId = FDKreadBits(hBs, 7);
+ pDown->targetChannelCount = FDKreadBits(hBs, 7);
+ pDown->targetLayout = FDKreadBits(hBs, 8);
+ pDown->downmixCoefficientsPresent = FDKreadBits(hBs, 1);
+
+ if (pDown->downmixCoefficientsPresent) {
+ int nDownmixCoeffs = pDown->targetChannelCount * pChan->baseChannelCount;
+ int i;
+ if (nDownmixCoeffs > 8 * 8) return DE_NOT_OK;
+ if (version == 0) {
+ pDown->bsDownmixOffset = 0;
+ for (i = 0; i < nDownmixCoeffs; i++) {
+ /* LFE downmix coefficients are not supported. */
+ pDown->downmixCoefficient[i] = downmixCoeff[FDKreadBits(hBs, 4)];
+ }
+ } else {
+ pDown->bsDownmixOffset = FDKreadBits(hBs, 4);
+ for (i = 0; i < nDownmixCoeffs; i++) {
+ pDown->downmixCoefficient[i] = downmixCoeffV1[FDKreadBits(hBs, 5)];
+ }
+ }
+ }
+ return err;
+}
+
+static DRC_ERROR _readDrcExtensionV1(HANDLE_FDK_BITSTREAM hBs,
+ HANDLE_UNI_DRC_CONFIG hUniDrcConfig) {
+ DRC_ERROR err = DE_OK;
+ int downmixInstructionsV1Present;
+ int drcCoeffsAndInstructionsUniDrcV1Present;
+ int loudEqInstructionsPresent, loudEqInstructionsCount;
+ int eqPresent, eqInstructionsCount;
+ int i, offset;
+ int diff = hUniDrcConfig->diff;
+
+ downmixInstructionsV1Present = FDKreadBits(hBs, 1);
+ if (downmixInstructionsV1Present == 1) {
+ diff |= _compAssign(&hUniDrcConfig->downmixInstructionsCountV1,
+ FDKreadBits(hBs, 7));
+ offset = hUniDrcConfig->downmixInstructionsCountV0;
+ hUniDrcConfig->downmixInstructionsCount = fMin(
+ (UCHAR)(offset + hUniDrcConfig->downmixInstructionsCountV1), (UCHAR)6);
+ for (i = 0; i < hUniDrcConfig->downmixInstructionsCountV1; i++) {
+ DOWNMIX_INSTRUCTIONS tmpDown;
+ FDKmemclear(&tmpDown, sizeof(DOWNMIX_INSTRUCTIONS));
+ err = _readDownmixInstructions(hBs, 1, &hUniDrcConfig->channelLayout,
+ &tmpDown);
+ if (err) return err;
+ if ((offset + i) >= 6) continue;
+ if (!diff)
+ diff |= (FDKmemcmp(&tmpDown,
+ &(hUniDrcConfig->downmixInstructions[offset + i]),
+ sizeof(DOWNMIX_INSTRUCTIONS)) != 0);
+ hUniDrcConfig->downmixInstructions[offset + i] = tmpDown;
+ }
+ } else {
+ diff |= _compAssign(&hUniDrcConfig->downmixInstructionsCountV1, 0);
+ }
+
+ drcCoeffsAndInstructionsUniDrcV1Present = FDKreadBits(hBs, 1);
+ if (drcCoeffsAndInstructionsUniDrcV1Present == 1) {
+ diff |= _compAssign(&hUniDrcConfig->drcCoefficientsUniDrcCountV1,
+ FDKreadBits(hBs, 3));
+ offset = hUniDrcConfig->drcCoefficientsUniDrcCountV0;
+ hUniDrcConfig->drcCoefficientsUniDrcCount =
+ fMin((UCHAR)(offset + hUniDrcConfig->drcCoefficientsUniDrcCountV1),
+ (UCHAR)2);
+ for (i = 0; i < hUniDrcConfig->drcCoefficientsUniDrcCountV1; i++) {
+ DRC_COEFFICIENTS_UNI_DRC tmpCoef;
+ FDKmemclear(&tmpCoef, sizeof(DRC_COEFFICIENTS_UNI_DRC));
+ err = _readDrcCoefficientsUniDrc(hBs, 1, &tmpCoef);
+ if (err) return err;
+ if ((offset + i) >= 2) continue;
+ if (!diff)
+ diff |= (FDKmemcmp(&tmpCoef,
+ &(hUniDrcConfig->drcCoefficientsUniDrc[offset + i]),
+ sizeof(DRC_COEFFICIENTS_UNI_DRC)) != 0);
+ hUniDrcConfig->drcCoefficientsUniDrc[offset + i] = tmpCoef;
+ }
+
+ diff |= _compAssign(&hUniDrcConfig->drcInstructionsUniDrcCountV1,
+ FDKreadBits(hBs, 6));
+ offset = hUniDrcConfig->drcInstructionsUniDrcCount;
+ hUniDrcConfig->drcInstructionsUniDrcCount =
+ fMin((UCHAR)(offset + hUniDrcConfig->drcInstructionsUniDrcCountV1),
+ (UCHAR)12);
+ for (i = 0; i < hUniDrcConfig->drcInstructionsUniDrcCount; i++) {
+ DRC_INSTRUCTIONS_UNI_DRC tmpInst;
+ FDKmemclear(&tmpInst, sizeof(DRC_INSTRUCTIONS_UNI_DRC));
+ err = _readDrcInstructionsUniDrc(hBs, 1, hUniDrcConfig, &tmpInst);
+ if (err) return err;
+ if ((offset + i) >= 12) continue;
+ if (!diff)
+ diff |= (FDKmemcmp(&tmpInst,
+ &(hUniDrcConfig->drcInstructionsUniDrc[offset + i]),
+ sizeof(DRC_INSTRUCTIONS_UNI_DRC)) != 0);
+ hUniDrcConfig->drcInstructionsUniDrc[offset + i] = tmpInst;
+ }
+ } else {
+ diff |= _compAssign(&hUniDrcConfig->drcCoefficientsUniDrcCountV1, 0);
+ diff |= _compAssign(&hUniDrcConfig->drcInstructionsUniDrcCountV1, 0);
+ }
+
+ loudEqInstructionsPresent = FDKreadBits(hBs, 1);
+ if (loudEqInstructionsPresent == 1) {
+ loudEqInstructionsCount = FDKreadBits(hBs, 4);
+ for (i = 0; i < loudEqInstructionsCount; i++) {
+ _skipLoudEqInstructions(hBs);
+ }
+ }
+
+ eqPresent = FDKreadBits(hBs, 1);
+ if (eqPresent == 1) {
+ _skipEqCoefficients(hBs);
+ eqInstructionsCount = FDKreadBits(hBs, 4);
+ for (i = 0; i < eqInstructionsCount; i++) {
+ _skipEqInstructions(hBs, hUniDrcConfig);
+ }
+ }
+
+ hUniDrcConfig->diff = diff;
+
+ return err;
+}
+
+static DRC_ERROR _readUniDrcConfigExtension(
+ HANDLE_FDK_BITSTREAM hBs, HANDLE_UNI_DRC_CONFIG hUniDrcConfig) {
+ DRC_ERROR err = DE_OK;
+ int k, bitSizeLen, extSizeBits, bitSize;
+ INT nBitsRemaining;
+ UNI_DRC_CONFIG_EXTENSION* pExt = &(hUniDrcConfig->uniDrcConfigExt);
+
+ k = 0;
+ pExt->uniDrcConfigExtType[k] = FDKreadBits(hBs, 4);
+ while (pExt->uniDrcConfigExtType[k] != UNIDRCCONFEXT_TERM) {
+ if (k >= (8 - 1)) return DE_MEMORY_ERROR;
+ bitSizeLen = FDKreadBits(hBs, 4);
+ extSizeBits = bitSizeLen + 4;
+
+ bitSize = FDKreadBits(hBs, extSizeBits);
+ pExt->extBitSize[k] = bitSize + 1;
+ nBitsRemaining = (INT)FDKgetValidBits(hBs);
+
+ switch (pExt->uniDrcConfigExtType[k]) {
+ case UNIDRCCONFEXT_V1:
+ err = _readDrcExtensionV1(hBs, hUniDrcConfig);
+ if (err) return err;
+ if (nBitsRemaining !=
+ ((INT)pExt->extBitSize[k] + (INT)FDKgetValidBits(hBs)))
+ return DE_NOT_OK;
+ break;
+ case UNIDRCCONFEXT_PARAM_DRC:
+ /* add future extensions here */
+ default:
+ FDKpushFor(hBs, pExt->extBitSize[k]);
+ break;
+ }
+ k++;
+ pExt->uniDrcConfigExtType[k] = FDKreadBits(hBs, 4);
+ }
+
+ return err;
+}
+
+DRC_ERROR
+drcDec_readUniDrcConfig(HANDLE_FDK_BITSTREAM hBs,
+ HANDLE_UNI_DRC_CONFIG hUniDrcConfig) {
+ DRC_ERROR err = DE_OK;
+ int i, diff = 0;
+ int drcDescriptionBasicPresent, drcCoefficientsBasicCount,
+ drcInstructionsBasicCount;
+ CHANNEL_LAYOUT tmpChan;
+ FDKmemclear(&tmpChan, sizeof(CHANNEL_LAYOUT));
+ if (hUniDrcConfig == NULL) return DE_NOT_OK;
+
+ diff |= _compAssign(&hUniDrcConfig->sampleRatePresent, FDKreadBits(hBs, 1));
+
+ if (hUniDrcConfig->sampleRatePresent == 1) {
+ diff |=
+ _compAssign(&hUniDrcConfig->sampleRate, FDKreadBits(hBs, 18) + 1000);
+ }
+
+ diff |= _compAssign(&hUniDrcConfig->downmixInstructionsCountV0,
+ FDKreadBits(hBs, 7));
+
+ drcDescriptionBasicPresent = FDKreadBits(hBs, 1);
+ if (drcDescriptionBasicPresent == 1) {
+ drcCoefficientsBasicCount = FDKreadBits(hBs, 3);
+ drcInstructionsBasicCount = FDKreadBits(hBs, 4);
+ } else {
+ drcCoefficientsBasicCount = 0;
+ drcInstructionsBasicCount = 0;
+ }
+
+ diff |= _compAssign(&hUniDrcConfig->drcCoefficientsUniDrcCountV0,
+ FDKreadBits(hBs, 3));
+ diff |= _compAssign(&hUniDrcConfig->drcInstructionsUniDrcCountV0,
+ FDKreadBits(hBs, 6));
+
+ err = _readChannelLayout(hBs, &tmpChan);
+ if (err) return err;
+
+ if (!diff)
+ diff |= (FDKmemcmp(&tmpChan, &hUniDrcConfig->channelLayout,
+ sizeof(CHANNEL_LAYOUT)) != 0);
+ hUniDrcConfig->channelLayout = tmpChan;
+
+ hUniDrcConfig->downmixInstructionsCount =
+ fMin(hUniDrcConfig->downmixInstructionsCountV0, (UCHAR)6);
+ for (i = 0; i < hUniDrcConfig->downmixInstructionsCountV0; i++) {
+ DOWNMIX_INSTRUCTIONS tmpDown;
+ FDKmemclear(&tmpDown, sizeof(DOWNMIX_INSTRUCTIONS));
+ err = _readDownmixInstructions(hBs, 0, &hUniDrcConfig->channelLayout,
+ &tmpDown);
+ if (err) return err;
+ if (i >= 6) continue;
+ if (!diff)
+ diff |= (FDKmemcmp(&tmpDown, &(hUniDrcConfig->downmixInstructions[i]),
+ sizeof(DOWNMIX_INSTRUCTIONS)) != 0);
+ hUniDrcConfig->downmixInstructions[i] = tmpDown;
+ }
+
+ for (i = 0; i < drcCoefficientsBasicCount; i++) {
+ _skipDrcCoefficientsBasic(hBs);
+ }
+ for (i = 0; i < drcInstructionsBasicCount; i++) {
+ _skipDrcInstructionsBasic(hBs);
+ }
+
+ hUniDrcConfig->drcCoefficientsUniDrcCount =
+ fMin(hUniDrcConfig->drcCoefficientsUniDrcCountV0, (UCHAR)2);
+ for (i = 0; i < hUniDrcConfig->drcCoefficientsUniDrcCountV0; i++) {
+ DRC_COEFFICIENTS_UNI_DRC tmpCoef;
+ FDKmemclear(&tmpCoef, sizeof(DRC_COEFFICIENTS_UNI_DRC));
+ err = _readDrcCoefficientsUniDrc(hBs, 0, &tmpCoef);
+ if (err) return err;
+ if (i >= 2) continue;
+ if (!diff)
+ diff |= (FDKmemcmp(&tmpCoef, &(hUniDrcConfig->drcCoefficientsUniDrc[i]),
+ sizeof(DRC_COEFFICIENTS_UNI_DRC)) != 0);
+ hUniDrcConfig->drcCoefficientsUniDrc[i] = tmpCoef;
+ }
+
+ hUniDrcConfig->drcInstructionsUniDrcCount =
+ fMin(hUniDrcConfig->drcInstructionsUniDrcCountV0, (UCHAR)12);
+ for (i = 0; i < hUniDrcConfig->drcInstructionsUniDrcCountV0; i++) {
+ DRC_INSTRUCTIONS_UNI_DRC tmpInst;
+ FDKmemclear(&tmpInst, sizeof(DRC_INSTRUCTIONS_UNI_DRC));
+ err = _readDrcInstructionsUniDrc(hBs, 0, hUniDrcConfig, &tmpInst);
+ if (err) return err;
+ if (i >= 12) continue;
+ if (!diff)
+ diff |= (FDKmemcmp(&tmpInst, &(hUniDrcConfig->drcInstructionsUniDrc[i]),
+ sizeof(DRC_INSTRUCTIONS_UNI_DRC)) != 0);
+ hUniDrcConfig->drcInstructionsUniDrc[i] = tmpInst;
+ }
+
+ diff |=
+ _compAssign(&hUniDrcConfig->uniDrcConfigExtPresent, FDKreadBits(hBs, 1));
+ hUniDrcConfig->diff = diff;
+
+ if (hUniDrcConfig->uniDrcConfigExtPresent == 1) {
+ err = _readUniDrcConfigExtension(hBs, hUniDrcConfig);
+ if (err) return err;
+ }
+
+ return err;
+}
+
+/*******************/
+/* loudnessInfoSet */
+/*******************/
+
+static DRC_ERROR _decodeMethodValue(HANDLE_FDK_BITSTREAM hBs,
+ const UCHAR methodDefinition,
+ FIXP_DBL* methodValue, INT isBox) {
+ int tmp;
+ FIXP_DBL val;
+ switch (methodDefinition) {
+ case MD_UNKNOWN_OTHER:
+ case MD_PROGRAM_LOUDNESS:
+ case MD_ANCHOR_LOUDNESS:
+ case MD_MAX_OF_LOUDNESS_RANGE:
+ case MD_MOMENTARY_LOUDNESS_MAX:
+ case MD_SHORT_TERM_LOUDNESS_MAX:
+ tmp = FDKreadBits(hBs, 8);
+ val = FL2FXCONST_DBL(-57.75f / (float)(1 << 7)) +
+ (FIXP_DBL)(
+ tmp << (DFRACT_BITS - 1 - 2 - 7)); /* -57.75 + tmp * 0.25; */
+ break;
+ case MD_LOUDNESS_RANGE:
+ tmp = FDKreadBits(hBs, 8);
+ if (tmp == 0)
+ val = (FIXP_DBL)0;
+ else if (tmp <= 128)
+ val = (FIXP_DBL)(tmp << (DFRACT_BITS - 1 - 2 - 7)); /* tmp * 0.25; */
+ else if (tmp <= 204) {
+ val = (FIXP_DBL)(tmp << (DFRACT_BITS - 1 - 1 - 7)) -
+ FL2FXCONST_DBL(32.0f / (float)(1 << 7)); /* 0.5 * tmp - 32.0f; */
+ } else {
+ /* downscale by 1 more bit to prevent overflow at intermediate result */
+ val = (FIXP_DBL)(tmp << (DFRACT_BITS - 1 - 8)) -
+ FL2FXCONST_DBL(134.0f / (float)(1 << 8)); /* tmp - 134.0; */
+ val <<= 1;
+ }
+ break;
+ case MD_MIXING_LEVEL:
+ tmp = FDKreadBits(hBs, isBox ? 8 : 5);
+ val = (FIXP_DBL)(tmp << (DFRACT_BITS - 1 - 7)) +
+ FL2FXCONST_DBL(80.0f / (float)(1 << 7)); /* tmp + 80.0; */
+ break;
+ case MD_ROOM_TYPE:
+ tmp = FDKreadBits(hBs, isBox ? 8 : 2);
+ val = (FIXP_DBL)(tmp << (DFRACT_BITS - 1 - 7)); /* tmp; */
+ break;
+ case MD_SHORT_TERM_LOUDNESS:
+ tmp = FDKreadBits(hBs, 8);
+ val = FL2FXCONST_DBL(-116.0f / (float)(1 << 7)) +
+ (FIXP_DBL)(
+ tmp << (DFRACT_BITS - 1 - 1 - 7)); /* -116.0 + tmp * 0.5; */
+ break;
+ default:
+ return DE_NOT_OK; /* invalid methodDefinition value */
+ }
+ *methodValue = val;
+ return DE_OK;
+}
+
+static DRC_ERROR _readLoudnessMeasurement(HANDLE_FDK_BITSTREAM hBs,
+ LOUDNESS_MEASUREMENT* pMeas) {
+ DRC_ERROR err = DE_OK;
+
+ pMeas->methodDefinition = FDKreadBits(hBs, 4);
+ err =
+ _decodeMethodValue(hBs, pMeas->methodDefinition, &pMeas->methodValue, 0);
+ if (err) return err;
+ pMeas->measurementSystem = FDKreadBits(hBs, 4);
+ pMeas->reliability = FDKreadBits(hBs, 2);
+
+ return err;
+}
+
+static DRC_ERROR _readLoudnessInfo(HANDLE_FDK_BITSTREAM hBs, const int version,
+ LOUDNESS_INFO* loudnessInfo) {
+ DRC_ERROR err = DE_OK;
+ int bsSamplePeakLevel, bsTruePeakLevel, i;
+ int measurementCount;
+
+ loudnessInfo->drcSetId = FDKreadBits(hBs, 6);
+ if (version >= 1) {
+ loudnessInfo->eqSetId = FDKreadBits(hBs, 6);
+ } else {
+ loudnessInfo->eqSetId = 0;
+ }
+ loudnessInfo->downmixId = FDKreadBits(hBs, 7);
+
+ loudnessInfo->samplePeakLevelPresent = FDKreadBits(hBs, 1);
+ if (loudnessInfo->samplePeakLevelPresent) {
+ bsSamplePeakLevel = FDKreadBits(hBs, 12);
+ if (bsSamplePeakLevel == 0) {
+ loudnessInfo->samplePeakLevelPresent = 0;
+ loudnessInfo->samplePeakLevel = (FIXP_DBL)0;
+ } else { /* 20.0 - bsSamplePeakLevel * 0.03125; */
+ loudnessInfo->samplePeakLevel =
+ FL2FXCONST_DBL(20.0f / (float)(1 << 7)) -
+ (FIXP_DBL)(bsSamplePeakLevel << (DFRACT_BITS - 1 - 5 - 7));
+ }
+ }
+
+ loudnessInfo->truePeakLevelPresent = FDKreadBits(hBs, 1);
+ if (loudnessInfo->truePeakLevelPresent) {
+ bsTruePeakLevel = FDKreadBits(hBs, 12);
+ if (bsTruePeakLevel == 0) {
+ loudnessInfo->truePeakLevelPresent = 0;
+ loudnessInfo->truePeakLevel = (FIXP_DBL)0;
+ } else {
+ loudnessInfo->truePeakLevel =
+ FL2FXCONST_DBL(20.0f / (float)(1 << 7)) -
+ (FIXP_DBL)(bsTruePeakLevel << (DFRACT_BITS - 1 - 5 - 7));
+ }
+ loudnessInfo->truePeakLevelMeasurementSystem = FDKreadBits(hBs, 4);
+ loudnessInfo->truePeakLevelReliability = FDKreadBits(hBs, 2);
+ }
+
+ measurementCount = FDKreadBits(hBs, 4);
+ loudnessInfo->measurementCount = fMin(measurementCount, 8);
+ for (i = 0; i < measurementCount; i++) {
+ LOUDNESS_MEASUREMENT tmpMeas;
+ FDKmemclear(&tmpMeas, sizeof(LOUDNESS_MEASUREMENT));
+ err = _readLoudnessMeasurement(hBs, &tmpMeas);
+ if (err) return err;
+ if (i >= 8) continue;
+ loudnessInfo->loudnessMeasurement[i] = tmpMeas;
+ }
+
+ return err;
+}
+
+static DRC_ERROR _readLoudnessInfoSetExtEq(
+ HANDLE_FDK_BITSTREAM hBs, HANDLE_LOUDNESS_INFO_SET hLoudnessInfoSet) {
+ DRC_ERROR err = DE_OK;
+ int i, offset;
+ int diff = hLoudnessInfoSet->diff;
+
+ diff |= _compAssign(&hLoudnessInfoSet->loudnessInfoAlbumCountV1,
+ FDKreadBits(hBs, 6));
+ diff |=
+ _compAssign(&hLoudnessInfoSet->loudnessInfoCountV1, FDKreadBits(hBs, 6));
+
+ offset = hLoudnessInfoSet->loudnessInfoAlbumCountV0;
+ hLoudnessInfoSet->loudnessInfoAlbumCount = fMin(
+ (UCHAR)(offset + hLoudnessInfoSet->loudnessInfoAlbumCountV1), (UCHAR)12);
+ for (i = 0; i < hLoudnessInfoSet->loudnessInfoAlbumCountV1; i++) {
+ LOUDNESS_INFO tmpLoud;
+ FDKmemclear(&tmpLoud, sizeof(LOUDNESS_INFO));
+ err = _readLoudnessInfo(hBs, 1, &tmpLoud);
+ if (err) return err;
+ if ((offset + i) >= 12) continue;
+ if (!diff)
+ diff |= (FDKmemcmp(&tmpLoud,
+ &(hLoudnessInfoSet->loudnessInfoAlbum[offset + i]),
+ sizeof(LOUDNESS_INFO)) != 0);
+ hLoudnessInfoSet->loudnessInfoAlbum[offset + i] = tmpLoud;
+ }
+
+ offset = hLoudnessInfoSet->loudnessInfoCountV0;
+ hLoudnessInfoSet->loudnessInfoCount =
+ fMin((UCHAR)(offset + hLoudnessInfoSet->loudnessInfoCountV1), (UCHAR)12);
+ for (i = 0; i < hLoudnessInfoSet->loudnessInfoCountV1; i++) {
+ LOUDNESS_INFO tmpLoud;
+ FDKmemclear(&tmpLoud, sizeof(LOUDNESS_INFO));
+ err = _readLoudnessInfo(hBs, 1, &tmpLoud);
+ if (err) return err;
+ if ((offset + i) >= 12) continue;
+ if (!diff)
+ diff |=
+ (FDKmemcmp(&tmpLoud, &(hLoudnessInfoSet->loudnessInfo[offset + i]),
+ sizeof(LOUDNESS_INFO)) != 0);
+ hLoudnessInfoSet->loudnessInfo[offset + i] = tmpLoud;
+ }
+ hLoudnessInfoSet->diff = diff;
+ return err;
+}
+
+static DRC_ERROR _readLoudnessInfoSetExtension(
+ HANDLE_FDK_BITSTREAM hBs, HANDLE_LOUDNESS_INFO_SET hLoudnessInfoSet) {
+ DRC_ERROR err = DE_OK;
+ int k, bitSizeLen, extSizeBits, bitSize;
+ INT nBitsRemaining;
+ LOUDNESS_INFO_SET_EXTENSION* pExt = &(hLoudnessInfoSet->loudnessInfoSetExt);
+
+ k = 0;
+ pExt->loudnessInfoSetExtType[k] = FDKreadBits(hBs, 4);
+ while (pExt->loudnessInfoSetExtType[k] != UNIDRCLOUDEXT_TERM) {
+ if (k >= (8 - 1)) return DE_MEMORY_ERROR;
+ bitSizeLen = FDKreadBits(hBs, 4);
+ extSizeBits = bitSizeLen + 4;
+
+ bitSize = FDKreadBits(hBs, extSizeBits);
+ pExt->extBitSize[k] = bitSize + 1;
+ nBitsRemaining = (INT)FDKgetValidBits(hBs);
+
+ switch (pExt->loudnessInfoSetExtType[k]) {
+ case UNIDRCLOUDEXT_EQ:
+ err = _readLoudnessInfoSetExtEq(hBs, hLoudnessInfoSet);
+ if (err) return err;
+ if (nBitsRemaining !=
+ ((INT)pExt->extBitSize[k] + (INT)FDKgetValidBits(hBs)))
+ return DE_NOT_OK;
+ break;
+ /* add future extensions here */
+ default:
+ FDKpushFor(hBs, pExt->extBitSize[k]);
+ break;
+ }
+ k++;
+ pExt->loudnessInfoSetExtType[k] = FDKreadBits(hBs, 4);
+ }
+
+ return err;
+}
+
+/* Parser for loundessInfoSet() */
+DRC_ERROR
+drcDec_readLoudnessInfoSet(HANDLE_FDK_BITSTREAM hBs,
+ HANDLE_LOUDNESS_INFO_SET hLoudnessInfoSet) {
+ DRC_ERROR err = DE_OK;
+ int i, diff = 0;
+ if (hLoudnessInfoSet == NULL) return DE_NOT_OK;
+
+ diff |= _compAssign(&hLoudnessInfoSet->loudnessInfoAlbumCountV0,
+ FDKreadBits(hBs, 6));
+ diff |=
+ _compAssign(&hLoudnessInfoSet->loudnessInfoCountV0, FDKreadBits(hBs, 6));
+
+ hLoudnessInfoSet->loudnessInfoAlbumCount =
+ fMin(hLoudnessInfoSet->loudnessInfoAlbumCountV0, (UCHAR)12);
+ for (i = 0; i < hLoudnessInfoSet->loudnessInfoAlbumCountV0; i++) {
+ LOUDNESS_INFO tmpLoud;
+ FDKmemclear(&tmpLoud, sizeof(LOUDNESS_INFO));
+ err = _readLoudnessInfo(hBs, 0, &tmpLoud);
+ if (err) return err;
+ if (i >= 12) continue;
+ if (!diff)
+ diff |= (FDKmemcmp(&tmpLoud, &(hLoudnessInfoSet->loudnessInfoAlbum[i]),
+ sizeof(LOUDNESS_INFO)) != 0);
+ hLoudnessInfoSet->loudnessInfoAlbum[i] = tmpLoud;
+ }
+
+ hLoudnessInfoSet->loudnessInfoCount =
+ fMin(hLoudnessInfoSet->loudnessInfoCountV0, (UCHAR)12);
+ for (i = 0; i < hLoudnessInfoSet->loudnessInfoCountV0; i++) {
+ LOUDNESS_INFO tmpLoud;
+ FDKmemclear(&tmpLoud, sizeof(LOUDNESS_INFO));
+ err = _readLoudnessInfo(hBs, 0, &tmpLoud);
+ if (err) return err;
+ if (i >= 12) continue;
+ if (!diff)
+ diff |= (FDKmemcmp(&tmpLoud, &(hLoudnessInfoSet->loudnessInfo[i]),
+ sizeof(LOUDNESS_INFO)) != 0);
+ hLoudnessInfoSet->loudnessInfo[i] = tmpLoud;
+ }
+
+ diff |= _compAssign(&hLoudnessInfoSet->loudnessInfoSetExtPresent,
+ FDKreadBits(hBs, 1));
+ hLoudnessInfoSet->diff = diff;
+
+ if (hLoudnessInfoSet->loudnessInfoSetExtPresent) {
+ err = _readLoudnessInfoSetExtension(hBs, hLoudnessInfoSet);
+ if (err) return err;
+ }
+
+ return err;
+}