From 6cfabd35363c3ef5e3b209b867169a500b3ccc3c Mon Sep 17 00:00:00 2001 From: Fraunhofer IIS FDK Date: Mon, 26 Feb 2018 20:17:00 +0100 Subject: Upgrade to FDKv2 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 --- libDRCdec/src/drcDec_reader.cpp | 2027 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 2027 insertions(+) create mode 100644 libDRCdec/src/drcDec_reader.cpp (limited to 'libDRCdec/src/drcDec_reader.cpp') diff --git a/libDRCdec/src/drcDec_reader.cpp b/libDRCdec/src/drcDec_reader.cpp new file mode 100644 index 0000000..db5fab7 --- /dev/null +++ b/libDRCdec/src/drcDec_reader.cpp @@ -0,0 +1,2027 @@ +/* ----------------------------------------------------------------------------- +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; + UINT 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 = FDKgetValidBits(hBs); + + switch (pExt->uniDrcConfigExtType[k]) { + case UNIDRCCONFEXT_V1: + err = _readDrcExtensionV1(hBs, hUniDrcConfig); + if (err) return err; + if (nBitsRemaining != (pExt->extBitSize[k] + 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; + UINT 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 = FDKgetValidBits(hBs); + + switch (pExt->loudnessInfoSetExtType[k]) { + case UNIDRCLOUDEXT_EQ: + err = _readLoudnessInfoSetExtEq(hBs, hLoudnessInfoSet); + if (err) return err; + if (nBitsRemaining != (pExt->extBitSize[k] + 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; +} -- cgit v1.2.3