xref: /aosp_15_r20/external/aac/libMpegTPDec/src/tpdec_asc.cpp (revision e54365361535b070c2db7374cec45c159c7d0e7a)
1*e5436536SAndroid Build Coastguard Worker /* -----------------------------------------------------------------------------
2*e5436536SAndroid Build Coastguard Worker Software License for The Fraunhofer FDK AAC Codec Library for Android
3*e5436536SAndroid Build Coastguard Worker 
4*e5436536SAndroid Build Coastguard Worker © Copyright  1995 - 2020 Fraunhofer-Gesellschaft zur Förderung der angewandten
5*e5436536SAndroid Build Coastguard Worker Forschung e.V. All rights reserved.
6*e5436536SAndroid Build Coastguard Worker 
7*e5436536SAndroid Build Coastguard Worker  1.    INTRODUCTION
8*e5436536SAndroid Build Coastguard Worker The Fraunhofer FDK AAC Codec Library for Android ("FDK AAC Codec") is software
9*e5436536SAndroid Build Coastguard Worker that implements the MPEG Advanced Audio Coding ("AAC") encoding and decoding
10*e5436536SAndroid Build Coastguard Worker scheme for digital audio. This FDK AAC Codec software is intended to be used on
11*e5436536SAndroid Build Coastguard Worker a wide variety of Android devices.
12*e5436536SAndroid Build Coastguard Worker 
13*e5436536SAndroid Build Coastguard Worker AAC's HE-AAC and HE-AAC v2 versions are regarded as today's most efficient
14*e5436536SAndroid Build Coastguard Worker general perceptual audio codecs. AAC-ELD is considered the best-performing
15*e5436536SAndroid Build Coastguard Worker full-bandwidth communications codec by independent studies and is widely
16*e5436536SAndroid Build Coastguard Worker deployed. AAC has been standardized by ISO and IEC as part of the MPEG
17*e5436536SAndroid Build Coastguard Worker specifications.
18*e5436536SAndroid Build Coastguard Worker 
19*e5436536SAndroid Build Coastguard Worker Patent licenses for necessary patent claims for the FDK AAC Codec (including
20*e5436536SAndroid Build Coastguard Worker those of Fraunhofer) may be obtained through Via Licensing
21*e5436536SAndroid Build Coastguard Worker (www.vialicensing.com) or through the respective patent owners individually for
22*e5436536SAndroid Build Coastguard Worker the purpose of encoding or decoding bit streams in products that are compliant
23*e5436536SAndroid Build Coastguard Worker with the ISO/IEC MPEG audio standards. Please note that most manufacturers of
24*e5436536SAndroid Build Coastguard Worker Android devices already license these patent claims through Via Licensing or
25*e5436536SAndroid Build Coastguard Worker directly from the patent owners, and therefore FDK AAC Codec software may
26*e5436536SAndroid Build Coastguard Worker already be covered under those patent licenses when it is used for those
27*e5436536SAndroid Build Coastguard Worker licensed purposes only.
28*e5436536SAndroid Build Coastguard Worker 
29*e5436536SAndroid Build Coastguard Worker Commercially-licensed AAC software libraries, including floating-point versions
30*e5436536SAndroid Build Coastguard Worker with enhanced sound quality, are also available from Fraunhofer. Users are
31*e5436536SAndroid Build Coastguard Worker encouraged to check the Fraunhofer website for additional applications
32*e5436536SAndroid Build Coastguard Worker information and documentation.
33*e5436536SAndroid Build Coastguard Worker 
34*e5436536SAndroid Build Coastguard Worker 2.    COPYRIGHT LICENSE
35*e5436536SAndroid Build Coastguard Worker 
36*e5436536SAndroid Build Coastguard Worker Redistribution and use in source and binary forms, with or without modification,
37*e5436536SAndroid Build Coastguard Worker are permitted without payment of copyright license fees provided that you
38*e5436536SAndroid Build Coastguard Worker satisfy the following conditions:
39*e5436536SAndroid Build Coastguard Worker 
40*e5436536SAndroid Build Coastguard Worker You must retain the complete text of this software license in redistributions of
41*e5436536SAndroid Build Coastguard Worker the FDK AAC Codec or your modifications thereto in source code form.
42*e5436536SAndroid Build Coastguard Worker 
43*e5436536SAndroid Build Coastguard Worker You must retain the complete text of this software license in the documentation
44*e5436536SAndroid Build Coastguard Worker and/or other materials provided with redistributions of the FDK AAC Codec or
45*e5436536SAndroid Build Coastguard Worker your modifications thereto in binary form. You must make available free of
46*e5436536SAndroid Build Coastguard Worker charge copies of the complete source code of the FDK AAC Codec and your
47*e5436536SAndroid Build Coastguard Worker modifications thereto to recipients of copies in binary form.
48*e5436536SAndroid Build Coastguard Worker 
49*e5436536SAndroid Build Coastguard Worker The name of Fraunhofer may not be used to endorse or promote products derived
50*e5436536SAndroid Build Coastguard Worker from this library without prior written permission.
51*e5436536SAndroid Build Coastguard Worker 
52*e5436536SAndroid Build Coastguard Worker You may not charge copyright license fees for anyone to use, copy or distribute
53*e5436536SAndroid Build Coastguard Worker the FDK AAC Codec software or your modifications thereto.
54*e5436536SAndroid Build Coastguard Worker 
55*e5436536SAndroid Build Coastguard Worker Your modified versions of the FDK AAC Codec must carry prominent notices stating
56*e5436536SAndroid Build Coastguard Worker that you changed the software and the date of any change. For modified versions
57*e5436536SAndroid Build Coastguard Worker of the FDK AAC Codec, the term "Fraunhofer FDK AAC Codec Library for Android"
58*e5436536SAndroid Build Coastguard Worker must be replaced by the term "Third-Party Modified Version of the Fraunhofer FDK
59*e5436536SAndroid Build Coastguard Worker AAC Codec Library for Android."
60*e5436536SAndroid Build Coastguard Worker 
61*e5436536SAndroid Build Coastguard Worker 3.    NO PATENT LICENSE
62*e5436536SAndroid Build Coastguard Worker 
63*e5436536SAndroid Build Coastguard Worker NO EXPRESS OR IMPLIED LICENSES TO ANY PATENT CLAIMS, including without
64*e5436536SAndroid Build Coastguard Worker limitation the patents of Fraunhofer, ARE GRANTED BY THIS SOFTWARE LICENSE.
65*e5436536SAndroid Build Coastguard Worker Fraunhofer provides no warranty of patent non-infringement with respect to this
66*e5436536SAndroid Build Coastguard Worker software.
67*e5436536SAndroid Build Coastguard Worker 
68*e5436536SAndroid Build Coastguard Worker You may use this FDK AAC Codec software or modifications thereto only for
69*e5436536SAndroid Build Coastguard Worker purposes that are authorized by appropriate patent licenses.
70*e5436536SAndroid Build Coastguard Worker 
71*e5436536SAndroid Build Coastguard Worker 4.    DISCLAIMER
72*e5436536SAndroid Build Coastguard Worker 
73*e5436536SAndroid Build Coastguard Worker This FDK AAC Codec software is provided by Fraunhofer on behalf of the copyright
74*e5436536SAndroid Build Coastguard Worker holders and contributors "AS IS" and WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES,
75*e5436536SAndroid Build Coastguard Worker including but not limited to the implied warranties of merchantability and
76*e5436536SAndroid Build Coastguard Worker fitness for a particular purpose. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
77*e5436536SAndroid Build Coastguard Worker CONTRIBUTORS BE LIABLE for any direct, indirect, incidental, special, exemplary,
78*e5436536SAndroid Build Coastguard Worker or consequential damages, including but not limited to procurement of substitute
79*e5436536SAndroid Build Coastguard Worker goods or services; loss of use, data, or profits, or business interruption,
80*e5436536SAndroid Build Coastguard Worker however caused and on any theory of liability, whether in contract, strict
81*e5436536SAndroid Build Coastguard Worker liability, or tort (including negligence), arising in any way out of the use of
82*e5436536SAndroid Build Coastguard Worker this software, even if advised of the possibility of such damage.
83*e5436536SAndroid Build Coastguard Worker 
84*e5436536SAndroid Build Coastguard Worker 5.    CONTACT INFORMATION
85*e5436536SAndroid Build Coastguard Worker 
86*e5436536SAndroid Build Coastguard Worker Fraunhofer Institute for Integrated Circuits IIS
87*e5436536SAndroid Build Coastguard Worker Attention: Audio and Multimedia Departments - FDK AAC LL
88*e5436536SAndroid Build Coastguard Worker Am Wolfsmantel 33
89*e5436536SAndroid Build Coastguard Worker 91058 Erlangen, Germany
90*e5436536SAndroid Build Coastguard Worker 
91*e5436536SAndroid Build Coastguard Worker www.iis.fraunhofer.de/amm
92*e5436536SAndroid Build Coastguard Worker [email protected]
93*e5436536SAndroid Build Coastguard Worker ----------------------------------------------------------------------------- */
94*e5436536SAndroid Build Coastguard Worker 
95*e5436536SAndroid Build Coastguard Worker /******************* MPEG transport format decoder library *********************
96*e5436536SAndroid Build Coastguard Worker 
97*e5436536SAndroid Build Coastguard Worker    Author(s):   Daniel Homm
98*e5436536SAndroid Build Coastguard Worker 
99*e5436536SAndroid Build Coastguard Worker    Description:
100*e5436536SAndroid Build Coastguard Worker 
101*e5436536SAndroid Build Coastguard Worker *******************************************************************************/
102*e5436536SAndroid Build Coastguard Worker 
103*e5436536SAndroid Build Coastguard Worker #include "tpdec_lib.h"
104*e5436536SAndroid Build Coastguard Worker #include "tp_data.h"
105*e5436536SAndroid Build Coastguard Worker 
106*e5436536SAndroid Build Coastguard Worker #include "FDK_crc.h"
107*e5436536SAndroid Build Coastguard Worker 
108*e5436536SAndroid Build Coastguard Worker #include "common_fix.h"
109*e5436536SAndroid Build Coastguard Worker 
110*e5436536SAndroid Build Coastguard Worker /**
111*e5436536SAndroid Build Coastguard Worker  * The following arrays provide the IDs of the consecutive elements for each
112*e5436536SAndroid Build Coastguard Worker  * channel configuration. Every channel_configuration has to be finalized with
113*e5436536SAndroid Build Coastguard Worker  * ID_NONE.
114*e5436536SAndroid Build Coastguard Worker  */
115*e5436536SAndroid Build Coastguard Worker static const MP4_ELEMENT_ID channel_configuration_0[] = {ID_NONE};
116*e5436536SAndroid Build Coastguard Worker static const MP4_ELEMENT_ID channel_configuration_1[] = {ID_SCE, ID_NONE};
117*e5436536SAndroid Build Coastguard Worker static const MP4_ELEMENT_ID channel_configuration_2[] = {ID_CPE, ID_NONE};
118*e5436536SAndroid Build Coastguard Worker static const MP4_ELEMENT_ID channel_configuration_3[] = {ID_SCE, ID_CPE,
119*e5436536SAndroid Build Coastguard Worker                                                          ID_NONE};
120*e5436536SAndroid Build Coastguard Worker static const MP4_ELEMENT_ID channel_configuration_4[] = {ID_SCE, ID_CPE, ID_SCE,
121*e5436536SAndroid Build Coastguard Worker                                                          ID_NONE};
122*e5436536SAndroid Build Coastguard Worker static const MP4_ELEMENT_ID channel_configuration_5[] = {ID_SCE, ID_CPE, ID_CPE,
123*e5436536SAndroid Build Coastguard Worker                                                          ID_NONE};
124*e5436536SAndroid Build Coastguard Worker static const MP4_ELEMENT_ID channel_configuration_6[] = {ID_SCE, ID_CPE, ID_CPE,
125*e5436536SAndroid Build Coastguard Worker                                                          ID_LFE, ID_NONE};
126*e5436536SAndroid Build Coastguard Worker static const MP4_ELEMENT_ID channel_configuration_7[] = {
127*e5436536SAndroid Build Coastguard Worker     ID_SCE, ID_CPE, ID_CPE, ID_CPE, ID_LFE, ID_NONE};
128*e5436536SAndroid Build Coastguard Worker static const MP4_ELEMENT_ID channel_configuration_8[] = {
129*e5436536SAndroid Build Coastguard Worker     ID_NONE}; /* reserved */
130*e5436536SAndroid Build Coastguard Worker static const MP4_ELEMENT_ID channel_configuration_9[] = {
131*e5436536SAndroid Build Coastguard Worker     ID_NONE}; /* reserved */
132*e5436536SAndroid Build Coastguard Worker static const MP4_ELEMENT_ID channel_configuration_10[] = {
133*e5436536SAndroid Build Coastguard Worker     ID_NONE}; /* reserved */
134*e5436536SAndroid Build Coastguard Worker static const MP4_ELEMENT_ID channel_configuration_11[] = {
135*e5436536SAndroid Build Coastguard Worker     ID_SCE, ID_CPE, ID_CPE, ID_SCE, ID_LFE, ID_NONE};
136*e5436536SAndroid Build Coastguard Worker static const MP4_ELEMENT_ID channel_configuration_12[] = {
137*e5436536SAndroid Build Coastguard Worker     ID_SCE, ID_CPE, ID_CPE, ID_CPE, ID_LFE, ID_NONE};
138*e5436536SAndroid Build Coastguard Worker static const MP4_ELEMENT_ID channel_configuration_13[] = {
139*e5436536SAndroid Build Coastguard Worker     ID_SCE, ID_CPE, ID_CPE, ID_CPE, ID_CPE, ID_SCE, ID_LFE, ID_LFE, ID_SCE,
140*e5436536SAndroid Build Coastguard Worker     ID_CPE, ID_CPE, ID_SCE, ID_CPE, ID_SCE, ID_SCE, ID_CPE, ID_NONE};
141*e5436536SAndroid Build Coastguard Worker static const MP4_ELEMENT_ID channel_configuration_14[] = {
142*e5436536SAndroid Build Coastguard Worker     ID_SCE, ID_CPE, ID_CPE, ID_LFE, ID_CPE, ID_NONE};
143*e5436536SAndroid Build Coastguard Worker 
144*e5436536SAndroid Build Coastguard Worker static const MP4_ELEMENT_ID *channel_configuration_array[] = {
145*e5436536SAndroid Build Coastguard Worker     channel_configuration_0,  channel_configuration_1,
146*e5436536SAndroid Build Coastguard Worker     channel_configuration_2,  channel_configuration_3,
147*e5436536SAndroid Build Coastguard Worker     channel_configuration_4,  channel_configuration_5,
148*e5436536SAndroid Build Coastguard Worker     channel_configuration_6,  channel_configuration_7,
149*e5436536SAndroid Build Coastguard Worker     channel_configuration_8,  channel_configuration_9,
150*e5436536SAndroid Build Coastguard Worker     channel_configuration_10, channel_configuration_11,
151*e5436536SAndroid Build Coastguard Worker     channel_configuration_12, channel_configuration_13,
152*e5436536SAndroid Build Coastguard Worker     channel_configuration_14};
153*e5436536SAndroid Build Coastguard Worker 
154*e5436536SAndroid Build Coastguard Worker #define TP_USAC_MAX_CHANNEL_CONFIGURATION_INDEX (13)
155*e5436536SAndroid Build Coastguard Worker #define SC_CHANNEL_CONFIG_TAB_SIZE (TP_USAC_MAX_CHANNEL_CONFIGURATION_INDEX + 1)
156*e5436536SAndroid Build Coastguard Worker 
157*e5436536SAndroid Build Coastguard Worker /* channel config structure used for sanity check */
158*e5436536SAndroid Build Coastguard Worker typedef struct {
159*e5436536SAndroid Build Coastguard Worker   SCHAR nCh;  /* number of channels */
160*e5436536SAndroid Build Coastguard Worker   SCHAR nSCE; /* number of SCE's */
161*e5436536SAndroid Build Coastguard Worker   SCHAR nCPE; /* number of CPE's */
162*e5436536SAndroid Build Coastguard Worker   SCHAR nLFE; /* number of LFE's */
163*e5436536SAndroid Build Coastguard Worker } SC_CHANNEL_CONFIG;
164*e5436536SAndroid Build Coastguard Worker 
165*e5436536SAndroid Build Coastguard Worker static const SC_CHANNEL_CONFIG sc_chan_config_tab[SC_CHANNEL_CONFIG_TAB_SIZE] =
166*e5436536SAndroid Build Coastguard Worker     {
167*e5436536SAndroid Build Coastguard Worker         /* nCh, nSCE, nCPE, nLFE,     cci */
168*e5436536SAndroid Build Coastguard Worker         {0, 0, 0, 0}, /*  0 */
169*e5436536SAndroid Build Coastguard Worker         {1, 1, 0, 0}, /*  1 */
170*e5436536SAndroid Build Coastguard Worker         {2, 0, 1, 0}, /*  2 */
171*e5436536SAndroid Build Coastguard Worker         {3, 1, 1, 0}, /*  3 */
172*e5436536SAndroid Build Coastguard Worker         {4, 2, 1, 0}, /*  4 */
173*e5436536SAndroid Build Coastguard Worker         {5, 1, 2, 0}, /*  5 */
174*e5436536SAndroid Build Coastguard Worker         {6, 1, 2, 1}, /*  6 */
175*e5436536SAndroid Build Coastguard Worker         {8, 1, 3, 1}, /*  7 */
176*e5436536SAndroid Build Coastguard Worker         {2, 2, 0, 0}, /*  8 */
177*e5436536SAndroid Build Coastguard Worker         {3, 1, 1, 0}, /*  9 */
178*e5436536SAndroid Build Coastguard Worker         {4, 0, 2, 0}, /* 10 */
179*e5436536SAndroid Build Coastguard Worker         {7, 2, 2, 1}, /* 11 */
180*e5436536SAndroid Build Coastguard Worker         {8, 1, 3, 1}, /* 12 */
181*e5436536SAndroid Build Coastguard Worker         {24, 6, 8, 2} /* 13 */
182*e5436536SAndroid Build Coastguard Worker };
183*e5436536SAndroid Build Coastguard Worker 
CProgramConfig_Reset(CProgramConfig * pPce)184*e5436536SAndroid Build Coastguard Worker void CProgramConfig_Reset(CProgramConfig *pPce) { pPce->elCounter = 0; }
185*e5436536SAndroid Build Coastguard Worker 
CProgramConfig_Init(CProgramConfig * pPce)186*e5436536SAndroid Build Coastguard Worker void CProgramConfig_Init(CProgramConfig *pPce) {
187*e5436536SAndroid Build Coastguard Worker   FDKmemclear(pPce, sizeof(CProgramConfig));
188*e5436536SAndroid Build Coastguard Worker   pPce->SamplingFrequencyIndex = 0xf;
189*e5436536SAndroid Build Coastguard Worker }
190*e5436536SAndroid Build Coastguard Worker 
CProgramConfig_IsValid(const CProgramConfig * pPce)191*e5436536SAndroid Build Coastguard Worker int CProgramConfig_IsValid(const CProgramConfig *pPce) {
192*e5436536SAndroid Build Coastguard Worker   return ((pPce->isValid) ? 1 : 0);
193*e5436536SAndroid Build Coastguard Worker }
194*e5436536SAndroid Build Coastguard Worker 
195*e5436536SAndroid Build Coastguard Worker #define PCE_HEIGHT_EXT_SYNC (0xAC)
196*e5436536SAndroid Build Coastguard Worker 
197*e5436536SAndroid Build Coastguard Worker /*
198*e5436536SAndroid Build Coastguard Worker  * Read the extension for height info.
199*e5436536SAndroid Build Coastguard Worker  * return 0 if successfull,
200*e5436536SAndroid Build Coastguard Worker  *       -1 if the CRC failed,
201*e5436536SAndroid Build Coastguard Worker  *       -2 if invalid HeightInfo.
202*e5436536SAndroid Build Coastguard Worker  */
CProgramConfig_ReadHeightExt(CProgramConfig * pPce,HANDLE_FDK_BITSTREAM bs,int * const bytesAvailable,const UINT alignmentAnchor)203*e5436536SAndroid Build Coastguard Worker static int CProgramConfig_ReadHeightExt(CProgramConfig *pPce,
204*e5436536SAndroid Build Coastguard Worker                                         HANDLE_FDK_BITSTREAM bs,
205*e5436536SAndroid Build Coastguard Worker                                         int *const bytesAvailable,
206*e5436536SAndroid Build Coastguard Worker                                         const UINT alignmentAnchor) {
207*e5436536SAndroid Build Coastguard Worker   int err = 0;
208*e5436536SAndroid Build Coastguard Worker   FDK_CRCINFO crcInfo; /* CRC state info */
209*e5436536SAndroid Build Coastguard Worker   INT crcReg;
210*e5436536SAndroid Build Coastguard Worker   FDKcrcInit(&crcInfo, 0x07, 0xFF, 8);
211*e5436536SAndroid Build Coastguard Worker   crcReg = FDKcrcStartReg(&crcInfo, bs, 0);
212*e5436536SAndroid Build Coastguard Worker   UINT startAnchor = FDKgetValidBits(bs);
213*e5436536SAndroid Build Coastguard Worker 
214*e5436536SAndroid Build Coastguard Worker   FDK_ASSERT(pPce != NULL);
215*e5436536SAndroid Build Coastguard Worker   FDK_ASSERT(bs != NULL);
216*e5436536SAndroid Build Coastguard Worker   FDK_ASSERT(bytesAvailable != NULL);
217*e5436536SAndroid Build Coastguard Worker 
218*e5436536SAndroid Build Coastguard Worker   if ((startAnchor >= 24) && (*bytesAvailable >= 3) &&
219*e5436536SAndroid Build Coastguard Worker       (FDKreadBits(bs, 8) == PCE_HEIGHT_EXT_SYNC)) {
220*e5436536SAndroid Build Coastguard Worker     int i;
221*e5436536SAndroid Build Coastguard Worker 
222*e5436536SAndroid Build Coastguard Worker     for (i = 0; i < pPce->NumFrontChannelElements; i++) {
223*e5436536SAndroid Build Coastguard Worker       if ((pPce->FrontElementHeightInfo[i] = (UCHAR)FDKreadBits(bs, 2)) >=
224*e5436536SAndroid Build Coastguard Worker           PC_NUM_HEIGHT_LAYER) {
225*e5436536SAndroid Build Coastguard Worker         err = -2; /* height information is out of the valid range */
226*e5436536SAndroid Build Coastguard Worker       }
227*e5436536SAndroid Build Coastguard Worker     }
228*e5436536SAndroid Build Coastguard Worker     for (i = 0; i < pPce->NumSideChannelElements; i++) {
229*e5436536SAndroid Build Coastguard Worker       if ((pPce->SideElementHeightInfo[i] = (UCHAR)FDKreadBits(bs, 2)) >=
230*e5436536SAndroid Build Coastguard Worker           PC_NUM_HEIGHT_LAYER) {
231*e5436536SAndroid Build Coastguard Worker         err = -2; /* height information is out of the valid range */
232*e5436536SAndroid Build Coastguard Worker       }
233*e5436536SAndroid Build Coastguard Worker     }
234*e5436536SAndroid Build Coastguard Worker     for (i = 0; i < pPce->NumBackChannelElements; i++) {
235*e5436536SAndroid Build Coastguard Worker       if ((pPce->BackElementHeightInfo[i] = (UCHAR)FDKreadBits(bs, 2)) >=
236*e5436536SAndroid Build Coastguard Worker           PC_NUM_HEIGHT_LAYER) {
237*e5436536SAndroid Build Coastguard Worker         err = -2; /* height information is out of the valid range */
238*e5436536SAndroid Build Coastguard Worker       }
239*e5436536SAndroid Build Coastguard Worker     }
240*e5436536SAndroid Build Coastguard Worker     FDKbyteAlign(bs, alignmentAnchor);
241*e5436536SAndroid Build Coastguard Worker 
242*e5436536SAndroid Build Coastguard Worker     FDKcrcEndReg(&crcInfo, bs, crcReg);
243*e5436536SAndroid Build Coastguard Worker     if ((USHORT)FDKreadBits(bs, 8) != FDKcrcGetCRC(&crcInfo)) {
244*e5436536SAndroid Build Coastguard Worker       /* CRC failed */
245*e5436536SAndroid Build Coastguard Worker       err = -1;
246*e5436536SAndroid Build Coastguard Worker     }
247*e5436536SAndroid Build Coastguard Worker     if (err != 0) {
248*e5436536SAndroid Build Coastguard Worker       /* Reset whole height information in case an error occured during parsing.
249*e5436536SAndroid Build Coastguard Worker          The return value ensures that pPce->isValid is set to 0 and implicit
250*e5436536SAndroid Build Coastguard Worker          channel mapping is used. */
251*e5436536SAndroid Build Coastguard Worker       FDKmemclear(pPce->FrontElementHeightInfo,
252*e5436536SAndroid Build Coastguard Worker                   sizeof(pPce->FrontElementHeightInfo));
253*e5436536SAndroid Build Coastguard Worker       FDKmemclear(pPce->SideElementHeightInfo,
254*e5436536SAndroid Build Coastguard Worker                   sizeof(pPce->SideElementHeightInfo));
255*e5436536SAndroid Build Coastguard Worker       FDKmemclear(pPce->BackElementHeightInfo,
256*e5436536SAndroid Build Coastguard Worker                   sizeof(pPce->BackElementHeightInfo));
257*e5436536SAndroid Build Coastguard Worker     }
258*e5436536SAndroid Build Coastguard Worker   } else {
259*e5436536SAndroid Build Coastguard Worker     /* No valid extension data found -> restore the initial bitbuffer state */
260*e5436536SAndroid Build Coastguard Worker     FDKpushBack(bs, (INT)startAnchor - (INT)FDKgetValidBits(bs));
261*e5436536SAndroid Build Coastguard Worker   }
262*e5436536SAndroid Build Coastguard Worker 
263*e5436536SAndroid Build Coastguard Worker   /* Always report the bytes read. */
264*e5436536SAndroid Build Coastguard Worker   *bytesAvailable -= ((INT)startAnchor - (INT)FDKgetValidBits(bs)) >> 3;
265*e5436536SAndroid Build Coastguard Worker 
266*e5436536SAndroid Build Coastguard Worker   return (err);
267*e5436536SAndroid Build Coastguard Worker }
268*e5436536SAndroid Build Coastguard Worker 
269*e5436536SAndroid Build Coastguard Worker /**
270*e5436536SAndroid Build Coastguard Worker  * \brief Sanity checks for program config element.
271*e5436536SAndroid Build Coastguard Worker  *        Check order of elements according to ISO/IEC 13818-7:2003(E),
272*e5436536SAndroid Build Coastguard Worker  * chapter 8.5.1
273*e5436536SAndroid Build Coastguard Worker  *
274*e5436536SAndroid Build Coastguard Worker  * \param pPce  pointer to program config element.
275*e5436536SAndroid Build Coastguard Worker  *
276*e5436536SAndroid Build Coastguard Worker  * \return  0 if successful, otherwise 1.
277*e5436536SAndroid Build Coastguard Worker  */
CProgramConfig_Check(CProgramConfig * pPce)278*e5436536SAndroid Build Coastguard Worker static int CProgramConfig_Check(CProgramConfig *pPce) {
279*e5436536SAndroid Build Coastguard Worker   INT i;
280*e5436536SAndroid Build Coastguard Worker   INT err = 0;
281*e5436536SAndroid Build Coastguard Worker   INT numBackChannels[3] = {0};
282*e5436536SAndroid Build Coastguard Worker   INT numSideChannels[3] = {0};
283*e5436536SAndroid Build Coastguard Worker   INT numFrontChannels[3] = {0};
284*e5436536SAndroid Build Coastguard Worker   UCHAR *pCpeFront = pPce->FrontElementIsCpe;
285*e5436536SAndroid Build Coastguard Worker   UCHAR *pCpeSide = pPce->SideElementIsCpe;
286*e5436536SAndroid Build Coastguard Worker   UCHAR *pCpeBack = pPce->BackElementIsCpe;
287*e5436536SAndroid Build Coastguard Worker   UCHAR *pHeight;
288*e5436536SAndroid Build Coastguard Worker 
289*e5436536SAndroid Build Coastguard Worker   pHeight = pPce->BackElementHeightInfo;
290*e5436536SAndroid Build Coastguard Worker   for (i = 0; i < pPce->NumBackChannelElements; i++) {
291*e5436536SAndroid Build Coastguard Worker     numBackChannels[*pHeight] += pPce->BackElementIsCpe[i] ? 2 : 1;
292*e5436536SAndroid Build Coastguard Worker     pHeight++;
293*e5436536SAndroid Build Coastguard Worker   }
294*e5436536SAndroid Build Coastguard Worker   pHeight = pPce->SideElementHeightInfo;
295*e5436536SAndroid Build Coastguard Worker   for (i = 0; i < pPce->NumSideChannelElements; i++) {
296*e5436536SAndroid Build Coastguard Worker     numSideChannels[*pHeight] += pPce->SideElementIsCpe[i] ? 2 : 1;
297*e5436536SAndroid Build Coastguard Worker     pHeight++;
298*e5436536SAndroid Build Coastguard Worker   }
299*e5436536SAndroid Build Coastguard Worker   pHeight = pPce->FrontElementHeightInfo;
300*e5436536SAndroid Build Coastguard Worker   for (i = 0; i < pPce->NumFrontChannelElements; i++) {
301*e5436536SAndroid Build Coastguard Worker     numFrontChannels[*pHeight] += pPce->FrontElementIsCpe[i] ? 2 : 1;
302*e5436536SAndroid Build Coastguard Worker     pHeight++;
303*e5436536SAndroid Build Coastguard Worker   }
304*e5436536SAndroid Build Coastguard Worker 
305*e5436536SAndroid Build Coastguard Worker   /* 0 = normal height channels, 1 = top height channels, 2 = bottom height
306*e5436536SAndroid Build Coastguard Worker    * channels */
307*e5436536SAndroid Build Coastguard Worker   for (i = 0; i < 3; i++) {
308*e5436536SAndroid Build Coastguard Worker     /* if number of channels is odd => first element must be a SCE (front center
309*e5436536SAndroid Build Coastguard Worker      * channel) */
310*e5436536SAndroid Build Coastguard Worker     if (numFrontChannels[i] & 1) {
311*e5436536SAndroid Build Coastguard Worker       if (*pCpeFront++ == ID_CPE) {
312*e5436536SAndroid Build Coastguard Worker         err = 1;
313*e5436536SAndroid Build Coastguard Worker         goto bail;
314*e5436536SAndroid Build Coastguard Worker       }
315*e5436536SAndroid Build Coastguard Worker       numFrontChannels[i]--;
316*e5436536SAndroid Build Coastguard Worker     }
317*e5436536SAndroid Build Coastguard Worker     while (numFrontChannels[i] > 0) {
318*e5436536SAndroid Build Coastguard Worker       /* must be CPE or paired SCE */
319*e5436536SAndroid Build Coastguard Worker       if (*pCpeFront++ == ID_SCE) {
320*e5436536SAndroid Build Coastguard Worker         if (*pCpeFront++ == ID_CPE) {
321*e5436536SAndroid Build Coastguard Worker           err = 1;
322*e5436536SAndroid Build Coastguard Worker           goto bail;
323*e5436536SAndroid Build Coastguard Worker         }
324*e5436536SAndroid Build Coastguard Worker       }
325*e5436536SAndroid Build Coastguard Worker       numFrontChannels[i] -= 2;
326*e5436536SAndroid Build Coastguard Worker     };
327*e5436536SAndroid Build Coastguard Worker 
328*e5436536SAndroid Build Coastguard Worker     /* in case that a top center surround channel (Ts) is transmitted the number
329*e5436536SAndroid Build Coastguard Worker      * of channels can be odd */
330*e5436536SAndroid Build Coastguard Worker     if (i != 1) {
331*e5436536SAndroid Build Coastguard Worker       /* number of channels must be even */
332*e5436536SAndroid Build Coastguard Worker       if (numSideChannels[i] & 1) {
333*e5436536SAndroid Build Coastguard Worker         err = 1;
334*e5436536SAndroid Build Coastguard Worker         goto bail;
335*e5436536SAndroid Build Coastguard Worker       }
336*e5436536SAndroid Build Coastguard Worker       while (numSideChannels[i] > 0) {
337*e5436536SAndroid Build Coastguard Worker         /* must be CPE or paired SCE */
338*e5436536SAndroid Build Coastguard Worker         if (*pCpeSide++ == ID_SCE) {
339*e5436536SAndroid Build Coastguard Worker           if (*pCpeSide++ == ID_CPE) {
340*e5436536SAndroid Build Coastguard Worker             err = 1;
341*e5436536SAndroid Build Coastguard Worker             goto bail;
342*e5436536SAndroid Build Coastguard Worker           }
343*e5436536SAndroid Build Coastguard Worker         }
344*e5436536SAndroid Build Coastguard Worker         numSideChannels[i] -= 2;
345*e5436536SAndroid Build Coastguard Worker       };
346*e5436536SAndroid Build Coastguard Worker     }
347*e5436536SAndroid Build Coastguard Worker 
348*e5436536SAndroid Build Coastguard Worker     while (numBackChannels[i] > 1) {
349*e5436536SAndroid Build Coastguard Worker       /* must be CPE or paired SCE */
350*e5436536SAndroid Build Coastguard Worker       if (*pCpeBack++ == ID_SCE) {
351*e5436536SAndroid Build Coastguard Worker         if (*pCpeBack++ == ID_CPE) {
352*e5436536SAndroid Build Coastguard Worker           err = 1;
353*e5436536SAndroid Build Coastguard Worker           goto bail;
354*e5436536SAndroid Build Coastguard Worker         }
355*e5436536SAndroid Build Coastguard Worker       }
356*e5436536SAndroid Build Coastguard Worker       numBackChannels[i] -= 2;
357*e5436536SAndroid Build Coastguard Worker     };
358*e5436536SAndroid Build Coastguard Worker     /* if number of channels is odd => last element must be a SCE (back center
359*e5436536SAndroid Build Coastguard Worker      * channel) */
360*e5436536SAndroid Build Coastguard Worker     if (numBackChannels[i]) {
361*e5436536SAndroid Build Coastguard Worker       if (*pCpeBack++ == ID_CPE) {
362*e5436536SAndroid Build Coastguard Worker         err = 1;
363*e5436536SAndroid Build Coastguard Worker         goto bail;
364*e5436536SAndroid Build Coastguard Worker       }
365*e5436536SAndroid Build Coastguard Worker     }
366*e5436536SAndroid Build Coastguard Worker   }
367*e5436536SAndroid Build Coastguard Worker 
368*e5436536SAndroid Build Coastguard Worker bail:
369*e5436536SAndroid Build Coastguard Worker 
370*e5436536SAndroid Build Coastguard Worker   return err;
371*e5436536SAndroid Build Coastguard Worker }
372*e5436536SAndroid Build Coastguard Worker 
CProgramConfig_Read(CProgramConfig * pPce,HANDLE_FDK_BITSTREAM bs,UINT alignmentAnchor)373*e5436536SAndroid Build Coastguard Worker void CProgramConfig_Read(CProgramConfig *pPce, HANDLE_FDK_BITSTREAM bs,
374*e5436536SAndroid Build Coastguard Worker                          UINT alignmentAnchor) {
375*e5436536SAndroid Build Coastguard Worker   int i;
376*e5436536SAndroid Build Coastguard Worker   int commentBytes;
377*e5436536SAndroid Build Coastguard Worker   UCHAR tag, isCpe;
378*e5436536SAndroid Build Coastguard Worker   UCHAR checkElementTagSelect[3][PC_FSB_CHANNELS_MAX] = {{0}};
379*e5436536SAndroid Build Coastguard Worker 
380*e5436536SAndroid Build Coastguard Worker   pPce->isValid = 1;
381*e5436536SAndroid Build Coastguard Worker   pPce->NumEffectiveChannels = 0;
382*e5436536SAndroid Build Coastguard Worker   pPce->NumChannels = 0;
383*e5436536SAndroid Build Coastguard Worker   pPce->ElementInstanceTag = (UCHAR)FDKreadBits(bs, 4);
384*e5436536SAndroid Build Coastguard Worker   pPce->Profile = (UCHAR)FDKreadBits(bs, 2);
385*e5436536SAndroid Build Coastguard Worker   pPce->SamplingFrequencyIndex = (UCHAR)FDKreadBits(bs, 4);
386*e5436536SAndroid Build Coastguard Worker   pPce->NumFrontChannelElements = (UCHAR)FDKreadBits(bs, 4);
387*e5436536SAndroid Build Coastguard Worker   pPce->NumSideChannelElements = (UCHAR)FDKreadBits(bs, 4);
388*e5436536SAndroid Build Coastguard Worker   pPce->NumBackChannelElements = (UCHAR)FDKreadBits(bs, 4);
389*e5436536SAndroid Build Coastguard Worker   pPce->NumLfeChannelElements = (UCHAR)FDKreadBits(bs, 2);
390*e5436536SAndroid Build Coastguard Worker   pPce->NumAssocDataElements = (UCHAR)FDKreadBits(bs, 3);
391*e5436536SAndroid Build Coastguard Worker   pPce->NumValidCcElements = (UCHAR)FDKreadBits(bs, 4);
392*e5436536SAndroid Build Coastguard Worker 
393*e5436536SAndroid Build Coastguard Worker   if ((pPce->MonoMixdownPresent = (UCHAR)FDKreadBits(bs, 1)) != 0) {
394*e5436536SAndroid Build Coastguard Worker     pPce->MonoMixdownElementNumber = (UCHAR)FDKreadBits(bs, 4);
395*e5436536SAndroid Build Coastguard Worker   }
396*e5436536SAndroid Build Coastguard Worker 
397*e5436536SAndroid Build Coastguard Worker   if ((pPce->StereoMixdownPresent = (UCHAR)FDKreadBits(bs, 1)) != 0) {
398*e5436536SAndroid Build Coastguard Worker     pPce->StereoMixdownElementNumber = (UCHAR)FDKreadBits(bs, 4);
399*e5436536SAndroid Build Coastguard Worker   }
400*e5436536SAndroid Build Coastguard Worker 
401*e5436536SAndroid Build Coastguard Worker   if ((pPce->MatrixMixdownIndexPresent = (UCHAR)FDKreadBits(bs, 1)) != 0) {
402*e5436536SAndroid Build Coastguard Worker     pPce->MatrixMixdownIndex = (UCHAR)FDKreadBits(bs, 2);
403*e5436536SAndroid Build Coastguard Worker     pPce->PseudoSurroundEnable = (UCHAR)FDKreadBits(bs, 1);
404*e5436536SAndroid Build Coastguard Worker   }
405*e5436536SAndroid Build Coastguard Worker 
406*e5436536SAndroid Build Coastguard Worker   for (i = 0; i < pPce->NumFrontChannelElements; i++) {
407*e5436536SAndroid Build Coastguard Worker     pPce->FrontElementIsCpe[i] = isCpe = (UCHAR)FDKreadBits(bs, 1);
408*e5436536SAndroid Build Coastguard Worker     pPce->FrontElementTagSelect[i] = tag = (UCHAR)FDKreadBits(bs, 4);
409*e5436536SAndroid Build Coastguard Worker     pPce->NumChannels += pPce->FrontElementIsCpe[i] ? 2 : 1;
410*e5436536SAndroid Build Coastguard Worker 
411*e5436536SAndroid Build Coastguard Worker     /* Check element instance tag according to ISO/IEC 13818-7:2003(E),
412*e5436536SAndroid Build Coastguard Worker      * chapter 8.2.1.1 */
413*e5436536SAndroid Build Coastguard Worker     if (checkElementTagSelect[isCpe][tag] == 0) {
414*e5436536SAndroid Build Coastguard Worker       checkElementTagSelect[isCpe][tag] = 1;
415*e5436536SAndroid Build Coastguard Worker     } else {
416*e5436536SAndroid Build Coastguard Worker       pPce->isValid = 0;
417*e5436536SAndroid Build Coastguard Worker     }
418*e5436536SAndroid Build Coastguard Worker   }
419*e5436536SAndroid Build Coastguard Worker 
420*e5436536SAndroid Build Coastguard Worker   for (i = 0; i < pPce->NumSideChannelElements; i++) {
421*e5436536SAndroid Build Coastguard Worker     pPce->SideElementIsCpe[i] = isCpe = (UCHAR)FDKreadBits(bs, 1);
422*e5436536SAndroid Build Coastguard Worker     pPce->SideElementTagSelect[i] = tag = (UCHAR)FDKreadBits(bs, 4);
423*e5436536SAndroid Build Coastguard Worker     pPce->NumChannels += pPce->SideElementIsCpe[i] ? 2 : 1;
424*e5436536SAndroid Build Coastguard Worker 
425*e5436536SAndroid Build Coastguard Worker     /* Check element instance tag according to ISO/IEC 13818-7:2003(E),
426*e5436536SAndroid Build Coastguard Worker      * chapter 8.2.1.1 */
427*e5436536SAndroid Build Coastguard Worker     if (checkElementTagSelect[isCpe][tag] == 0) {
428*e5436536SAndroid Build Coastguard Worker       checkElementTagSelect[isCpe][tag] = 1;
429*e5436536SAndroid Build Coastguard Worker     } else {
430*e5436536SAndroid Build Coastguard Worker       pPce->isValid = 0;
431*e5436536SAndroid Build Coastguard Worker     }
432*e5436536SAndroid Build Coastguard Worker   }
433*e5436536SAndroid Build Coastguard Worker 
434*e5436536SAndroid Build Coastguard Worker   for (i = 0; i < pPce->NumBackChannelElements; i++) {
435*e5436536SAndroid Build Coastguard Worker     pPce->BackElementIsCpe[i] = isCpe = (UCHAR)FDKreadBits(bs, 1);
436*e5436536SAndroid Build Coastguard Worker     pPce->BackElementTagSelect[i] = tag = (UCHAR)FDKreadBits(bs, 4);
437*e5436536SAndroid Build Coastguard Worker     pPce->NumChannels += pPce->BackElementIsCpe[i] ? 2 : 1;
438*e5436536SAndroid Build Coastguard Worker 
439*e5436536SAndroid Build Coastguard Worker     /* Check element instance tag according to ISO/IEC 13818-7:2003(E),
440*e5436536SAndroid Build Coastguard Worker      * chapter 8.2.1.1 */
441*e5436536SAndroid Build Coastguard Worker     if (checkElementTagSelect[isCpe][tag] == 0) {
442*e5436536SAndroid Build Coastguard Worker       checkElementTagSelect[isCpe][tag] = 1;
443*e5436536SAndroid Build Coastguard Worker     } else {
444*e5436536SAndroid Build Coastguard Worker       pPce->isValid = 0;
445*e5436536SAndroid Build Coastguard Worker     }
446*e5436536SAndroid Build Coastguard Worker   }
447*e5436536SAndroid Build Coastguard Worker 
448*e5436536SAndroid Build Coastguard Worker   pPce->NumEffectiveChannels = pPce->NumChannels;
449*e5436536SAndroid Build Coastguard Worker 
450*e5436536SAndroid Build Coastguard Worker   for (i = 0; i < pPce->NumLfeChannelElements; i++) {
451*e5436536SAndroid Build Coastguard Worker     pPce->LfeElementTagSelect[i] = tag = (UCHAR)FDKreadBits(bs, 4);
452*e5436536SAndroid Build Coastguard Worker     pPce->NumChannels += 1;
453*e5436536SAndroid Build Coastguard Worker 
454*e5436536SAndroid Build Coastguard Worker     /* Check element instance tag according to ISO/IEC 13818-7:2003(E),
455*e5436536SAndroid Build Coastguard Worker      * chapter 8.2.1.1 */
456*e5436536SAndroid Build Coastguard Worker     if (checkElementTagSelect[2][tag] == 0) {
457*e5436536SAndroid Build Coastguard Worker       checkElementTagSelect[2][tag] = 1;
458*e5436536SAndroid Build Coastguard Worker     } else {
459*e5436536SAndroid Build Coastguard Worker       pPce->isValid = 0;
460*e5436536SAndroid Build Coastguard Worker     }
461*e5436536SAndroid Build Coastguard Worker   }
462*e5436536SAndroid Build Coastguard Worker 
463*e5436536SAndroid Build Coastguard Worker   for (i = 0; i < pPce->NumAssocDataElements; i++) {
464*e5436536SAndroid Build Coastguard Worker     pPce->AssocDataElementTagSelect[i] = (UCHAR)FDKreadBits(bs, 4);
465*e5436536SAndroid Build Coastguard Worker   }
466*e5436536SAndroid Build Coastguard Worker 
467*e5436536SAndroid Build Coastguard Worker   for (i = 0; i < pPce->NumValidCcElements; i++) {
468*e5436536SAndroid Build Coastguard Worker     pPce->CcElementIsIndSw[i] = (UCHAR)FDKreadBits(bs, 1);
469*e5436536SAndroid Build Coastguard Worker     pPce->ValidCcElementTagSelect[i] = (UCHAR)FDKreadBits(bs, 4);
470*e5436536SAndroid Build Coastguard Worker   }
471*e5436536SAndroid Build Coastguard Worker 
472*e5436536SAndroid Build Coastguard Worker   FDKbyteAlign(bs, alignmentAnchor);
473*e5436536SAndroid Build Coastguard Worker 
474*e5436536SAndroid Build Coastguard Worker   pPce->CommentFieldBytes = (UCHAR)FDKreadBits(bs, 8);
475*e5436536SAndroid Build Coastguard Worker   commentBytes = pPce->CommentFieldBytes;
476*e5436536SAndroid Build Coastguard Worker 
477*e5436536SAndroid Build Coastguard Worker   /* Search for height info extension and read it if available */
478*e5436536SAndroid Build Coastguard Worker   if (CProgramConfig_ReadHeightExt(pPce, bs, &commentBytes, alignmentAnchor)) {
479*e5436536SAndroid Build Coastguard Worker     pPce->isValid = 0;
480*e5436536SAndroid Build Coastguard Worker   }
481*e5436536SAndroid Build Coastguard Worker 
482*e5436536SAndroid Build Coastguard Worker   /* Check order of elements according to ISO / IEC 13818 - 7:2003(E),
483*e5436536SAndroid Build Coastguard Worker    * chapter 8.5.1 */
484*e5436536SAndroid Build Coastguard Worker   if (CProgramConfig_Check(pPce)) {
485*e5436536SAndroid Build Coastguard Worker     pPce->isValid = 0;
486*e5436536SAndroid Build Coastguard Worker   }
487*e5436536SAndroid Build Coastguard Worker 
488*e5436536SAndroid Build Coastguard Worker   for (i = 0; i < commentBytes; i++) {
489*e5436536SAndroid Build Coastguard Worker     UCHAR text;
490*e5436536SAndroid Build Coastguard Worker 
491*e5436536SAndroid Build Coastguard Worker     text = (UCHAR)FDKreadBits(bs, 8);
492*e5436536SAndroid Build Coastguard Worker 
493*e5436536SAndroid Build Coastguard Worker     if (i < PC_COMMENTLENGTH) {
494*e5436536SAndroid Build Coastguard Worker       pPce->Comment[i] = text;
495*e5436536SAndroid Build Coastguard Worker     }
496*e5436536SAndroid Build Coastguard Worker   }
497*e5436536SAndroid Build Coastguard Worker }
498*e5436536SAndroid Build Coastguard Worker 
499*e5436536SAndroid Build Coastguard Worker /*
500*e5436536SAndroid Build Coastguard Worker  * Compare two program configurations.
501*e5436536SAndroid Build Coastguard Worker  * Returns the result of the comparison:
502*e5436536SAndroid Build Coastguard Worker  *  -1 - completely different
503*e5436536SAndroid Build Coastguard Worker  *   0 - completely equal
504*e5436536SAndroid Build Coastguard Worker  *   1 - different but same channel configuration
505*e5436536SAndroid Build Coastguard Worker  *   2 - different channel configuration but same number of channels
506*e5436536SAndroid Build Coastguard Worker  */
CProgramConfig_Compare(const CProgramConfig * const pPce1,const CProgramConfig * const pPce2)507*e5436536SAndroid Build Coastguard Worker int CProgramConfig_Compare(const CProgramConfig *const pPce1,
508*e5436536SAndroid Build Coastguard Worker                            const CProgramConfig *const pPce2) {
509*e5436536SAndroid Build Coastguard Worker   int result = 0; /* Innocent until proven false. */
510*e5436536SAndroid Build Coastguard Worker 
511*e5436536SAndroid Build Coastguard Worker   if (FDKmemcmp(pPce1, pPce2, sizeof(CProgramConfig)) !=
512*e5436536SAndroid Build Coastguard Worker       0) { /* Configurations are not completely equal.
513*e5436536SAndroid Build Coastguard Worker               So look into details and analyse the channel configurations: */
514*e5436536SAndroid Build Coastguard Worker     result = -1;
515*e5436536SAndroid Build Coastguard Worker 
516*e5436536SAndroid Build Coastguard Worker     if (pPce1->NumChannels ==
517*e5436536SAndroid Build Coastguard Worker         pPce2->NumChannels) { /* Now the logic changes. We first assume to have
518*e5436536SAndroid Build Coastguard Worker                                  the same channel configuration and then prove
519*e5436536SAndroid Build Coastguard Worker                                  if this assumption is true. */
520*e5436536SAndroid Build Coastguard Worker       result = 1;
521*e5436536SAndroid Build Coastguard Worker 
522*e5436536SAndroid Build Coastguard Worker       /* Front channels */
523*e5436536SAndroid Build Coastguard Worker       if (pPce1->NumFrontChannelElements != pPce2->NumFrontChannelElements) {
524*e5436536SAndroid Build Coastguard Worker         result = 2; /* different number of front channel elements */
525*e5436536SAndroid Build Coastguard Worker       } else {
526*e5436536SAndroid Build Coastguard Worker         int el, numCh1 = 0, numCh2 = 0;
527*e5436536SAndroid Build Coastguard Worker         for (el = 0; el < pPce1->NumFrontChannelElements; el += 1) {
528*e5436536SAndroid Build Coastguard Worker           if (pPce1->FrontElementHeightInfo[el] !=
529*e5436536SAndroid Build Coastguard Worker               pPce2->FrontElementHeightInfo[el]) {
530*e5436536SAndroid Build Coastguard Worker             result = 2; /* different height info */
531*e5436536SAndroid Build Coastguard Worker             break;
532*e5436536SAndroid Build Coastguard Worker           }
533*e5436536SAndroid Build Coastguard Worker           numCh1 += pPce1->FrontElementIsCpe[el] ? 2 : 1;
534*e5436536SAndroid Build Coastguard Worker           numCh2 += pPce2->FrontElementIsCpe[el] ? 2 : 1;
535*e5436536SAndroid Build Coastguard Worker         }
536*e5436536SAndroid Build Coastguard Worker         if (numCh1 != numCh2) {
537*e5436536SAndroid Build Coastguard Worker           result = 2; /* different number of front channels */
538*e5436536SAndroid Build Coastguard Worker         }
539*e5436536SAndroid Build Coastguard Worker       }
540*e5436536SAndroid Build Coastguard Worker       /* Side channels */
541*e5436536SAndroid Build Coastguard Worker       if (pPce1->NumSideChannelElements != pPce2->NumSideChannelElements) {
542*e5436536SAndroid Build Coastguard Worker         result = 2; /* different number of side channel elements */
543*e5436536SAndroid Build Coastguard Worker       } else {
544*e5436536SAndroid Build Coastguard Worker         int el, numCh1 = 0, numCh2 = 0;
545*e5436536SAndroid Build Coastguard Worker         for (el = 0; el < pPce1->NumSideChannelElements; el += 1) {
546*e5436536SAndroid Build Coastguard Worker           if (pPce1->SideElementHeightInfo[el] !=
547*e5436536SAndroid Build Coastguard Worker               pPce2->SideElementHeightInfo[el]) {
548*e5436536SAndroid Build Coastguard Worker             result = 2; /* different height info */
549*e5436536SAndroid Build Coastguard Worker             break;
550*e5436536SAndroid Build Coastguard Worker           }
551*e5436536SAndroid Build Coastguard Worker           numCh1 += pPce1->SideElementIsCpe[el] ? 2 : 1;
552*e5436536SAndroid Build Coastguard Worker           numCh2 += pPce2->SideElementIsCpe[el] ? 2 : 1;
553*e5436536SAndroid Build Coastguard Worker         }
554*e5436536SAndroid Build Coastguard Worker         if (numCh1 != numCh2) {
555*e5436536SAndroid Build Coastguard Worker           result = 2; /* different number of side channels */
556*e5436536SAndroid Build Coastguard Worker         }
557*e5436536SAndroid Build Coastguard Worker       }
558*e5436536SAndroid Build Coastguard Worker       /* Back channels */
559*e5436536SAndroid Build Coastguard Worker       if (pPce1->NumBackChannelElements != pPce2->NumBackChannelElements) {
560*e5436536SAndroid Build Coastguard Worker         result = 2; /* different number of back channel elements */
561*e5436536SAndroid Build Coastguard Worker       } else {
562*e5436536SAndroid Build Coastguard Worker         int el, numCh1 = 0, numCh2 = 0;
563*e5436536SAndroid Build Coastguard Worker         for (el = 0; el < pPce1->NumBackChannelElements; el += 1) {
564*e5436536SAndroid Build Coastguard Worker           if (pPce1->BackElementHeightInfo[el] !=
565*e5436536SAndroid Build Coastguard Worker               pPce2->BackElementHeightInfo[el]) {
566*e5436536SAndroid Build Coastguard Worker             result = 2; /* different height info */
567*e5436536SAndroid Build Coastguard Worker             break;
568*e5436536SAndroid Build Coastguard Worker           }
569*e5436536SAndroid Build Coastguard Worker           numCh1 += pPce1->BackElementIsCpe[el] ? 2 : 1;
570*e5436536SAndroid Build Coastguard Worker           numCh2 += pPce2->BackElementIsCpe[el] ? 2 : 1;
571*e5436536SAndroid Build Coastguard Worker         }
572*e5436536SAndroid Build Coastguard Worker         if (numCh1 != numCh2) {
573*e5436536SAndroid Build Coastguard Worker           result = 2; /* different number of back channels */
574*e5436536SAndroid Build Coastguard Worker         }
575*e5436536SAndroid Build Coastguard Worker       }
576*e5436536SAndroid Build Coastguard Worker       /* LFE channels */
577*e5436536SAndroid Build Coastguard Worker       if (pPce1->NumLfeChannelElements != pPce2->NumLfeChannelElements) {
578*e5436536SAndroid Build Coastguard Worker         result = 2; /* different number of lfe channels */
579*e5436536SAndroid Build Coastguard Worker       }
580*e5436536SAndroid Build Coastguard Worker       /* LFEs are always SCEs so we don't need to count the channels. */
581*e5436536SAndroid Build Coastguard Worker     }
582*e5436536SAndroid Build Coastguard Worker   }
583*e5436536SAndroid Build Coastguard Worker 
584*e5436536SAndroid Build Coastguard Worker   return result;
585*e5436536SAndroid Build Coastguard Worker }
586*e5436536SAndroid Build Coastguard Worker 
CProgramConfig_GetDefault(CProgramConfig * pPce,const UINT channelConfig)587*e5436536SAndroid Build Coastguard Worker void CProgramConfig_GetDefault(CProgramConfig *pPce, const UINT channelConfig) {
588*e5436536SAndroid Build Coastguard Worker   FDK_ASSERT(pPce != NULL);
589*e5436536SAndroid Build Coastguard Worker 
590*e5436536SAndroid Build Coastguard Worker   /* Init PCE */
591*e5436536SAndroid Build Coastguard Worker   CProgramConfig_Init(pPce);
592*e5436536SAndroid Build Coastguard Worker   pPce->Profile =
593*e5436536SAndroid Build Coastguard Worker       1; /* Set AAC LC because it is the only supported object type. */
594*e5436536SAndroid Build Coastguard Worker 
595*e5436536SAndroid Build Coastguard Worker   switch (channelConfig) {
596*e5436536SAndroid Build Coastguard Worker     /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
597*e5436536SAndroid Build Coastguard Worker     case 32: /* 7.1 side channel configuration as defined in FDK_audio.h */
598*e5436536SAndroid Build Coastguard Worker       pPce->NumFrontChannelElements = 2;
599*e5436536SAndroid Build Coastguard Worker       pPce->FrontElementIsCpe[0] = 0;
600*e5436536SAndroid Build Coastguard Worker       pPce->FrontElementIsCpe[1] = 1;
601*e5436536SAndroid Build Coastguard Worker       pPce->NumSideChannelElements = 1;
602*e5436536SAndroid Build Coastguard Worker       pPce->SideElementIsCpe[0] = 1;
603*e5436536SAndroid Build Coastguard Worker       pPce->NumBackChannelElements = 1;
604*e5436536SAndroid Build Coastguard Worker       pPce->BackElementIsCpe[0] = 1;
605*e5436536SAndroid Build Coastguard Worker       pPce->NumLfeChannelElements = 1;
606*e5436536SAndroid Build Coastguard Worker       pPce->NumChannels = 8;
607*e5436536SAndroid Build Coastguard Worker       pPce->NumEffectiveChannels = 7;
608*e5436536SAndroid Build Coastguard Worker       pPce->isValid = 1;
609*e5436536SAndroid Build Coastguard Worker       break;
610*e5436536SAndroid Build Coastguard Worker     /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
611*e5436536SAndroid Build Coastguard Worker     case 12: /* 3/0/4.1ch surround back */
612*e5436536SAndroid Build Coastguard Worker       pPce->BackElementIsCpe[1] = 1;
613*e5436536SAndroid Build Coastguard Worker       pPce->NumChannels += 1;
614*e5436536SAndroid Build Coastguard Worker       pPce->NumEffectiveChannels += 1;
615*e5436536SAndroid Build Coastguard Worker       FDK_FALLTHROUGH;
616*e5436536SAndroid Build Coastguard Worker     case 11: /* 3/0/3.1ch */
617*e5436536SAndroid Build Coastguard Worker       pPce->NumFrontChannelElements += 2;
618*e5436536SAndroid Build Coastguard Worker       pPce->FrontElementIsCpe[0] = 0;
619*e5436536SAndroid Build Coastguard Worker       pPce->FrontElementIsCpe[1] = 1;
620*e5436536SAndroid Build Coastguard Worker       pPce->NumBackChannelElements += 2;
621*e5436536SAndroid Build Coastguard Worker       pPce->BackElementIsCpe[0] = 1;
622*e5436536SAndroid Build Coastguard Worker       pPce->BackElementIsCpe[1] += 0;
623*e5436536SAndroid Build Coastguard Worker       pPce->NumLfeChannelElements += 1;
624*e5436536SAndroid Build Coastguard Worker       pPce->NumChannels += 7;
625*e5436536SAndroid Build Coastguard Worker       pPce->NumEffectiveChannels += 6;
626*e5436536SAndroid Build Coastguard Worker       pPce->isValid = 1;
627*e5436536SAndroid Build Coastguard Worker       break;
628*e5436536SAndroid Build Coastguard Worker     /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
629*e5436536SAndroid Build Coastguard Worker     case 14:                               /* 2/0/0-3/0/2-0.1ch front height */
630*e5436536SAndroid Build Coastguard Worker       pPce->FrontElementHeightInfo[2] = 1; /* Top speaker */
631*e5436536SAndroid Build Coastguard Worker       FDK_FALLTHROUGH;
632*e5436536SAndroid Build Coastguard Worker     case 7: /* 5/0/2.1ch front */
633*e5436536SAndroid Build Coastguard Worker       pPce->NumFrontChannelElements += 1;
634*e5436536SAndroid Build Coastguard Worker       pPce->FrontElementIsCpe[2] = 1;
635*e5436536SAndroid Build Coastguard Worker       pPce->NumChannels += 2;
636*e5436536SAndroid Build Coastguard Worker       pPce->NumEffectiveChannels += 2;
637*e5436536SAndroid Build Coastguard Worker       FDK_FALLTHROUGH;
638*e5436536SAndroid Build Coastguard Worker     case 6: /* 3/0/2.1ch */
639*e5436536SAndroid Build Coastguard Worker       pPce->NumLfeChannelElements += 1;
640*e5436536SAndroid Build Coastguard Worker       pPce->NumChannels += 1;
641*e5436536SAndroid Build Coastguard Worker       FDK_FALLTHROUGH;
642*e5436536SAndroid Build Coastguard Worker     case 5: /* 3/0/2.0ch */
643*e5436536SAndroid Build Coastguard Worker     case 4: /* 3/0/1.0ch */
644*e5436536SAndroid Build Coastguard Worker       pPce->NumBackChannelElements += 1;
645*e5436536SAndroid Build Coastguard Worker       pPce->BackElementIsCpe[0] = (channelConfig > 4) ? 1 : 0;
646*e5436536SAndroid Build Coastguard Worker       pPce->NumChannels += (channelConfig > 4) ? 2 : 1;
647*e5436536SAndroid Build Coastguard Worker       pPce->NumEffectiveChannels += (channelConfig > 4) ? 2 : 1;
648*e5436536SAndroid Build Coastguard Worker       FDK_FALLTHROUGH;
649*e5436536SAndroid Build Coastguard Worker     case 3: /* 3/0/0.0ch */
650*e5436536SAndroid Build Coastguard Worker       pPce->NumFrontChannelElements += 1;
651*e5436536SAndroid Build Coastguard Worker       pPce->FrontElementIsCpe[1] = 1;
652*e5436536SAndroid Build Coastguard Worker       pPce->NumChannels += 2;
653*e5436536SAndroid Build Coastguard Worker       pPce->NumEffectiveChannels += 2;
654*e5436536SAndroid Build Coastguard Worker       FDK_FALLTHROUGH;
655*e5436536SAndroid Build Coastguard Worker     case 1: /* 1/0/0.0ch */
656*e5436536SAndroid Build Coastguard Worker       pPce->NumFrontChannelElements += 1;
657*e5436536SAndroid Build Coastguard Worker       pPce->FrontElementIsCpe[0] = 0;
658*e5436536SAndroid Build Coastguard Worker       pPce->NumChannels += 1;
659*e5436536SAndroid Build Coastguard Worker       pPce->NumEffectiveChannels += 1;
660*e5436536SAndroid Build Coastguard Worker       pPce->isValid = 1;
661*e5436536SAndroid Build Coastguard Worker       break;
662*e5436536SAndroid Build Coastguard Worker     /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
663*e5436536SAndroid Build Coastguard Worker     case 2: /* 2/0/0.ch */
664*e5436536SAndroid Build Coastguard Worker       pPce->NumFrontChannelElements = 1;
665*e5436536SAndroid Build Coastguard Worker       pPce->FrontElementIsCpe[0] = 1;
666*e5436536SAndroid Build Coastguard Worker       pPce->NumChannels += 2;
667*e5436536SAndroid Build Coastguard Worker       pPce->NumEffectiveChannels += 2;
668*e5436536SAndroid Build Coastguard Worker       pPce->isValid = 1;
669*e5436536SAndroid Build Coastguard Worker       break;
670*e5436536SAndroid Build Coastguard Worker     /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
671*e5436536SAndroid Build Coastguard Worker     default:
672*e5436536SAndroid Build Coastguard Worker       pPce->isValid = 0; /* To be explicit! */
673*e5436536SAndroid Build Coastguard Worker       break;
674*e5436536SAndroid Build Coastguard Worker   }
675*e5436536SAndroid Build Coastguard Worker 
676*e5436536SAndroid Build Coastguard Worker   if (pPce->isValid) {
677*e5436536SAndroid Build Coastguard Worker     /* Create valid element instance tags */
678*e5436536SAndroid Build Coastguard Worker     int el, elTagSce = 0, elTagCpe = 0;
679*e5436536SAndroid Build Coastguard Worker 
680*e5436536SAndroid Build Coastguard Worker     for (el = 0; el < pPce->NumFrontChannelElements; el += 1) {
681*e5436536SAndroid Build Coastguard Worker       pPce->FrontElementTagSelect[el] =
682*e5436536SAndroid Build Coastguard Worker           (pPce->FrontElementIsCpe[el]) ? elTagCpe++ : elTagSce++;
683*e5436536SAndroid Build Coastguard Worker     }
684*e5436536SAndroid Build Coastguard Worker     for (el = 0; el < pPce->NumSideChannelElements; el += 1) {
685*e5436536SAndroid Build Coastguard Worker       pPce->SideElementTagSelect[el] =
686*e5436536SAndroid Build Coastguard Worker           (pPce->SideElementIsCpe[el]) ? elTagCpe++ : elTagSce++;
687*e5436536SAndroid Build Coastguard Worker     }
688*e5436536SAndroid Build Coastguard Worker     for (el = 0; el < pPce->NumBackChannelElements; el += 1) {
689*e5436536SAndroid Build Coastguard Worker       pPce->BackElementTagSelect[el] =
690*e5436536SAndroid Build Coastguard Worker           (pPce->BackElementIsCpe[el]) ? elTagCpe++ : elTagSce++;
691*e5436536SAndroid Build Coastguard Worker     }
692*e5436536SAndroid Build Coastguard Worker     elTagSce = 0;
693*e5436536SAndroid Build Coastguard Worker     for (el = 0; el < pPce->NumLfeChannelElements; el += 1) {
694*e5436536SAndroid Build Coastguard Worker       pPce->LfeElementTagSelect[el] = elTagSce++;
695*e5436536SAndroid Build Coastguard Worker     }
696*e5436536SAndroid Build Coastguard Worker   }
697*e5436536SAndroid Build Coastguard Worker }
698*e5436536SAndroid Build Coastguard Worker 
699*e5436536SAndroid Build Coastguard Worker /**
700*e5436536SAndroid Build Coastguard Worker  * \brief get implicit audio channel type for given channelConfig and MPEG
701*e5436536SAndroid Build Coastguard Worker  * ordered channel index
702*e5436536SAndroid Build Coastguard Worker  * \param channelConfig MPEG channelConfiguration from 1 upto 14
703*e5436536SAndroid Build Coastguard Worker  * \param index MPEG channel order index
704*e5436536SAndroid Build Coastguard Worker  * \return audio channel type.
705*e5436536SAndroid Build Coastguard Worker  */
getImplicitAudioChannelTypeAndIndex(AUDIO_CHANNEL_TYPE * chType,UCHAR * chIndex,UINT channelConfig,UINT index)706*e5436536SAndroid Build Coastguard Worker static void getImplicitAudioChannelTypeAndIndex(AUDIO_CHANNEL_TYPE *chType,
707*e5436536SAndroid Build Coastguard Worker                                                 UCHAR *chIndex,
708*e5436536SAndroid Build Coastguard Worker                                                 UINT channelConfig,
709*e5436536SAndroid Build Coastguard Worker                                                 UINT index) {
710*e5436536SAndroid Build Coastguard Worker   if (index < 3) {
711*e5436536SAndroid Build Coastguard Worker     *chType = ACT_FRONT;
712*e5436536SAndroid Build Coastguard Worker     *chIndex = index;
713*e5436536SAndroid Build Coastguard Worker   } else {
714*e5436536SAndroid Build Coastguard Worker     switch (channelConfig) {
715*e5436536SAndroid Build Coastguard Worker       case 4: /* SCE, CPE, SCE */
716*e5436536SAndroid Build Coastguard Worker       case 5: /* SCE, CPE, CPE */
717*e5436536SAndroid Build Coastguard Worker       case 6: /* SCE, CPE, CPE, LFE */
718*e5436536SAndroid Build Coastguard Worker         switch (index) {
719*e5436536SAndroid Build Coastguard Worker           case 3:
720*e5436536SAndroid Build Coastguard Worker           case 4:
721*e5436536SAndroid Build Coastguard Worker             *chType = ACT_BACK;
722*e5436536SAndroid Build Coastguard Worker             *chIndex = index - 3;
723*e5436536SAndroid Build Coastguard Worker             break;
724*e5436536SAndroid Build Coastguard Worker           case 5:
725*e5436536SAndroid Build Coastguard Worker             *chType = ACT_LFE;
726*e5436536SAndroid Build Coastguard Worker             *chIndex = 0;
727*e5436536SAndroid Build Coastguard Worker             break;
728*e5436536SAndroid Build Coastguard Worker         }
729*e5436536SAndroid Build Coastguard Worker         break;
730*e5436536SAndroid Build Coastguard Worker       case 7: /* SCE,CPE,CPE,CPE,LFE */
731*e5436536SAndroid Build Coastguard Worker         switch (index) {
732*e5436536SAndroid Build Coastguard Worker           case 3:
733*e5436536SAndroid Build Coastguard Worker           case 4:
734*e5436536SAndroid Build Coastguard Worker             *chType = ACT_FRONT;
735*e5436536SAndroid Build Coastguard Worker             *chIndex = index;
736*e5436536SAndroid Build Coastguard Worker             break;
737*e5436536SAndroid Build Coastguard Worker           case 5:
738*e5436536SAndroid Build Coastguard Worker           case 6:
739*e5436536SAndroid Build Coastguard Worker             *chType = ACT_BACK;
740*e5436536SAndroid Build Coastguard Worker             *chIndex = index - 5;
741*e5436536SAndroid Build Coastguard Worker             break;
742*e5436536SAndroid Build Coastguard Worker           case 7:
743*e5436536SAndroid Build Coastguard Worker             *chType = ACT_LFE;
744*e5436536SAndroid Build Coastguard Worker             *chIndex = 0;
745*e5436536SAndroid Build Coastguard Worker             break;
746*e5436536SAndroid Build Coastguard Worker         }
747*e5436536SAndroid Build Coastguard Worker         break;
748*e5436536SAndroid Build Coastguard Worker       case 11: /* SCE,CPE,CPE,SCE,LFE */
749*e5436536SAndroid Build Coastguard Worker         if (index < 6) {
750*e5436536SAndroid Build Coastguard Worker           *chType = ACT_BACK;
751*e5436536SAndroid Build Coastguard Worker           *chIndex = index - 3;
752*e5436536SAndroid Build Coastguard Worker         } else {
753*e5436536SAndroid Build Coastguard Worker           *chType = ACT_LFE;
754*e5436536SAndroid Build Coastguard Worker           *chIndex = 0;
755*e5436536SAndroid Build Coastguard Worker         }
756*e5436536SAndroid Build Coastguard Worker         break;
757*e5436536SAndroid Build Coastguard Worker       case 12: /* SCE,CPE,CPE,CPE,LFE */
758*e5436536SAndroid Build Coastguard Worker         if (index < 7) {
759*e5436536SAndroid Build Coastguard Worker           *chType = ACT_BACK;
760*e5436536SAndroid Build Coastguard Worker           *chIndex = index - 3;
761*e5436536SAndroid Build Coastguard Worker         } else {
762*e5436536SAndroid Build Coastguard Worker           *chType = ACT_LFE;
763*e5436536SAndroid Build Coastguard Worker           *chIndex = 0;
764*e5436536SAndroid Build Coastguard Worker         }
765*e5436536SAndroid Build Coastguard Worker         break;
766*e5436536SAndroid Build Coastguard Worker       case 14: /* SCE,CPE,CPE,LFE,CPE */
767*e5436536SAndroid Build Coastguard Worker         switch (index) {
768*e5436536SAndroid Build Coastguard Worker           case 3:
769*e5436536SAndroid Build Coastguard Worker           case 4:
770*e5436536SAndroid Build Coastguard Worker             *chType = ACT_BACK;
771*e5436536SAndroid Build Coastguard Worker             *chIndex = index - 3;
772*e5436536SAndroid Build Coastguard Worker             break;
773*e5436536SAndroid Build Coastguard Worker           case 5:
774*e5436536SAndroid Build Coastguard Worker             *chType = ACT_LFE;
775*e5436536SAndroid Build Coastguard Worker             *chIndex = 0;
776*e5436536SAndroid Build Coastguard Worker             break;
777*e5436536SAndroid Build Coastguard Worker           case 6:
778*e5436536SAndroid Build Coastguard Worker           case 7:
779*e5436536SAndroid Build Coastguard Worker             *chType = ACT_FRONT_TOP;
780*e5436536SAndroid Build Coastguard Worker             *chIndex = index - 6; /* handle the top layer independently */
781*e5436536SAndroid Build Coastguard Worker             break;
782*e5436536SAndroid Build Coastguard Worker         }
783*e5436536SAndroid Build Coastguard Worker         break;
784*e5436536SAndroid Build Coastguard Worker       default:
785*e5436536SAndroid Build Coastguard Worker         *chType = ACT_NONE;
786*e5436536SAndroid Build Coastguard Worker         break;
787*e5436536SAndroid Build Coastguard Worker     }
788*e5436536SAndroid Build Coastguard Worker   }
789*e5436536SAndroid Build Coastguard Worker }
790*e5436536SAndroid Build Coastguard Worker 
CProgramConfig_LookupElement(CProgramConfig * pPce,UINT channelConfig,const UINT tag,const UINT channelIdx,UCHAR chMapping[],AUDIO_CHANNEL_TYPE chType[],UCHAR chIndex[],const UINT chDescrLen,UCHAR * elMapping,MP4_ELEMENT_ID elList[],MP4_ELEMENT_ID elType)791*e5436536SAndroid Build Coastguard Worker int CProgramConfig_LookupElement(CProgramConfig *pPce, UINT channelConfig,
792*e5436536SAndroid Build Coastguard Worker                                  const UINT tag, const UINT channelIdx,
793*e5436536SAndroid Build Coastguard Worker                                  UCHAR chMapping[], AUDIO_CHANNEL_TYPE chType[],
794*e5436536SAndroid Build Coastguard Worker                                  UCHAR chIndex[], const UINT chDescrLen,
795*e5436536SAndroid Build Coastguard Worker                                  UCHAR *elMapping, MP4_ELEMENT_ID elList[],
796*e5436536SAndroid Build Coastguard Worker                                  MP4_ELEMENT_ID elType) {
797*e5436536SAndroid Build Coastguard Worker   if (channelConfig > 0) {
798*e5436536SAndroid Build Coastguard Worker     /* Constant channel mapping must have
799*e5436536SAndroid Build Coastguard Worker        been set during initialization. */
800*e5436536SAndroid Build Coastguard Worker     if (IS_CHANNEL_ELEMENT(elType)) {
801*e5436536SAndroid Build Coastguard Worker       *elMapping = pPce->elCounter;
802*e5436536SAndroid Build Coastguard Worker       if (elList[pPce->elCounter] != elType &&
803*e5436536SAndroid Build Coastguard Worker           !IS_USAC_CHANNEL_ELEMENT(elType)) {
804*e5436536SAndroid Build Coastguard Worker         /* Not in the list */
805*e5436536SAndroid Build Coastguard Worker         if ((channelConfig == 2) &&
806*e5436536SAndroid Build Coastguard Worker             (elType == ID_SCE)) { /* This scenario occurs with HE-AAC v2 streams
807*e5436536SAndroid Build Coastguard Worker                                      of buggy encoders. In other decoder
808*e5436536SAndroid Build Coastguard Worker                                      implementations decoding of this kind of
809*e5436536SAndroid Build Coastguard Worker                                      streams is desired. */
810*e5436536SAndroid Build Coastguard Worker           channelConfig = 1;
811*e5436536SAndroid Build Coastguard Worker         } else if ((elList[pPce->elCounter] == ID_LFE) &&
812*e5436536SAndroid Build Coastguard Worker                    (elType ==
813*e5436536SAndroid Build Coastguard Worker                     ID_SCE)) { /* Decode bitstreams which wrongly use ID_SCE
814*e5436536SAndroid Build Coastguard Worker                                   instead of ID_LFE element type. */
815*e5436536SAndroid Build Coastguard Worker           ;
816*e5436536SAndroid Build Coastguard Worker         } else {
817*e5436536SAndroid Build Coastguard Worker           return 0;
818*e5436536SAndroid Build Coastguard Worker         }
819*e5436536SAndroid Build Coastguard Worker       }
820*e5436536SAndroid Build Coastguard Worker       /* Assume all front channels */
821*e5436536SAndroid Build Coastguard Worker       getImplicitAudioChannelTypeAndIndex(
822*e5436536SAndroid Build Coastguard Worker           &chType[channelIdx], &chIndex[channelIdx], channelConfig, channelIdx);
823*e5436536SAndroid Build Coastguard Worker       if (elType == ID_CPE || elType == ID_USAC_CPE) {
824*e5436536SAndroid Build Coastguard Worker         chType[channelIdx + 1] = chType[channelIdx];
825*e5436536SAndroid Build Coastguard Worker         chIndex[channelIdx + 1] = chIndex[channelIdx] + 1;
826*e5436536SAndroid Build Coastguard Worker       }
827*e5436536SAndroid Build Coastguard Worker       pPce->elCounter++;
828*e5436536SAndroid Build Coastguard Worker     }
829*e5436536SAndroid Build Coastguard Worker     /* Accept all non-channel elements, too. */
830*e5436536SAndroid Build Coastguard Worker     return 1;
831*e5436536SAndroid Build Coastguard Worker   } else {
832*e5436536SAndroid Build Coastguard Worker     if ((!pPce->isValid) || (pPce->NumChannels > chDescrLen)) {
833*e5436536SAndroid Build Coastguard Worker       /* Implicit channel mapping. */
834*e5436536SAndroid Build Coastguard Worker       if (IS_USAC_CHANNEL_ELEMENT(elType)) {
835*e5436536SAndroid Build Coastguard Worker         *elMapping = pPce->elCounter++;
836*e5436536SAndroid Build Coastguard Worker       } else if (IS_MP4_CHANNEL_ELEMENT(elType)) {
837*e5436536SAndroid Build Coastguard Worker         /* Store all channel element IDs */
838*e5436536SAndroid Build Coastguard Worker         elList[pPce->elCounter] = elType;
839*e5436536SAndroid Build Coastguard Worker         *elMapping = pPce->elCounter++;
840*e5436536SAndroid Build Coastguard Worker       }
841*e5436536SAndroid Build Coastguard Worker     } else {
842*e5436536SAndroid Build Coastguard Worker       /* Accept the additional channel(s), only if the tag is in the lists */
843*e5436536SAndroid Build Coastguard Worker       int isCpe = 0, i;
844*e5436536SAndroid Build Coastguard Worker       /* Element counter */
845*e5436536SAndroid Build Coastguard Worker       int ec[PC_NUM_HEIGHT_LAYER] = {0};
846*e5436536SAndroid Build Coastguard Worker       /* Channel counters */
847*e5436536SAndroid Build Coastguard Worker       int cc[PC_NUM_HEIGHT_LAYER] = {0};
848*e5436536SAndroid Build Coastguard Worker       int fc[PC_NUM_HEIGHT_LAYER] = {0}; /* front channel counter */
849*e5436536SAndroid Build Coastguard Worker       int sc[PC_NUM_HEIGHT_LAYER] = {0}; /* side channel counter */
850*e5436536SAndroid Build Coastguard Worker       int bc[PC_NUM_HEIGHT_LAYER] = {0}; /* back channel counter */
851*e5436536SAndroid Build Coastguard Worker       int lc = 0;                        /* lfe channel counter */
852*e5436536SAndroid Build Coastguard Worker 
853*e5436536SAndroid Build Coastguard Worker       /* General MPEG (PCE) composition rules:
854*e5436536SAndroid Build Coastguard Worker          - Over all:
855*e5436536SAndroid Build Coastguard Worker              <normal height channels><top height channels><bottom height
856*e5436536SAndroid Build Coastguard Worker          channels>
857*e5436536SAndroid Build Coastguard Worker          - Within each height layer:
858*e5436536SAndroid Build Coastguard Worker              <front channels><side channels><back channels>
859*e5436536SAndroid Build Coastguard Worker          - Exception:
860*e5436536SAndroid Build Coastguard Worker              The LFE channels have no height info and thus they are arranged at
861*e5436536SAndroid Build Coastguard Worker          the very end of the normal height layer channels.
862*e5436536SAndroid Build Coastguard Worker        */
863*e5436536SAndroid Build Coastguard Worker 
864*e5436536SAndroid Build Coastguard Worker       switch (elType) {
865*e5436536SAndroid Build Coastguard Worker         case ID_CPE:
866*e5436536SAndroid Build Coastguard Worker           isCpe = 1;
867*e5436536SAndroid Build Coastguard Worker           FDK_FALLTHROUGH;
868*e5436536SAndroid Build Coastguard Worker         case ID_SCE:
869*e5436536SAndroid Build Coastguard Worker           /* search in front channels */
870*e5436536SAndroid Build Coastguard Worker           for (i = 0; i < pPce->NumFrontChannelElements; i++) {
871*e5436536SAndroid Build Coastguard Worker             int heightLayer = pPce->FrontElementHeightInfo[i];
872*e5436536SAndroid Build Coastguard Worker             if (isCpe == pPce->FrontElementIsCpe[i] &&
873*e5436536SAndroid Build Coastguard Worker                 pPce->FrontElementTagSelect[i] == tag) {
874*e5436536SAndroid Build Coastguard Worker               int h, elIdx = ec[heightLayer], chIdx = cc[heightLayer];
875*e5436536SAndroid Build Coastguard Worker               AUDIO_CHANNEL_TYPE aChType =
876*e5436536SAndroid Build Coastguard Worker                   (AUDIO_CHANNEL_TYPE)((heightLayer << 4) | ACT_FRONT);
877*e5436536SAndroid Build Coastguard Worker               for (h = heightLayer - 1; h >= 0; h -= 1) {
878*e5436536SAndroid Build Coastguard Worker                 int el;
879*e5436536SAndroid Build Coastguard Worker                 /* Count front channels/elements */
880*e5436536SAndroid Build Coastguard Worker                 for (el = 0; el < pPce->NumFrontChannelElements; el += 1) {
881*e5436536SAndroid Build Coastguard Worker                   if (pPce->FrontElementHeightInfo[el] == h) {
882*e5436536SAndroid Build Coastguard Worker                     elIdx += 1;
883*e5436536SAndroid Build Coastguard Worker                     chIdx += (pPce->FrontElementIsCpe[el]) ? 2 : 1;
884*e5436536SAndroid Build Coastguard Worker                   }
885*e5436536SAndroid Build Coastguard Worker                 }
886*e5436536SAndroid Build Coastguard Worker                 /* Count side channels/elements */
887*e5436536SAndroid Build Coastguard Worker                 for (el = 0; el < pPce->NumSideChannelElements; el += 1) {
888*e5436536SAndroid Build Coastguard Worker                   if (pPce->SideElementHeightInfo[el] == h) {
889*e5436536SAndroid Build Coastguard Worker                     elIdx += 1;
890*e5436536SAndroid Build Coastguard Worker                     chIdx += (pPce->SideElementIsCpe[el]) ? 2 : 1;
891*e5436536SAndroid Build Coastguard Worker                   }
892*e5436536SAndroid Build Coastguard Worker                 }
893*e5436536SAndroid Build Coastguard Worker                 /* Count back channels/elements */
894*e5436536SAndroid Build Coastguard Worker                 for (el = 0; el < pPce->NumBackChannelElements; el += 1) {
895*e5436536SAndroid Build Coastguard Worker                   if (pPce->BackElementHeightInfo[el] == h) {
896*e5436536SAndroid Build Coastguard Worker                     elIdx += 1;
897*e5436536SAndroid Build Coastguard Worker                     chIdx += (pPce->BackElementIsCpe[el]) ? 2 : 1;
898*e5436536SAndroid Build Coastguard Worker                   }
899*e5436536SAndroid Build Coastguard Worker                 }
900*e5436536SAndroid Build Coastguard Worker                 if (h == 0) { /* normal height */
901*e5436536SAndroid Build Coastguard Worker                   elIdx += pPce->NumLfeChannelElements;
902*e5436536SAndroid Build Coastguard Worker                   chIdx += pPce->NumLfeChannelElements;
903*e5436536SAndroid Build Coastguard Worker                 }
904*e5436536SAndroid Build Coastguard Worker               }
905*e5436536SAndroid Build Coastguard Worker               chMapping[chIdx] = channelIdx;
906*e5436536SAndroid Build Coastguard Worker               chType[chIdx] = aChType;
907*e5436536SAndroid Build Coastguard Worker               chIndex[chIdx] = fc[heightLayer];
908*e5436536SAndroid Build Coastguard Worker               if (isCpe) {
909*e5436536SAndroid Build Coastguard Worker                 chMapping[chIdx + 1] = channelIdx + 1;
910*e5436536SAndroid Build Coastguard Worker                 chType[chIdx + 1] = aChType;
911*e5436536SAndroid Build Coastguard Worker                 chIndex[chIdx + 1] = fc[heightLayer] + 1;
912*e5436536SAndroid Build Coastguard Worker               }
913*e5436536SAndroid Build Coastguard Worker               *elMapping = elIdx;
914*e5436536SAndroid Build Coastguard Worker               return 1;
915*e5436536SAndroid Build Coastguard Worker             }
916*e5436536SAndroid Build Coastguard Worker             ec[heightLayer] += 1;
917*e5436536SAndroid Build Coastguard Worker             if (pPce->FrontElementIsCpe[i]) {
918*e5436536SAndroid Build Coastguard Worker               cc[heightLayer] += 2;
919*e5436536SAndroid Build Coastguard Worker               fc[heightLayer] += 2;
920*e5436536SAndroid Build Coastguard Worker             } else {
921*e5436536SAndroid Build Coastguard Worker               cc[heightLayer] += 1;
922*e5436536SAndroid Build Coastguard Worker               fc[heightLayer] += 1;
923*e5436536SAndroid Build Coastguard Worker             }
924*e5436536SAndroid Build Coastguard Worker           }
925*e5436536SAndroid Build Coastguard Worker           /* search in side channels */
926*e5436536SAndroid Build Coastguard Worker           for (i = 0; i < pPce->NumSideChannelElements; i++) {
927*e5436536SAndroid Build Coastguard Worker             int heightLayer = pPce->SideElementHeightInfo[i];
928*e5436536SAndroid Build Coastguard Worker             if (isCpe == pPce->SideElementIsCpe[i] &&
929*e5436536SAndroid Build Coastguard Worker                 pPce->SideElementTagSelect[i] == tag) {
930*e5436536SAndroid Build Coastguard Worker               int h, elIdx = ec[heightLayer], chIdx = cc[heightLayer];
931*e5436536SAndroid Build Coastguard Worker               AUDIO_CHANNEL_TYPE aChType =
932*e5436536SAndroid Build Coastguard Worker                   (AUDIO_CHANNEL_TYPE)((heightLayer << 4) | ACT_SIDE);
933*e5436536SAndroid Build Coastguard Worker               for (h = heightLayer - 1; h >= 0; h -= 1) {
934*e5436536SAndroid Build Coastguard Worker                 int el;
935*e5436536SAndroid Build Coastguard Worker                 /* Count front channels/elements */
936*e5436536SAndroid Build Coastguard Worker                 for (el = 0; el < pPce->NumFrontChannelElements; el += 1) {
937*e5436536SAndroid Build Coastguard Worker                   if (pPce->FrontElementHeightInfo[el] == h) {
938*e5436536SAndroid Build Coastguard Worker                     elIdx += 1;
939*e5436536SAndroid Build Coastguard Worker                     chIdx += (pPce->FrontElementIsCpe[el]) ? 2 : 1;
940*e5436536SAndroid Build Coastguard Worker                   }
941*e5436536SAndroid Build Coastguard Worker                 }
942*e5436536SAndroid Build Coastguard Worker                 /* Count side channels/elements */
943*e5436536SAndroid Build Coastguard Worker                 for (el = 0; el < pPce->NumSideChannelElements; el += 1) {
944*e5436536SAndroid Build Coastguard Worker                   if (pPce->SideElementHeightInfo[el] == h) {
945*e5436536SAndroid Build Coastguard Worker                     elIdx += 1;
946*e5436536SAndroid Build Coastguard Worker                     chIdx += (pPce->SideElementIsCpe[el]) ? 2 : 1;
947*e5436536SAndroid Build Coastguard Worker                   }
948*e5436536SAndroid Build Coastguard Worker                 }
949*e5436536SAndroid Build Coastguard Worker                 /* Count back channels/elements */
950*e5436536SAndroid Build Coastguard Worker                 for (el = 0; el < pPce->NumBackChannelElements; el += 1) {
951*e5436536SAndroid Build Coastguard Worker                   if (pPce->BackElementHeightInfo[el] == h) {
952*e5436536SAndroid Build Coastguard Worker                     elIdx += 1;
953*e5436536SAndroid Build Coastguard Worker                     chIdx += (pPce->BackElementIsCpe[el]) ? 2 : 1;
954*e5436536SAndroid Build Coastguard Worker                   }
955*e5436536SAndroid Build Coastguard Worker                 }
956*e5436536SAndroid Build Coastguard Worker                 if (h ==
957*e5436536SAndroid Build Coastguard Worker                     0) { /* LFE channels belong to the normal height layer */
958*e5436536SAndroid Build Coastguard Worker                   elIdx += pPce->NumLfeChannelElements;
959*e5436536SAndroid Build Coastguard Worker                   chIdx += pPce->NumLfeChannelElements;
960*e5436536SAndroid Build Coastguard Worker                 }
961*e5436536SAndroid Build Coastguard Worker               }
962*e5436536SAndroid Build Coastguard Worker               chMapping[chIdx] = channelIdx;
963*e5436536SAndroid Build Coastguard Worker               chType[chIdx] = aChType;
964*e5436536SAndroid Build Coastguard Worker               chIndex[chIdx] = sc[heightLayer];
965*e5436536SAndroid Build Coastguard Worker               if (isCpe) {
966*e5436536SAndroid Build Coastguard Worker                 chMapping[chIdx + 1] = channelIdx + 1;
967*e5436536SAndroid Build Coastguard Worker                 chType[chIdx + 1] = aChType;
968*e5436536SAndroid Build Coastguard Worker                 chIndex[chIdx + 1] = sc[heightLayer] + 1;
969*e5436536SAndroid Build Coastguard Worker               }
970*e5436536SAndroid Build Coastguard Worker               *elMapping = elIdx;
971*e5436536SAndroid Build Coastguard Worker               return 1;
972*e5436536SAndroid Build Coastguard Worker             }
973*e5436536SAndroid Build Coastguard Worker             ec[heightLayer] += 1;
974*e5436536SAndroid Build Coastguard Worker             if (pPce->SideElementIsCpe[i]) {
975*e5436536SAndroid Build Coastguard Worker               cc[heightLayer] += 2;
976*e5436536SAndroid Build Coastguard Worker               sc[heightLayer] += 2;
977*e5436536SAndroid Build Coastguard Worker             } else {
978*e5436536SAndroid Build Coastguard Worker               cc[heightLayer] += 1;
979*e5436536SAndroid Build Coastguard Worker               sc[heightLayer] += 1;
980*e5436536SAndroid Build Coastguard Worker             }
981*e5436536SAndroid Build Coastguard Worker           }
982*e5436536SAndroid Build Coastguard Worker           /* search in back channels */
983*e5436536SAndroid Build Coastguard Worker           for (i = 0; i < pPce->NumBackChannelElements; i++) {
984*e5436536SAndroid Build Coastguard Worker             int heightLayer = pPce->BackElementHeightInfo[i];
985*e5436536SAndroid Build Coastguard Worker             if (isCpe == pPce->BackElementIsCpe[i] &&
986*e5436536SAndroid Build Coastguard Worker                 pPce->BackElementTagSelect[i] == tag) {
987*e5436536SAndroid Build Coastguard Worker               int h, elIdx = ec[heightLayer], chIdx = cc[heightLayer];
988*e5436536SAndroid Build Coastguard Worker               AUDIO_CHANNEL_TYPE aChType =
989*e5436536SAndroid Build Coastguard Worker                   (AUDIO_CHANNEL_TYPE)((heightLayer << 4) | ACT_BACK);
990*e5436536SAndroid Build Coastguard Worker               for (h = heightLayer - 1; h >= 0; h -= 1) {
991*e5436536SAndroid Build Coastguard Worker                 int el;
992*e5436536SAndroid Build Coastguard Worker                 /* Count front channels/elements */
993*e5436536SAndroid Build Coastguard Worker                 for (el = 0; el < pPce->NumFrontChannelElements; el += 1) {
994*e5436536SAndroid Build Coastguard Worker                   if (pPce->FrontElementHeightInfo[el] == h) {
995*e5436536SAndroid Build Coastguard Worker                     elIdx += 1;
996*e5436536SAndroid Build Coastguard Worker                     chIdx += (pPce->FrontElementIsCpe[el]) ? 2 : 1;
997*e5436536SAndroid Build Coastguard Worker                   }
998*e5436536SAndroid Build Coastguard Worker                 }
999*e5436536SAndroid Build Coastguard Worker                 /* Count side channels/elements */
1000*e5436536SAndroid Build Coastguard Worker                 for (el = 0; el < pPce->NumSideChannelElements; el += 1) {
1001*e5436536SAndroid Build Coastguard Worker                   if (pPce->SideElementHeightInfo[el] == h) {
1002*e5436536SAndroid Build Coastguard Worker                     elIdx += 1;
1003*e5436536SAndroid Build Coastguard Worker                     chIdx += (pPce->SideElementIsCpe[el]) ? 2 : 1;
1004*e5436536SAndroid Build Coastguard Worker                   }
1005*e5436536SAndroid Build Coastguard Worker                 }
1006*e5436536SAndroid Build Coastguard Worker                 /* Count back channels/elements */
1007*e5436536SAndroid Build Coastguard Worker                 for (el = 0; el < pPce->NumBackChannelElements; el += 1) {
1008*e5436536SAndroid Build Coastguard Worker                   if (pPce->BackElementHeightInfo[el] == h) {
1009*e5436536SAndroid Build Coastguard Worker                     elIdx += 1;
1010*e5436536SAndroid Build Coastguard Worker                     chIdx += (pPce->BackElementIsCpe[el]) ? 2 : 1;
1011*e5436536SAndroid Build Coastguard Worker                   }
1012*e5436536SAndroid Build Coastguard Worker                 }
1013*e5436536SAndroid Build Coastguard Worker                 if (h == 0) { /* normal height */
1014*e5436536SAndroid Build Coastguard Worker                   elIdx += pPce->NumLfeChannelElements;
1015*e5436536SAndroid Build Coastguard Worker                   chIdx += pPce->NumLfeChannelElements;
1016*e5436536SAndroid Build Coastguard Worker                 }
1017*e5436536SAndroid Build Coastguard Worker               }
1018*e5436536SAndroid Build Coastguard Worker               chMapping[chIdx] = channelIdx;
1019*e5436536SAndroid Build Coastguard Worker               chType[chIdx] = aChType;
1020*e5436536SAndroid Build Coastguard Worker               chIndex[chIdx] = bc[heightLayer];
1021*e5436536SAndroid Build Coastguard Worker               if (isCpe) {
1022*e5436536SAndroid Build Coastguard Worker                 chMapping[chIdx + 1] = channelIdx + 1;
1023*e5436536SAndroid Build Coastguard Worker                 chType[chIdx + 1] = aChType;
1024*e5436536SAndroid Build Coastguard Worker                 chIndex[chIdx + 1] = bc[heightLayer] + 1;
1025*e5436536SAndroid Build Coastguard Worker               }
1026*e5436536SAndroid Build Coastguard Worker               *elMapping = elIdx;
1027*e5436536SAndroid Build Coastguard Worker               return 1;
1028*e5436536SAndroid Build Coastguard Worker             }
1029*e5436536SAndroid Build Coastguard Worker             ec[heightLayer] += 1;
1030*e5436536SAndroid Build Coastguard Worker             if (pPce->BackElementIsCpe[i]) {
1031*e5436536SAndroid Build Coastguard Worker               cc[heightLayer] += 2;
1032*e5436536SAndroid Build Coastguard Worker               bc[heightLayer] += 2;
1033*e5436536SAndroid Build Coastguard Worker             } else {
1034*e5436536SAndroid Build Coastguard Worker               cc[heightLayer] += 1;
1035*e5436536SAndroid Build Coastguard Worker               bc[heightLayer] += 1;
1036*e5436536SAndroid Build Coastguard Worker             }
1037*e5436536SAndroid Build Coastguard Worker           }
1038*e5436536SAndroid Build Coastguard Worker           break;
1039*e5436536SAndroid Build Coastguard Worker 
1040*e5436536SAndroid Build Coastguard Worker         case ID_LFE: { /* Unfortunately we have to go through all normal height
1041*e5436536SAndroid Build Coastguard Worker                           layer elements to get the position of the LFE
1042*e5436536SAndroid Build Coastguard Worker                           channels. Start with counting the front
1043*e5436536SAndroid Build Coastguard Worker                           channels/elements at normal height */
1044*e5436536SAndroid Build Coastguard Worker           for (i = 0; i < pPce->NumFrontChannelElements; i += 1) {
1045*e5436536SAndroid Build Coastguard Worker             int heightLayer = pPce->FrontElementHeightInfo[i];
1046*e5436536SAndroid Build Coastguard Worker             ec[heightLayer] += 1;
1047*e5436536SAndroid Build Coastguard Worker             cc[heightLayer] += (pPce->FrontElementIsCpe[i]) ? 2 : 1;
1048*e5436536SAndroid Build Coastguard Worker           }
1049*e5436536SAndroid Build Coastguard Worker           /* Count side channels/elements at normal height */
1050*e5436536SAndroid Build Coastguard Worker           for (i = 0; i < pPce->NumSideChannelElements; i += 1) {
1051*e5436536SAndroid Build Coastguard Worker             int heightLayer = pPce->SideElementHeightInfo[i];
1052*e5436536SAndroid Build Coastguard Worker             ec[heightLayer] += 1;
1053*e5436536SAndroid Build Coastguard Worker             cc[heightLayer] += (pPce->SideElementIsCpe[i]) ? 2 : 1;
1054*e5436536SAndroid Build Coastguard Worker           }
1055*e5436536SAndroid Build Coastguard Worker           /* Count back channels/elements at normal height */
1056*e5436536SAndroid Build Coastguard Worker           for (i = 0; i < pPce->NumBackChannelElements; i += 1) {
1057*e5436536SAndroid Build Coastguard Worker             int heightLayer = pPce->BackElementHeightInfo[i];
1058*e5436536SAndroid Build Coastguard Worker             ec[heightLayer] += 1;
1059*e5436536SAndroid Build Coastguard Worker             cc[heightLayer] += (pPce->BackElementIsCpe[i]) ? 2 : 1;
1060*e5436536SAndroid Build Coastguard Worker           }
1061*e5436536SAndroid Build Coastguard Worker 
1062*e5436536SAndroid Build Coastguard Worker           /* search in lfe channels */
1063*e5436536SAndroid Build Coastguard Worker           for (i = 0; i < pPce->NumLfeChannelElements; i++) {
1064*e5436536SAndroid Build Coastguard Worker             int elIdx =
1065*e5436536SAndroid Build Coastguard Worker                 ec[0]; /* LFE channels belong to the normal height layer */
1066*e5436536SAndroid Build Coastguard Worker             int chIdx = cc[0];
1067*e5436536SAndroid Build Coastguard Worker             if (pPce->LfeElementTagSelect[i] == tag) {
1068*e5436536SAndroid Build Coastguard Worker               chMapping[chIdx] = channelIdx;
1069*e5436536SAndroid Build Coastguard Worker               *elMapping = elIdx;
1070*e5436536SAndroid Build Coastguard Worker               chType[chIdx] = ACT_LFE;
1071*e5436536SAndroid Build Coastguard Worker               chIndex[chIdx] = lc;
1072*e5436536SAndroid Build Coastguard Worker               return 1;
1073*e5436536SAndroid Build Coastguard Worker             }
1074*e5436536SAndroid Build Coastguard Worker             ec[0] += 1;
1075*e5436536SAndroid Build Coastguard Worker             cc[0] += 1;
1076*e5436536SAndroid Build Coastguard Worker             lc += 1;
1077*e5436536SAndroid Build Coastguard Worker           }
1078*e5436536SAndroid Build Coastguard Worker         } break;
1079*e5436536SAndroid Build Coastguard Worker 
1080*e5436536SAndroid Build Coastguard Worker         /* Non audio elements */
1081*e5436536SAndroid Build Coastguard Worker         case ID_CCE:
1082*e5436536SAndroid Build Coastguard Worker           /* search in cce channels */
1083*e5436536SAndroid Build Coastguard Worker           for (i = 0; i < pPce->NumValidCcElements; i++) {
1084*e5436536SAndroid Build Coastguard Worker             if (pPce->ValidCcElementTagSelect[i] == tag) {
1085*e5436536SAndroid Build Coastguard Worker               return 1;
1086*e5436536SAndroid Build Coastguard Worker             }
1087*e5436536SAndroid Build Coastguard Worker           }
1088*e5436536SAndroid Build Coastguard Worker           break;
1089*e5436536SAndroid Build Coastguard Worker         case ID_DSE:
1090*e5436536SAndroid Build Coastguard Worker           /* search associated data elements */
1091*e5436536SAndroid Build Coastguard Worker           for (i = 0; i < pPce->NumAssocDataElements; i++) {
1092*e5436536SAndroid Build Coastguard Worker             if (pPce->AssocDataElementTagSelect[i] == tag) {
1093*e5436536SAndroid Build Coastguard Worker               return 1;
1094*e5436536SAndroid Build Coastguard Worker             }
1095*e5436536SAndroid Build Coastguard Worker           }
1096*e5436536SAndroid Build Coastguard Worker           break;
1097*e5436536SAndroid Build Coastguard Worker         default:
1098*e5436536SAndroid Build Coastguard Worker           return 0;
1099*e5436536SAndroid Build Coastguard Worker       }
1100*e5436536SAndroid Build Coastguard Worker       return 0; /* not found in any list */
1101*e5436536SAndroid Build Coastguard Worker     }
1102*e5436536SAndroid Build Coastguard Worker   }
1103*e5436536SAndroid Build Coastguard Worker 
1104*e5436536SAndroid Build Coastguard Worker   return 1;
1105*e5436536SAndroid Build Coastguard Worker }
1106*e5436536SAndroid Build Coastguard Worker 
1107*e5436536SAndroid Build Coastguard Worker #define SPEAKER_PLANE_NORMAL 0
1108*e5436536SAndroid Build Coastguard Worker #define SPEAKER_PLANE_TOP 1
1109*e5436536SAndroid Build Coastguard Worker #define SPEAKER_PLANE_BOTTOM 2
1110*e5436536SAndroid Build Coastguard Worker 
CProgramConfig_GetChannelDescription(const UINT chConfig,const CProgramConfig * pPce,AUDIO_CHANNEL_TYPE chType[],UCHAR chIndex[])1111*e5436536SAndroid Build Coastguard Worker void CProgramConfig_GetChannelDescription(const UINT chConfig,
1112*e5436536SAndroid Build Coastguard Worker                                           const CProgramConfig *pPce,
1113*e5436536SAndroid Build Coastguard Worker                                           AUDIO_CHANNEL_TYPE chType[],
1114*e5436536SAndroid Build Coastguard Worker                                           UCHAR chIndex[]) {
1115*e5436536SAndroid Build Coastguard Worker   FDK_ASSERT(chType != NULL);
1116*e5436536SAndroid Build Coastguard Worker   FDK_ASSERT(chIndex != NULL);
1117*e5436536SAndroid Build Coastguard Worker 
1118*e5436536SAndroid Build Coastguard Worker   if ((chConfig == 0) && (pPce != NULL)) {
1119*e5436536SAndroid Build Coastguard Worker     if (pPce->isValid) {
1120*e5436536SAndroid Build Coastguard Worker       int spkPlane, chIdx = 0;
1121*e5436536SAndroid Build Coastguard Worker       for (spkPlane = SPEAKER_PLANE_NORMAL; spkPlane <= SPEAKER_PLANE_BOTTOM;
1122*e5436536SAndroid Build Coastguard Worker            spkPlane += 1) {
1123*e5436536SAndroid Build Coastguard Worker         int elIdx, grpChIdx = 0;
1124*e5436536SAndroid Build Coastguard Worker         for (elIdx = 0; elIdx < pPce->NumFrontChannelElements; elIdx += 1) {
1125*e5436536SAndroid Build Coastguard Worker           if (pPce->FrontElementHeightInfo[elIdx] == spkPlane) {
1126*e5436536SAndroid Build Coastguard Worker             chType[chIdx] = (AUDIO_CHANNEL_TYPE)((spkPlane << 4) | ACT_FRONT);
1127*e5436536SAndroid Build Coastguard Worker             chIndex[chIdx++] = grpChIdx++;
1128*e5436536SAndroid Build Coastguard Worker             if (pPce->FrontElementIsCpe[elIdx]) {
1129*e5436536SAndroid Build Coastguard Worker               chType[chIdx] = (AUDIO_CHANNEL_TYPE)((spkPlane << 4) | ACT_FRONT);
1130*e5436536SAndroid Build Coastguard Worker               chIndex[chIdx++] = grpChIdx++;
1131*e5436536SAndroid Build Coastguard Worker             }
1132*e5436536SAndroid Build Coastguard Worker           }
1133*e5436536SAndroid Build Coastguard Worker         }
1134*e5436536SAndroid Build Coastguard Worker         grpChIdx = 0;
1135*e5436536SAndroid Build Coastguard Worker         for (elIdx = 0; elIdx < pPce->NumSideChannelElements; elIdx += 1) {
1136*e5436536SAndroid Build Coastguard Worker           if (pPce->SideElementHeightInfo[elIdx] == spkPlane) {
1137*e5436536SAndroid Build Coastguard Worker             chType[chIdx] = (AUDIO_CHANNEL_TYPE)((spkPlane << 4) | ACT_SIDE);
1138*e5436536SAndroid Build Coastguard Worker             chIndex[chIdx++] = grpChIdx++;
1139*e5436536SAndroid Build Coastguard Worker             if (pPce->SideElementIsCpe[elIdx]) {
1140*e5436536SAndroid Build Coastguard Worker               chType[chIdx] = (AUDIO_CHANNEL_TYPE)((spkPlane << 4) | ACT_SIDE);
1141*e5436536SAndroid Build Coastguard Worker               chIndex[chIdx++] = grpChIdx++;
1142*e5436536SAndroid Build Coastguard Worker             }
1143*e5436536SAndroid Build Coastguard Worker           }
1144*e5436536SAndroid Build Coastguard Worker         }
1145*e5436536SAndroid Build Coastguard Worker         grpChIdx = 0;
1146*e5436536SAndroid Build Coastguard Worker         for (elIdx = 0; elIdx < pPce->NumBackChannelElements; elIdx += 1) {
1147*e5436536SAndroid Build Coastguard Worker           if (pPce->BackElementHeightInfo[elIdx] == spkPlane) {
1148*e5436536SAndroid Build Coastguard Worker             chType[chIdx] = (AUDIO_CHANNEL_TYPE)((spkPlane << 4) | ACT_BACK);
1149*e5436536SAndroid Build Coastguard Worker             chIndex[chIdx++] = grpChIdx++;
1150*e5436536SAndroid Build Coastguard Worker             if (pPce->BackElementIsCpe[elIdx]) {
1151*e5436536SAndroid Build Coastguard Worker               chType[chIdx] = (AUDIO_CHANNEL_TYPE)((spkPlane << 4) | ACT_BACK);
1152*e5436536SAndroid Build Coastguard Worker               chIndex[chIdx++] = grpChIdx++;
1153*e5436536SAndroid Build Coastguard Worker             }
1154*e5436536SAndroid Build Coastguard Worker           }
1155*e5436536SAndroid Build Coastguard Worker         }
1156*e5436536SAndroid Build Coastguard Worker         grpChIdx = 0;
1157*e5436536SAndroid Build Coastguard Worker         if (spkPlane == SPEAKER_PLANE_NORMAL) {
1158*e5436536SAndroid Build Coastguard Worker           for (elIdx = 0; elIdx < pPce->NumLfeChannelElements; elIdx += 1) {
1159*e5436536SAndroid Build Coastguard Worker             chType[chIdx] = ACT_LFE;
1160*e5436536SAndroid Build Coastguard Worker             chIndex[chIdx++] = grpChIdx++;
1161*e5436536SAndroid Build Coastguard Worker           }
1162*e5436536SAndroid Build Coastguard Worker         }
1163*e5436536SAndroid Build Coastguard Worker       }
1164*e5436536SAndroid Build Coastguard Worker     }
1165*e5436536SAndroid Build Coastguard Worker   } else {
1166*e5436536SAndroid Build Coastguard Worker     int chIdx;
1167*e5436536SAndroid Build Coastguard Worker     for (chIdx = 0; chIdx < getNumberOfTotalChannels(chConfig); chIdx += 1) {
1168*e5436536SAndroid Build Coastguard Worker       getImplicitAudioChannelTypeAndIndex(&chType[chIdx], &chIndex[chIdx],
1169*e5436536SAndroid Build Coastguard Worker                                           chConfig, chIdx);
1170*e5436536SAndroid Build Coastguard Worker     }
1171*e5436536SAndroid Build Coastguard Worker   }
1172*e5436536SAndroid Build Coastguard Worker }
1173*e5436536SAndroid Build Coastguard Worker 
CProgramConfig_GetPceChMap(const CProgramConfig * pPce,UCHAR pceChMap[],const UINT pceChMapLen)1174*e5436536SAndroid Build Coastguard Worker int CProgramConfig_GetPceChMap(const CProgramConfig *pPce, UCHAR pceChMap[],
1175*e5436536SAndroid Build Coastguard Worker                                const UINT pceChMapLen) {
1176*e5436536SAndroid Build Coastguard Worker   const UCHAR *nElements = &pPce->NumFrontChannelElements;
1177*e5436536SAndroid Build Coastguard Worker   const UCHAR *elHeight[3], *elIsCpe[3];
1178*e5436536SAndroid Build Coastguard Worker   unsigned chIdx, plane, grp, offset, totCh[3], numCh[3][4];
1179*e5436536SAndroid Build Coastguard Worker 
1180*e5436536SAndroid Build Coastguard Worker   FDK_ASSERT(pPce != NULL);
1181*e5436536SAndroid Build Coastguard Worker   FDK_ASSERT(pceChMap != NULL);
1182*e5436536SAndroid Build Coastguard Worker 
1183*e5436536SAndroid Build Coastguard Worker   /* Init counter: */
1184*e5436536SAndroid Build Coastguard Worker   FDKmemclear(totCh, 3 * sizeof(unsigned));
1185*e5436536SAndroid Build Coastguard Worker   FDKmemclear(numCh, 3 * 4 * sizeof(unsigned));
1186*e5436536SAndroid Build Coastguard Worker 
1187*e5436536SAndroid Build Coastguard Worker   /* Analyse PCE: */
1188*e5436536SAndroid Build Coastguard Worker   elHeight[0] = pPce->FrontElementHeightInfo;
1189*e5436536SAndroid Build Coastguard Worker   elIsCpe[0] = pPce->FrontElementIsCpe;
1190*e5436536SAndroid Build Coastguard Worker   elHeight[1] = pPce->SideElementHeightInfo;
1191*e5436536SAndroid Build Coastguard Worker   elIsCpe[1] = pPce->SideElementIsCpe;
1192*e5436536SAndroid Build Coastguard Worker   elHeight[2] = pPce->BackElementHeightInfo;
1193*e5436536SAndroid Build Coastguard Worker   elIsCpe[2] = pPce->BackElementIsCpe;
1194*e5436536SAndroid Build Coastguard Worker 
1195*e5436536SAndroid Build Coastguard Worker   for (plane = 0; plane <= SPEAKER_PLANE_BOTTOM; plane += 1) {
1196*e5436536SAndroid Build Coastguard Worker     for (grp = 0; grp < 3; grp += 1) { /* front, side, back */
1197*e5436536SAndroid Build Coastguard Worker       unsigned el;
1198*e5436536SAndroid Build Coastguard Worker       for (el = 0; el < nElements[grp]; el += 1) {
1199*e5436536SAndroid Build Coastguard Worker         if (elHeight[grp][el] == plane) {
1200*e5436536SAndroid Build Coastguard Worker           unsigned elCh = elIsCpe[grp][el] ? 2 : 1;
1201*e5436536SAndroid Build Coastguard Worker           numCh[plane][grp] += elCh;
1202*e5436536SAndroid Build Coastguard Worker           totCh[plane] += elCh;
1203*e5436536SAndroid Build Coastguard Worker         }
1204*e5436536SAndroid Build Coastguard Worker       }
1205*e5436536SAndroid Build Coastguard Worker     }
1206*e5436536SAndroid Build Coastguard Worker     if (plane == SPEAKER_PLANE_NORMAL) {
1207*e5436536SAndroid Build Coastguard Worker       unsigned elCh = pPce->NumLfeChannelElements;
1208*e5436536SAndroid Build Coastguard Worker       numCh[plane][grp] += elCh;
1209*e5436536SAndroid Build Coastguard Worker       totCh[plane] += elCh;
1210*e5436536SAndroid Build Coastguard Worker     }
1211*e5436536SAndroid Build Coastguard Worker   }
1212*e5436536SAndroid Build Coastguard Worker   /* Sanity checks: */
1213*e5436536SAndroid Build Coastguard Worker   chIdx = totCh[SPEAKER_PLANE_NORMAL] + totCh[SPEAKER_PLANE_TOP] +
1214*e5436536SAndroid Build Coastguard Worker           totCh[SPEAKER_PLANE_BOTTOM];
1215*e5436536SAndroid Build Coastguard Worker   if (chIdx > pceChMapLen) {
1216*e5436536SAndroid Build Coastguard Worker     return -1;
1217*e5436536SAndroid Build Coastguard Worker   }
1218*e5436536SAndroid Build Coastguard Worker 
1219*e5436536SAndroid Build Coastguard Worker   /* Create map: */
1220*e5436536SAndroid Build Coastguard Worker   offset = grp = 0;
1221*e5436536SAndroid Build Coastguard Worker   unsigned grpThresh = numCh[SPEAKER_PLANE_NORMAL][grp];
1222*e5436536SAndroid Build Coastguard Worker   for (chIdx = 0; chIdx < totCh[SPEAKER_PLANE_NORMAL]; chIdx += 1) {
1223*e5436536SAndroid Build Coastguard Worker     while ((chIdx >= grpThresh) && (grp < 3)) {
1224*e5436536SAndroid Build Coastguard Worker       offset += numCh[1][grp] + numCh[2][grp];
1225*e5436536SAndroid Build Coastguard Worker       grp += 1;
1226*e5436536SAndroid Build Coastguard Worker       grpThresh += numCh[SPEAKER_PLANE_NORMAL][grp];
1227*e5436536SAndroid Build Coastguard Worker     }
1228*e5436536SAndroid Build Coastguard Worker     pceChMap[chIdx] = chIdx + offset;
1229*e5436536SAndroid Build Coastguard Worker   }
1230*e5436536SAndroid Build Coastguard Worker   offset = 0;
1231*e5436536SAndroid Build Coastguard Worker   for (grp = 0; grp < 4; grp += 1) { /* front, side, back and lfe */
1232*e5436536SAndroid Build Coastguard Worker     offset += numCh[SPEAKER_PLANE_NORMAL][grp];
1233*e5436536SAndroid Build Coastguard Worker     for (plane = SPEAKER_PLANE_TOP; plane <= SPEAKER_PLANE_BOTTOM; plane += 1) {
1234*e5436536SAndroid Build Coastguard Worker       unsigned mapCh;
1235*e5436536SAndroid Build Coastguard Worker       for (mapCh = 0; mapCh < numCh[plane][grp]; mapCh += 1) {
1236*e5436536SAndroid Build Coastguard Worker         pceChMap[chIdx++] = offset;
1237*e5436536SAndroid Build Coastguard Worker         offset += 1;
1238*e5436536SAndroid Build Coastguard Worker       }
1239*e5436536SAndroid Build Coastguard Worker     }
1240*e5436536SAndroid Build Coastguard Worker   }
1241*e5436536SAndroid Build Coastguard Worker   return 0;
1242*e5436536SAndroid Build Coastguard Worker }
1243*e5436536SAndroid Build Coastguard Worker 
CProgramConfig_GetElementTable(const CProgramConfig * pPce,MP4_ELEMENT_ID elList[],const INT elListSize,UCHAR * pChMapIdx)1244*e5436536SAndroid Build Coastguard Worker int CProgramConfig_GetElementTable(const CProgramConfig *pPce,
1245*e5436536SAndroid Build Coastguard Worker                                    MP4_ELEMENT_ID elList[],
1246*e5436536SAndroid Build Coastguard Worker                                    const INT elListSize, UCHAR *pChMapIdx) {
1247*e5436536SAndroid Build Coastguard Worker   int i, el = 0;
1248*e5436536SAndroid Build Coastguard Worker 
1249*e5436536SAndroid Build Coastguard Worker   FDK_ASSERT(elList != NULL);
1250*e5436536SAndroid Build Coastguard Worker   FDK_ASSERT(pChMapIdx != NULL);
1251*e5436536SAndroid Build Coastguard Worker   FDK_ASSERT(pPce != NULL);
1252*e5436536SAndroid Build Coastguard Worker 
1253*e5436536SAndroid Build Coastguard Worker   *pChMapIdx = 0;
1254*e5436536SAndroid Build Coastguard Worker 
1255*e5436536SAndroid Build Coastguard Worker   if ((elListSize <
1256*e5436536SAndroid Build Coastguard Worker        pPce->NumFrontChannelElements + pPce->NumSideChannelElements +
1257*e5436536SAndroid Build Coastguard Worker            pPce->NumBackChannelElements + pPce->NumLfeChannelElements) ||
1258*e5436536SAndroid Build Coastguard Worker       (pPce->NumChannels == 0)) {
1259*e5436536SAndroid Build Coastguard Worker     return 0;
1260*e5436536SAndroid Build Coastguard Worker   }
1261*e5436536SAndroid Build Coastguard Worker 
1262*e5436536SAndroid Build Coastguard Worker   for (i = 0; i < pPce->NumFrontChannelElements; i += 1) {
1263*e5436536SAndroid Build Coastguard Worker     elList[el++] = (pPce->FrontElementIsCpe[i]) ? ID_CPE : ID_SCE;
1264*e5436536SAndroid Build Coastguard Worker   }
1265*e5436536SAndroid Build Coastguard Worker 
1266*e5436536SAndroid Build Coastguard Worker   for (i = 0; i < pPce->NumSideChannelElements; i += 1) {
1267*e5436536SAndroid Build Coastguard Worker     elList[el++] = (pPce->SideElementIsCpe[i]) ? ID_CPE : ID_SCE;
1268*e5436536SAndroid Build Coastguard Worker   }
1269*e5436536SAndroid Build Coastguard Worker 
1270*e5436536SAndroid Build Coastguard Worker   for (i = 0; i < pPce->NumBackChannelElements; i += 1) {
1271*e5436536SAndroid Build Coastguard Worker     elList[el++] = (pPce->BackElementIsCpe[i]) ? ID_CPE : ID_SCE;
1272*e5436536SAndroid Build Coastguard Worker   }
1273*e5436536SAndroid Build Coastguard Worker 
1274*e5436536SAndroid Build Coastguard Worker   for (i = 0; i < pPce->NumLfeChannelElements; i += 1) {
1275*e5436536SAndroid Build Coastguard Worker     elList[el++] = ID_LFE;
1276*e5436536SAndroid Build Coastguard Worker   }
1277*e5436536SAndroid Build Coastguard Worker 
1278*e5436536SAndroid Build Coastguard Worker   /* Find an corresponding channel configuration if possible */
1279*e5436536SAndroid Build Coastguard Worker   switch (pPce->NumChannels) {
1280*e5436536SAndroid Build Coastguard Worker     case 1:
1281*e5436536SAndroid Build Coastguard Worker     case 2:
1282*e5436536SAndroid Build Coastguard Worker       /* One and two channels have no alternatives. */
1283*e5436536SAndroid Build Coastguard Worker       *pChMapIdx = pPce->NumChannels;
1284*e5436536SAndroid Build Coastguard Worker       break;
1285*e5436536SAndroid Build Coastguard Worker     case 3:
1286*e5436536SAndroid Build Coastguard Worker     case 4:
1287*e5436536SAndroid Build Coastguard Worker     case 5:
1288*e5436536SAndroid Build Coastguard Worker     case 6: { /* Test if the number of channels can be used as channel config:
1289*e5436536SAndroid Build Coastguard Worker                */
1290*e5436536SAndroid Build Coastguard Worker       C_ALLOC_SCRATCH_START(tmpPce, CProgramConfig, 1);
1291*e5436536SAndroid Build Coastguard Worker       /* Create a PCE for the config to test ... */
1292*e5436536SAndroid Build Coastguard Worker       CProgramConfig_GetDefault(tmpPce, pPce->NumChannels);
1293*e5436536SAndroid Build Coastguard Worker       /* ... and compare it with the given one. */
1294*e5436536SAndroid Build Coastguard Worker       *pChMapIdx = (!(CProgramConfig_Compare(pPce, tmpPce) & 0xE))
1295*e5436536SAndroid Build Coastguard Worker                        ? pPce->NumChannels
1296*e5436536SAndroid Build Coastguard Worker                        : 0;
1297*e5436536SAndroid Build Coastguard Worker       /* If compare result is 0 or 1 we can be sure that it is channel
1298*e5436536SAndroid Build Coastguard Worker        * config 11. */
1299*e5436536SAndroid Build Coastguard Worker       C_ALLOC_SCRATCH_END(tmpPce, CProgramConfig, 1);
1300*e5436536SAndroid Build Coastguard Worker     } break;
1301*e5436536SAndroid Build Coastguard Worker     case 7: {
1302*e5436536SAndroid Build Coastguard Worker       C_ALLOC_SCRATCH_START(tmpPce, CProgramConfig, 1);
1303*e5436536SAndroid Build Coastguard Worker       /* Create a PCE for the config to test ... */
1304*e5436536SAndroid Build Coastguard Worker       CProgramConfig_GetDefault(tmpPce, 11);
1305*e5436536SAndroid Build Coastguard Worker       /* ... and compare it with the given one. */
1306*e5436536SAndroid Build Coastguard Worker       *pChMapIdx = (!(CProgramConfig_Compare(pPce, tmpPce) & 0xE)) ? 11 : 0;
1307*e5436536SAndroid Build Coastguard Worker       /* If compare result is 0 or 1 we can be sure that it is channel
1308*e5436536SAndroid Build Coastguard Worker        * config 11. */
1309*e5436536SAndroid Build Coastguard Worker       C_ALLOC_SCRATCH_END(tmpPce, CProgramConfig, 1);
1310*e5436536SAndroid Build Coastguard Worker     } break;
1311*e5436536SAndroid Build Coastguard Worker     case 8: { /* Try the four possible 7.1ch configurations. One after the
1312*e5436536SAndroid Build Coastguard Worker                  other. */
1313*e5436536SAndroid Build Coastguard Worker       UCHAR testCfg[4] = {32, 14, 12, 7};
1314*e5436536SAndroid Build Coastguard Worker       C_ALLOC_SCRATCH_START(tmpPce, CProgramConfig, 1);
1315*e5436536SAndroid Build Coastguard Worker       for (i = 0; i < 4; i += 1) {
1316*e5436536SAndroid Build Coastguard Worker         /* Create a PCE for the config to test ... */
1317*e5436536SAndroid Build Coastguard Worker         CProgramConfig_GetDefault(tmpPce, testCfg[i]);
1318*e5436536SAndroid Build Coastguard Worker         /* ... and compare it with the given one. */
1319*e5436536SAndroid Build Coastguard Worker         if (!(CProgramConfig_Compare(pPce, tmpPce) & 0xE)) {
1320*e5436536SAndroid Build Coastguard Worker           /* If the compare result is 0 or 1 than the two channel configurations
1321*e5436536SAndroid Build Coastguard Worker            * match. */
1322*e5436536SAndroid Build Coastguard Worker           /* Explicit mapping of 7.1 side channel configuration to 7.1 rear
1323*e5436536SAndroid Build Coastguard Worker            * channel mapping. */
1324*e5436536SAndroid Build Coastguard Worker           *pChMapIdx = (testCfg[i] == 32) ? 12 : testCfg[i];
1325*e5436536SAndroid Build Coastguard Worker         }
1326*e5436536SAndroid Build Coastguard Worker       }
1327*e5436536SAndroid Build Coastguard Worker       C_ALLOC_SCRATCH_END(tmpPce, CProgramConfig, 1);
1328*e5436536SAndroid Build Coastguard Worker     } break;
1329*e5436536SAndroid Build Coastguard Worker     default:
1330*e5436536SAndroid Build Coastguard Worker       /* The PCE does not match any predefined channel configuration. */
1331*e5436536SAndroid Build Coastguard Worker       *pChMapIdx = 0;
1332*e5436536SAndroid Build Coastguard Worker       break;
1333*e5436536SAndroid Build Coastguard Worker   }
1334*e5436536SAndroid Build Coastguard Worker 
1335*e5436536SAndroid Build Coastguard Worker   return el;
1336*e5436536SAndroid Build Coastguard Worker }
1337*e5436536SAndroid Build Coastguard Worker 
getAOT(HANDLE_FDK_BITSTREAM bs)1338*e5436536SAndroid Build Coastguard Worker static AUDIO_OBJECT_TYPE getAOT(HANDLE_FDK_BITSTREAM bs) {
1339*e5436536SAndroid Build Coastguard Worker   int tmp = 0;
1340*e5436536SAndroid Build Coastguard Worker 
1341*e5436536SAndroid Build Coastguard Worker   tmp = FDKreadBits(bs, 5);
1342*e5436536SAndroid Build Coastguard Worker   if (tmp == AOT_ESCAPE) {
1343*e5436536SAndroid Build Coastguard Worker     int tmp2 = FDKreadBits(bs, 6);
1344*e5436536SAndroid Build Coastguard Worker     tmp = 32 + tmp2;
1345*e5436536SAndroid Build Coastguard Worker   }
1346*e5436536SAndroid Build Coastguard Worker 
1347*e5436536SAndroid Build Coastguard Worker   return (AUDIO_OBJECT_TYPE)tmp;
1348*e5436536SAndroid Build Coastguard Worker }
1349*e5436536SAndroid Build Coastguard Worker 
getSampleRate(HANDLE_FDK_BITSTREAM bs,UCHAR * index,int nBits)1350*e5436536SAndroid Build Coastguard Worker static INT getSampleRate(HANDLE_FDK_BITSTREAM bs, UCHAR *index, int nBits) {
1351*e5436536SAndroid Build Coastguard Worker   INT sampleRate;
1352*e5436536SAndroid Build Coastguard Worker   int idx;
1353*e5436536SAndroid Build Coastguard Worker 
1354*e5436536SAndroid Build Coastguard Worker   idx = FDKreadBits(bs, nBits);
1355*e5436536SAndroid Build Coastguard Worker   if (idx == (1 << nBits) - 1) {
1356*e5436536SAndroid Build Coastguard Worker     if (FDKgetValidBits(bs) < 24) {
1357*e5436536SAndroid Build Coastguard Worker       return 0;
1358*e5436536SAndroid Build Coastguard Worker     }
1359*e5436536SAndroid Build Coastguard Worker     sampleRate = FDKreadBits(bs, 24);
1360*e5436536SAndroid Build Coastguard Worker   } else {
1361*e5436536SAndroid Build Coastguard Worker     sampleRate = SamplingRateTable[idx];
1362*e5436536SAndroid Build Coastguard Worker   }
1363*e5436536SAndroid Build Coastguard Worker 
1364*e5436536SAndroid Build Coastguard Worker   *index = idx;
1365*e5436536SAndroid Build Coastguard Worker 
1366*e5436536SAndroid Build Coastguard Worker   return sampleRate;
1367*e5436536SAndroid Build Coastguard Worker }
1368*e5436536SAndroid Build Coastguard Worker 
GaSpecificConfig_Parse(CSGaSpecificConfig * self,CSAudioSpecificConfig * asc,HANDLE_FDK_BITSTREAM bs,UINT ascStartAnchor)1369*e5436536SAndroid Build Coastguard Worker static TRANSPORTDEC_ERROR GaSpecificConfig_Parse(CSGaSpecificConfig *self,
1370*e5436536SAndroid Build Coastguard Worker                                                  CSAudioSpecificConfig *asc,
1371*e5436536SAndroid Build Coastguard Worker                                                  HANDLE_FDK_BITSTREAM bs,
1372*e5436536SAndroid Build Coastguard Worker                                                  UINT ascStartAnchor) {
1373*e5436536SAndroid Build Coastguard Worker   TRANSPORTDEC_ERROR ErrorStatus = TRANSPORTDEC_OK;
1374*e5436536SAndroid Build Coastguard Worker 
1375*e5436536SAndroid Build Coastguard Worker   self->m_frameLengthFlag = FDKreadBits(bs, 1);
1376*e5436536SAndroid Build Coastguard Worker 
1377*e5436536SAndroid Build Coastguard Worker   self->m_dependsOnCoreCoder = FDKreadBits(bs, 1);
1378*e5436536SAndroid Build Coastguard Worker 
1379*e5436536SAndroid Build Coastguard Worker   if (self->m_dependsOnCoreCoder) self->m_coreCoderDelay = FDKreadBits(bs, 14);
1380*e5436536SAndroid Build Coastguard Worker 
1381*e5436536SAndroid Build Coastguard Worker   self->m_extensionFlag = FDKreadBits(bs, 1);
1382*e5436536SAndroid Build Coastguard Worker 
1383*e5436536SAndroid Build Coastguard Worker   if (asc->m_channelConfiguration == 0) {
1384*e5436536SAndroid Build Coastguard Worker     CProgramConfig_Read(&asc->m_progrConfigElement, bs, ascStartAnchor);
1385*e5436536SAndroid Build Coastguard Worker   }
1386*e5436536SAndroid Build Coastguard Worker 
1387*e5436536SAndroid Build Coastguard Worker   if ((asc->m_aot == AOT_AAC_SCAL) || (asc->m_aot == AOT_ER_AAC_SCAL)) {
1388*e5436536SAndroid Build Coastguard Worker     self->m_layer = FDKreadBits(bs, 3);
1389*e5436536SAndroid Build Coastguard Worker   }
1390*e5436536SAndroid Build Coastguard Worker 
1391*e5436536SAndroid Build Coastguard Worker   if (self->m_extensionFlag) {
1392*e5436536SAndroid Build Coastguard Worker     if (asc->m_aot == AOT_ER_BSAC) {
1393*e5436536SAndroid Build Coastguard Worker       self->m_numOfSubFrame = FDKreadBits(bs, 5);
1394*e5436536SAndroid Build Coastguard Worker       self->m_layerLength = FDKreadBits(bs, 11);
1395*e5436536SAndroid Build Coastguard Worker     }
1396*e5436536SAndroid Build Coastguard Worker 
1397*e5436536SAndroid Build Coastguard Worker     if ((asc->m_aot == AOT_ER_AAC_LC) || (asc->m_aot == AOT_ER_AAC_LTP) ||
1398*e5436536SAndroid Build Coastguard Worker         (asc->m_aot == AOT_ER_AAC_SCAL) || (asc->m_aot == AOT_ER_AAC_LD)) {
1399*e5436536SAndroid Build Coastguard Worker       asc->m_vcb11Flag = FDKreadBits(bs, 1); /* aacSectionDataResilienceFlag */
1400*e5436536SAndroid Build Coastguard Worker       asc->m_rvlcFlag =
1401*e5436536SAndroid Build Coastguard Worker           FDKreadBits(bs, 1); /* aacScalefactorDataResilienceFlag */
1402*e5436536SAndroid Build Coastguard Worker       asc->m_hcrFlag = FDKreadBits(bs, 1); /* aacSpectralDataResilienceFlag */
1403*e5436536SAndroid Build Coastguard Worker     }
1404*e5436536SAndroid Build Coastguard Worker 
1405*e5436536SAndroid Build Coastguard Worker     self->m_extensionFlag3 = FDKreadBits(bs, 1);
1406*e5436536SAndroid Build Coastguard Worker   }
1407*e5436536SAndroid Build Coastguard Worker   return (ErrorStatus);
1408*e5436536SAndroid Build Coastguard Worker }
1409*e5436536SAndroid Build Coastguard Worker 
skipSbrHeader(HANDLE_FDK_BITSTREAM hBs,int isUsac)1410*e5436536SAndroid Build Coastguard Worker static INT skipSbrHeader(HANDLE_FDK_BITSTREAM hBs, int isUsac) {
1411*e5436536SAndroid Build Coastguard Worker   /* Dummy parse SbrDfltHeader() */
1412*e5436536SAndroid Build Coastguard Worker   INT dflt_header_extra1, dflt_header_extra2, bitsToSkip = 0;
1413*e5436536SAndroid Build Coastguard Worker 
1414*e5436536SAndroid Build Coastguard Worker   if (!isUsac) {
1415*e5436536SAndroid Build Coastguard Worker     bitsToSkip = 6;
1416*e5436536SAndroid Build Coastguard Worker     FDKpushFor(hBs, 6); /* amp res 1, xover freq 3, reserved 2 */
1417*e5436536SAndroid Build Coastguard Worker   }
1418*e5436536SAndroid Build Coastguard Worker   bitsToSkip += 8;
1419*e5436536SAndroid Build Coastguard Worker   FDKpushFor(hBs, 8); /* start / stop freq */
1420*e5436536SAndroid Build Coastguard Worker   bitsToSkip += 2;
1421*e5436536SAndroid Build Coastguard Worker   dflt_header_extra1 = FDKreadBit(hBs);
1422*e5436536SAndroid Build Coastguard Worker   dflt_header_extra2 = FDKreadBit(hBs);
1423*e5436536SAndroid Build Coastguard Worker   bitsToSkip += 5 * dflt_header_extra1 + 6 * dflt_header_extra2;
1424*e5436536SAndroid Build Coastguard Worker   FDKpushFor(hBs, 5 * dflt_header_extra1 + 6 * dflt_header_extra2);
1425*e5436536SAndroid Build Coastguard Worker 
1426*e5436536SAndroid Build Coastguard Worker   return bitsToSkip;
1427*e5436536SAndroid Build Coastguard Worker }
1428*e5436536SAndroid Build Coastguard Worker 
ld_sbr_header(CSAudioSpecificConfig * asc,const INT dsFactor,HANDLE_FDK_BITSTREAM hBs,CSTpCallBacks * cb)1429*e5436536SAndroid Build Coastguard Worker static INT ld_sbr_header(CSAudioSpecificConfig *asc, const INT dsFactor,
1430*e5436536SAndroid Build Coastguard Worker                          HANDLE_FDK_BITSTREAM hBs, CSTpCallBacks *cb) {
1431*e5436536SAndroid Build Coastguard Worker   const int channelConfiguration = asc->m_channelConfiguration;
1432*e5436536SAndroid Build Coastguard Worker   int i = 0, j = 0;
1433*e5436536SAndroid Build Coastguard Worker   INT error = 0;
1434*e5436536SAndroid Build Coastguard Worker   MP4_ELEMENT_ID element = ID_NONE;
1435*e5436536SAndroid Build Coastguard Worker 
1436*e5436536SAndroid Build Coastguard Worker   /* check whether the channelConfiguration is defined in
1437*e5436536SAndroid Build Coastguard Worker    * channel_configuration_array */
1438*e5436536SAndroid Build Coastguard Worker   if (channelConfiguration < 0 ||
1439*e5436536SAndroid Build Coastguard Worker       channelConfiguration > (INT)(sizeof(channel_configuration_array) /
1440*e5436536SAndroid Build Coastguard Worker                                        sizeof(MP4_ELEMENT_ID **) -
1441*e5436536SAndroid Build Coastguard Worker                                    1)) {
1442*e5436536SAndroid Build Coastguard Worker     return TRANSPORTDEC_PARSE_ERROR;
1443*e5436536SAndroid Build Coastguard Worker   }
1444*e5436536SAndroid Build Coastguard Worker 
1445*e5436536SAndroid Build Coastguard Worker   /* read elements of the passed channel_configuration until there is ID_NONE */
1446*e5436536SAndroid Build Coastguard Worker   while ((element = channel_configuration_array[channelConfiguration][j]) !=
1447*e5436536SAndroid Build Coastguard Worker          ID_NONE) {
1448*e5436536SAndroid Build Coastguard Worker     /* Setup LFE element for upsampling too. This is essential especially for
1449*e5436536SAndroid Build Coastguard Worker      * channel configs where the LFE element is not at the last position for
1450*e5436536SAndroid Build Coastguard Worker      * example in channel config 13 or 14. It leads to memory leaks if the setup
1451*e5436536SAndroid Build Coastguard Worker      * of the LFE element would be done later in the core. */
1452*e5436536SAndroid Build Coastguard Worker     if (element == ID_SCE || element == ID_CPE || element == ID_LFE) {
1453*e5436536SAndroid Build Coastguard Worker       error |= cb->cbSbr(
1454*e5436536SAndroid Build Coastguard Worker           cb->cbSbrData, hBs, asc->m_samplingFrequency / dsFactor,
1455*e5436536SAndroid Build Coastguard Worker           asc->m_extensionSamplingFrequency / dsFactor,
1456*e5436536SAndroid Build Coastguard Worker           asc->m_samplesPerFrame / dsFactor, AOT_ER_AAC_ELD, element, i++, 0, 0,
1457*e5436536SAndroid Build Coastguard Worker           asc->configMode, &asc->SbrConfigChanged, dsFactor);
1458*e5436536SAndroid Build Coastguard Worker       if (error != TRANSPORTDEC_OK) {
1459*e5436536SAndroid Build Coastguard Worker         goto bail;
1460*e5436536SAndroid Build Coastguard Worker       }
1461*e5436536SAndroid Build Coastguard Worker     }
1462*e5436536SAndroid Build Coastguard Worker     j++;
1463*e5436536SAndroid Build Coastguard Worker   }
1464*e5436536SAndroid Build Coastguard Worker bail:
1465*e5436536SAndroid Build Coastguard Worker   return error;
1466*e5436536SAndroid Build Coastguard Worker }
1467*e5436536SAndroid Build Coastguard Worker 
EldSpecificConfig_Parse(CSAudioSpecificConfig * asc,HANDLE_FDK_BITSTREAM hBs,CSTpCallBacks * cb)1468*e5436536SAndroid Build Coastguard Worker static TRANSPORTDEC_ERROR EldSpecificConfig_Parse(CSAudioSpecificConfig *asc,
1469*e5436536SAndroid Build Coastguard Worker                                                   HANDLE_FDK_BITSTREAM hBs,
1470*e5436536SAndroid Build Coastguard Worker                                                   CSTpCallBacks *cb) {
1471*e5436536SAndroid Build Coastguard Worker   TRANSPORTDEC_ERROR ErrorStatus = TRANSPORTDEC_OK;
1472*e5436536SAndroid Build Coastguard Worker   CSEldSpecificConfig *esc = &asc->m_sc.m_eldSpecificConfig;
1473*e5436536SAndroid Build Coastguard Worker   UINT eldExtType;
1474*e5436536SAndroid Build Coastguard Worker   int eldExtLen, len, cnt, ldSbrLen = 0, eldExtLenSum, numSbrHeader = 0,
1475*e5436536SAndroid Build Coastguard Worker                            sbrIndex, eldExtCnt = 0;
1476*e5436536SAndroid Build Coastguard Worker 
1477*e5436536SAndroid Build Coastguard Worker   unsigned char downscale_fill_nibble;
1478*e5436536SAndroid Build Coastguard Worker 
1479*e5436536SAndroid Build Coastguard Worker   FDKmemclear(esc, sizeof(CSEldSpecificConfig));
1480*e5436536SAndroid Build Coastguard Worker 
1481*e5436536SAndroid Build Coastguard Worker   esc->m_frameLengthFlag = FDKreadBits(hBs, 1);
1482*e5436536SAndroid Build Coastguard Worker   if (esc->m_frameLengthFlag) {
1483*e5436536SAndroid Build Coastguard Worker     asc->m_samplesPerFrame = 480;
1484*e5436536SAndroid Build Coastguard Worker   } else {
1485*e5436536SAndroid Build Coastguard Worker     asc->m_samplesPerFrame = 512;
1486*e5436536SAndroid Build Coastguard Worker   }
1487*e5436536SAndroid Build Coastguard Worker 
1488*e5436536SAndroid Build Coastguard Worker   asc->m_vcb11Flag = FDKreadBits(hBs, 1);
1489*e5436536SAndroid Build Coastguard Worker   asc->m_rvlcFlag = FDKreadBits(hBs, 1);
1490*e5436536SAndroid Build Coastguard Worker   asc->m_hcrFlag = FDKreadBits(hBs, 1);
1491*e5436536SAndroid Build Coastguard Worker 
1492*e5436536SAndroid Build Coastguard Worker   esc->m_sbrPresentFlag = FDKreadBits(hBs, 1);
1493*e5436536SAndroid Build Coastguard Worker 
1494*e5436536SAndroid Build Coastguard Worker   if (esc->m_sbrPresentFlag == 1) {
1495*e5436536SAndroid Build Coastguard Worker     esc->m_sbrSamplingRate =
1496*e5436536SAndroid Build Coastguard Worker         FDKreadBits(hBs, 1); /* 0: single rate, 1: dual rate */
1497*e5436536SAndroid Build Coastguard Worker     esc->m_sbrCrcFlag = FDKreadBits(hBs, 1);
1498*e5436536SAndroid Build Coastguard Worker 
1499*e5436536SAndroid Build Coastguard Worker     asc->m_extensionSamplingFrequency = asc->m_samplingFrequency
1500*e5436536SAndroid Build Coastguard Worker                                         << esc->m_sbrSamplingRate;
1501*e5436536SAndroid Build Coastguard Worker 
1502*e5436536SAndroid Build Coastguard Worker     if (cb->cbSbr != NULL) {
1503*e5436536SAndroid Build Coastguard Worker       /* ELD reduced delay mode: LD-SBR initialization has to know the downscale
1504*e5436536SAndroid Build Coastguard Worker          information. Postpone LD-SBR initialization and read ELD extension
1505*e5436536SAndroid Build Coastguard Worker          information first. */
1506*e5436536SAndroid Build Coastguard Worker       switch (asc->m_channelConfiguration) {
1507*e5436536SAndroid Build Coastguard Worker         case 1:
1508*e5436536SAndroid Build Coastguard Worker         case 2:
1509*e5436536SAndroid Build Coastguard Worker           numSbrHeader = 1;
1510*e5436536SAndroid Build Coastguard Worker           break;
1511*e5436536SAndroid Build Coastguard Worker         case 3:
1512*e5436536SAndroid Build Coastguard Worker           numSbrHeader = 2;
1513*e5436536SAndroid Build Coastguard Worker           break;
1514*e5436536SAndroid Build Coastguard Worker         case 4:
1515*e5436536SAndroid Build Coastguard Worker         case 5:
1516*e5436536SAndroid Build Coastguard Worker         case 6:
1517*e5436536SAndroid Build Coastguard Worker           numSbrHeader = 3;
1518*e5436536SAndroid Build Coastguard Worker           break;
1519*e5436536SAndroid Build Coastguard Worker         case 7:
1520*e5436536SAndroid Build Coastguard Worker         case 11:
1521*e5436536SAndroid Build Coastguard Worker         case 12:
1522*e5436536SAndroid Build Coastguard Worker         case 14:
1523*e5436536SAndroid Build Coastguard Worker           numSbrHeader = 4;
1524*e5436536SAndroid Build Coastguard Worker           break;
1525*e5436536SAndroid Build Coastguard Worker         default:
1526*e5436536SAndroid Build Coastguard Worker           numSbrHeader = 0;
1527*e5436536SAndroid Build Coastguard Worker           break;
1528*e5436536SAndroid Build Coastguard Worker       }
1529*e5436536SAndroid Build Coastguard Worker       for (sbrIndex = 0; sbrIndex < numSbrHeader; sbrIndex++) {
1530*e5436536SAndroid Build Coastguard Worker         ldSbrLen += skipSbrHeader(hBs, 0);
1531*e5436536SAndroid Build Coastguard Worker       }
1532*e5436536SAndroid Build Coastguard Worker     } else {
1533*e5436536SAndroid Build Coastguard Worker       return TRANSPORTDEC_UNSUPPORTED_FORMAT;
1534*e5436536SAndroid Build Coastguard Worker     }
1535*e5436536SAndroid Build Coastguard Worker   }
1536*e5436536SAndroid Build Coastguard Worker   esc->m_useLdQmfTimeAlign = 0;
1537*e5436536SAndroid Build Coastguard Worker 
1538*e5436536SAndroid Build Coastguard Worker   /* new ELD syntax */
1539*e5436536SAndroid Build Coastguard Worker   eldExtLenSum = FDKgetValidBits(hBs);
1540*e5436536SAndroid Build Coastguard Worker   esc->m_downscaledSamplingFrequency = asc->m_samplingFrequency;
1541*e5436536SAndroid Build Coastguard Worker   /* parse ExtTypeConfigData */
1542*e5436536SAndroid Build Coastguard Worker   while (((eldExtType = FDKreadBits(hBs, 4)) != ELDEXT_TERM) &&
1543*e5436536SAndroid Build Coastguard Worker          ((INT)FDKgetValidBits(hBs) >= 0) && (eldExtCnt++ < 15)) {
1544*e5436536SAndroid Build Coastguard Worker     eldExtLen = len = FDKreadBits(hBs, 4);
1545*e5436536SAndroid Build Coastguard Worker     if (len == 0xf) {
1546*e5436536SAndroid Build Coastguard Worker       len = FDKreadBits(hBs, 8);
1547*e5436536SAndroid Build Coastguard Worker       eldExtLen += len;
1548*e5436536SAndroid Build Coastguard Worker 
1549*e5436536SAndroid Build Coastguard Worker       if (len == 0xff) {
1550*e5436536SAndroid Build Coastguard Worker         len = FDKreadBits(hBs, 16);
1551*e5436536SAndroid Build Coastguard Worker         eldExtLen += len;
1552*e5436536SAndroid Build Coastguard Worker       }
1553*e5436536SAndroid Build Coastguard Worker     }
1554*e5436536SAndroid Build Coastguard Worker 
1555*e5436536SAndroid Build Coastguard Worker     switch (eldExtType) {
1556*e5436536SAndroid Build Coastguard Worker       case ELDEXT_LDSAC:
1557*e5436536SAndroid Build Coastguard Worker         esc->m_useLdQmfTimeAlign = 1;
1558*e5436536SAndroid Build Coastguard Worker         if (cb->cbSsc != NULL) {
1559*e5436536SAndroid Build Coastguard Worker           ErrorStatus = (TRANSPORTDEC_ERROR)cb->cbSsc(
1560*e5436536SAndroid Build Coastguard Worker               cb->cbSscData, hBs, asc->m_aot,
1561*e5436536SAndroid Build Coastguard Worker               asc->m_samplingFrequency << esc->m_sbrSamplingRate,
1562*e5436536SAndroid Build Coastguard Worker               asc->m_samplesPerFrame << esc->m_sbrSamplingRate,
1563*e5436536SAndroid Build Coastguard Worker               asc->m_channelConfiguration, 1, /* stereoConfigIndex */
1564*e5436536SAndroid Build Coastguard Worker               -1, /* nTimeSlots: read from bitstream */
1565*e5436536SAndroid Build Coastguard Worker               eldExtLen, asc->configMode, &asc->SacConfigChanged);
1566*e5436536SAndroid Build Coastguard Worker           if (ErrorStatus != TRANSPORTDEC_OK) {
1567*e5436536SAndroid Build Coastguard Worker             return TRANSPORTDEC_PARSE_ERROR;
1568*e5436536SAndroid Build Coastguard Worker           }
1569*e5436536SAndroid Build Coastguard Worker           if (esc->m_downscaledSamplingFrequency != asc->m_samplingFrequency) {
1570*e5436536SAndroid Build Coastguard Worker             return TRANSPORTDEC_UNSUPPORTED_FORMAT; /* ELDv2 w/ ELD downscaled
1571*e5436536SAndroid Build Coastguard Worker                                                        mode not allowed */
1572*e5436536SAndroid Build Coastguard Worker           }
1573*e5436536SAndroid Build Coastguard Worker           break;
1574*e5436536SAndroid Build Coastguard Worker         }
1575*e5436536SAndroid Build Coastguard Worker 
1576*e5436536SAndroid Build Coastguard Worker         FDK_FALLTHROUGH;
1577*e5436536SAndroid Build Coastguard Worker       default:
1578*e5436536SAndroid Build Coastguard Worker         for (cnt = 0; cnt < eldExtLen; cnt++) {
1579*e5436536SAndroid Build Coastguard Worker           FDKreadBits(hBs, 8);
1580*e5436536SAndroid Build Coastguard Worker         }
1581*e5436536SAndroid Build Coastguard Worker         break;
1582*e5436536SAndroid Build Coastguard Worker 
1583*e5436536SAndroid Build Coastguard Worker       case ELDEXT_DOWNSCALEINFO:
1584*e5436536SAndroid Build Coastguard Worker         UCHAR tmpDownscaleFreqIdx;
1585*e5436536SAndroid Build Coastguard Worker         esc->m_downscaledSamplingFrequency =
1586*e5436536SAndroid Build Coastguard Worker             getSampleRate(hBs, &tmpDownscaleFreqIdx, 4);
1587*e5436536SAndroid Build Coastguard Worker         if (esc->m_downscaledSamplingFrequency == 0 ||
1588*e5436536SAndroid Build Coastguard Worker             esc->m_downscaledSamplingFrequency > 96000) {
1589*e5436536SAndroid Build Coastguard Worker           return TRANSPORTDEC_PARSE_ERROR;
1590*e5436536SAndroid Build Coastguard Worker         }
1591*e5436536SAndroid Build Coastguard Worker         downscale_fill_nibble = FDKreadBits(hBs, 4);
1592*e5436536SAndroid Build Coastguard Worker         if (downscale_fill_nibble != 0x0) {
1593*e5436536SAndroid Build Coastguard Worker           return TRANSPORTDEC_PARSE_ERROR;
1594*e5436536SAndroid Build Coastguard Worker         }
1595*e5436536SAndroid Build Coastguard Worker         if (esc->m_useLdQmfTimeAlign == 1) {
1596*e5436536SAndroid Build Coastguard Worker           return TRANSPORTDEC_UNSUPPORTED_FORMAT; /* ELDv2 w/ ELD downscaled
1597*e5436536SAndroid Build Coastguard Worker                                                      mode not allowed */
1598*e5436536SAndroid Build Coastguard Worker         }
1599*e5436536SAndroid Build Coastguard Worker         break;
1600*e5436536SAndroid Build Coastguard Worker     }
1601*e5436536SAndroid Build Coastguard Worker   }
1602*e5436536SAndroid Build Coastguard Worker   if (eldExtType != ELDEXT_TERM) {
1603*e5436536SAndroid Build Coastguard Worker     return TRANSPORTDEC_PARSE_ERROR;
1604*e5436536SAndroid Build Coastguard Worker   }
1605*e5436536SAndroid Build Coastguard Worker 
1606*e5436536SAndroid Build Coastguard Worker   if ((INT)FDKgetValidBits(hBs) < 0) {
1607*e5436536SAndroid Build Coastguard Worker     return TRANSPORTDEC_PARSE_ERROR;
1608*e5436536SAndroid Build Coastguard Worker   }
1609*e5436536SAndroid Build Coastguard Worker 
1610*e5436536SAndroid Build Coastguard Worker   if (esc->m_sbrPresentFlag == 1 && numSbrHeader != 0) {
1611*e5436536SAndroid Build Coastguard Worker     INT dsFactor = 1; /* Downscale factor must be 1 or even for SBR */
1612*e5436536SAndroid Build Coastguard Worker     if (esc->m_downscaledSamplingFrequency != 0) {
1613*e5436536SAndroid Build Coastguard Worker       if (asc->m_samplingFrequency % esc->m_downscaledSamplingFrequency != 0) {
1614*e5436536SAndroid Build Coastguard Worker         return TRANSPORTDEC_UNSUPPORTED_FORMAT;
1615*e5436536SAndroid Build Coastguard Worker       }
1616*e5436536SAndroid Build Coastguard Worker       dsFactor = asc->m_samplingFrequency / esc->m_downscaledSamplingFrequency;
1617*e5436536SAndroid Build Coastguard Worker       if (dsFactor != 1 && (dsFactor)&1) {
1618*e5436536SAndroid Build Coastguard Worker         return TRANSPORTDEC_UNSUPPORTED_FORMAT; /* SBR needs an even downscale
1619*e5436536SAndroid Build Coastguard Worker                                                    factor */
1620*e5436536SAndroid Build Coastguard Worker       }
1621*e5436536SAndroid Build Coastguard Worker       if (dsFactor != 1 && dsFactor != 2 && dsFactor != 4) {
1622*e5436536SAndroid Build Coastguard Worker         dsFactor = 1; /* don't apply dsf for not yet supported even dsfs */
1623*e5436536SAndroid Build Coastguard Worker       }
1624*e5436536SAndroid Build Coastguard Worker       if ((INT)asc->m_samplesPerFrame % dsFactor != 0) {
1625*e5436536SAndroid Build Coastguard Worker         return TRANSPORTDEC_UNSUPPORTED_FORMAT; /* frameSize/dsf must be an
1626*e5436536SAndroid Build Coastguard Worker                                                    integer number */
1627*e5436536SAndroid Build Coastguard Worker       }
1628*e5436536SAndroid Build Coastguard Worker     }
1629*e5436536SAndroid Build Coastguard Worker     eldExtLenSum = eldExtLenSum - FDKgetValidBits(hBs);
1630*e5436536SAndroid Build Coastguard Worker     FDKpushBack(hBs, eldExtLenSum + ldSbrLen);
1631*e5436536SAndroid Build Coastguard Worker     if (0 != ld_sbr_header(asc, dsFactor, hBs, cb)) {
1632*e5436536SAndroid Build Coastguard Worker       return TRANSPORTDEC_PARSE_ERROR;
1633*e5436536SAndroid Build Coastguard Worker     }
1634*e5436536SAndroid Build Coastguard Worker     FDKpushFor(hBs, eldExtLenSum);
1635*e5436536SAndroid Build Coastguard Worker   }
1636*e5436536SAndroid Build Coastguard Worker   return (ErrorStatus);
1637*e5436536SAndroid Build Coastguard Worker }
1638*e5436536SAndroid Build Coastguard Worker 
1639*e5436536SAndroid Build Coastguard Worker /*
1640*e5436536SAndroid Build Coastguard Worker Subroutine to store config in UCHAR buffer. Bit stream position does not change.
1641*e5436536SAndroid Build Coastguard Worker */
StoreConfigAsBitstream(HANDLE_FDK_BITSTREAM hBs,const INT configSize_bits,UCHAR * configTargetBuffer,const USHORT configTargetBufferSize_bytes)1642*e5436536SAndroid Build Coastguard Worker static UINT StoreConfigAsBitstream(
1643*e5436536SAndroid Build Coastguard Worker     HANDLE_FDK_BITSTREAM hBs, const INT configSize_bits, /* If < 0 (> 0) config
1644*e5436536SAndroid Build Coastguard Worker                                                             to read is before
1645*e5436536SAndroid Build Coastguard Worker                                                             (after) current bit
1646*e5436536SAndroid Build Coastguard Worker                                                             stream position. */
1647*e5436536SAndroid Build Coastguard Worker     UCHAR *configTargetBuffer, const USHORT configTargetBufferSize_bytes) {
1648*e5436536SAndroid Build Coastguard Worker   FDK_BITSTREAM usacConf;
1649*e5436536SAndroid Build Coastguard Worker   UINT const nBits = fAbs(configSize_bits);
1650*e5436536SAndroid Build Coastguard Worker   UINT j, tmp;
1651*e5436536SAndroid Build Coastguard Worker 
1652*e5436536SAndroid Build Coastguard Worker   if (nBits > 8 * (UINT)configTargetBufferSize_bytes) {
1653*e5436536SAndroid Build Coastguard Worker     return 1;
1654*e5436536SAndroid Build Coastguard Worker   }
1655*e5436536SAndroid Build Coastguard Worker   FDKmemclear(configTargetBuffer, configTargetBufferSize_bytes);
1656*e5436536SAndroid Build Coastguard Worker 
1657*e5436536SAndroid Build Coastguard Worker   FDKinitBitStream(&usacConf, configTargetBuffer, configTargetBufferSize_bytes,
1658*e5436536SAndroid Build Coastguard Worker                    nBits, BS_WRITER);
1659*e5436536SAndroid Build Coastguard Worker   if (configSize_bits < 0) {
1660*e5436536SAndroid Build Coastguard Worker     FDKpushBack(hBs, nBits);
1661*e5436536SAndroid Build Coastguard Worker   }
1662*e5436536SAndroid Build Coastguard Worker   for (j = nBits; j > 31; j -= 32) {
1663*e5436536SAndroid Build Coastguard Worker     tmp = FDKreadBits(hBs, 32);
1664*e5436536SAndroid Build Coastguard Worker     FDKwriteBits(&usacConf, tmp, 32);
1665*e5436536SAndroid Build Coastguard Worker   }
1666*e5436536SAndroid Build Coastguard Worker   if (j > 0) {
1667*e5436536SAndroid Build Coastguard Worker     tmp = FDKreadBits(hBs, j);
1668*e5436536SAndroid Build Coastguard Worker     FDKwriteBits(&usacConf, tmp, j);
1669*e5436536SAndroid Build Coastguard Worker   }
1670*e5436536SAndroid Build Coastguard Worker   FDKsyncCache(&usacConf);
1671*e5436536SAndroid Build Coastguard Worker   if (configSize_bits > 0) {
1672*e5436536SAndroid Build Coastguard Worker     FDKpushBack(hBs, nBits);
1673*e5436536SAndroid Build Coastguard Worker   }
1674*e5436536SAndroid Build Coastguard Worker 
1675*e5436536SAndroid Build Coastguard Worker   return 0;
1676*e5436536SAndroid Build Coastguard Worker }
1677*e5436536SAndroid Build Coastguard Worker 
1678*e5436536SAndroid Build Coastguard Worker /* maps coreSbrFrameLengthIndex to coreCoderFrameLength */
1679*e5436536SAndroid Build Coastguard Worker static const USHORT usacFrameLength[8] = {768, 1024, 2048, 2048, 4096, 0, 0, 0};
1680*e5436536SAndroid Build Coastguard Worker /* maps coreSbrFrameLengthIndex to sbrRatioIndex */
1681*e5436536SAndroid Build Coastguard Worker static const UCHAR sbrRatioIndex[8] = {0, 0, 2, 3, 1, 0, 0, 0};
1682*e5436536SAndroid Build Coastguard Worker 
1683*e5436536SAndroid Build Coastguard Worker /*
1684*e5436536SAndroid Build Coastguard Worker   subroutine for parsing extension element configuration:
1685*e5436536SAndroid Build Coastguard Worker   UsacExtElementConfig() q.v. ISO/IEC FDIS 23003-3:2011(E) Table 14
1686*e5436536SAndroid Build Coastguard Worker   rsv603daExtElementConfig() q.v. ISO/IEC DIS 23008-3 Table 13
1687*e5436536SAndroid Build Coastguard Worker */
extElementConfig(CSUsacExtElementConfig * extElement,HANDLE_FDK_BITSTREAM hBs,const CSTpCallBacks * cb,const UCHAR numSignalsInGroup,const UINT coreFrameLength,const int subStreamIndex,const AUDIO_OBJECT_TYPE aot)1688*e5436536SAndroid Build Coastguard Worker static TRANSPORTDEC_ERROR extElementConfig(CSUsacExtElementConfig *extElement,
1689*e5436536SAndroid Build Coastguard Worker                                            HANDLE_FDK_BITSTREAM hBs,
1690*e5436536SAndroid Build Coastguard Worker                                            const CSTpCallBacks *cb,
1691*e5436536SAndroid Build Coastguard Worker                                            const UCHAR numSignalsInGroup,
1692*e5436536SAndroid Build Coastguard Worker                                            const UINT coreFrameLength,
1693*e5436536SAndroid Build Coastguard Worker                                            const int subStreamIndex,
1694*e5436536SAndroid Build Coastguard Worker                                            const AUDIO_OBJECT_TYPE aot) {
1695*e5436536SAndroid Build Coastguard Worker   TRANSPORTDEC_ERROR ErrorStatus = TRANSPORTDEC_OK;
1696*e5436536SAndroid Build Coastguard Worker 
1697*e5436536SAndroid Build Coastguard Worker   UINT usacExtElementType = escapedValue(hBs, 4, 8, 16);
1698*e5436536SAndroid Build Coastguard Worker 
1699*e5436536SAndroid Build Coastguard Worker   /* recurve extension elements which are invalid for USAC */
1700*e5436536SAndroid Build Coastguard Worker   if (aot == AOT_USAC) {
1701*e5436536SAndroid Build Coastguard Worker     switch (usacExtElementType) {
1702*e5436536SAndroid Build Coastguard Worker       case ID_EXT_ELE_FILL:
1703*e5436536SAndroid Build Coastguard Worker       case ID_EXT_ELE_MPEGS:
1704*e5436536SAndroid Build Coastguard Worker       case ID_EXT_ELE_SAOC:
1705*e5436536SAndroid Build Coastguard Worker       case ID_EXT_ELE_AUDIOPREROLL:
1706*e5436536SAndroid Build Coastguard Worker       case ID_EXT_ELE_UNI_DRC:
1707*e5436536SAndroid Build Coastguard Worker         break;
1708*e5436536SAndroid Build Coastguard Worker       default:
1709*e5436536SAndroid Build Coastguard Worker         usacExtElementType = ID_EXT_ELE_UNKNOWN;
1710*e5436536SAndroid Build Coastguard Worker         break;
1711*e5436536SAndroid Build Coastguard Worker     }
1712*e5436536SAndroid Build Coastguard Worker   }
1713*e5436536SAndroid Build Coastguard Worker 
1714*e5436536SAndroid Build Coastguard Worker   int usacExtElementConfigLength = escapedValue(hBs, 4, 8, 16);
1715*e5436536SAndroid Build Coastguard Worker   extElement->usacExtElementConfigLength = (USHORT)usacExtElementConfigLength;
1716*e5436536SAndroid Build Coastguard Worker   INT bsAnchor;
1717*e5436536SAndroid Build Coastguard Worker 
1718*e5436536SAndroid Build Coastguard Worker   if (FDKreadBit(hBs)) /* usacExtElementDefaultLengthPresent */
1719*e5436536SAndroid Build Coastguard Worker     extElement->usacExtElementDefaultLength = escapedValue(hBs, 8, 16, 0) + 1;
1720*e5436536SAndroid Build Coastguard Worker   else
1721*e5436536SAndroid Build Coastguard Worker     extElement->usacExtElementDefaultLength = 0;
1722*e5436536SAndroid Build Coastguard Worker 
1723*e5436536SAndroid Build Coastguard Worker   extElement->usacExtElementPayloadFrag = FDKreadBit(hBs);
1724*e5436536SAndroid Build Coastguard Worker 
1725*e5436536SAndroid Build Coastguard Worker   bsAnchor = (INT)FDKgetValidBits(hBs);
1726*e5436536SAndroid Build Coastguard Worker 
1727*e5436536SAndroid Build Coastguard Worker   switch (usacExtElementType) {
1728*e5436536SAndroid Build Coastguard Worker     case ID_EXT_ELE_UNKNOWN:
1729*e5436536SAndroid Build Coastguard Worker     case ID_EXT_ELE_FILL:
1730*e5436536SAndroid Build Coastguard Worker       break;
1731*e5436536SAndroid Build Coastguard Worker     case ID_EXT_ELE_AUDIOPREROLL:
1732*e5436536SAndroid Build Coastguard Worker       /* No configuration element */
1733*e5436536SAndroid Build Coastguard Worker       extElement->usacExtElementHasAudioPreRoll = 1;
1734*e5436536SAndroid Build Coastguard Worker       break;
1735*e5436536SAndroid Build Coastguard Worker     case ID_EXT_ELE_UNI_DRC: {
1736*e5436536SAndroid Build Coastguard Worker       if (cb->cbUniDrc != NULL) {
1737*e5436536SAndroid Build Coastguard Worker         ErrorStatus = (TRANSPORTDEC_ERROR)cb->cbUniDrc(
1738*e5436536SAndroid Build Coastguard Worker             cb->cbUniDrcData, hBs, usacExtElementConfigLength,
1739*e5436536SAndroid Build Coastguard Worker             0, /* uniDrcConfig */
1740*e5436536SAndroid Build Coastguard Worker             subStreamIndex, 0, aot);
1741*e5436536SAndroid Build Coastguard Worker         if (ErrorStatus != TRANSPORTDEC_OK) {
1742*e5436536SAndroid Build Coastguard Worker           return ErrorStatus;
1743*e5436536SAndroid Build Coastguard Worker         }
1744*e5436536SAndroid Build Coastguard Worker       }
1745*e5436536SAndroid Build Coastguard Worker     } break;
1746*e5436536SAndroid Build Coastguard Worker     default:
1747*e5436536SAndroid Build Coastguard Worker       usacExtElementType = ID_EXT_ELE_UNKNOWN;
1748*e5436536SAndroid Build Coastguard Worker       break;
1749*e5436536SAndroid Build Coastguard Worker   }
1750*e5436536SAndroid Build Coastguard Worker   extElement->usacExtElementType = (USAC_EXT_ELEMENT_TYPE)usacExtElementType;
1751*e5436536SAndroid Build Coastguard Worker 
1752*e5436536SAndroid Build Coastguard Worker   /* Adjust bit stream position. This is required because of byte alignment and
1753*e5436536SAndroid Build Coastguard Worker    * unhandled extensions. */
1754*e5436536SAndroid Build Coastguard Worker   {
1755*e5436536SAndroid Build Coastguard Worker     INT left_bits = (usacExtElementConfigLength << 3) -
1756*e5436536SAndroid Build Coastguard Worker                     (bsAnchor - (INT)FDKgetValidBits(hBs));
1757*e5436536SAndroid Build Coastguard Worker     if (left_bits >= 0) {
1758*e5436536SAndroid Build Coastguard Worker       FDKpushFor(hBs, left_bits);
1759*e5436536SAndroid Build Coastguard Worker     } else {
1760*e5436536SAndroid Build Coastguard Worker       /* parsed too many bits */
1761*e5436536SAndroid Build Coastguard Worker       ErrorStatus = TRANSPORTDEC_PARSE_ERROR;
1762*e5436536SAndroid Build Coastguard Worker     }
1763*e5436536SAndroid Build Coastguard Worker   }
1764*e5436536SAndroid Build Coastguard Worker 
1765*e5436536SAndroid Build Coastguard Worker   return ErrorStatus;
1766*e5436536SAndroid Build Coastguard Worker }
1767*e5436536SAndroid Build Coastguard Worker 
1768*e5436536SAndroid Build Coastguard Worker /*
1769*e5436536SAndroid Build Coastguard Worker   subroutine for parsing the USAC / RSVD60 configuration extension:
1770*e5436536SAndroid Build Coastguard Worker   UsacConfigExtension() q.v. ISO/IEC FDIS 23003-3:2011(E) Table 15
1771*e5436536SAndroid Build Coastguard Worker   rsv603daConfigExtension() q.v. ISO/IEC DIS 23008-3 Table 14
1772*e5436536SAndroid Build Coastguard Worker */
configExtension(CSUsacConfig * usc,HANDLE_FDK_BITSTREAM hBs,const CSTpCallBacks * cb)1773*e5436536SAndroid Build Coastguard Worker static TRANSPORTDEC_ERROR configExtension(CSUsacConfig *usc,
1774*e5436536SAndroid Build Coastguard Worker                                           HANDLE_FDK_BITSTREAM hBs,
1775*e5436536SAndroid Build Coastguard Worker                                           const CSTpCallBacks *cb) {
1776*e5436536SAndroid Build Coastguard Worker   TRANSPORTDEC_ERROR ErrorStatus = TRANSPORTDEC_OK;
1777*e5436536SAndroid Build Coastguard Worker 
1778*e5436536SAndroid Build Coastguard Worker   int numConfigExtensions;
1779*e5436536SAndroid Build Coastguard Worker   UINT usacConfigExtType;
1780*e5436536SAndroid Build Coastguard Worker   int usacConfigExtLength;
1781*e5436536SAndroid Build Coastguard Worker   int loudnessInfoSetIndex =
1782*e5436536SAndroid Build Coastguard Worker       -1; /* index of loudnessInfoSet config extension. -1 if not contained. */
1783*e5436536SAndroid Build Coastguard Worker   int tmp_subStreamIndex = 0;
1784*e5436536SAndroid Build Coastguard Worker   AUDIO_OBJECT_TYPE tmp_aot = AOT_USAC;
1785*e5436536SAndroid Build Coastguard Worker 
1786*e5436536SAndroid Build Coastguard Worker   numConfigExtensions = (int)escapedValue(hBs, 2, 4, 8) + 1;
1787*e5436536SAndroid Build Coastguard Worker   for (int confExtIdx = 0; confExtIdx < numConfigExtensions; confExtIdx++) {
1788*e5436536SAndroid Build Coastguard Worker     INT nbits;
1789*e5436536SAndroid Build Coastguard Worker     int loudnessInfoSetConfigExtensionPosition = FDKgetValidBits(hBs);
1790*e5436536SAndroid Build Coastguard Worker     usacConfigExtType = escapedValue(hBs, 4, 8, 16);
1791*e5436536SAndroid Build Coastguard Worker     usacConfigExtLength = (int)escapedValue(hBs, 4, 8, 16);
1792*e5436536SAndroid Build Coastguard Worker 
1793*e5436536SAndroid Build Coastguard Worker     /* Start bit position of config extension */
1794*e5436536SAndroid Build Coastguard Worker     nbits = (INT)FDKgetValidBits(hBs);
1795*e5436536SAndroid Build Coastguard Worker 
1796*e5436536SAndroid Build Coastguard Worker     /* Return an error in case the bitbuffer fill level is too low. */
1797*e5436536SAndroid Build Coastguard Worker     if (nbits < usacConfigExtLength * 8) {
1798*e5436536SAndroid Build Coastguard Worker       return TRANSPORTDEC_PARSE_ERROR;
1799*e5436536SAndroid Build Coastguard Worker     }
1800*e5436536SAndroid Build Coastguard Worker 
1801*e5436536SAndroid Build Coastguard Worker     switch (usacConfigExtType) {
1802*e5436536SAndroid Build Coastguard Worker       case ID_CONFIG_EXT_FILL:
1803*e5436536SAndroid Build Coastguard Worker         for (int i = 0; i < usacConfigExtLength; i++) {
1804*e5436536SAndroid Build Coastguard Worker           if (FDKreadBits(hBs, 8) != 0xa5) {
1805*e5436536SAndroid Build Coastguard Worker             return TRANSPORTDEC_PARSE_ERROR;
1806*e5436536SAndroid Build Coastguard Worker           }
1807*e5436536SAndroid Build Coastguard Worker         }
1808*e5436536SAndroid Build Coastguard Worker         break;
1809*e5436536SAndroid Build Coastguard Worker       case ID_CONFIG_EXT_LOUDNESS_INFO: {
1810*e5436536SAndroid Build Coastguard Worker         if (cb->cbUniDrc != NULL) {
1811*e5436536SAndroid Build Coastguard Worker           ErrorStatus = (TRANSPORTDEC_ERROR)cb->cbUniDrc(
1812*e5436536SAndroid Build Coastguard Worker               cb->cbUniDrcData, hBs, usacConfigExtLength,
1813*e5436536SAndroid Build Coastguard Worker               1, /* loudnessInfoSet */
1814*e5436536SAndroid Build Coastguard Worker               tmp_subStreamIndex, loudnessInfoSetConfigExtensionPosition,
1815*e5436536SAndroid Build Coastguard Worker               tmp_aot);
1816*e5436536SAndroid Build Coastguard Worker           if (ErrorStatus != TRANSPORTDEC_OK) {
1817*e5436536SAndroid Build Coastguard Worker             return ErrorStatus;
1818*e5436536SAndroid Build Coastguard Worker           }
1819*e5436536SAndroid Build Coastguard Worker           loudnessInfoSetIndex = confExtIdx;
1820*e5436536SAndroid Build Coastguard Worker         }
1821*e5436536SAndroid Build Coastguard Worker       } break;
1822*e5436536SAndroid Build Coastguard Worker       default:
1823*e5436536SAndroid Build Coastguard Worker         break;
1824*e5436536SAndroid Build Coastguard Worker     }
1825*e5436536SAndroid Build Coastguard Worker 
1826*e5436536SAndroid Build Coastguard Worker     /* Skip remaining bits. If too many bits were parsed, assume error. */
1827*e5436536SAndroid Build Coastguard Worker     usacConfigExtLength =
1828*e5436536SAndroid Build Coastguard Worker         8 * usacConfigExtLength - (nbits - (INT)FDKgetValidBits(hBs));
1829*e5436536SAndroid Build Coastguard Worker     if (usacConfigExtLength < 0) {
1830*e5436536SAndroid Build Coastguard Worker       return TRANSPORTDEC_PARSE_ERROR;
1831*e5436536SAndroid Build Coastguard Worker     }
1832*e5436536SAndroid Build Coastguard Worker     FDKpushFor(hBs, usacConfigExtLength);
1833*e5436536SAndroid Build Coastguard Worker   }
1834*e5436536SAndroid Build Coastguard Worker 
1835*e5436536SAndroid Build Coastguard Worker   if (loudnessInfoSetIndex == -1 && cb->cbUniDrc != NULL) {
1836*e5436536SAndroid Build Coastguard Worker     /* no loudnessInfoSet contained. Clear the loudnessInfoSet struct by feeding
1837*e5436536SAndroid Build Coastguard Worker      * an empty config extension */
1838*e5436536SAndroid Build Coastguard Worker     ErrorStatus = (TRANSPORTDEC_ERROR)cb->cbUniDrc(
1839*e5436536SAndroid Build Coastguard Worker         cb->cbUniDrcData, NULL, 0, 1 /* loudnessInfoSet */, tmp_subStreamIndex,
1840*e5436536SAndroid Build Coastguard Worker         0, tmp_aot);
1841*e5436536SAndroid Build Coastguard Worker     if (ErrorStatus != TRANSPORTDEC_OK) {
1842*e5436536SAndroid Build Coastguard Worker       return ErrorStatus;
1843*e5436536SAndroid Build Coastguard Worker     }
1844*e5436536SAndroid Build Coastguard Worker   }
1845*e5436536SAndroid Build Coastguard Worker 
1846*e5436536SAndroid Build Coastguard Worker   return ErrorStatus;
1847*e5436536SAndroid Build Coastguard Worker }
1848*e5436536SAndroid Build Coastguard Worker 
1849*e5436536SAndroid Build Coastguard Worker /* This function unifies decoder config parsing of USAC and RSV60:
1850*e5436536SAndroid Build Coastguard Worker    rsv603daDecoderConfig() ISO/IEC DIS 23008-3   Table 8
1851*e5436536SAndroid Build Coastguard Worker    UsacDecoderConfig()     ISO/IEC FDIS 23003-3  Table 6
1852*e5436536SAndroid Build Coastguard Worker   */
UsacRsv60DecoderConfig_Parse(CSAudioSpecificConfig * asc,HANDLE_FDK_BITSTREAM hBs,const CSTpCallBacks * cb)1853*e5436536SAndroid Build Coastguard Worker static TRANSPORTDEC_ERROR UsacRsv60DecoderConfig_Parse(
1854*e5436536SAndroid Build Coastguard Worker     CSAudioSpecificConfig *asc, HANDLE_FDK_BITSTREAM hBs,
1855*e5436536SAndroid Build Coastguard Worker     const CSTpCallBacks *cb) {
1856*e5436536SAndroid Build Coastguard Worker   TRANSPORTDEC_ERROR ErrorStatus = TRANSPORTDEC_OK;
1857*e5436536SAndroid Build Coastguard Worker   CSUsacConfig *usc = &asc->m_sc.m_usacConfig;
1858*e5436536SAndroid Build Coastguard Worker   int i, numberOfElements;
1859*e5436536SAndroid Build Coastguard Worker   int channelElementIdx =
1860*e5436536SAndroid Build Coastguard Worker       0; /* index for elements which contain audio channels (sce, cpe, lfe) */
1861*e5436536SAndroid Build Coastguard Worker   SC_CHANNEL_CONFIG sc_chan_config = {0, 0, 0, 0};
1862*e5436536SAndroid Build Coastguard Worker   int uniDrcElement =
1863*e5436536SAndroid Build Coastguard Worker       -1; /* index of uniDrc extension element. -1 if not contained. */
1864*e5436536SAndroid Build Coastguard Worker 
1865*e5436536SAndroid Build Coastguard Worker   numberOfElements = (int)escapedValue(hBs, 4, 8, 16) + 1;
1866*e5436536SAndroid Build Coastguard Worker   usc->m_usacNumElements = numberOfElements;
1867*e5436536SAndroid Build Coastguard Worker   if (numberOfElements > TP_USAC_MAX_ELEMENTS) {
1868*e5436536SAndroid Build Coastguard Worker     return TRANSPORTDEC_UNSUPPORTED_FORMAT;
1869*e5436536SAndroid Build Coastguard Worker   }
1870*e5436536SAndroid Build Coastguard Worker   usc->m_nUsacChannels = 0;
1871*e5436536SAndroid Build Coastguard Worker   usc->m_channelConfigurationIndex = asc->m_channelConfiguration;
1872*e5436536SAndroid Build Coastguard Worker 
1873*e5436536SAndroid Build Coastguard Worker   if (asc->m_aot == AOT_USAC) {
1874*e5436536SAndroid Build Coastguard Worker     sc_chan_config = sc_chan_config_tab[usc->m_channelConfigurationIndex];
1875*e5436536SAndroid Build Coastguard Worker 
1876*e5436536SAndroid Build Coastguard Worker     if (sc_chan_config.nCh > (SCHAR)TP_USAC_MAX_SPEAKERS) {
1877*e5436536SAndroid Build Coastguard Worker       return TRANSPORTDEC_PARSE_ERROR;
1878*e5436536SAndroid Build Coastguard Worker     }
1879*e5436536SAndroid Build Coastguard Worker   }
1880*e5436536SAndroid Build Coastguard Worker 
1881*e5436536SAndroid Build Coastguard Worker   for (i = 0; i < numberOfElements; i++) {
1882*e5436536SAndroid Build Coastguard Worker     MP4_ELEMENT_ID usacElementType = (MP4_ELEMENT_ID)(
1883*e5436536SAndroid Build Coastguard Worker         FDKreadBits(hBs, 2) | USAC_ID_BIT); /* set USAC_ID_BIT to map
1884*e5436536SAndroid Build Coastguard Worker                                                usacElementType to
1885*e5436536SAndroid Build Coastguard Worker                                                MP4_ELEMENT_ID enum */
1886*e5436536SAndroid Build Coastguard Worker     usc->element[i].usacElementType = usacElementType;
1887*e5436536SAndroid Build Coastguard Worker 
1888*e5436536SAndroid Build Coastguard Worker     /* sanity check: update element counter */
1889*e5436536SAndroid Build Coastguard Worker     if (asc->m_aot == AOT_USAC) {
1890*e5436536SAndroid Build Coastguard Worker       switch (usacElementType) {
1891*e5436536SAndroid Build Coastguard Worker         case ID_USAC_SCE:
1892*e5436536SAndroid Build Coastguard Worker           sc_chan_config.nSCE--;
1893*e5436536SAndroid Build Coastguard Worker           break;
1894*e5436536SAndroid Build Coastguard Worker         case ID_USAC_CPE:
1895*e5436536SAndroid Build Coastguard Worker           sc_chan_config.nCPE--;
1896*e5436536SAndroid Build Coastguard Worker           break;
1897*e5436536SAndroid Build Coastguard Worker         case ID_USAC_LFE:
1898*e5436536SAndroid Build Coastguard Worker           sc_chan_config.nLFE--;
1899*e5436536SAndroid Build Coastguard Worker           break;
1900*e5436536SAndroid Build Coastguard Worker         default:
1901*e5436536SAndroid Build Coastguard Worker           break;
1902*e5436536SAndroid Build Coastguard Worker       }
1903*e5436536SAndroid Build Coastguard Worker       if (usc->m_channelConfigurationIndex) {
1904*e5436536SAndroid Build Coastguard Worker         /* sanity check: no element counter may be smaller zero */
1905*e5436536SAndroid Build Coastguard Worker         if (sc_chan_config.nCPE < 0 || sc_chan_config.nSCE < 0 ||
1906*e5436536SAndroid Build Coastguard Worker             sc_chan_config.nLFE < 0) {
1907*e5436536SAndroid Build Coastguard Worker           return TRANSPORTDEC_PARSE_ERROR;
1908*e5436536SAndroid Build Coastguard Worker         }
1909*e5436536SAndroid Build Coastguard Worker       }
1910*e5436536SAndroid Build Coastguard Worker     }
1911*e5436536SAndroid Build Coastguard Worker 
1912*e5436536SAndroid Build Coastguard Worker     switch (usacElementType) {
1913*e5436536SAndroid Build Coastguard Worker       case ID_USAC_SCE:
1914*e5436536SAndroid Build Coastguard Worker         /* UsacCoreConfig() ISO/IEC FDIS 23003-3  Table 10 */
1915*e5436536SAndroid Build Coastguard Worker         if (FDKreadBit(hBs)) { /* tw_mdct */
1916*e5436536SAndroid Build Coastguard Worker           return TRANSPORTDEC_UNSUPPORTED_FORMAT;
1917*e5436536SAndroid Build Coastguard Worker         }
1918*e5436536SAndroid Build Coastguard Worker         usc->element[i].m_noiseFilling = FDKreadBits(hBs, 1);
1919*e5436536SAndroid Build Coastguard Worker         /* end of UsacCoreConfig() */
1920*e5436536SAndroid Build Coastguard Worker         if (usc->m_sbrRatioIndex > 0) {
1921*e5436536SAndroid Build Coastguard Worker           if (cb->cbSbr == NULL) {
1922*e5436536SAndroid Build Coastguard Worker             return TRANSPORTDEC_UNKOWN_ERROR;
1923*e5436536SAndroid Build Coastguard Worker           }
1924*e5436536SAndroid Build Coastguard Worker           /* SbrConfig() ISO/IEC FDIS 23003-3  Table 11 */
1925*e5436536SAndroid Build Coastguard Worker           usc->element[i].m_harmonicSBR = FDKreadBit(hBs);
1926*e5436536SAndroid Build Coastguard Worker           usc->element[i].m_interTes = FDKreadBit(hBs);
1927*e5436536SAndroid Build Coastguard Worker           usc->element[i].m_pvc = FDKreadBit(hBs);
1928*e5436536SAndroid Build Coastguard Worker           if (cb->cbSbr(cb->cbSbrData, hBs, asc->m_samplingFrequency,
1929*e5436536SAndroid Build Coastguard Worker                         asc->m_extensionSamplingFrequency,
1930*e5436536SAndroid Build Coastguard Worker                         asc->m_samplesPerFrame, asc->m_aot, ID_SCE,
1931*e5436536SAndroid Build Coastguard Worker                         channelElementIdx, usc->element[i].m_harmonicSBR,
1932*e5436536SAndroid Build Coastguard Worker                         usc->element[i].m_stereoConfigIndex, asc->configMode,
1933*e5436536SAndroid Build Coastguard Worker                         &asc->SbrConfigChanged, 1)) {
1934*e5436536SAndroid Build Coastguard Worker             return TRANSPORTDEC_PARSE_ERROR;
1935*e5436536SAndroid Build Coastguard Worker           }
1936*e5436536SAndroid Build Coastguard Worker           /* end of SbrConfig() */
1937*e5436536SAndroid Build Coastguard Worker         }
1938*e5436536SAndroid Build Coastguard Worker         usc->m_nUsacChannels += 1;
1939*e5436536SAndroid Build Coastguard Worker         channelElementIdx++;
1940*e5436536SAndroid Build Coastguard Worker         break;
1941*e5436536SAndroid Build Coastguard Worker 
1942*e5436536SAndroid Build Coastguard Worker       case ID_USAC_CPE:
1943*e5436536SAndroid Build Coastguard Worker         /* UsacCoreConfig() ISO/IEC FDIS 23003-3  Table 10 */
1944*e5436536SAndroid Build Coastguard Worker         if (FDKreadBit(hBs)) { /* tw_mdct */
1945*e5436536SAndroid Build Coastguard Worker           return TRANSPORTDEC_UNSUPPORTED_FORMAT;
1946*e5436536SAndroid Build Coastguard Worker         }
1947*e5436536SAndroid Build Coastguard Worker         usc->element[i].m_noiseFilling = FDKreadBits(hBs, 1);
1948*e5436536SAndroid Build Coastguard Worker         /* end of UsacCoreConfig() */
1949*e5436536SAndroid Build Coastguard Worker         if (usc->m_sbrRatioIndex > 0) {
1950*e5436536SAndroid Build Coastguard Worker           if (cb->cbSbr == NULL) return TRANSPORTDEC_UNKOWN_ERROR;
1951*e5436536SAndroid Build Coastguard Worker           /* SbrConfig() ISO/IEC FDIS 23003-3 */
1952*e5436536SAndroid Build Coastguard Worker           usc->element[i].m_harmonicSBR = FDKreadBit(hBs);
1953*e5436536SAndroid Build Coastguard Worker           usc->element[i].m_interTes = FDKreadBit(hBs);
1954*e5436536SAndroid Build Coastguard Worker           usc->element[i].m_pvc = FDKreadBit(hBs);
1955*e5436536SAndroid Build Coastguard Worker           {
1956*e5436536SAndroid Build Coastguard Worker             INT bitsToSkip = skipSbrHeader(hBs, 1);
1957*e5436536SAndroid Build Coastguard Worker             /* read stereoConfigIndex */
1958*e5436536SAndroid Build Coastguard Worker             usc->element[i].m_stereoConfigIndex = FDKreadBits(hBs, 2);
1959*e5436536SAndroid Build Coastguard Worker             /* rewind */
1960*e5436536SAndroid Build Coastguard Worker             FDKpushBack(hBs, bitsToSkip + 2);
1961*e5436536SAndroid Build Coastguard Worker           }
1962*e5436536SAndroid Build Coastguard Worker           {
1963*e5436536SAndroid Build Coastguard Worker             MP4_ELEMENT_ID el_type =
1964*e5436536SAndroid Build Coastguard Worker                 (usc->element[i].m_stereoConfigIndex == 1 ||
1965*e5436536SAndroid Build Coastguard Worker                  usc->element[i].m_stereoConfigIndex == 2)
1966*e5436536SAndroid Build Coastguard Worker                     ? ID_SCE
1967*e5436536SAndroid Build Coastguard Worker                     : ID_CPE;
1968*e5436536SAndroid Build Coastguard Worker             if (cb->cbSbr(cb->cbSbrData, hBs, asc->m_samplingFrequency,
1969*e5436536SAndroid Build Coastguard Worker                           asc->m_extensionSamplingFrequency,
1970*e5436536SAndroid Build Coastguard Worker                           asc->m_samplesPerFrame, asc->m_aot, el_type,
1971*e5436536SAndroid Build Coastguard Worker                           channelElementIdx, usc->element[i].m_harmonicSBR,
1972*e5436536SAndroid Build Coastguard Worker                           usc->element[i].m_stereoConfigIndex, asc->configMode,
1973*e5436536SAndroid Build Coastguard Worker                           &asc->SbrConfigChanged, 1)) {
1974*e5436536SAndroid Build Coastguard Worker               return TRANSPORTDEC_PARSE_ERROR;
1975*e5436536SAndroid Build Coastguard Worker             }
1976*e5436536SAndroid Build Coastguard Worker           }
1977*e5436536SAndroid Build Coastguard Worker           /* end of SbrConfig() */
1978*e5436536SAndroid Build Coastguard Worker 
1979*e5436536SAndroid Build Coastguard Worker           usc->element[i].m_stereoConfigIndex =
1980*e5436536SAndroid Build Coastguard Worker               FDKreadBits(hBs, 2); /* Needed in RM5 syntax */
1981*e5436536SAndroid Build Coastguard Worker 
1982*e5436536SAndroid Build Coastguard Worker           if (usc->element[i].m_stereoConfigIndex > 0) {
1983*e5436536SAndroid Build Coastguard Worker             if (cb->cbSsc != NULL) {
1984*e5436536SAndroid Build Coastguard Worker               int samplesPerFrame = asc->m_samplesPerFrame;
1985*e5436536SAndroid Build Coastguard Worker 
1986*e5436536SAndroid Build Coastguard Worker               if (usc->m_sbrRatioIndex == 1) samplesPerFrame <<= 2;
1987*e5436536SAndroid Build Coastguard Worker               if (usc->m_sbrRatioIndex == 2)
1988*e5436536SAndroid Build Coastguard Worker                 samplesPerFrame = (samplesPerFrame * 8) / 3;
1989*e5436536SAndroid Build Coastguard Worker               if (usc->m_sbrRatioIndex == 3) samplesPerFrame <<= 1;
1990*e5436536SAndroid Build Coastguard Worker 
1991*e5436536SAndroid Build Coastguard Worker               /* Mps212Config() ISO/IEC FDIS 23003-3 */
1992*e5436536SAndroid Build Coastguard Worker               if (cb->cbSsc(cb->cbSscData, hBs, asc->m_aot,
1993*e5436536SAndroid Build Coastguard Worker                             asc->m_extensionSamplingFrequency, samplesPerFrame,
1994*e5436536SAndroid Build Coastguard Worker                             1, /* only downmix channels (residual channels are
1995*e5436536SAndroid Build Coastguard Worker                                   not counted) */
1996*e5436536SAndroid Build Coastguard Worker                             usc->element[i].m_stereoConfigIndex,
1997*e5436536SAndroid Build Coastguard Worker                             usc->m_coreSbrFrameLengthIndex,
1998*e5436536SAndroid Build Coastguard Worker                             0, /* don't know the length */
1999*e5436536SAndroid Build Coastguard Worker                             asc->configMode, &asc->SacConfigChanged)) {
2000*e5436536SAndroid Build Coastguard Worker                 return TRANSPORTDEC_PARSE_ERROR;
2001*e5436536SAndroid Build Coastguard Worker               }
2002*e5436536SAndroid Build Coastguard Worker               /* end of Mps212Config() */
2003*e5436536SAndroid Build Coastguard Worker             } else {
2004*e5436536SAndroid Build Coastguard Worker               return TRANSPORTDEC_UNKOWN_ERROR;
2005*e5436536SAndroid Build Coastguard Worker             }
2006*e5436536SAndroid Build Coastguard Worker           }
2007*e5436536SAndroid Build Coastguard Worker         } else {
2008*e5436536SAndroid Build Coastguard Worker           usc->element[i].m_stereoConfigIndex = 0;
2009*e5436536SAndroid Build Coastguard Worker         }
2010*e5436536SAndroid Build Coastguard Worker         usc->m_nUsacChannels += 2;
2011*e5436536SAndroid Build Coastguard Worker 
2012*e5436536SAndroid Build Coastguard Worker         channelElementIdx++;
2013*e5436536SAndroid Build Coastguard Worker         break;
2014*e5436536SAndroid Build Coastguard Worker 
2015*e5436536SAndroid Build Coastguard Worker       case ID_USAC_LFE:
2016*e5436536SAndroid Build Coastguard Worker         usc->element[i].m_noiseFilling = 0;
2017*e5436536SAndroid Build Coastguard Worker         usc->m_nUsacChannels += 1;
2018*e5436536SAndroid Build Coastguard Worker         if (usc->m_sbrRatioIndex > 0) {
2019*e5436536SAndroid Build Coastguard Worker           /* Use SBR for upsampling */
2020*e5436536SAndroid Build Coastguard Worker           if (cb->cbSbr == NULL) return ErrorStatus = TRANSPORTDEC_UNKOWN_ERROR;
2021*e5436536SAndroid Build Coastguard Worker           usc->element[i].m_harmonicSBR = (UCHAR)0;
2022*e5436536SAndroid Build Coastguard Worker           usc->element[i].m_interTes = (UCHAR)0;
2023*e5436536SAndroid Build Coastguard Worker           usc->element[i].m_pvc = (UCHAR)0;
2024*e5436536SAndroid Build Coastguard Worker           if (cb->cbSbr(cb->cbSbrData, hBs, asc->m_samplingFrequency,
2025*e5436536SAndroid Build Coastguard Worker                         asc->m_extensionSamplingFrequency,
2026*e5436536SAndroid Build Coastguard Worker                         asc->m_samplesPerFrame, asc->m_aot, ID_LFE,
2027*e5436536SAndroid Build Coastguard Worker                         channelElementIdx, usc->element[i].m_harmonicSBR,
2028*e5436536SAndroid Build Coastguard Worker                         usc->element[i].m_stereoConfigIndex, asc->configMode,
2029*e5436536SAndroid Build Coastguard Worker                         &asc->SbrConfigChanged, 1)) {
2030*e5436536SAndroid Build Coastguard Worker             return ErrorStatus = TRANSPORTDEC_PARSE_ERROR;
2031*e5436536SAndroid Build Coastguard Worker           }
2032*e5436536SAndroid Build Coastguard Worker         }
2033*e5436536SAndroid Build Coastguard Worker         channelElementIdx++;
2034*e5436536SAndroid Build Coastguard Worker         break;
2035*e5436536SAndroid Build Coastguard Worker 
2036*e5436536SAndroid Build Coastguard Worker       case ID_USAC_EXT:
2037*e5436536SAndroid Build Coastguard Worker         ErrorStatus = extElementConfig(&usc->element[i].extElement, hBs, cb, 0,
2038*e5436536SAndroid Build Coastguard Worker                                        asc->m_samplesPerFrame, 0, asc->m_aot);
2039*e5436536SAndroid Build Coastguard Worker         if (usc->element[i].extElement.usacExtElementType ==
2040*e5436536SAndroid Build Coastguard Worker             ID_EXT_ELE_UNI_DRC) {
2041*e5436536SAndroid Build Coastguard Worker           uniDrcElement = i;
2042*e5436536SAndroid Build Coastguard Worker         }
2043*e5436536SAndroid Build Coastguard Worker 
2044*e5436536SAndroid Build Coastguard Worker         if (ErrorStatus) {
2045*e5436536SAndroid Build Coastguard Worker           return ErrorStatus;
2046*e5436536SAndroid Build Coastguard Worker         }
2047*e5436536SAndroid Build Coastguard Worker         break;
2048*e5436536SAndroid Build Coastguard Worker 
2049*e5436536SAndroid Build Coastguard Worker       default:
2050*e5436536SAndroid Build Coastguard Worker         /* non USAC-element encountered */
2051*e5436536SAndroid Build Coastguard Worker         return TRANSPORTDEC_PARSE_ERROR;
2052*e5436536SAndroid Build Coastguard Worker     }
2053*e5436536SAndroid Build Coastguard Worker   }
2054*e5436536SAndroid Build Coastguard Worker 
2055*e5436536SAndroid Build Coastguard Worker   if (asc->m_aot == AOT_USAC) {
2056*e5436536SAndroid Build Coastguard Worker     if (usc->m_channelConfigurationIndex) {
2057*e5436536SAndroid Build Coastguard Worker       /* sanity check: all element counter must be zero */
2058*e5436536SAndroid Build Coastguard Worker       if (sc_chan_config.nCPE | sc_chan_config.nSCE | sc_chan_config.nLFE) {
2059*e5436536SAndroid Build Coastguard Worker         return TRANSPORTDEC_PARSE_ERROR;
2060*e5436536SAndroid Build Coastguard Worker       }
2061*e5436536SAndroid Build Coastguard Worker     } else {
2062*e5436536SAndroid Build Coastguard Worker       /* sanity check: number of audio channels shall be equal to or smaller
2063*e5436536SAndroid Build Coastguard Worker        * than the accumulated sum of all channels */
2064*e5436536SAndroid Build Coastguard Worker       if ((INT)(-2 * sc_chan_config.nCPE - sc_chan_config.nSCE -
2065*e5436536SAndroid Build Coastguard Worker                 sc_chan_config.nLFE) < (INT)usc->numAudioChannels) {
2066*e5436536SAndroid Build Coastguard Worker         return TRANSPORTDEC_PARSE_ERROR;
2067*e5436536SAndroid Build Coastguard Worker       }
2068*e5436536SAndroid Build Coastguard Worker     }
2069*e5436536SAndroid Build Coastguard Worker   }
2070*e5436536SAndroid Build Coastguard Worker 
2071*e5436536SAndroid Build Coastguard Worker   if (uniDrcElement == -1 && cb->cbUniDrc != NULL) {
2072*e5436536SAndroid Build Coastguard Worker     /* no uniDrcConfig contained. Clear the uniDrcConfig struct by feeding an
2073*e5436536SAndroid Build Coastguard Worker      * empty extension element */
2074*e5436536SAndroid Build Coastguard Worker     int subStreamIndex = 0;
2075*e5436536SAndroid Build Coastguard Worker     ErrorStatus = (TRANSPORTDEC_ERROR)cb->cbUniDrc(
2076*e5436536SAndroid Build Coastguard Worker         cb->cbUniDrcData, NULL, 0, 0 /* uniDrcConfig */, subStreamIndex, 0,
2077*e5436536SAndroid Build Coastguard Worker         asc->m_aot);
2078*e5436536SAndroid Build Coastguard Worker     if (ErrorStatus != TRANSPORTDEC_OK) {
2079*e5436536SAndroid Build Coastguard Worker       return ErrorStatus;
2080*e5436536SAndroid Build Coastguard Worker     }
2081*e5436536SAndroid Build Coastguard Worker   }
2082*e5436536SAndroid Build Coastguard Worker 
2083*e5436536SAndroid Build Coastguard Worker   return ErrorStatus;
2084*e5436536SAndroid Build Coastguard Worker }
2085*e5436536SAndroid Build Coastguard Worker 
2086*e5436536SAndroid Build Coastguard Worker /* Mapping of coreSbrFrameLengthIndex defined by Table 70 in ISO/IEC 23003-3 */
UsacConfig_SetCoreSbrFrameLengthIndex(CSAudioSpecificConfig * asc,int coreSbrFrameLengthIndex)2087*e5436536SAndroid Build Coastguard Worker static TRANSPORTDEC_ERROR UsacConfig_SetCoreSbrFrameLengthIndex(
2088*e5436536SAndroid Build Coastguard Worker     CSAudioSpecificConfig *asc, int coreSbrFrameLengthIndex) {
2089*e5436536SAndroid Build Coastguard Worker   int sbrRatioIndex_val;
2090*e5436536SAndroid Build Coastguard Worker 
2091*e5436536SAndroid Build Coastguard Worker   if (coreSbrFrameLengthIndex > 4) {
2092*e5436536SAndroid Build Coastguard Worker     return TRANSPORTDEC_PARSE_ERROR; /* reserved values */
2093*e5436536SAndroid Build Coastguard Worker   }
2094*e5436536SAndroid Build Coastguard Worker   asc->m_sc.m_usacConfig.m_coreSbrFrameLengthIndex = coreSbrFrameLengthIndex;
2095*e5436536SAndroid Build Coastguard Worker   asc->m_samplesPerFrame = usacFrameLength[coreSbrFrameLengthIndex];
2096*e5436536SAndroid Build Coastguard Worker   sbrRatioIndex_val = sbrRatioIndex[coreSbrFrameLengthIndex];
2097*e5436536SAndroid Build Coastguard Worker   asc->m_sc.m_usacConfig.m_sbrRatioIndex = sbrRatioIndex_val;
2098*e5436536SAndroid Build Coastguard Worker 
2099*e5436536SAndroid Build Coastguard Worker   if (sbrRatioIndex_val > 0) {
2100*e5436536SAndroid Build Coastguard Worker     asc->m_sbrPresentFlag = 1;
2101*e5436536SAndroid Build Coastguard Worker     asc->m_extensionSamplingFrequency = asc->m_samplingFrequency;
2102*e5436536SAndroid Build Coastguard Worker     asc->m_extensionSamplingFrequencyIndex = asc->m_samplingFrequencyIndex;
2103*e5436536SAndroid Build Coastguard Worker     switch (sbrRatioIndex_val) {
2104*e5436536SAndroid Build Coastguard Worker       case 1: /* sbrRatio = 4:1 */
2105*e5436536SAndroid Build Coastguard Worker         asc->m_samplingFrequency >>= 2;
2106*e5436536SAndroid Build Coastguard Worker         asc->m_samplesPerFrame >>= 2;
2107*e5436536SAndroid Build Coastguard Worker         break;
2108*e5436536SAndroid Build Coastguard Worker       case 2: /* sbrRatio = 8:3 */
2109*e5436536SAndroid Build Coastguard Worker         asc->m_samplingFrequency = (asc->m_samplingFrequency * 3) / 8;
2110*e5436536SAndroid Build Coastguard Worker         asc->m_samplesPerFrame = (asc->m_samplesPerFrame * 3) / 8;
2111*e5436536SAndroid Build Coastguard Worker         break;
2112*e5436536SAndroid Build Coastguard Worker       case 3: /* sbrRatio = 2:1 */
2113*e5436536SAndroid Build Coastguard Worker         asc->m_samplingFrequency >>= 1;
2114*e5436536SAndroid Build Coastguard Worker         asc->m_samplesPerFrame >>= 1;
2115*e5436536SAndroid Build Coastguard Worker         break;
2116*e5436536SAndroid Build Coastguard Worker       default:
2117*e5436536SAndroid Build Coastguard Worker         return TRANSPORTDEC_PARSE_ERROR;
2118*e5436536SAndroid Build Coastguard Worker     }
2119*e5436536SAndroid Build Coastguard Worker     asc->m_samplingFrequencyIndex =
2120*e5436536SAndroid Build Coastguard Worker         getSamplingRateIndex(asc->m_samplingFrequency, 4);
2121*e5436536SAndroid Build Coastguard Worker   }
2122*e5436536SAndroid Build Coastguard Worker 
2123*e5436536SAndroid Build Coastguard Worker   return TRANSPORTDEC_OK;
2124*e5436536SAndroid Build Coastguard Worker }
2125*e5436536SAndroid Build Coastguard Worker 
UsacConfig_Parse(CSAudioSpecificConfig * asc,HANDLE_FDK_BITSTREAM hBs,CSTpCallBacks * cb)2126*e5436536SAndroid Build Coastguard Worker static TRANSPORTDEC_ERROR UsacConfig_Parse(CSAudioSpecificConfig *asc,
2127*e5436536SAndroid Build Coastguard Worker                                            HANDLE_FDK_BITSTREAM hBs,
2128*e5436536SAndroid Build Coastguard Worker                                            CSTpCallBacks *cb) {
2129*e5436536SAndroid Build Coastguard Worker   int usacSamplingFrequency, channelConfigurationIndex, coreSbrFrameLengthIndex;
2130*e5436536SAndroid Build Coastguard Worker   TRANSPORTDEC_ERROR err = TRANSPORTDEC_OK;
2131*e5436536SAndroid Build Coastguard Worker 
2132*e5436536SAndroid Build Coastguard Worker   /* Start bit position of usacConfig */
2133*e5436536SAndroid Build Coastguard Worker   INT nbits = (INT)FDKgetValidBits(hBs);
2134*e5436536SAndroid Build Coastguard Worker 
2135*e5436536SAndroid Build Coastguard Worker   usacSamplingFrequency = getSampleRate(hBs, &asc->m_samplingFrequencyIndex, 5);
2136*e5436536SAndroid Build Coastguard Worker   if (usacSamplingFrequency == 0 || usacSamplingFrequency > 96000) {
2137*e5436536SAndroid Build Coastguard Worker     return TRANSPORTDEC_PARSE_ERROR;
2138*e5436536SAndroid Build Coastguard Worker   }
2139*e5436536SAndroid Build Coastguard Worker   asc->m_samplingFrequency = (UINT)usacSamplingFrequency;
2140*e5436536SAndroid Build Coastguard Worker 
2141*e5436536SAndroid Build Coastguard Worker   coreSbrFrameLengthIndex = FDKreadBits(hBs, 3);
2142*e5436536SAndroid Build Coastguard Worker   if (UsacConfig_SetCoreSbrFrameLengthIndex(asc, coreSbrFrameLengthIndex) !=
2143*e5436536SAndroid Build Coastguard Worker       TRANSPORTDEC_OK) {
2144*e5436536SAndroid Build Coastguard Worker     return TRANSPORTDEC_PARSE_ERROR;
2145*e5436536SAndroid Build Coastguard Worker   }
2146*e5436536SAndroid Build Coastguard Worker 
2147*e5436536SAndroid Build Coastguard Worker   channelConfigurationIndex = FDKreadBits(hBs, 5);
2148*e5436536SAndroid Build Coastguard Worker   if (channelConfigurationIndex > 2) {
2149*e5436536SAndroid Build Coastguard Worker     return TRANSPORTDEC_PARSE_ERROR; /* only channelConfigurationIndex = [1,2]
2150*e5436536SAndroid Build Coastguard Worker                                         are supported */
2151*e5436536SAndroid Build Coastguard Worker   }
2152*e5436536SAndroid Build Coastguard Worker 
2153*e5436536SAndroid Build Coastguard Worker   if (channelConfigurationIndex == 0) {
2154*e5436536SAndroid Build Coastguard Worker     return TRANSPORTDEC_PARSE_ERROR; /* only channelConfigurationIndex = [1,2]
2155*e5436536SAndroid Build Coastguard Worker                                         are supported */
2156*e5436536SAndroid Build Coastguard Worker   }
2157*e5436536SAndroid Build Coastguard Worker   asc->m_channelConfiguration = channelConfigurationIndex;
2158*e5436536SAndroid Build Coastguard Worker 
2159*e5436536SAndroid Build Coastguard Worker   err = UsacRsv60DecoderConfig_Parse(asc, hBs, cb);
2160*e5436536SAndroid Build Coastguard Worker   if (err != TRANSPORTDEC_OK) {
2161*e5436536SAndroid Build Coastguard Worker     return err;
2162*e5436536SAndroid Build Coastguard Worker   }
2163*e5436536SAndroid Build Coastguard Worker 
2164*e5436536SAndroid Build Coastguard Worker   if (FDKreadBits(hBs, 1)) { /* usacConfigExtensionPresent */
2165*e5436536SAndroid Build Coastguard Worker     err = configExtension(&asc->m_sc.m_usacConfig, hBs, cb);
2166*e5436536SAndroid Build Coastguard Worker     if (err != TRANSPORTDEC_OK) {
2167*e5436536SAndroid Build Coastguard Worker       return err;
2168*e5436536SAndroid Build Coastguard Worker     }
2169*e5436536SAndroid Build Coastguard Worker   } else if (cb->cbUniDrc != NULL) {
2170*e5436536SAndroid Build Coastguard Worker     /* no loudnessInfoSet contained. Clear the loudnessInfoSet struct by feeding
2171*e5436536SAndroid Build Coastguard Worker      * an empty config extension */
2172*e5436536SAndroid Build Coastguard Worker     err = (TRANSPORTDEC_ERROR)cb->cbUniDrc(
2173*e5436536SAndroid Build Coastguard Worker         cb->cbUniDrcData, NULL, 0, 1 /* loudnessInfoSet */, 0, 0, asc->m_aot);
2174*e5436536SAndroid Build Coastguard Worker     if (err != TRANSPORTDEC_OK) {
2175*e5436536SAndroid Build Coastguard Worker       return err;
2176*e5436536SAndroid Build Coastguard Worker     }
2177*e5436536SAndroid Build Coastguard Worker   }
2178*e5436536SAndroid Build Coastguard Worker 
2179*e5436536SAndroid Build Coastguard Worker   /* sanity check whether number of channels signaled in UsacDecoderConfig()
2180*e5436536SAndroid Build Coastguard Worker      matches the number of channels required by channelConfigurationIndex */
2181*e5436536SAndroid Build Coastguard Worker   if ((channelConfigurationIndex > 0) &&
2182*e5436536SAndroid Build Coastguard Worker       (sc_chan_config_tab[channelConfigurationIndex].nCh !=
2183*e5436536SAndroid Build Coastguard Worker        asc->m_sc.m_usacConfig.m_nUsacChannels)) {
2184*e5436536SAndroid Build Coastguard Worker     return TRANSPORTDEC_PARSE_ERROR;
2185*e5436536SAndroid Build Coastguard Worker   }
2186*e5436536SAndroid Build Coastguard Worker 
2187*e5436536SAndroid Build Coastguard Worker   /* Copy UsacConfig() to asc->m_sc.m_usacConfig.UsacConfig[] buffer. */
2188*e5436536SAndroid Build Coastguard Worker   INT configSize_bits = (INT)FDKgetValidBits(hBs) - nbits;
2189*e5436536SAndroid Build Coastguard Worker   if (StoreConfigAsBitstream(hBs, configSize_bits,
2190*e5436536SAndroid Build Coastguard Worker                              asc->m_sc.m_usacConfig.UsacConfig,
2191*e5436536SAndroid Build Coastguard Worker                              TP_USAC_MAX_CONFIG_LEN)) {
2192*e5436536SAndroid Build Coastguard Worker     return TRANSPORTDEC_PARSE_ERROR;
2193*e5436536SAndroid Build Coastguard Worker   }
2194*e5436536SAndroid Build Coastguard Worker   asc->m_sc.m_usacConfig.UsacConfigBits = fAbs(configSize_bits);
2195*e5436536SAndroid Build Coastguard Worker 
2196*e5436536SAndroid Build Coastguard Worker   return err;
2197*e5436536SAndroid Build Coastguard Worker }
2198*e5436536SAndroid Build Coastguard Worker 
AudioSpecificConfig_ExtensionParse(CSAudioSpecificConfig * self,HANDLE_FDK_BITSTREAM bs,CSTpCallBacks * cb)2199*e5436536SAndroid Build Coastguard Worker static TRANSPORTDEC_ERROR AudioSpecificConfig_ExtensionParse(
2200*e5436536SAndroid Build Coastguard Worker     CSAudioSpecificConfig *self, HANDLE_FDK_BITSTREAM bs, CSTpCallBacks *cb) {
2201*e5436536SAndroid Build Coastguard Worker   TP_ASC_EXTENSION_ID lastAscExt, ascExtId = ASCEXT_UNKOWN;
2202*e5436536SAndroid Build Coastguard Worker   INT bitsAvailable = (INT)FDKgetValidBits(bs);
2203*e5436536SAndroid Build Coastguard Worker 
2204*e5436536SAndroid Build Coastguard Worker   while (bitsAvailable >= 11) {
2205*e5436536SAndroid Build Coastguard Worker     lastAscExt = ascExtId;
2206*e5436536SAndroid Build Coastguard Worker     ascExtId = (TP_ASC_EXTENSION_ID)FDKreadBits(bs, 11);
2207*e5436536SAndroid Build Coastguard Worker     bitsAvailable -= 11;
2208*e5436536SAndroid Build Coastguard Worker 
2209*e5436536SAndroid Build Coastguard Worker     switch (ascExtId) {
2210*e5436536SAndroid Build Coastguard Worker       case ASCEXT_SBR: /* 0x2b7 */
2211*e5436536SAndroid Build Coastguard Worker         if ((self->m_extensionAudioObjectType != AOT_SBR) &&
2212*e5436536SAndroid Build Coastguard Worker             (bitsAvailable >= 5)) {
2213*e5436536SAndroid Build Coastguard Worker           self->m_extensionAudioObjectType = getAOT(bs);
2214*e5436536SAndroid Build Coastguard Worker 
2215*e5436536SAndroid Build Coastguard Worker           if ((self->m_extensionAudioObjectType == AOT_SBR) ||
2216*e5436536SAndroid Build Coastguard Worker               (self->m_extensionAudioObjectType ==
2217*e5436536SAndroid Build Coastguard Worker                AOT_ER_BSAC)) { /* Get SBR extension configuration */
2218*e5436536SAndroid Build Coastguard Worker             self->m_sbrPresentFlag = FDKreadBits(bs, 1);
2219*e5436536SAndroid Build Coastguard Worker             if (self->m_aot == AOT_USAC && self->m_sbrPresentFlag > 0 &&
2220*e5436536SAndroid Build Coastguard Worker                 self->m_sc.m_usacConfig.m_sbrRatioIndex == 0) {
2221*e5436536SAndroid Build Coastguard Worker               return TRANSPORTDEC_PARSE_ERROR;
2222*e5436536SAndroid Build Coastguard Worker             }
2223*e5436536SAndroid Build Coastguard Worker 
2224*e5436536SAndroid Build Coastguard Worker             if (self->m_sbrPresentFlag == 1) {
2225*e5436536SAndroid Build Coastguard Worker               self->m_extensionSamplingFrequency = getSampleRate(
2226*e5436536SAndroid Build Coastguard Worker                   bs, &self->m_extensionSamplingFrequencyIndex, 4);
2227*e5436536SAndroid Build Coastguard Worker 
2228*e5436536SAndroid Build Coastguard Worker               if (self->m_extensionSamplingFrequency == 0 ||
2229*e5436536SAndroid Build Coastguard Worker                   self->m_extensionSamplingFrequency > 96000) {
2230*e5436536SAndroid Build Coastguard Worker                 return TRANSPORTDEC_PARSE_ERROR;
2231*e5436536SAndroid Build Coastguard Worker               }
2232*e5436536SAndroid Build Coastguard Worker             }
2233*e5436536SAndroid Build Coastguard Worker             if (self->m_extensionAudioObjectType == AOT_ER_BSAC) {
2234*e5436536SAndroid Build Coastguard Worker               self->m_extensionChannelConfiguration = FDKreadBits(bs, 4);
2235*e5436536SAndroid Build Coastguard Worker             }
2236*e5436536SAndroid Build Coastguard Worker           }
2237*e5436536SAndroid Build Coastguard Worker           /* Update counter because of variable length fields (AOT and sampling
2238*e5436536SAndroid Build Coastguard Worker            * rate) */
2239*e5436536SAndroid Build Coastguard Worker           bitsAvailable = (INT)FDKgetValidBits(bs);
2240*e5436536SAndroid Build Coastguard Worker         }
2241*e5436536SAndroid Build Coastguard Worker         break;
2242*e5436536SAndroid Build Coastguard Worker       case ASCEXT_PS: /* 0x548 */
2243*e5436536SAndroid Build Coastguard Worker         if ((lastAscExt == ASCEXT_SBR) &&
2244*e5436536SAndroid Build Coastguard Worker             (self->m_extensionAudioObjectType == AOT_SBR) &&
2245*e5436536SAndroid Build Coastguard Worker             (bitsAvailable > 0)) { /* Get PS extension configuration */
2246*e5436536SAndroid Build Coastguard Worker           self->m_psPresentFlag = FDKreadBits(bs, 1);
2247*e5436536SAndroid Build Coastguard Worker           bitsAvailable -= 1;
2248*e5436536SAndroid Build Coastguard Worker         }
2249*e5436536SAndroid Build Coastguard Worker         break;
2250*e5436536SAndroid Build Coastguard Worker       case ASCEXT_MPS: /* 0x76a */
2251*e5436536SAndroid Build Coastguard Worker         if (self->m_extensionAudioObjectType == AOT_MPEGS) break;
2252*e5436536SAndroid Build Coastguard Worker         FDK_FALLTHROUGH;
2253*e5436536SAndroid Build Coastguard Worker       case ASCEXT_LDMPS: /* 0x7cc */
2254*e5436536SAndroid Build Coastguard Worker         if ((ascExtId == ASCEXT_LDMPS) &&
2255*e5436536SAndroid Build Coastguard Worker             (self->m_extensionAudioObjectType == AOT_LD_MPEGS))
2256*e5436536SAndroid Build Coastguard Worker           break;
2257*e5436536SAndroid Build Coastguard Worker         if (bitsAvailable >= 1) {
2258*e5436536SAndroid Build Coastguard Worker           bitsAvailable -= 1;
2259*e5436536SAndroid Build Coastguard Worker           if (FDKreadBits(bs, 1)) { /* self->m_mpsPresentFlag */
2260*e5436536SAndroid Build Coastguard Worker             int sscLen = FDKreadBits(bs, 8);
2261*e5436536SAndroid Build Coastguard Worker             bitsAvailable -= 8;
2262*e5436536SAndroid Build Coastguard Worker             if (sscLen == 0xFF) {
2263*e5436536SAndroid Build Coastguard Worker               sscLen += FDKreadBits(bs, 16);
2264*e5436536SAndroid Build Coastguard Worker               bitsAvailable -= 16;
2265*e5436536SAndroid Build Coastguard Worker             }
2266*e5436536SAndroid Build Coastguard Worker             FDKpushFor(bs, sscLen); /* Skip SSC to be able to read the next
2267*e5436536SAndroid Build Coastguard Worker                                        extension if there is one. */
2268*e5436536SAndroid Build Coastguard Worker 
2269*e5436536SAndroid Build Coastguard Worker             bitsAvailable -= sscLen * 8;
2270*e5436536SAndroid Build Coastguard Worker           }
2271*e5436536SAndroid Build Coastguard Worker         }
2272*e5436536SAndroid Build Coastguard Worker         break;
2273*e5436536SAndroid Build Coastguard Worker       case ASCEXT_SAOC:
2274*e5436536SAndroid Build Coastguard Worker         if ((ascExtId == ASCEXT_SAOC) &&
2275*e5436536SAndroid Build Coastguard Worker             (self->m_extensionAudioObjectType == AOT_SAOC))
2276*e5436536SAndroid Build Coastguard Worker           break;
2277*e5436536SAndroid Build Coastguard Worker         if (FDKreadBits(bs, 1)) { /* saocPresent */
2278*e5436536SAndroid Build Coastguard Worker           int saocscLen = FDKreadBits(bs, 8);
2279*e5436536SAndroid Build Coastguard Worker           bitsAvailable -= 8;
2280*e5436536SAndroid Build Coastguard Worker           if (saocscLen == 0xFF) {
2281*e5436536SAndroid Build Coastguard Worker             saocscLen += FDKreadBits(bs, 16);
2282*e5436536SAndroid Build Coastguard Worker             bitsAvailable -= 16;
2283*e5436536SAndroid Build Coastguard Worker           }
2284*e5436536SAndroid Build Coastguard Worker           FDKpushFor(bs, saocscLen);
2285*e5436536SAndroid Build Coastguard Worker           bitsAvailable -= saocscLen * 8;
2286*e5436536SAndroid Build Coastguard Worker         }
2287*e5436536SAndroid Build Coastguard Worker         break;
2288*e5436536SAndroid Build Coastguard Worker       default:
2289*e5436536SAndroid Build Coastguard Worker         /* Just ignore anything. */
2290*e5436536SAndroid Build Coastguard Worker         return TRANSPORTDEC_OK;
2291*e5436536SAndroid Build Coastguard Worker     }
2292*e5436536SAndroid Build Coastguard Worker   }
2293*e5436536SAndroid Build Coastguard Worker 
2294*e5436536SAndroid Build Coastguard Worker   return TRANSPORTDEC_OK;
2295*e5436536SAndroid Build Coastguard Worker }
2296*e5436536SAndroid Build Coastguard Worker 
2297*e5436536SAndroid Build Coastguard Worker /*
2298*e5436536SAndroid Build Coastguard Worker  * API Functions
2299*e5436536SAndroid Build Coastguard Worker  */
2300*e5436536SAndroid Build Coastguard Worker 
AudioSpecificConfig_Init(CSAudioSpecificConfig * asc)2301*e5436536SAndroid Build Coastguard Worker void AudioSpecificConfig_Init(CSAudioSpecificConfig *asc) {
2302*e5436536SAndroid Build Coastguard Worker   FDKmemclear(asc, sizeof(CSAudioSpecificConfig));
2303*e5436536SAndroid Build Coastguard Worker 
2304*e5436536SAndroid Build Coastguard Worker   /* Init all values that should not be zero. */
2305*e5436536SAndroid Build Coastguard Worker   asc->m_aot = AOT_NONE;
2306*e5436536SAndroid Build Coastguard Worker   asc->m_samplingFrequencyIndex = 0xf;
2307*e5436536SAndroid Build Coastguard Worker   asc->m_epConfig = -1;
2308*e5436536SAndroid Build Coastguard Worker   asc->m_extensionAudioObjectType = AOT_NULL_OBJECT;
2309*e5436536SAndroid Build Coastguard Worker   CProgramConfig_Init(&asc->m_progrConfigElement);
2310*e5436536SAndroid Build Coastguard Worker }
2311*e5436536SAndroid Build Coastguard Worker 
AudioSpecificConfig_Parse(CSAudioSpecificConfig * self,HANDLE_FDK_BITSTREAM bs,int fExplicitBackwardCompatible,CSTpCallBacks * cb,UCHAR configMode,UCHAR configChanged,AUDIO_OBJECT_TYPE m_aot)2312*e5436536SAndroid Build Coastguard Worker TRANSPORTDEC_ERROR AudioSpecificConfig_Parse(
2313*e5436536SAndroid Build Coastguard Worker     CSAudioSpecificConfig *self, HANDLE_FDK_BITSTREAM bs,
2314*e5436536SAndroid Build Coastguard Worker     int fExplicitBackwardCompatible, CSTpCallBacks *cb, UCHAR configMode,
2315*e5436536SAndroid Build Coastguard Worker     UCHAR configChanged, AUDIO_OBJECT_TYPE m_aot) {
2316*e5436536SAndroid Build Coastguard Worker   TRANSPORTDEC_ERROR ErrorStatus = TRANSPORTDEC_OK;
2317*e5436536SAndroid Build Coastguard Worker   UINT ascStartAnchor = FDKgetValidBits(bs);
2318*e5436536SAndroid Build Coastguard Worker   int frameLengthFlag = -1;
2319*e5436536SAndroid Build Coastguard Worker 
2320*e5436536SAndroid Build Coastguard Worker   AudioSpecificConfig_Init(self);
2321*e5436536SAndroid Build Coastguard Worker 
2322*e5436536SAndroid Build Coastguard Worker   self->configMode = configMode;
2323*e5436536SAndroid Build Coastguard Worker   self->AacConfigChanged = configChanged;
2324*e5436536SAndroid Build Coastguard Worker   self->SbrConfigChanged = configChanged;
2325*e5436536SAndroid Build Coastguard Worker   self->SacConfigChanged = configChanged;
2326*e5436536SAndroid Build Coastguard Worker 
2327*e5436536SAndroid Build Coastguard Worker   if (m_aot != AOT_NULL_OBJECT) {
2328*e5436536SAndroid Build Coastguard Worker     self->m_aot = m_aot;
2329*e5436536SAndroid Build Coastguard Worker   } else {
2330*e5436536SAndroid Build Coastguard Worker     self->m_aot = getAOT(bs);
2331*e5436536SAndroid Build Coastguard Worker     self->m_samplingFrequency =
2332*e5436536SAndroid Build Coastguard Worker         getSampleRate(bs, &self->m_samplingFrequencyIndex, 4);
2333*e5436536SAndroid Build Coastguard Worker     if (self->m_samplingFrequency <= 0 ||
2334*e5436536SAndroid Build Coastguard Worker         (self->m_samplingFrequency > 96000 && self->m_aot != 39) ||
2335*e5436536SAndroid Build Coastguard Worker         self->m_samplingFrequency > 4 * 96000) {
2336*e5436536SAndroid Build Coastguard Worker       return TRANSPORTDEC_PARSE_ERROR;
2337*e5436536SAndroid Build Coastguard Worker     }
2338*e5436536SAndroid Build Coastguard Worker 
2339*e5436536SAndroid Build Coastguard Worker     self->m_channelConfiguration = FDKreadBits(bs, 4);
2340*e5436536SAndroid Build Coastguard Worker 
2341*e5436536SAndroid Build Coastguard Worker     /* MPEG-04 standard ISO/IEC 14496-3: channelConfiguration == 0 is reserved
2342*e5436536SAndroid Build Coastguard Worker        in er_raw_data_block (table 4.19) and er_raw_data_block_eld (table 4.75)
2343*e5436536SAndroid Build Coastguard Worker        MPEG-04 conformance ISO/IEC 14496-4: channelConfiguration == 0 is not
2344*e5436536SAndroid Build Coastguard Worker        permitted for AOT_ER_AAC_LC, AOT_ER_AAC_LTP, AOT_ER_AAC_LD,
2345*e5436536SAndroid Build Coastguard Worker        AOT_ER_AAC_SCAL (chapter 6.6.4.1.2.1.1) */
2346*e5436536SAndroid Build Coastguard Worker     if ((self->m_channelConfiguration == 0) &&
2347*e5436536SAndroid Build Coastguard Worker         ((self->m_aot == AOT_ER_AAC_LC) || (self->m_aot == AOT_ER_AAC_LTP) ||
2348*e5436536SAndroid Build Coastguard Worker          (self->m_aot == AOT_ER_AAC_LD) || (self->m_aot == AOT_ER_AAC_SCAL) ||
2349*e5436536SAndroid Build Coastguard Worker          (self->m_aot == AOT_ER_AAC_ELD))) {
2350*e5436536SAndroid Build Coastguard Worker       return TRANSPORTDEC_UNSUPPORTED_FORMAT;
2351*e5436536SAndroid Build Coastguard Worker     }
2352*e5436536SAndroid Build Coastguard Worker     /* MPEG-04 conformance ISO/IEC 14496-4: channelConfiguration > 2 is not
2353*e5436536SAndroid Build Coastguard Worker      * permitted for AOT_AAC_SCAL and AOT_ER_AAC_SCAL (chapter 6.6.4.1.2.1.1) */
2354*e5436536SAndroid Build Coastguard Worker     if ((self->m_channelConfiguration > 2) &&
2355*e5436536SAndroid Build Coastguard Worker         ((self->m_aot == AOT_AAC_SCAL) || (self->m_aot == AOT_ER_AAC_SCAL))) {
2356*e5436536SAndroid Build Coastguard Worker       return TRANSPORTDEC_UNSUPPORTED_FORMAT;
2357*e5436536SAndroid Build Coastguard Worker     }
2358*e5436536SAndroid Build Coastguard Worker 
2359*e5436536SAndroid Build Coastguard Worker     /* SBR extension ( explicit non-backwards compatible mode ) */
2360*e5436536SAndroid Build Coastguard Worker     self->m_sbrPresentFlag = 0;
2361*e5436536SAndroid Build Coastguard Worker     self->m_psPresentFlag = 0;
2362*e5436536SAndroid Build Coastguard Worker 
2363*e5436536SAndroid Build Coastguard Worker     if (self->m_aot == AOT_SBR || self->m_aot == AOT_PS) {
2364*e5436536SAndroid Build Coastguard Worker       self->m_extensionAudioObjectType = AOT_SBR;
2365*e5436536SAndroid Build Coastguard Worker 
2366*e5436536SAndroid Build Coastguard Worker       self->m_sbrPresentFlag = 1;
2367*e5436536SAndroid Build Coastguard Worker       if (self->m_aot == AOT_PS) {
2368*e5436536SAndroid Build Coastguard Worker         self->m_psPresentFlag = 1;
2369*e5436536SAndroid Build Coastguard Worker       }
2370*e5436536SAndroid Build Coastguard Worker 
2371*e5436536SAndroid Build Coastguard Worker       self->m_extensionSamplingFrequency =
2372*e5436536SAndroid Build Coastguard Worker           getSampleRate(bs, &self->m_extensionSamplingFrequencyIndex, 4);
2373*e5436536SAndroid Build Coastguard Worker       if (self->m_extensionSamplingFrequency == 0 ||
2374*e5436536SAndroid Build Coastguard Worker           self->m_extensionSamplingFrequency > 96000) {
2375*e5436536SAndroid Build Coastguard Worker         return TRANSPORTDEC_PARSE_ERROR;
2376*e5436536SAndroid Build Coastguard Worker       }
2377*e5436536SAndroid Build Coastguard Worker       self->m_aot = getAOT(bs);
2378*e5436536SAndroid Build Coastguard Worker 
2379*e5436536SAndroid Build Coastguard Worker       switch (self->m_aot) {
2380*e5436536SAndroid Build Coastguard Worker         case AOT_AAC_LC:
2381*e5436536SAndroid Build Coastguard Worker           break;
2382*e5436536SAndroid Build Coastguard Worker         case AOT_ER_BSAC:
2383*e5436536SAndroid Build Coastguard Worker           break;
2384*e5436536SAndroid Build Coastguard Worker         default:
2385*e5436536SAndroid Build Coastguard Worker           return TRANSPORTDEC_UNSUPPORTED_FORMAT;
2386*e5436536SAndroid Build Coastguard Worker       }
2387*e5436536SAndroid Build Coastguard Worker 
2388*e5436536SAndroid Build Coastguard Worker       if (self->m_aot == AOT_ER_BSAC) {
2389*e5436536SAndroid Build Coastguard Worker         self->m_extensionChannelConfiguration = FDKreadBits(bs, 4);
2390*e5436536SAndroid Build Coastguard Worker       }
2391*e5436536SAndroid Build Coastguard Worker     } else {
2392*e5436536SAndroid Build Coastguard Worker       self->m_extensionAudioObjectType = AOT_NULL_OBJECT;
2393*e5436536SAndroid Build Coastguard Worker     }
2394*e5436536SAndroid Build Coastguard Worker   }
2395*e5436536SAndroid Build Coastguard Worker 
2396*e5436536SAndroid Build Coastguard Worker   /* Parse whatever specific configs */
2397*e5436536SAndroid Build Coastguard Worker   switch (self->m_aot) {
2398*e5436536SAndroid Build Coastguard Worker     case AOT_AAC_LC:
2399*e5436536SAndroid Build Coastguard Worker     case AOT_AAC_SCAL:
2400*e5436536SAndroid Build Coastguard Worker     case AOT_ER_AAC_LC:
2401*e5436536SAndroid Build Coastguard Worker     case AOT_ER_AAC_LD:
2402*e5436536SAndroid Build Coastguard Worker     case AOT_ER_AAC_SCAL:
2403*e5436536SAndroid Build Coastguard Worker     case AOT_ER_BSAC:
2404*e5436536SAndroid Build Coastguard Worker       if ((ErrorStatus = GaSpecificConfig_Parse(&self->m_sc.m_gaSpecificConfig,
2405*e5436536SAndroid Build Coastguard Worker                                                 self, bs, ascStartAnchor)) !=
2406*e5436536SAndroid Build Coastguard Worker           TRANSPORTDEC_OK) {
2407*e5436536SAndroid Build Coastguard Worker         return (ErrorStatus);
2408*e5436536SAndroid Build Coastguard Worker       }
2409*e5436536SAndroid Build Coastguard Worker       frameLengthFlag = self->m_sc.m_gaSpecificConfig.m_frameLengthFlag;
2410*e5436536SAndroid Build Coastguard Worker       break;
2411*e5436536SAndroid Build Coastguard Worker     case AOT_MPEGS:
2412*e5436536SAndroid Build Coastguard Worker       if (cb->cbSsc != NULL) {
2413*e5436536SAndroid Build Coastguard Worker         if (cb->cbSsc(cb->cbSscData, bs, self->m_aot, self->m_samplingFrequency,
2414*e5436536SAndroid Build Coastguard Worker                       self->m_samplesPerFrame, self->m_channelConfiguration, 1,
2415*e5436536SAndroid Build Coastguard Worker                       -1, /* nTimeSlots: read from bitstream */
2416*e5436536SAndroid Build Coastguard Worker                       0,  /* don't know the length */
2417*e5436536SAndroid Build Coastguard Worker                       self->configMode, &self->SacConfigChanged)) {
2418*e5436536SAndroid Build Coastguard Worker           return TRANSPORTDEC_UNSUPPORTED_FORMAT;
2419*e5436536SAndroid Build Coastguard Worker         }
2420*e5436536SAndroid Build Coastguard Worker       } else {
2421*e5436536SAndroid Build Coastguard Worker         return TRANSPORTDEC_UNSUPPORTED_FORMAT;
2422*e5436536SAndroid Build Coastguard Worker       }
2423*e5436536SAndroid Build Coastguard Worker       break;
2424*e5436536SAndroid Build Coastguard Worker     case AOT_ER_AAC_ELD:
2425*e5436536SAndroid Build Coastguard Worker       if ((ErrorStatus = EldSpecificConfig_Parse(self, bs, cb)) !=
2426*e5436536SAndroid Build Coastguard Worker           TRANSPORTDEC_OK) {
2427*e5436536SAndroid Build Coastguard Worker         return (ErrorStatus);
2428*e5436536SAndroid Build Coastguard Worker       }
2429*e5436536SAndroid Build Coastguard Worker       frameLengthFlag = self->m_sc.m_eldSpecificConfig.m_frameLengthFlag;
2430*e5436536SAndroid Build Coastguard Worker       self->m_sbrPresentFlag = self->m_sc.m_eldSpecificConfig.m_sbrPresentFlag;
2431*e5436536SAndroid Build Coastguard Worker       self->m_extensionSamplingFrequency =
2432*e5436536SAndroid Build Coastguard Worker           (self->m_sc.m_eldSpecificConfig.m_sbrSamplingRate + 1) *
2433*e5436536SAndroid Build Coastguard Worker           self->m_samplingFrequency;
2434*e5436536SAndroid Build Coastguard Worker       break;
2435*e5436536SAndroid Build Coastguard Worker     case AOT_USAC:
2436*e5436536SAndroid Build Coastguard Worker       if ((ErrorStatus = UsacConfig_Parse(self, bs, cb)) != TRANSPORTDEC_OK) {
2437*e5436536SAndroid Build Coastguard Worker         return (ErrorStatus);
2438*e5436536SAndroid Build Coastguard Worker       }
2439*e5436536SAndroid Build Coastguard Worker       break;
2440*e5436536SAndroid Build Coastguard Worker 
2441*e5436536SAndroid Build Coastguard Worker     default:
2442*e5436536SAndroid Build Coastguard Worker       return TRANSPORTDEC_UNSUPPORTED_FORMAT;
2443*e5436536SAndroid Build Coastguard Worker   }
2444*e5436536SAndroid Build Coastguard Worker 
2445*e5436536SAndroid Build Coastguard Worker   /* Frame length */
2446*e5436536SAndroid Build Coastguard Worker   switch (self->m_aot) {
2447*e5436536SAndroid Build Coastguard Worker     case AOT_AAC_LC:
2448*e5436536SAndroid Build Coastguard Worker     case AOT_AAC_SCAL:
2449*e5436536SAndroid Build Coastguard Worker     case AOT_ER_AAC_LC:
2450*e5436536SAndroid Build Coastguard Worker     case AOT_ER_AAC_SCAL:
2451*e5436536SAndroid Build Coastguard Worker     case AOT_ER_BSAC:
2452*e5436536SAndroid Build Coastguard Worker       /*case AOT_USAC:*/
2453*e5436536SAndroid Build Coastguard Worker       if (!frameLengthFlag)
2454*e5436536SAndroid Build Coastguard Worker         self->m_samplesPerFrame = 1024;
2455*e5436536SAndroid Build Coastguard Worker       else
2456*e5436536SAndroid Build Coastguard Worker         self->m_samplesPerFrame = 960;
2457*e5436536SAndroid Build Coastguard Worker       break;
2458*e5436536SAndroid Build Coastguard Worker     case AOT_ER_AAC_LD:
2459*e5436536SAndroid Build Coastguard Worker       if (!frameLengthFlag)
2460*e5436536SAndroid Build Coastguard Worker         self->m_samplesPerFrame = 512;
2461*e5436536SAndroid Build Coastguard Worker       else
2462*e5436536SAndroid Build Coastguard Worker         self->m_samplesPerFrame = 480;
2463*e5436536SAndroid Build Coastguard Worker       break;
2464*e5436536SAndroid Build Coastguard Worker     default:
2465*e5436536SAndroid Build Coastguard Worker       break;
2466*e5436536SAndroid Build Coastguard Worker   }
2467*e5436536SAndroid Build Coastguard Worker 
2468*e5436536SAndroid Build Coastguard Worker   switch (self->m_aot) {
2469*e5436536SAndroid Build Coastguard Worker     case AOT_ER_AAC_LC:
2470*e5436536SAndroid Build Coastguard Worker     case AOT_ER_AAC_LD:
2471*e5436536SAndroid Build Coastguard Worker     case AOT_ER_AAC_ELD:
2472*e5436536SAndroid Build Coastguard Worker     case AOT_ER_AAC_SCAL:
2473*e5436536SAndroid Build Coastguard Worker     case AOT_ER_CELP:
2474*e5436536SAndroid Build Coastguard Worker     case AOT_ER_HVXC:
2475*e5436536SAndroid Build Coastguard Worker     case AOT_ER_BSAC:
2476*e5436536SAndroid Build Coastguard Worker       self->m_epConfig = FDKreadBits(bs, 2);
2477*e5436536SAndroid Build Coastguard Worker 
2478*e5436536SAndroid Build Coastguard Worker       if (self->m_epConfig > 1) {
2479*e5436536SAndroid Build Coastguard Worker         return TRANSPORTDEC_UNSUPPORTED_FORMAT;  // EPCONFIG;
2480*e5436536SAndroid Build Coastguard Worker       }
2481*e5436536SAndroid Build Coastguard Worker       break;
2482*e5436536SAndroid Build Coastguard Worker     default:
2483*e5436536SAndroid Build Coastguard Worker       break;
2484*e5436536SAndroid Build Coastguard Worker   }
2485*e5436536SAndroid Build Coastguard Worker 
2486*e5436536SAndroid Build Coastguard Worker   if (fExplicitBackwardCompatible &&
2487*e5436536SAndroid Build Coastguard Worker       (self->m_aot == AOT_AAC_LC || self->m_aot == AOT_ER_AAC_LD ||
2488*e5436536SAndroid Build Coastguard Worker        self->m_aot == AOT_ER_BSAC)) {
2489*e5436536SAndroid Build Coastguard Worker     ErrorStatus = AudioSpecificConfig_ExtensionParse(self, bs, cb);
2490*e5436536SAndroid Build Coastguard Worker   }
2491*e5436536SAndroid Build Coastguard Worker 
2492*e5436536SAndroid Build Coastguard Worker   /* Copy config() to asc->config[] buffer. */
2493*e5436536SAndroid Build Coastguard Worker   if ((ErrorStatus == TRANSPORTDEC_OK) && (self->m_aot == AOT_USAC)) {
2494*e5436536SAndroid Build Coastguard Worker     INT configSize_bits = (INT)FDKgetValidBits(bs) - (INT)ascStartAnchor;
2495*e5436536SAndroid Build Coastguard Worker     if (StoreConfigAsBitstream(bs, configSize_bits, self->config,
2496*e5436536SAndroid Build Coastguard Worker                                TP_USAC_MAX_CONFIG_LEN)) {
2497*e5436536SAndroid Build Coastguard Worker       return TRANSPORTDEC_PARSE_ERROR;
2498*e5436536SAndroid Build Coastguard Worker     }
2499*e5436536SAndroid Build Coastguard Worker     self->configBits = fAbs(configSize_bits);
2500*e5436536SAndroid Build Coastguard Worker   }
2501*e5436536SAndroid Build Coastguard Worker 
2502*e5436536SAndroid Build Coastguard Worker   return (ErrorStatus);
2503*e5436536SAndroid Build Coastguard Worker }
2504*e5436536SAndroid Build Coastguard Worker 
Drm_xHEAACDecoderConfig(CSAudioSpecificConfig * asc,HANDLE_FDK_BITSTREAM hBs,int audioMode,CSTpCallBacks * cb)2505*e5436536SAndroid Build Coastguard Worker static TRANSPORTDEC_ERROR Drm_xHEAACDecoderConfig(
2506*e5436536SAndroid Build Coastguard Worker     CSAudioSpecificConfig *asc, HANDLE_FDK_BITSTREAM hBs, int audioMode,
2507*e5436536SAndroid Build Coastguard Worker     CSTpCallBacks *cb /* use cb == NULL to signal config check only mode */
2508*e5436536SAndroid Build Coastguard Worker ) {
2509*e5436536SAndroid Build Coastguard Worker   TRANSPORTDEC_ERROR ErrorStatus = TRANSPORTDEC_OK;
2510*e5436536SAndroid Build Coastguard Worker   CSUsacConfig *usc = &asc->m_sc.m_usacConfig;
2511*e5436536SAndroid Build Coastguard Worker   int elemIdx = 0;
2512*e5436536SAndroid Build Coastguard Worker 
2513*e5436536SAndroid Build Coastguard Worker   usc->element[elemIdx].m_stereoConfigIndex = 0;
2514*e5436536SAndroid Build Coastguard Worker 
2515*e5436536SAndroid Build Coastguard Worker   usc->m_usacNumElements = 1; /* Currently all extension elements are skipped
2516*e5436536SAndroid Build Coastguard Worker                                  -> only one SCE or CPE. */
2517*e5436536SAndroid Build Coastguard Worker 
2518*e5436536SAndroid Build Coastguard Worker   switch (audioMode) {
2519*e5436536SAndroid Build Coastguard Worker     case 0: /* mono: ID_USAC_SCE */
2520*e5436536SAndroid Build Coastguard Worker       usc->element[elemIdx].usacElementType = ID_USAC_SCE;
2521*e5436536SAndroid Build Coastguard Worker       usc->m_nUsacChannels = 1;
2522*e5436536SAndroid Build Coastguard Worker       usc->element[elemIdx].m_noiseFilling = FDKreadBits(hBs, 1);
2523*e5436536SAndroid Build Coastguard Worker       if (usc->m_sbrRatioIndex > 0) {
2524*e5436536SAndroid Build Coastguard Worker         if (cb == NULL) {
2525*e5436536SAndroid Build Coastguard Worker           return ErrorStatus;
2526*e5436536SAndroid Build Coastguard Worker         }
2527*e5436536SAndroid Build Coastguard Worker         if (cb->cbSbr != NULL) {
2528*e5436536SAndroid Build Coastguard Worker           usc->element[elemIdx].m_harmonicSBR = FDKreadBit(hBs);
2529*e5436536SAndroid Build Coastguard Worker           usc->element[elemIdx].m_interTes = FDKreadBit(hBs);
2530*e5436536SAndroid Build Coastguard Worker           usc->element[elemIdx].m_pvc = FDKreadBit(hBs);
2531*e5436536SAndroid Build Coastguard Worker           if (cb->cbSbr(cb->cbSbrData, hBs, asc->m_samplingFrequency,
2532*e5436536SAndroid Build Coastguard Worker                         asc->m_extensionSamplingFrequency,
2533*e5436536SAndroid Build Coastguard Worker                         asc->m_samplesPerFrame, asc->m_aot, ID_SCE, elemIdx,
2534*e5436536SAndroid Build Coastguard Worker                         usc->element[elemIdx].m_harmonicSBR,
2535*e5436536SAndroid Build Coastguard Worker                         usc->element[elemIdx].m_stereoConfigIndex,
2536*e5436536SAndroid Build Coastguard Worker                         asc->configMode, &asc->SbrConfigChanged, 1)) {
2537*e5436536SAndroid Build Coastguard Worker             return ErrorStatus = TRANSPORTDEC_PARSE_ERROR;
2538*e5436536SAndroid Build Coastguard Worker           }
2539*e5436536SAndroid Build Coastguard Worker         }
2540*e5436536SAndroid Build Coastguard Worker       }
2541*e5436536SAndroid Build Coastguard Worker       break;
2542*e5436536SAndroid Build Coastguard Worker     case 2: /* stereo: ID_USAC_CPE */
2543*e5436536SAndroid Build Coastguard Worker       usc->element[elemIdx].usacElementType = ID_USAC_CPE;
2544*e5436536SAndroid Build Coastguard Worker       usc->m_nUsacChannels = 2;
2545*e5436536SAndroid Build Coastguard Worker       usc->element[elemIdx].m_noiseFilling = FDKreadBits(hBs, 1);
2546*e5436536SAndroid Build Coastguard Worker       if (usc->m_sbrRatioIndex > 0) {
2547*e5436536SAndroid Build Coastguard Worker         usc->element[elemIdx].m_harmonicSBR = FDKreadBit(hBs);
2548*e5436536SAndroid Build Coastguard Worker         usc->element[elemIdx].m_interTes = FDKreadBit(hBs);
2549*e5436536SAndroid Build Coastguard Worker         usc->element[elemIdx].m_pvc = FDKreadBit(hBs);
2550*e5436536SAndroid Build Coastguard Worker         {
2551*e5436536SAndroid Build Coastguard Worker           INT bitsToSkip = skipSbrHeader(hBs, 1);
2552*e5436536SAndroid Build Coastguard Worker           /* read stereoConfigIndex */
2553*e5436536SAndroid Build Coastguard Worker           usc->element[elemIdx].m_stereoConfigIndex = FDKreadBits(hBs, 2);
2554*e5436536SAndroid Build Coastguard Worker           /* rewind */
2555*e5436536SAndroid Build Coastguard Worker           FDKpushBack(hBs, bitsToSkip + 2);
2556*e5436536SAndroid Build Coastguard Worker         }
2557*e5436536SAndroid Build Coastguard Worker         /*
2558*e5436536SAndroid Build Coastguard Worker         The application of the following tools is mutually exclusive per audio
2559*e5436536SAndroid Build Coastguard Worker         stream configuration (see clause 5.3.2, xHE-AAC codec configuration):
2560*e5436536SAndroid Build Coastguard Worker         - MPS212 parametric stereo tool with residual coding
2561*e5436536SAndroid Build Coastguard Worker         (stereoConfigIndex>1); and
2562*e5436536SAndroid Build Coastguard Worker         - QMF based Harmonic Transposer (harmonicSBR==1).
2563*e5436536SAndroid Build Coastguard Worker         */
2564*e5436536SAndroid Build Coastguard Worker         if ((usc->element[elemIdx].m_stereoConfigIndex > 1) &&
2565*e5436536SAndroid Build Coastguard Worker             usc->element[elemIdx].m_harmonicSBR) {
2566*e5436536SAndroid Build Coastguard Worker           return ErrorStatus = TRANSPORTDEC_PARSE_ERROR;
2567*e5436536SAndroid Build Coastguard Worker         }
2568*e5436536SAndroid Build Coastguard Worker         /*
2569*e5436536SAndroid Build Coastguard Worker         The 4:1 sbrRatio (sbrRatioIndex==1 in [11]) may only be employed:
2570*e5436536SAndroid Build Coastguard Worker         - in mono operation; or
2571*e5436536SAndroid Build Coastguard Worker         - in stereo operation if parametric stereo (MPS212) without residual
2572*e5436536SAndroid Build Coastguard Worker         coding is applied, i.e. if stereoConfigIndex==1 (see clause 5.3.2,
2573*e5436536SAndroid Build Coastguard Worker         xHE-AAC codec configuration).
2574*e5436536SAndroid Build Coastguard Worker         */
2575*e5436536SAndroid Build Coastguard Worker         if ((usc->m_sbrRatioIndex == 1) &&
2576*e5436536SAndroid Build Coastguard Worker             (usc->element[elemIdx].m_stereoConfigIndex != 1)) {
2577*e5436536SAndroid Build Coastguard Worker           return ErrorStatus = TRANSPORTDEC_PARSE_ERROR;
2578*e5436536SAndroid Build Coastguard Worker         }
2579*e5436536SAndroid Build Coastguard Worker         if (cb == NULL) {
2580*e5436536SAndroid Build Coastguard Worker           return ErrorStatus;
2581*e5436536SAndroid Build Coastguard Worker         }
2582*e5436536SAndroid Build Coastguard Worker         {
2583*e5436536SAndroid Build Coastguard Worker           MP4_ELEMENT_ID el_type =
2584*e5436536SAndroid Build Coastguard Worker               (usc->element[elemIdx].m_stereoConfigIndex == 1 ||
2585*e5436536SAndroid Build Coastguard Worker                usc->element[elemIdx].m_stereoConfigIndex == 2)
2586*e5436536SAndroid Build Coastguard Worker                   ? ID_SCE
2587*e5436536SAndroid Build Coastguard Worker                   : ID_CPE;
2588*e5436536SAndroid Build Coastguard Worker           if (cb->cbSbr == NULL) return ErrorStatus = TRANSPORTDEC_UNKOWN_ERROR;
2589*e5436536SAndroid Build Coastguard Worker           if (cb->cbSbr(cb->cbSbrData, hBs, asc->m_samplingFrequency,
2590*e5436536SAndroid Build Coastguard Worker                         asc->m_extensionSamplingFrequency,
2591*e5436536SAndroid Build Coastguard Worker                         asc->m_samplesPerFrame, asc->m_aot, el_type, elemIdx,
2592*e5436536SAndroid Build Coastguard Worker                         usc->element[elemIdx].m_harmonicSBR,
2593*e5436536SAndroid Build Coastguard Worker                         usc->element[elemIdx].m_stereoConfigIndex,
2594*e5436536SAndroid Build Coastguard Worker                         asc->configMode, &asc->SbrConfigChanged, 1)) {
2595*e5436536SAndroid Build Coastguard Worker             return ErrorStatus = TRANSPORTDEC_PARSE_ERROR;
2596*e5436536SAndroid Build Coastguard Worker           }
2597*e5436536SAndroid Build Coastguard Worker         }
2598*e5436536SAndroid Build Coastguard Worker         /*usc->element[elemIdx].m_stereoConfigIndex =*/FDKreadBits(hBs, 2);
2599*e5436536SAndroid Build Coastguard Worker         if (usc->element[elemIdx].m_stereoConfigIndex > 0) {
2600*e5436536SAndroid Build Coastguard Worker           if (cb->cbSsc != NULL) {
2601*e5436536SAndroid Build Coastguard Worker             int samplesPerFrame = asc->m_samplesPerFrame;
2602*e5436536SAndroid Build Coastguard Worker 
2603*e5436536SAndroid Build Coastguard Worker             if (usc->m_sbrRatioIndex == 1) samplesPerFrame <<= 2;
2604*e5436536SAndroid Build Coastguard Worker             if (usc->m_sbrRatioIndex == 2)
2605*e5436536SAndroid Build Coastguard Worker               samplesPerFrame = (samplesPerFrame * 8) / 3;
2606*e5436536SAndroid Build Coastguard Worker             if (usc->m_sbrRatioIndex == 3) samplesPerFrame <<= 1;
2607*e5436536SAndroid Build Coastguard Worker 
2608*e5436536SAndroid Build Coastguard Worker             ErrorStatus = (TRANSPORTDEC_ERROR)cb->cbSsc(
2609*e5436536SAndroid Build Coastguard Worker                 cb->cbSscData, hBs,
2610*e5436536SAndroid Build Coastguard Worker                 AOT_DRM_USAC, /* syntax differs from MPEG Mps212Config() */
2611*e5436536SAndroid Build Coastguard Worker                 asc->m_extensionSamplingFrequency, samplesPerFrame,
2612*e5436536SAndroid Build Coastguard Worker                 1, /* only downmix channels (residual channels are not
2613*e5436536SAndroid Build Coastguard Worker                       counted) */
2614*e5436536SAndroid Build Coastguard Worker                 usc->element[elemIdx].m_stereoConfigIndex,
2615*e5436536SAndroid Build Coastguard Worker                 usc->m_coreSbrFrameLengthIndex, 0, /* don't know the length */
2616*e5436536SAndroid Build Coastguard Worker                 asc->configMode, &asc->SacConfigChanged);
2617*e5436536SAndroid Build Coastguard Worker           } else {
2618*e5436536SAndroid Build Coastguard Worker             /* ErrorStatus = TRANSPORTDEC_UNSUPPORTED_FORMAT; */
2619*e5436536SAndroid Build Coastguard Worker           }
2620*e5436536SAndroid Build Coastguard Worker         }
2621*e5436536SAndroid Build Coastguard Worker       }
2622*e5436536SAndroid Build Coastguard Worker       break;
2623*e5436536SAndroid Build Coastguard Worker     default:
2624*e5436536SAndroid Build Coastguard Worker       return TRANSPORTDEC_PARSE_ERROR;
2625*e5436536SAndroid Build Coastguard Worker   }
2626*e5436536SAndroid Build Coastguard Worker 
2627*e5436536SAndroid Build Coastguard Worker   return ErrorStatus;
2628*e5436536SAndroid Build Coastguard Worker }
2629*e5436536SAndroid Build Coastguard Worker 
Drm_xHEAACStaticConfig(CSAudioSpecificConfig * asc,HANDLE_FDK_BITSTREAM bs,int audioMode,CSTpCallBacks * cb)2630*e5436536SAndroid Build Coastguard Worker TRANSPORTDEC_ERROR Drm_xHEAACStaticConfig(
2631*e5436536SAndroid Build Coastguard Worker     CSAudioSpecificConfig *asc, HANDLE_FDK_BITSTREAM bs, int audioMode,
2632*e5436536SAndroid Build Coastguard Worker     CSTpCallBacks *cb /* use cb == NULL to signal config check only mode */
2633*e5436536SAndroid Build Coastguard Worker ) {
2634*e5436536SAndroid Build Coastguard Worker   int coreSbrFrameLengthIndexDrm = FDKreadBits(bs, 2);
2635*e5436536SAndroid Build Coastguard Worker   if (UsacConfig_SetCoreSbrFrameLengthIndex(
2636*e5436536SAndroid Build Coastguard Worker           asc, coreSbrFrameLengthIndexDrm + 1) != TRANSPORTDEC_OK) {
2637*e5436536SAndroid Build Coastguard Worker     return TRANSPORTDEC_PARSE_ERROR;
2638*e5436536SAndroid Build Coastguard Worker   }
2639*e5436536SAndroid Build Coastguard Worker 
2640*e5436536SAndroid Build Coastguard Worker   asc->m_channelConfiguration = (audioMode) ? 2 : 1;
2641*e5436536SAndroid Build Coastguard Worker 
2642*e5436536SAndroid Build Coastguard Worker   if (Drm_xHEAACDecoderConfig(asc, bs, audioMode, cb) != TRANSPORTDEC_OK) {
2643*e5436536SAndroid Build Coastguard Worker     return TRANSPORTDEC_PARSE_ERROR;
2644*e5436536SAndroid Build Coastguard Worker   }
2645*e5436536SAndroid Build Coastguard Worker 
2646*e5436536SAndroid Build Coastguard Worker   return TRANSPORTDEC_OK;
2647*e5436536SAndroid Build Coastguard Worker }
2648*e5436536SAndroid Build Coastguard Worker 
2649*e5436536SAndroid Build Coastguard Worker /* Mapping of DRM audio sampling rate field to MPEG usacSamplingFrequencyIndex
2650*e5436536SAndroid Build Coastguard Worker  */
2651*e5436536SAndroid Build Coastguard Worker const UCHAR mapSr2MPEGIdx[8] = {
2652*e5436536SAndroid Build Coastguard Worker     0x1b, /*  9.6 kHz */
2653*e5436536SAndroid Build Coastguard Worker     0x09, /* 12.0 kHz */
2654*e5436536SAndroid Build Coastguard Worker     0x08, /* 16.0 kHz */
2655*e5436536SAndroid Build Coastguard Worker     0x17, /* 19.2 kHz */
2656*e5436536SAndroid Build Coastguard Worker     0x06, /* 24.0 kHz */
2657*e5436536SAndroid Build Coastguard Worker     0x05, /* 32.0 kHz */
2658*e5436536SAndroid Build Coastguard Worker     0x12, /* 38.4 kHz */
2659*e5436536SAndroid Build Coastguard Worker     0x03  /* 48.0 kHz */
2660*e5436536SAndroid Build Coastguard Worker };
2661*e5436536SAndroid Build Coastguard Worker 
DrmRawSdcAudioConfig_Parse(CSAudioSpecificConfig * self,HANDLE_FDK_BITSTREAM bs,CSTpCallBacks * cb,UCHAR configMode,UCHAR configChanged)2662*e5436536SAndroid Build Coastguard Worker TRANSPORTDEC_ERROR DrmRawSdcAudioConfig_Parse(
2663*e5436536SAndroid Build Coastguard Worker     CSAudioSpecificConfig *self, HANDLE_FDK_BITSTREAM bs,
2664*e5436536SAndroid Build Coastguard Worker     CSTpCallBacks *cb, /* use cb == NULL to signal config check only mode */
2665*e5436536SAndroid Build Coastguard Worker     UCHAR configMode, UCHAR configChanged) {
2666*e5436536SAndroid Build Coastguard Worker   TRANSPORTDEC_ERROR ErrorStatus = TRANSPORTDEC_OK;
2667*e5436536SAndroid Build Coastguard Worker 
2668*e5436536SAndroid Build Coastguard Worker   AudioSpecificConfig_Init(self);
2669*e5436536SAndroid Build Coastguard Worker 
2670*e5436536SAndroid Build Coastguard Worker   if ((INT)FDKgetValidBits(bs) < 16) {
2671*e5436536SAndroid Build Coastguard Worker     ErrorStatus = TRANSPORTDEC_PARSE_ERROR;
2672*e5436536SAndroid Build Coastguard Worker     goto bail;
2673*e5436536SAndroid Build Coastguard Worker   } else {
2674*e5436536SAndroid Build Coastguard Worker     /* DRM - Audio information data entity - type 9
2675*e5436536SAndroid Build Coastguard Worker        - Short Id            2 bits (not part of the config buffer)
2676*e5436536SAndroid Build Coastguard Worker        - Stream Id           2 bits (not part of the config buffer)
2677*e5436536SAndroid Build Coastguard Worker        - audio coding        2 bits
2678*e5436536SAndroid Build Coastguard Worker        - SBR flag            1 bit
2679*e5436536SAndroid Build Coastguard Worker        - audio mode          2 bits
2680*e5436536SAndroid Build Coastguard Worker        - audio sampling rate 3 bits
2681*e5436536SAndroid Build Coastguard Worker        - text flag           1 bit
2682*e5436536SAndroid Build Coastguard Worker        - enhancement flag    1 bit
2683*e5436536SAndroid Build Coastguard Worker        - coder field         5 bits
2684*e5436536SAndroid Build Coastguard Worker        - rfa                 1 bit  */
2685*e5436536SAndroid Build Coastguard Worker 
2686*e5436536SAndroid Build Coastguard Worker     int audioCoding, audioMode, cSamplingFreq, coderField, sfIdx, sbrFlag;
2687*e5436536SAndroid Build Coastguard Worker 
2688*e5436536SAndroid Build Coastguard Worker     self->configMode = configMode;
2689*e5436536SAndroid Build Coastguard Worker     self->AacConfigChanged = configChanged;
2690*e5436536SAndroid Build Coastguard Worker     self->SbrConfigChanged = configChanged;
2691*e5436536SAndroid Build Coastguard Worker     self->SacConfigChanged = configChanged;
2692*e5436536SAndroid Build Coastguard Worker 
2693*e5436536SAndroid Build Coastguard Worker     /* Read the SDC field */
2694*e5436536SAndroid Build Coastguard Worker     audioCoding = FDKreadBits(bs, 2);
2695*e5436536SAndroid Build Coastguard Worker     sbrFlag = FDKreadBits(bs, 1);
2696*e5436536SAndroid Build Coastguard Worker     audioMode = FDKreadBits(bs, 2);
2697*e5436536SAndroid Build Coastguard Worker     cSamplingFreq = FDKreadBits(bs, 3); /* audio sampling rate */
2698*e5436536SAndroid Build Coastguard Worker 
2699*e5436536SAndroid Build Coastguard Worker     FDKreadBits(bs, 2); /* Text and enhancement flag */
2700*e5436536SAndroid Build Coastguard Worker     coderField = FDKreadBits(bs, 5);
2701*e5436536SAndroid Build Coastguard Worker     FDKreadBits(bs, 1); /* rfa */
2702*e5436536SAndroid Build Coastguard Worker 
2703*e5436536SAndroid Build Coastguard Worker     /* Evaluate configuration and fill the ASC */
2704*e5436536SAndroid Build Coastguard Worker     if (audioCoding == 3) {
2705*e5436536SAndroid Build Coastguard Worker       sfIdx = (int)mapSr2MPEGIdx[cSamplingFreq];
2706*e5436536SAndroid Build Coastguard Worker       sbrFlag = 0; /* rfa */
2707*e5436536SAndroid Build Coastguard Worker     } else {
2708*e5436536SAndroid Build Coastguard Worker       switch (cSamplingFreq) {
2709*e5436536SAndroid Build Coastguard Worker         case 0: /*  8 kHz */
2710*e5436536SAndroid Build Coastguard Worker           sfIdx = 11;
2711*e5436536SAndroid Build Coastguard Worker           break;
2712*e5436536SAndroid Build Coastguard Worker         case 1: /* 12 kHz */
2713*e5436536SAndroid Build Coastguard Worker           sfIdx = 9;
2714*e5436536SAndroid Build Coastguard Worker           break;
2715*e5436536SAndroid Build Coastguard Worker         case 2: /* 16 kHz */
2716*e5436536SAndroid Build Coastguard Worker           sfIdx = 8;
2717*e5436536SAndroid Build Coastguard Worker           break;
2718*e5436536SAndroid Build Coastguard Worker         case 3: /* 24 kHz */
2719*e5436536SAndroid Build Coastguard Worker           sfIdx = 6;
2720*e5436536SAndroid Build Coastguard Worker           break;
2721*e5436536SAndroid Build Coastguard Worker         case 5: /* 48 kHz */
2722*e5436536SAndroid Build Coastguard Worker           sfIdx = 3;
2723*e5436536SAndroid Build Coastguard Worker           break;
2724*e5436536SAndroid Build Coastguard Worker         case 4: /* reserved */
2725*e5436536SAndroid Build Coastguard Worker         case 6: /* reserved */
2726*e5436536SAndroid Build Coastguard Worker         case 7: /* reserved */
2727*e5436536SAndroid Build Coastguard Worker         default:
2728*e5436536SAndroid Build Coastguard Worker           ErrorStatus = TRANSPORTDEC_PARSE_ERROR;
2729*e5436536SAndroid Build Coastguard Worker           goto bail;
2730*e5436536SAndroid Build Coastguard Worker       }
2731*e5436536SAndroid Build Coastguard Worker     }
2732*e5436536SAndroid Build Coastguard Worker 
2733*e5436536SAndroid Build Coastguard Worker     self->m_samplingFrequencyIndex = sfIdx;
2734*e5436536SAndroid Build Coastguard Worker     self->m_samplingFrequency = SamplingRateTable[sfIdx];
2735*e5436536SAndroid Build Coastguard Worker 
2736*e5436536SAndroid Build Coastguard Worker     if (sbrFlag) {
2737*e5436536SAndroid Build Coastguard Worker       UINT i;
2738*e5436536SAndroid Build Coastguard Worker       int tmp = -1;
2739*e5436536SAndroid Build Coastguard Worker       self->m_sbrPresentFlag = 1;
2740*e5436536SAndroid Build Coastguard Worker       self->m_extensionAudioObjectType = AOT_SBR;
2741*e5436536SAndroid Build Coastguard Worker       self->m_extensionSamplingFrequency = self->m_samplingFrequency << 1;
2742*e5436536SAndroid Build Coastguard Worker       for (i = 0;
2743*e5436536SAndroid Build Coastguard Worker            i < (sizeof(SamplingRateTable) / sizeof(SamplingRateTable[0]));
2744*e5436536SAndroid Build Coastguard Worker            i++) {
2745*e5436536SAndroid Build Coastguard Worker         if (SamplingRateTable[i] == self->m_extensionSamplingFrequency) {
2746*e5436536SAndroid Build Coastguard Worker           tmp = i;
2747*e5436536SAndroid Build Coastguard Worker           break;
2748*e5436536SAndroid Build Coastguard Worker         }
2749*e5436536SAndroid Build Coastguard Worker       }
2750*e5436536SAndroid Build Coastguard Worker       self->m_extensionSamplingFrequencyIndex = tmp;
2751*e5436536SAndroid Build Coastguard Worker     }
2752*e5436536SAndroid Build Coastguard Worker 
2753*e5436536SAndroid Build Coastguard Worker     switch (audioCoding) {
2754*e5436536SAndroid Build Coastguard Worker       case 0: /* AAC */
2755*e5436536SAndroid Build Coastguard Worker         if ((coderField >> 2) && (audioMode != 1)) {
2756*e5436536SAndroid Build Coastguard Worker           self->m_aot = AOT_DRM_SURROUND; /* Set pseudo AOT for Drm Surround */
2757*e5436536SAndroid Build Coastguard Worker         } else {
2758*e5436536SAndroid Build Coastguard Worker           self->m_aot = AOT_DRM_AAC; /* Set pseudo AOT for Drm AAC */
2759*e5436536SAndroid Build Coastguard Worker         }
2760*e5436536SAndroid Build Coastguard Worker         switch (audioMode) {
2761*e5436536SAndroid Build Coastguard Worker           case 1: /* parametric stereo */
2762*e5436536SAndroid Build Coastguard Worker             self->m_psPresentFlag = 1;
2763*e5436536SAndroid Build Coastguard Worker             FDK_FALLTHROUGH;
2764*e5436536SAndroid Build Coastguard Worker           case 0: /* mono */
2765*e5436536SAndroid Build Coastguard Worker             self->m_channelConfiguration = 1;
2766*e5436536SAndroid Build Coastguard Worker             break;
2767*e5436536SAndroid Build Coastguard Worker           case 2: /* stereo */
2768*e5436536SAndroid Build Coastguard Worker             self->m_channelConfiguration = 2;
2769*e5436536SAndroid Build Coastguard Worker             break;
2770*e5436536SAndroid Build Coastguard Worker           default:
2771*e5436536SAndroid Build Coastguard Worker             ErrorStatus = TRANSPORTDEC_PARSE_ERROR;
2772*e5436536SAndroid Build Coastguard Worker             goto bail;
2773*e5436536SAndroid Build Coastguard Worker         }
2774*e5436536SAndroid Build Coastguard Worker         self->m_vcb11Flag = 1;
2775*e5436536SAndroid Build Coastguard Worker         self->m_hcrFlag = 1;
2776*e5436536SAndroid Build Coastguard Worker         self->m_samplesPerFrame = 960;
2777*e5436536SAndroid Build Coastguard Worker         self->m_epConfig = 1;
2778*e5436536SAndroid Build Coastguard Worker         break;
2779*e5436536SAndroid Build Coastguard Worker       case 1: /* CELP */
2780*e5436536SAndroid Build Coastguard Worker         self->m_aot = AOT_ER_CELP;
2781*e5436536SAndroid Build Coastguard Worker         self->m_channelConfiguration = 1;
2782*e5436536SAndroid Build Coastguard Worker         break;
2783*e5436536SAndroid Build Coastguard Worker       case 2: /* HVXC */
2784*e5436536SAndroid Build Coastguard Worker         self->m_aot = AOT_ER_HVXC;
2785*e5436536SAndroid Build Coastguard Worker         self->m_channelConfiguration = 1;
2786*e5436536SAndroid Build Coastguard Worker         break;
2787*e5436536SAndroid Build Coastguard Worker       case 3: /* xHE-AAC */
2788*e5436536SAndroid Build Coastguard Worker       {
2789*e5436536SAndroid Build Coastguard Worker         /* payload is MPEG conform -> no pseudo DRM AOT needed */
2790*e5436536SAndroid Build Coastguard Worker         self->m_aot = AOT_USAC;
2791*e5436536SAndroid Build Coastguard Worker       }
2792*e5436536SAndroid Build Coastguard Worker         switch (audioMode) {
2793*e5436536SAndroid Build Coastguard Worker           case 0: /* mono */
2794*e5436536SAndroid Build Coastguard Worker           case 2: /* stereo */
2795*e5436536SAndroid Build Coastguard Worker             /* codec specific config 8n bits */
2796*e5436536SAndroid Build Coastguard Worker             ErrorStatus = Drm_xHEAACStaticConfig(self, bs, audioMode, cb);
2797*e5436536SAndroid Build Coastguard Worker             break;
2798*e5436536SAndroid Build Coastguard Worker           default:
2799*e5436536SAndroid Build Coastguard Worker             ErrorStatus = TRANSPORTDEC_PARSE_ERROR;
2800*e5436536SAndroid Build Coastguard Worker             goto bail;
2801*e5436536SAndroid Build Coastguard Worker         }
2802*e5436536SAndroid Build Coastguard Worker         break;
2803*e5436536SAndroid Build Coastguard Worker       default:
2804*e5436536SAndroid Build Coastguard Worker         ErrorStatus = TRANSPORTDEC_PARSE_ERROR;
2805*e5436536SAndroid Build Coastguard Worker         self->m_aot = AOT_NONE;
2806*e5436536SAndroid Build Coastguard Worker         break;
2807*e5436536SAndroid Build Coastguard Worker     }
2808*e5436536SAndroid Build Coastguard Worker 
2809*e5436536SAndroid Build Coastguard Worker     if (self->m_psPresentFlag && !self->m_sbrPresentFlag) {
2810*e5436536SAndroid Build Coastguard Worker       ErrorStatus = TRANSPORTDEC_PARSE_ERROR;
2811*e5436536SAndroid Build Coastguard Worker       goto bail;
2812*e5436536SAndroid Build Coastguard Worker     }
2813*e5436536SAndroid Build Coastguard Worker   }
2814*e5436536SAndroid Build Coastguard Worker 
2815*e5436536SAndroid Build Coastguard Worker bail:
2816*e5436536SAndroid Build Coastguard Worker   return (ErrorStatus);
2817*e5436536SAndroid Build Coastguard Worker }
2818