1/* -----------------------------------------------------------------------------
2Software License for The Fraunhofer FDK AAC Codec Library for Android
3
4© Copyright  1995 - 2018 Fraunhofer-Gesellschaft zur Förderung der angewandten
5Forschung e.V. All rights reserved.
6
7 1.    INTRODUCTION
8The Fraunhofer FDK AAC Codec Library for Android ("FDK AAC Codec") is software
9that implements the MPEG Advanced Audio Coding ("AAC") encoding and decoding
10scheme for digital audio. This FDK AAC Codec software is intended to be used on
11a wide variety of Android devices.
12
13AAC's HE-AAC and HE-AAC v2 versions are regarded as today's most efficient
14general perceptual audio codecs. AAC-ELD is considered the best-performing
15full-bandwidth communications codec by independent studies and is widely
16deployed. AAC has been standardized by ISO and IEC as part of the MPEG
17specifications.
18
19Patent licenses for necessary patent claims for the FDK AAC Codec (including
20those of Fraunhofer) may be obtained through Via Licensing
21(www.vialicensing.com) or through the respective patent owners individually for
22the purpose of encoding or decoding bit streams in products that are compliant
23with the ISO/IEC MPEG audio standards. Please note that most manufacturers of
24Android devices already license these patent claims through Via Licensing or
25directly from the patent owners, and therefore FDK AAC Codec software may
26already be covered under those patent licenses when it is used for those
27licensed purposes only.
28
29Commercially-licensed AAC software libraries, including floating-point versions
30with enhanced sound quality, are also available from Fraunhofer. Users are
31encouraged to check the Fraunhofer website for additional applications
32information and documentation.
33
342.    COPYRIGHT LICENSE
35
36Redistribution and use in source and binary forms, with or without modification,
37are permitted without payment of copyright license fees provided that you
38satisfy the following conditions:
39
40You must retain the complete text of this software license in redistributions of
41the FDK AAC Codec or your modifications thereto in source code form.
42
43You must retain the complete text of this software license in the documentation
44and/or other materials provided with redistributions of the FDK AAC Codec or
45your modifications thereto in binary form. You must make available free of
46charge copies of the complete source code of the FDK AAC Codec and your
47modifications thereto to recipients of copies in binary form.
48
49The name of Fraunhofer may not be used to endorse or promote products derived
50from this library without prior written permission.
51
52You may not charge copyright license fees for anyone to use, copy or distribute
53the FDK AAC Codec software or your modifications thereto.
54
55Your modified versions of the FDK AAC Codec must carry prominent notices stating
56that you changed the software and the date of any change. For modified versions
57of the FDK AAC Codec, the term "Fraunhofer FDK AAC Codec Library for Android"
58must be replaced by the term "Third-Party Modified Version of the Fraunhofer FDK
59AAC Codec Library for Android."
60
613.    NO PATENT LICENSE
62
63NO EXPRESS OR IMPLIED LICENSES TO ANY PATENT CLAIMS, including without
64limitation the patents of Fraunhofer, ARE GRANTED BY THIS SOFTWARE LICENSE.
65Fraunhofer provides no warranty of patent non-infringement with respect to this
66software.
67
68You may use this FDK AAC Codec software or modifications thereto only for
69purposes that are authorized by appropriate patent licenses.
70
714.    DISCLAIMER
72
73This FDK AAC Codec software is provided by Fraunhofer on behalf of the copyright
74holders and contributors "AS IS" and WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES,
75including but not limited to the implied warranties of merchantability and
76fitness for a particular purpose. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
77CONTRIBUTORS BE LIABLE for any direct, indirect, incidental, special, exemplary,
78or consequential damages, including but not limited to procurement of substitute
79goods or services; loss of use, data, or profits, or business interruption,
80however caused and on any theory of liability, whether in contract, strict
81liability, or tort (including negligence), arising in any way out of the use of
82this software, even if advised of the possibility of such damage.
83
845.    CONTACT INFORMATION
85
86Fraunhofer Institute for Integrated Circuits IIS
87Attention: Audio and Multimedia Departments - FDK AAC LL
88Am Wolfsmantel 33
8991058 Erlangen, Germany
90
91www.iis.fraunhofer.de/amm
92amm-info@iis.fraunhofer.de
93----------------------------------------------------------------------------- */
94
95/*********************** MPEG surround encoder library *************************
96
97   Author(s):   Max Neuendorf
98
99   Description: Encoder Library Interface
100                Tree Structure for Space Encoder
101
102*******************************************************************************/
103
104/* Includes ******************************************************************/
105#include "sacenc_tree.h"
106#include "genericStds.h"
107#include "sacenc_const.h"
108#include "sacenc_paramextract.h"
109#include "sacenc_framewindowing.h"
110#include "FDK_matrixCalloc.h"
111
112/* Defines *******************************************************************/
113enum { BOX_0 = 0, BOX_1 = 1 };
114
115enum { CH_L = 0, CH_R = 1 };
116
117enum { TTO_CH_0 = 0, TTO_CH_1 = 1 };
118
119enum { WIN_INACTIV = 0, WIN_ACTIV = 1 };
120
121enum { MAX_KEEP_FRAMECOUNT = 100 };
122
123/* Data Types ****************************************************************/
124struct SPACE_TREE {
125  SPACETREE_MODE mode;
126  SPACE_TREE_DESCRIPTION descr;
127  HANDLE_TTO_BOX ttoBox[SACENC_MAX_NUM_BOXES];
128  UCHAR nParamBands;
129  UCHAR bUseCoarseQuantTtoIcc;
130  UCHAR bUseCoarseQuantTtoCld;
131  QUANTMODE quantMode;
132  INT frameCount;
133  UCHAR bFrameKeep;
134
135  /* Intermediate buffers */
136  UCHAR pCld_prev[SACENC_MAX_NUM_BOXES][MAX_NUM_PARAM_BANDS];
137  UCHAR pIcc_prev[SACENC_MAX_NUM_BOXES][MAX_NUM_PARAM_BANDS];
138
139  UCHAR nChannelsInMax;
140  UCHAR nHybridBandsMax;
141};
142
143typedef struct {
144  UCHAR boxId;
145  UCHAR inCh1;
146  UCHAR inCh2;
147  UCHAR inCh3;
148  UCHAR inCh4;
149  UCHAR wCh1;
150  UCHAR wCh2;
151
152} TTO_DESCRIPTOR;
153
154typedef struct {
155  SPACETREE_MODE mode;
156  SPACE_TREE_DESCRIPTION treeDescription;
157
158} TREE_CONFIG;
159
160typedef struct {
161  SPACETREE_MODE mode;
162  UCHAR nChannelsIn;
163  UCHAR nChannelsOut;
164  UCHAR nTtoBoxes;
165  TTO_DESCRIPTOR tto_descriptor[1];
166
167} TREE_SETUP;
168
169/* Constants *****************************************************************/
170static const TREE_CONFIG treeConfigTable[] = {
171    {SPACETREE_INVALID_MODE, {0, 0, 0}}, {SPACETREE_212, {1, 1, 2}}};
172
173static const TREE_SETUP treeSetupTable[] = {
174    {SPACETREE_INVALID_MODE, 0, 0, 0, {{0, 0, 0, 0, 0, 0, 0}}},
175    {SPACETREE_212,
176     2,
177     1,
178     1,
179     {{BOX_0, CH_L, CH_R, TTO_CH_0, TTO_CH_1, WIN_ACTIV, WIN_ACTIV}}}};
180
181/* Function / Class Declarations *********************************************/
182
183/* Function / Class Definition ***********************************************/
184static FDK_SACENC_ERROR getTreeConfig(
185    const SPACETREE_MODE mode, SPACE_TREE_DESCRIPTION *pTreeDescription) {
186  FDK_SACENC_ERROR error = SACENC_INIT_ERROR;
187
188  if (pTreeDescription == NULL) {
189    error = SACENC_INVALID_HANDLE;
190  } else {
191    int i;
192    for (i = 0; i < (int)(sizeof(treeConfigTable) / sizeof(TREE_CONFIG)); i++) {
193      if (treeConfigTable[i].mode == mode) {
194        *pTreeDescription = treeConfigTable[i].treeDescription;
195        error = SACENC_OK;
196        break;
197      }
198    }
199  } /* valid handle */
200  return error;
201}
202
203static const TREE_SETUP *getTreeSetup(const SPACETREE_MODE mode) {
204  int i;
205  const TREE_SETUP *setup = NULL;
206
207  for (i = 0; i < (int)(sizeof(treeSetupTable) / sizeof(TREE_SETUP)); i++) {
208    if (treeSetupTable[i].mode == mode) {
209      setup = &treeSetupTable[i];
210      break;
211    }
212  }
213  return setup;
214}
215
216FDK_SACENC_ERROR fdk_sacenc_spaceTree_Open(HANDLE_SPACE_TREE *phSpaceTree) {
217  FDK_SACENC_ERROR error = SACENC_OK;
218  HANDLE_SPACE_TREE hSpaceTree = NULL;
219
220  if (NULL == phSpaceTree) {
221    error = SACENC_INVALID_HANDLE;
222  } else {
223    int box;
224
225    FDK_ALLOCATE_MEMORY_1D(hSpaceTree, 1, struct SPACE_TREE);
226
227    for (box = 0; box < SACENC_MAX_NUM_BOXES; box++) {
228      HANDLE_TTO_BOX ttoBox = NULL;
229      if (SACENC_OK != (error = fdk_sacenc_createTtoBox(&ttoBox))) {
230        goto bail;
231      }
232      if (NULL != hSpaceTree) {
233        hSpaceTree->ttoBox[box] = ttoBox;
234      }
235    }
236    *phSpaceTree = hSpaceTree;
237  }
238  return error;
239
240bail:
241  fdk_sacenc_spaceTree_Close(&hSpaceTree);
242  return ((SACENC_OK == error) ? SACENC_MEMORY_ERROR : error);
243}
244
245FDK_SACENC_ERROR fdk_sacenc_spaceTree_Init(
246    HANDLE_SPACE_TREE hST, const SPACE_TREE_SETUP *const hSetup,
247    UCHAR *pParameterBand2HybridBandOffset, const INT bFrameKeep) {
248  FDK_SACENC_ERROR error = SACENC_OK;
249
250  if ((hST == NULL) || (hSetup == NULL)) {
251    error = SACENC_INVALID_HANDLE;
252  } else {
253    int bTtoBoxFrontBackCombin[SACENC_MAX_NUM_BOXES] = {0};
254    int box = 0;
255
256    hST->frameCount = 0;
257    hST->bFrameKeep = bFrameKeep;
258
259    /* Init */
260    hST->mode = hSetup->mode;
261    hST->nParamBands = hSetup->nParamBands;
262    hST->bUseCoarseQuantTtoIcc = hSetup->bUseCoarseQuantTtoIcc;
263    hST->bUseCoarseQuantTtoCld = hSetup->bUseCoarseQuantTtoCld;
264    hST->quantMode = hSetup->quantMode;
265    hST->nChannelsInMax = hSetup->nChannelsInMax;
266    hST->nHybridBandsMax = hSetup->nHybridBandsMax;
267
268    if (SACENC_OK != (error = getTreeConfig(hST->mode, &hST->descr))) {
269      goto bail;
270    }
271
272    switch (hST->mode) {
273      case SPACETREE_212:
274        bTtoBoxFrontBackCombin[BOX_0] = 0;
275        break;
276      case SPACETREE_INVALID_MODE:
277      default:
278        error = SACENC_INIT_ERROR;
279        goto bail;
280    } /* switch (hST->mode) */
281
282    if (hST->descr.nOttBoxes > SACENC_MAX_NUM_BOXES) {
283      error = SACENC_INIT_ERROR;
284      goto bail;
285    }
286
287    for (box = 0; box < hST->descr.nOttBoxes; box++) {
288      TTO_BOX_CONFIG boxConfig;
289      boxConfig.subbandConfig = (BOX_SUBBAND_CONFIG)hST->nParamBands;
290      boxConfig.bUseCoarseQuantCld = hST->bUseCoarseQuantTtoCld;
291      boxConfig.bUseCoarseQuantIcc = hST->bUseCoarseQuantTtoIcc;
292      boxConfig.bUseCoherenceIccOnly = bTtoBoxFrontBackCombin[box];
293      boxConfig.boxQuantMode = (BOX_QUANTMODE)hST->quantMode;
294      boxConfig.nHybridBandsMax = hST->nHybridBandsMax;
295      boxConfig.bFrameKeep = hST->bFrameKeep;
296
297      if (SACENC_OK !=
298          (error = fdk_sacenc_initTtoBox(hST->ttoBox[box], &boxConfig,
299                                         pParameterBand2HybridBandOffset))) {
300        goto bail;
301      }
302    } /* for box */
303
304  } /* valid handle */
305
306bail:
307  return error;
308}
309
310static void SpaceTree_FrameKeep212(const HANDLE_SPACE_TREE hST,
311                                   SPATIALFRAME *const hSTOut,
312                                   const INT avoid_keep) {
313  int pb;
314
315  if (avoid_keep == 0) {
316    if (hST->frameCount % 2 == 0) {
317      for (pb = 0; pb < hST->nParamBands; pb++) {
318        hST->pIcc_prev[BOX_0][pb] = hSTOut->ottData.icc[BOX_0][0][pb];
319        hSTOut->ottData.cld[BOX_0][0][pb] = hST->pCld_prev[BOX_0][pb];
320      }
321    } else {
322      for (pb = 0; pb < hST->nParamBands; pb++) {
323        hSTOut->ottData.icc[BOX_0][0][pb] = hST->pIcc_prev[BOX_0][pb];
324        hST->pCld_prev[BOX_0][pb] = hSTOut->ottData.cld[BOX_0][0][pb];
325      }
326    }
327  } else {
328    for (pb = 0; pb < hST->nParamBands; pb++) {
329      hST->pIcc_prev[BOX_0][pb] = hSTOut->ottData.icc[BOX_0][0][pb];
330      hST->pCld_prev[BOX_0][pb] = hSTOut->ottData.cld[BOX_0][0][pb];
331    }
332  }
333  hST->frameCount++;
334  if (hST->frameCount == MAX_KEEP_FRAMECOUNT) {
335    hST->frameCount = 0;
336  }
337}
338
339static FDK_SACENC_ERROR SpaceTree_FrameKeep(const HANDLE_SPACE_TREE hST,
340                                            SPATIALFRAME *const hSTOut,
341                                            const INT avoid_keep) {
342  FDK_SACENC_ERROR error = SACENC_OK;
343
344  switch (hST->mode) {
345    case SPACETREE_212:
346      SpaceTree_FrameKeep212(hST, hSTOut, avoid_keep);
347      break;
348    case SPACETREE_INVALID_MODE:
349    default:
350      error = SACENC_INVALID_CONFIG;
351      break;
352  }
353  return error;
354}
355
356FDK_SACENC_ERROR fdk_sacenc_spaceTree_Apply(
357    HANDLE_SPACE_TREE hST, const INT paramSet, const INT nChannelsIn,
358    const INT nTimeSlots, const INT startTimeSlot, const INT nHybridBands,
359    FIXP_WIN *pFrameWindowAna__FDK,
360    FIXP_DPK *const *const *const pppHybrid__FDK,
361    FIXP_DPK *const *const *const pppHybridIn__FDK, SPATIALFRAME *const hSTOut,
362    const INT avoid_keep, INT *pEncoderInputChScale) {
363  /** \verbatim
364   =============================================================================================================================
365      TREE_212
366   =============================================================================================================================
367                         _______
368        L -- TTO_CH_0 --|       |
369                        | TTO_0 |-- TTO_CH_0
370        R -- TTO_CH_1 --|_______|
371
372  \endverbatim */
373
374  FDK_SACENC_ERROR error = SACENC_OK;
375  int k;
376  const TREE_SETUP *treeSetup = NULL;
377
378  if ((hST == NULL) || (hSTOut == NULL) || (pppHybrid__FDK == NULL) ||
379      (pppHybridIn__FDK == NULL)) {
380    error = SACENC_INVALID_HANDLE;
381    goto bail;
382  }
383
384  if ((treeSetup = getTreeSetup(hST->mode)) == NULL) {
385    error = SACENC_INVALID_CONFIG;
386    goto bail;
387  }
388
389  /* Sanity Checks */
390  if ((nChannelsIn != treeSetup->nChannelsIn) ||
391      (nChannelsIn > hST->nChannelsInMax) ||
392      (nHybridBands > hST->nHybridBandsMax)) {
393    error = SACENC_INVALID_CONFIG;
394    goto bail;
395  }
396
397  /* Apply all TTO boxes. */
398  for (k = 0; k < treeSetup->nTtoBoxes; k++) {
399    const TTO_DESCRIPTOR *pTTO = &treeSetup->tto_descriptor[k];
400
401    int i, inCh[2], outCh[2], win[2];
402
403    inCh[0] = pTTO->inCh1;
404    outCh[0] = pTTO->inCh3;
405    win[0] = pTTO->wCh1;
406    inCh[1] = pTTO->inCh2;
407    outCh[1] = pTTO->inCh4;
408    win[1] = pTTO->wCh2;
409
410    for (i = 0; i < 2; i++) {
411      if (win[i] == WIN_ACTIV) {
412        fdk_sacenc_analysisWindowing(
413            nTimeSlots, startTimeSlot, pFrameWindowAna__FDK,
414            pppHybrid__FDK[inCh[i]], pppHybridIn__FDK[outCh[i]], nHybridBands,
415            FW_LEAVE_DIM);
416      }
417    }
418
419    /* Calculate output downmix within last TTO box, if no TTT box is applied.
420     */
421    if (SACENC_OK !=
422        (error = fdk_sacenc_applyTtoBox(
423             hST->ttoBox[pTTO->boxId], nTimeSlots, startTimeSlot, nHybridBands,
424             pppHybridIn__FDK[pTTO->inCh3], pppHybridIn__FDK[pTTO->inCh4],
425             hSTOut->ottData.icc[pTTO->boxId][paramSet],
426             &(hSTOut->ICCLosslessData.bsQuantCoarseXXX[pTTO->boxId][paramSet]),
427             hSTOut->ottData.cld[pTTO->boxId][paramSet],
428             &(hSTOut->CLDLosslessData.bsQuantCoarseXXX[pTTO->boxId][paramSet]),
429             hSTOut->bUseBBCues, &pEncoderInputChScale[inCh[0]],
430             &pEncoderInputChScale[inCh[1]]))) {
431      goto bail;
432    }
433  }
434
435  if (hST->bFrameKeep == 1) {
436    if (SACENC_OK != (error = SpaceTree_FrameKeep(hST, hSTOut, avoid_keep))) {
437      goto bail;
438    }
439  }
440
441bail:
442  return error;
443}
444
445FDK_SACENC_ERROR fdk_sacenc_spaceTree_Close(HANDLE_SPACE_TREE *phSpaceTree) {
446  FDK_SACENC_ERROR error = SACENC_OK;
447
448  if ((phSpaceTree == NULL) || (*phSpaceTree == NULL)) {
449    error = SACENC_INVALID_HANDLE;
450  } else {
451    int box;
452    HANDLE_SPACE_TREE const hST = *phSpaceTree;
453
454    /* for (box = 0; box < hST->descr.nOttBoxes; ++box) { */
455    for (box = 0; box < SACENC_MAX_NUM_BOXES; ++box) {
456      if (SACENC_OK != (error = fdk_sacenc_destroyTtoBox(&hST->ttoBox[box]))) {
457        goto bail;
458      }
459    }
460
461    FDKfree(*phSpaceTree);
462    *phSpaceTree = NULL;
463  }
464bail:
465  return error;
466}
467
468FDK_SACENC_ERROR fdk_sacenc_spaceTree_GetDescription(
469    const HANDLE_SPACE_TREE hSpaceTree,
470    SPACE_TREE_DESCRIPTION *pSpaceTreeDescription) {
471  FDK_SACENC_ERROR error = SACENC_OK;
472
473  if ((hSpaceTree == NULL) || (pSpaceTreeDescription == NULL)) {
474    error = SACENC_INVALID_HANDLE;
475  } else {
476    *pSpaceTreeDescription = hSpaceTree->descr;
477  }
478  return error;
479}
480
481INT fdk_sacenc_spaceTree_Hybrid2ParamBand(const INT nParamBands,
482                                          const INT nHybridBand) {
483  return fdk_sacenc_subband2ParamBand((BOX_SUBBAND_CONFIG)nParamBands,
484                                      nHybridBand);
485}
486
487/*****************************************************************************
488******************************************************************************/
489