Coverage Report

Created: 2023-03-26 06:07

/src/aac/libSACenc/src/sacenc_lib.cpp
Line
Count
Source (jump to first uncovered line)
1
/* -----------------------------------------------------------------------------
2
Software License for The Fraunhofer FDK AAC Codec Library for Android
3
4
© Copyright  1995 - 2018 Fraunhofer-Gesellschaft zur Förderung der angewandten
5
Forschung e.V. All rights reserved.
6
7
 1.    INTRODUCTION
8
The Fraunhofer FDK AAC Codec Library for Android ("FDK AAC Codec") is software
9
that implements the MPEG Advanced Audio Coding ("AAC") encoding and decoding
10
scheme for digital audio. This FDK AAC Codec software is intended to be used on
11
a wide variety of Android devices.
12
13
AAC's HE-AAC and HE-AAC v2 versions are regarded as today's most efficient
14
general perceptual audio codecs. AAC-ELD is considered the best-performing
15
full-bandwidth communications codec by independent studies and is widely
16
deployed. AAC has been standardized by ISO and IEC as part of the MPEG
17
specifications.
18
19
Patent licenses for necessary patent claims for the FDK AAC Codec (including
20
those of Fraunhofer) may be obtained through Via Licensing
21
(www.vialicensing.com) or through the respective patent owners individually for
22
the purpose of encoding or decoding bit streams in products that are compliant
23
with the ISO/IEC MPEG audio standards. Please note that most manufacturers of
24
Android devices already license these patent claims through Via Licensing or
25
directly from the patent owners, and therefore FDK AAC Codec software may
26
already be covered under those patent licenses when it is used for those
27
licensed purposes only.
28
29
Commercially-licensed AAC software libraries, including floating-point versions
30
with enhanced sound quality, are also available from Fraunhofer. Users are
31
encouraged to check the Fraunhofer website for additional applications
32
information and documentation.
33
34
2.    COPYRIGHT LICENSE
35
36
Redistribution and use in source and binary forms, with or without modification,
37
are permitted without payment of copyright license fees provided that you
38
satisfy the following conditions:
39
40
You must retain the complete text of this software license in redistributions of
41
the FDK AAC Codec or your modifications thereto in source code form.
42
43
You must retain the complete text of this software license in the documentation
44
and/or other materials provided with redistributions of the FDK AAC Codec or
45
your modifications thereto in binary form. You must make available free of
46
charge copies of the complete source code of the FDK AAC Codec and your
47
modifications thereto to recipients of copies in binary form.
48
49
The name of Fraunhofer may not be used to endorse or promote products derived
50
from this library without prior written permission.
51
52
You may not charge copyright license fees for anyone to use, copy or distribute
53
the FDK AAC Codec software or your modifications thereto.
54
55
Your modified versions of the FDK AAC Codec must carry prominent notices stating
56
that you changed the software and the date of any change. For modified versions
57
of the FDK AAC Codec, the term "Fraunhofer FDK AAC Codec Library for Android"
58
must be replaced by the term "Third-Party Modified Version of the Fraunhofer FDK
59
AAC Codec Library for Android."
60
61
3.    NO PATENT LICENSE
62
63
NO EXPRESS OR IMPLIED LICENSES TO ANY PATENT CLAIMS, including without
64
limitation the patents of Fraunhofer, ARE GRANTED BY THIS SOFTWARE LICENSE.
65
Fraunhofer provides no warranty of patent non-infringement with respect to this
66
software.
67
68
You may use this FDK AAC Codec software or modifications thereto only for
69
purposes that are authorized by appropriate patent licenses.
70
71
4.    DISCLAIMER
72
73
This FDK AAC Codec software is provided by Fraunhofer on behalf of the copyright
74
holders and contributors "AS IS" and WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES,
75
including but not limited to the implied warranties of merchantability and
76
fitness for a particular purpose. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
77
CONTRIBUTORS BE LIABLE for any direct, indirect, incidental, special, exemplary,
78
or consequential damages, including but not limited to procurement of substitute
79
goods or services; loss of use, data, or profits, or business interruption,
80
however caused and on any theory of liability, whether in contract, strict
81
liability, or tort (including negligence), arising in any way out of the use of
82
this software, even if advised of the possibility of such damage.
83
84
5.    CONTACT INFORMATION
85
86
Fraunhofer Institute for Integrated Circuits IIS
87
Attention: Audio and Multimedia Departments - FDK AAC LL
88
Am Wolfsmantel 33
89
91058 Erlangen, Germany
90
91
www.iis.fraunhofer.de/amm
92
amm-info@iis.fraunhofer.de
93
----------------------------------------------------------------------------- */
94
95
/*********************** MPEG surround encoder library *************************
96
97
   Author(s):   Max Neuendorf
98
99
   Description: Encoder Library Interface
100
                Interface to Spacial Audio Coding Encoder lib
101
102
*******************************************************************************/
103
104
/****************************************************************************
105
\file
106
Description of file contents
107
******************************************************************************/
108
109
/* Includes ******************************************************************/
110
#include "sacenc_lib.h"
111
#include "sacenc_const.h"
112
#include "genericStds.h"
113
#include "FDK_core.h"
114
#include "sacenc_tree.h"
115
#include "sacenc_bitstream.h"
116
#include "sacenc_onsetdetect.h"
117
#include "sacenc_framewindowing.h"
118
#include "sacenc_filter.h"
119
#include "sacenc_paramextract.h"
120
#include "sacenc_staticgain.h"
121
#include "sacenc_delay.h"
122
#include "sacenc_dmx_tdom_enh.h"
123
#include "sacenc_vectorfunctions.h"
124
#include "qmf.h"
125
126
/* Defines *******************************************************************/
127
128
/* Encoder library info */
129
#define SACENC_LIB_VL0 2
130
#define SACENC_LIB_VL1 0
131
#define SACENC_LIB_VL2 0
132
0
#define SACENC_LIB_TITLE "MPEG Surround Encoder"
133
#ifdef SUPPRESS_BUILD_DATE_INFO
134
#define SACENC_LIB_BUILD_DATE ""
135
#define SACENC_LIB_BUILD_TIME ""
136
#else
137
0
#define SACENC_LIB_BUILD_DATE __DATE__
138
0
#define SACENC_LIB_BUILD_TIME __TIME__
139
#endif
140
141
0
#define MAX_MPEGS_BYTES (1 << 14)
142
0
#define MAX_SSC_BYTES (1 << 6)
143
144
#define MAX_SPACE_TREE_CHANNELS 2
145
0
#define NUM_KEEP_WINDOWS 3
146
147
/* Data Types ****************************************************************/
148
typedef struct {
149
  MP4SPACEENC_MODE encMode;
150
  MP4SPACEENC_BANDS_CONFIG nParamBands;
151
  MP4SPACEENC_QUANTMODE quantMode;
152
  UCHAR bUseCoarseQuant;
153
  UCHAR bLdMode;
154
  UCHAR bTimeDomainDmx;
155
  UINT sampleRate;
156
  UINT frameTimeSlots;     /* e.g. 32 when used with HE-AAC */
157
  UINT independencyFactor; /* how often should we set the independency flag */
158
  INT timeAlignment;       /* additional delay for downmix */
159
160
} MP4SPACEENC_SETUP, *HANDLE_MP4SPACEENC_SETUP;
161
162
struct ENC_CONFIG_SETUP {
163
  UCHAR bEncMode_212;
164
  UCHAR maxHybridInStaticSlots;
165
  LONG maxSamplingrate;
166
  INT maxAnalysisLengthTimeSlots;
167
  INT maxHybridBands;
168
  INT maxQmfBands;
169
  INT maxChIn;
170
  INT maxFrameTimeSlots;
171
  INT maxFrameLength;
172
  INT maxChOut;
173
  INT maxChTotOut;
174
};
175
176
struct MP4SPACE_ENCODER {
177
  MP4SPACEENC_SETUP user;
178
179
  ENC_CONFIG_SETUP setup; /* describe allocated instance */
180
181
  HANDLE_FRAMEWINDOW
182
  hFrameWindow;      /* Windowing, only created+updated, but not used */
183
  INT nSamplesValid; /* Input Buffer Handling */
184
185
  /* Routing Sensible Switches/Variables */
186
  MP4SPACEENC_BANDS_CONFIG nParamBands;
187
  UCHAR useTimeDomDownmix;
188
189
  /* not Routing Sensible Switches/Varibles - must be contained in Check */
190
  MP4SPACEENC_MODE encMode;
191
  UCHAR bEncMode_212_only;
192
193
  /* not Routing Sensible Switches/Varibles + lower Classes */
194
  UCHAR useFrameKeep;
195
  UINT independencyFactor;
196
  UINT nSampleRate;
197
  UCHAR nInputChannels;
198
  UCHAR nOutputChannels;
199
  UCHAR nFrameTimeSlots; /* e.g. 32 when used with HE-AAC */
200
  UCHAR nQmfBands;
201
  UCHAR nHybridBands;
202
  UINT nFrameLength; /* number of output waveform samples/channel/frame */
203
204
  /* not Routing Sensible Switches/Varibles + lower Classes, secondary computed
205
   */
206
  INT nSamplesNext;
207
  INT nAnalysisLengthTimeSlots;
208
  INT nAnalysisLookaheadTimeSlots;
209
  INT nUpdateHybridPositionTimeSlots;
210
  INT *pnOutputBits;
211
  INT nInputDelay;
212
  INT nOutputBufferDelay;
213
  INT nSurroundAnalysisBufferDelay;
214
  INT nBitstreamDelayBuffer;
215
  INT nBitstreamBufferRead;
216
  INT nBitstreamBufferWrite;
217
  INT nDiscardOutFrames;
218
  INT avoid_keep;
219
220
  /* not Routing Sensible Switches/Varibles -> moved to lower Classes */
221
  UCHAR useCoarseQuantCld;    /* Only Used in SpaceTreeSetup */
222
  UCHAR useCoarseQuantIcc;    /* Only Used in SpaceTreeSetup */
223
  UCHAR useCoarseQuantCpc;    /* Only Used in SpaceTreeSetup */
224
  UCHAR useCoarseQuantArbDmx; /* ArbitraryDmx,... not available yet */
225
  MP4SPACEENC_QUANTMODE
226
  quantMode;          /* Used for quanitzation and in bitstream writer */
227
  INT coreCoderDelay; /* Used in delay compensation */
228
  INT timeAlignment;  /* Used in delay compensation */
229
230
  /* Local Processing Variables */
231
  INT independencyCount;
232
  INT independencyFlag;
233
  INT **ppTrCurrPos;                /* belongs somehow to Onset Detection */
234
  INT trPrevPos[2 * MAX_NUM_TRANS]; /* belongs somehow to Onset Detection */
235
236
  FRAMEWIN_LIST frameWinList;
237
  SPATIALFRAME saveFrame;
238
239
  /* Module-Handles */
240
  SPACE_TREE_SETUP spaceTreeSetup;
241
  MPEG4SPACEENC_SSCBUF sscBuf;
242
  FIXP_WIN *pFrameWindowAna__FDK[MAX_NUM_PARAMS];
243
  HANDLE_QMF_FILTER_BANK *phQmfFiltIn__FDK;
244
  HANDLE_DC_FILTER phDCFilterSigIn[SACENC_MAX_INPUT_CHANNELS];
245
  HANDLE_ONSET_DETECT phOnset[SACENC_MAX_INPUT_CHANNELS];
246
  HANDLE_SPACE_TREE hSpaceTree;
247
  HANDLE_BSF_INSTANCE hBitstreamFormatter;
248
  HANDLE_STATIC_GAIN_CONFIG hStaticGainConfig;
249
  HANDLE_STATIC_GAIN hStaticGain;
250
  HANDLE_DELAY hDelay;
251
252
  /* enhanced time domain downmix (for stereo input) */
253
  HANDLE_ENHANCED_TIME_DOMAIN_DMX hEnhancedTimeDmx;
254
255
  /* Data Buffers */
256
  INT_PCM **ppTimeSigIn__FDK;
257
  INT_PCM **ppTimeSigDelayIn__FDK;
258
  INT_PCM **ppTimeSigOut__FDK;
259
  FIXP_DPK ***pppHybridIn__FDK;
260
  FIXP_DPK ***pppHybridInStatic__FDK;
261
  FIXP_DPK ***pppProcDataIn__FDK;
262
  INT_PCM *pOutputDelayBuffer__FDK;
263
264
  UCHAR **ppBitstreamDelayBuffer;
265
266
  UCHAR *pParameterBand2HybridBandOffset;
267
  INT staticGainScale;
268
269
  INT *pEncoderInputChScale;
270
  INT *staticTimeDomainDmxInScale;
271
};
272
273
/* Constants *****************************************************************/
274
static const UCHAR pValidBands_Ld[8] = {4, 5, 7, 9, 12, 15, 23, 40};
275
276
static const UCHAR qmf2qmf[] = /* Bypass the HybridAnylyis/Synthesis*/
277
    {0,   1,   2,   3,   4,   5,   6,   7,   8,   9,   10,  11,  12,  13,  14,
278
     15,  16,  17,  18,  19,  20,  21,  22,  23,  24,  25,  26,  27,  28,  29,
279
     30,  31,  32,  33,  34,  35,  36,  37,  38,  39,  40,  41,  42,  43,  44,
280
     45,  46,  47,  48,  49,  50,  51,  52,  53,  54,  55,  56,  57,  58,  59,
281
     60,  61,  62,  63,  64,  65,  66,  67,  68,  69,  70,  71,  72,  73,  74,
282
     75,  76,  77,  78,  79,  80,  81,  82,  83,  84,  85,  86,  87,  88,  89,
283
     90,  91,  92,  93,  94,  95,  96,  97,  98,  99,  100, 101, 102, 103, 104,
284
     105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119,
285
     120, 121, 122, 123, 124, 125, 126, 127};
286
287
/* Function / Class Declarations *********************************************/
288
static FDK_SACENC_ERROR mp4SpaceEnc_create(
289
    HANDLE_MP4SPACE_ENCODER *phMp4SpaceEnc);
290
291
static FDK_SACENC_ERROR FillSpatialSpecificConfig(
292
    const HANDLE_MP4SPACE_ENCODER hEnc, SPATIALSPECIFICCONFIG *const hSsc);
293
294
static FDK_SACENC_ERROR mp4SpaceEnc_FillSpaceTreeSetup(
295
    const HANDLE_MP4SPACE_ENCODER hEnc,
296
    SPACE_TREE_SETUP *const hSpaceTreeSetup);
297
298
static FDK_SACENC_ERROR mp4SpaceEnc_InitDelayCompensation(
299
    HANDLE_MP4SPACE_ENCODER hMp4SpaceEnc, const INT coreCoderDelay);
300
301
static FDK_SACENC_ERROR mp4SpaceEnc_InitDefault(
302
    HANDLE_MP4SPACE_ENCODER hMp4SpaceEnc);
303
304
static DECORRCONFIG mp4SpaceEnc_GetDecorrConfig(const MP4SPACEENC_MODE encMode);
305
306
static FDK_SACENC_ERROR mp4SpaceEnc_InitNumParamBands(
307
    HANDLE_MP4SPACE_ENCODER hEnc, const MP4SPACEENC_BANDS_CONFIG nParamBands);
308
309
/* Function / Class Definition ***********************************************/
310
0
static UINT mp4SpaceEnc_GetNumQmfBands(const UINT nSampleRate) {
311
0
  UINT nQmfBands = 0;
312
313
0
  if (nSampleRate < 27713)
314
0
    nQmfBands = 32;
315
0
  else if (nSampleRate < 55426)
316
0
    nQmfBands = 64;
317
318
0
  return nQmfBands;
319
0
}
320
321
0
static UINT updateQmfFlags(const UINT flags, const INT keepStates) {
322
0
  UINT qmfFlags = flags;
323
324
0
  qmfFlags = (qmfFlags & (~(UINT)QMF_FLAG_LP));
325
0
  qmfFlags = (qmfFlags | QMF_FLAG_MPSLDFB);
326
0
  qmfFlags = (keepStates) ? (qmfFlags | QMF_FLAG_KEEP_STATES)
327
0
                          : (qmfFlags & (~(UINT)QMF_FLAG_KEEP_STATES));
328
329
0
  return qmfFlags;
330
0
}
331
332
static INT freq2HybridBand(const UINT nFrequency, const UINT nSampleRate,
333
0
                           const UINT nQmfBands) {
334
  /*
335
    nQmfSlotWidth = (nSampleRate/2) / nQmfBands;
336
    nQmfBand      = nFrequency / nQmfSlotWidth;
337
  */
338
0
  int nHybridBand = -1;
339
0
  int scale = 0;
340
0
  const FIXP_DBL temp = fDivNorm((FIXP_DBL)(2 * nFrequency * nQmfBands),
341
0
                                 (FIXP_DBL)nSampleRate, &scale);
342
0
  const int nQmfBand = scaleValue(temp, scale - (DFRACT_BITS - 1));
343
344
0
  if ((nQmfBand > -1) && (nQmfBand < (int)nQmfBands)) {
345
0
    nHybridBand = qmf2qmf[nQmfBand];
346
0
  }
347
348
0
  return nHybridBand;
349
0
}
350
351
/*
352
 * Examine buffer descriptor regarding choosen type.
353
 *
354
 * \param pBufDesc              Pointer to buffer descriptor
355
 * \param type                  Buffer type to look for.
356
357
 * \return - Buffer descriptor index.
358
 *         -1, if there is no entry available.
359
 */
360
0
static INT getBufDescIdx(const FDK_bufDescr *pBufDesc, const UINT type) {
361
0
  INT i, idx = -1;
362
363
0
  for (i = 0; i < (int)pBufDesc->numBufs; i++) {
364
0
    if (pBufDesc->pBufType[i] == type) {
365
0
      idx = i;
366
0
      break;
367
0
    }
368
0
  }
369
0
  return idx;
370
0
}
371
372
0
FDK_SACENC_ERROR FDK_sacenc_open(HANDLE_MP4SPACE_ENCODER *phMp4SpaceEnc) {
373
0
  return mp4SpaceEnc_create(phMp4SpaceEnc);
374
0
}
375
376
static FDK_SACENC_ERROR mp4SpaceEnc_create(
377
0
    HANDLE_MP4SPACE_ENCODER *phMp4SpaceEnc) {
378
0
  FDK_SACENC_ERROR error = SACENC_OK;
379
0
  HANDLE_MP4SPACE_ENCODER hEnc = NULL;
380
0
  ENC_CONFIG_SETUP setup;
381
382
0
  if (NULL == phMp4SpaceEnc) {
383
0
    error = SACENC_INVALID_HANDLE;
384
0
  } else {
385
0
    int i, ch;
386
0
    FDKmemclear(&setup, sizeof(ENC_CONFIG_SETUP));
387
388
    /* Allocate Encoder Instance */
389
0
    FDK_ALLOCATE_MEMORY_1D(hEnc, 1, struct MP4SPACE_ENCODER);
390
391
    /* Clear everything, also pointers. */
392
0
    if (NULL != hEnc) {
393
0
      FDKmemclear(hEnc, sizeof(struct MP4SPACE_ENCODER));
394
0
    }
395
396
0
    setup.maxSamplingrate = 48000;
397
0
    setup.maxFrameTimeSlots = 16;
398
399
0
    setup.maxAnalysisLengthTimeSlots = 3 * setup.maxFrameTimeSlots;
400
0
    setup.maxQmfBands = mp4SpaceEnc_GetNumQmfBands(setup.maxSamplingrate);
401
0
    ;
402
0
    setup.maxHybridBands = setup.maxQmfBands;
403
0
    setup.maxFrameLength = setup.maxQmfBands * setup.maxFrameTimeSlots;
404
405
0
    setup.maxChIn = 2;
406
0
    setup.maxChOut = 1;
407
0
    setup.maxChTotOut = setup.maxChOut;
408
0
    setup.bEncMode_212 = 1;
409
0
    setup.maxHybridInStaticSlots = 24;
410
411
    /* Open Static Gain*/
412
0
    if (SACENC_OK !=
413
0
        (error = fdk_sacenc_staticGain_OpenConfig(&hEnc->hStaticGainConfig))) {
414
0
      goto bail;
415
0
    }
416
417
    /* enhanced time domain downmix (for stereo input) */
418
0
    if (SACENC_OK != (error = fdk_sacenc_open_enhancedTimeDomainDmx(
419
0
                          &hEnc->hEnhancedTimeDmx, setup.maxFrameLength))) {
420
0
      goto bail;
421
0
    }
422
423
0
    FDK_ALLOCATE_MEMORY_1D(hEnc->pParameterBand2HybridBandOffset,
424
0
                           MAX_NUM_PARAM_BANDS, UCHAR);
425
426
    /* Create Space Tree first, to get number of in-/output channels */
427
0
    if (SACENC_OK != (error = fdk_sacenc_spaceTree_Open(&hEnc->hSpaceTree))) {
428
0
      goto bail;
429
0
    }
430
431
0
    FDK_ALLOCATE_MEMORY_1D(hEnc->pEncoderInputChScale, setup.maxChIn, INT);
432
0
    FDK_ALLOCATE_MEMORY_1D(hEnc->staticTimeDomainDmxInScale, setup.maxChIn,
433
0
                           INT);
434
435
0
    FDK_ALLOCATE_MEMORY_1D(hEnc->phQmfFiltIn__FDK, setup.maxChIn,
436
0
                           HANDLE_QMF_FILTER_BANK);
437
438
    /* Allocate Analysis Filterbank Structs */
439
0
    for (ch = 0; ch < setup.maxChIn; ch++) {
440
0
      FDK_ALLOCATE_MEMORY_1D_INT(hEnc->phQmfFiltIn__FDK[ch], 1,
441
0
                                 struct QMF_FILTER_BANK, SECT_DATA_L2)
442
0
      FDK_ALLOCATE_MEMORY_1D_INT(hEnc->phQmfFiltIn__FDK[ch]->FilterStates,
443
0
                                 2 * 5 * setup.maxQmfBands, FIXP_QAS,
444
0
                                 SECT_DATA_L2)
445
0
    }
446
447
    /* Allocate Synthesis Filterbank Structs for arbitrary downmix */
448
449
    /* Allocate DC Filter Struct for normal signal input */
450
0
    for (ch = 0; ch < setup.maxChIn; ch++) {
451
0
      if (SACENC_OK !=
452
0
          (error = fdk_sacenc_createDCFilter(&hEnc->phDCFilterSigIn[ch]))) {
453
0
        goto bail;
454
0
      }
455
0
    }
456
457
    /* Open Onset Detection */
458
0
    for (ch = 0; ch < setup.maxChIn; ch++) {
459
0
      if (SACENC_OK != (error = fdk_sacenc_onsetDetect_Open(
460
0
                            &hEnc->phOnset[ch], setup.maxFrameTimeSlots))) {
461
0
        goto bail;
462
0
      }
463
0
    }
464
465
0
    FDK_ALLOCATE_MEMORY_2D(hEnc->ppTrCurrPos, setup.maxChIn, MAX_NUM_TRANS,
466
0
                           INT);
467
468
    /* Create Windowing */
469
0
    if (SACENC_OK !=
470
0
        (error = fdk_sacenc_frameWindow_Create(&hEnc->hFrameWindow))) {
471
0
      goto bail;
472
0
    }
473
474
    /* Open static gain */
475
0
    if (SACENC_OK != (error = fdk_sacenc_staticGain_Open(&hEnc->hStaticGain))) {
476
0
      goto bail;
477
0
    }
478
479
    /* create bitstream encoder */
480
0
    if (SACENC_OK != (error = fdk_sacenc_createSpatialBitstreamEncoder(
481
0
                          &hEnc->hBitstreamFormatter))) {
482
0
      goto bail;
483
0
    }
484
485
0
    FDK_ALLOCATE_MEMORY_1D(hEnc->sscBuf.pSsc, MAX_SSC_BYTES, UCHAR);
486
487
0
    {
488
0
      FDK_ALLOCATE_MEMORY_2D(hEnc->ppTimeSigIn__FDK, setup.maxChIn,
489
0
                             setup.maxFrameLength + MAX_DELAY_SURROUND_ANALYSIS,
490
0
                             INT_PCM);
491
0
    }
492
0
    FDK_ALLOCATE_MEMORY_2D(hEnc->ppTimeSigDelayIn__FDK, setup.maxChIn,
493
0
                           MAX_DELAY_SURROUND_ANALYSIS, INT_PCM);
494
495
    /* Create new buffers for several signals (including arbitrary downmix) */
496
0
    if (setup.bEncMode_212 == 0) {
497
      /* pOutputDelayBuffer__FDK buffer is not needed for SACENC_212 mode */
498
0
      FDK_ALLOCATE_MEMORY_1D(
499
0
          hEnc->pOutputDelayBuffer__FDK,
500
0
          (setup.maxFrameLength + MAX_DELAY_OUTPUT) * setup.maxChOut, INT_PCM);
501
0
    }
502
503
    /* allocate buffers */
504
0
    if (setup.bEncMode_212 == 0) {
505
      /* ppTimeSigOut__FDK buffer is not needed for SACENC_212 mode */
506
0
      FDK_ALLOCATE_MEMORY_2D(hEnc->ppTimeSigOut__FDK, setup.maxChTotOut,
507
0
                             setup.maxFrameLength, INT_PCM);
508
0
    }
509
510
0
    if (setup.bEncMode_212 == 1) {
511
      /* pppHybridIn__FDK buffer can be reduced by maxFrameTimeSlots/2 slots for
512
       * SACENC_212 mode */
513
0
      FDK_ALLOCATE_MEMORY_3D(
514
0
          hEnc->pppHybridIn__FDK, setup.maxChIn,
515
0
          setup.maxAnalysisLengthTimeSlots - (setup.maxFrameTimeSlots >> 1),
516
0
          setup.maxHybridBands, FIXP_DPK);
517
0
      FDK_ALLOCATE_MEMORY_3D(hEnc->pppHybridInStatic__FDK, setup.maxChIn,
518
0
                             setup.maxHybridInStaticSlots, setup.maxHybridBands,
519
0
                             FIXP_DPK);
520
0
    } else {
521
0
      FDK_ALLOCATE_MEMORY_3D(hEnc->pppHybridIn__FDK, setup.maxChIn,
522
0
                             setup.maxAnalysisLengthTimeSlots,
523
0
                             setup.maxHybridBands, FIXP_DPK);
524
0
    }
525
526
0
    if (setup.bEncMode_212 == 0) {
527
      /* pppProcDataIn__FDK buffer is not needed for SACENC_212 mode */
528
0
      FDK_ALLOCATE_MEMORY_3D(hEnc->pppProcDataIn__FDK, MAX_SPACE_TREE_CHANNELS,
529
0
                             setup.maxAnalysisLengthTimeSlots,
530
0
                             setup.maxHybridBands, FIXP_DPK);
531
0
    }
532
0
    for (i = 0; i < MAX_NUM_PARAMS; i++) {
533
0
      FDK_ALLOCATE_MEMORY_1D(hEnc->pFrameWindowAna__FDK[i],
534
0
                             setup.maxAnalysisLengthTimeSlots, FIXP_WIN);
535
0
    } /* for i */
536
537
0
    if (SACENC_OK != (error = fdk_sacenc_delay_Open(&hEnc->hDelay))) {
538
0
      goto bail;
539
0
    }
540
541
0
    if (setup.bEncMode_212 == 0) {
542
      /* ppBitstreamDelayBuffer buffer is not needed for SACENC_212 mode */
543
0
      FDK_ALLOCATE_MEMORY_2D(hEnc->ppBitstreamDelayBuffer, MAX_BITSTREAM_DELAY,
544
0
                             MAX_MPEGS_BYTES, UCHAR);
545
0
    }
546
0
    FDK_ALLOCATE_MEMORY_1D(hEnc->pnOutputBits, MAX_BITSTREAM_DELAY, INT);
547
548
0
    hEnc->setup = setup; /* save configuration used while encoder allocation. */
549
0
    mp4SpaceEnc_InitDefault(hEnc);
550
551
0
    if (NULL != phMp4SpaceEnc) {
552
0
      *phMp4SpaceEnc = hEnc; /* return encoder handle */
553
0
    }
554
555
0
  } /* valid handle */
556
557
0
  return error;
558
559
0
bail:
560
0
  if (NULL != hEnc) {
561
0
    hEnc->setup = setup;
562
0
    FDK_sacenc_close(&hEnc);
563
0
  }
564
0
  return ((SACENC_OK == error) ? SACENC_MEMORY_ERROR : error);
565
0
}
566
567
0
static FDK_SACENC_ERROR mp4SpaceEnc_InitDefault(HANDLE_MP4SPACE_ENCODER hEnc) {
568
0
  FDK_SACENC_ERROR err = SACENC_OK;
569
570
  /* Get default static gain configuration. */
571
0
  if (SACENC_OK != (err = fdk_sacenc_staticGain_InitDefaultConfig(
572
0
                        hEnc->hStaticGainConfig))) {
573
0
    goto bail;
574
0
  }
575
576
0
bail:
577
0
  return err;
578
0
}
579
580
static FDK_SACENC_ERROR FDK_sacenc_configure(
581
0
    HANDLE_MP4SPACE_ENCODER hEnc, const HANDLE_MP4SPACEENC_SETUP hSetup) {
582
0
  FDK_SACENC_ERROR error = SACENC_OK;
583
584
0
  hEnc->nSampleRate = hSetup->sampleRate;
585
0
  hEnc->encMode = hSetup->encMode;
586
0
  hEnc->nQmfBands = mp4SpaceEnc_GetNumQmfBands(hEnc->nSampleRate);
587
588
  /* Make sure that we have set time domain downmix for 212 */
589
0
  if (hSetup->encMode == SACENC_212 && hSetup->bTimeDomainDmx == 0) {
590
0
    error = SACENC_INVALID_CONFIG;
591
0
  } else {
592
0
    hEnc->useTimeDomDownmix = hSetup->bTimeDomainDmx;
593
0
  }
594
595
0
  hEnc->timeAlignment = hSetup->timeAlignment;
596
0
  hEnc->quantMode = hSetup->quantMode;
597
598
0
  hEnc->useCoarseQuantCld = hSetup->bUseCoarseQuant;
599
0
  hEnc->useCoarseQuantCpc = hSetup->bUseCoarseQuant;
600
0
  hEnc->useFrameKeep = (hSetup->bLdMode == 2);
601
0
  hEnc->useCoarseQuantIcc = 0;    /* not available */
602
0
  hEnc->useCoarseQuantArbDmx = 0; /* not available for user right now */
603
0
  hEnc->independencyFactor = hSetup->independencyFactor;
604
0
  hEnc->independencyCount = 0;
605
0
  hEnc->independencyFlag = 1;
606
607
  /* set number of Hybrid bands */
608
0
  hEnc->nHybridBands = hEnc->nQmfBands;
609
0
  hEnc->nFrameTimeSlots = hSetup->frameTimeSlots;
610
0
  mp4SpaceEnc_InitNumParamBands(hEnc, hSetup->nParamBands);
611
612
0
  return error;
613
0
}
614
615
FDK_SACENC_ERROR FDK_sacenc_init(HANDLE_MP4SPACE_ENCODER hEnc,
616
0
                                 const INT dmxDelay) {
617
0
  FDK_SACENC_ERROR error = SACENC_OK;
618
619
  /* Sanity Checks */
620
0
  if (NULL == hEnc) {
621
0
    error = SACENC_INVALID_HANDLE;
622
0
  } else {
623
0
    const int initStatesFlag = 1;
624
625
0
    int ch; /* loop counter */
626
0
    int nChInArbDmx;
627
628
0
    if (SACENC_OK != (error = FDK_sacenc_configure(hEnc, &hEnc->user))) {
629
0
      goto bail;
630
0
    }
631
632
0
    hEnc->bEncMode_212_only = hEnc->setup.bEncMode_212;
633
634
    /* Slots per Frame and Frame Length */
635
0
    if (hEnc->nFrameTimeSlots < 1) {
636
0
      error = SACENC_INVALID_CONFIG;
637
0
      goto bail;
638
0
    }
639
0
    hEnc->nFrameLength = hEnc->nQmfBands * hEnc->nFrameTimeSlots;
640
641
0
    if (hEnc->useFrameKeep == 1) {
642
0
      hEnc->nAnalysisLengthTimeSlots = 3 * hEnc->nFrameTimeSlots;
643
0
      hEnc->nUpdateHybridPositionTimeSlots = hEnc->nFrameTimeSlots;
644
0
    } else {
645
0
      hEnc->nAnalysisLengthTimeSlots = 2 * hEnc->nFrameTimeSlots;
646
0
      hEnc->nUpdateHybridPositionTimeSlots = 0;
647
0
    }
648
649
0
    {
650
0
      hEnc->nAnalysisLookaheadTimeSlots =
651
0
          hEnc->nAnalysisLengthTimeSlots - 3 * hEnc->nFrameTimeSlots / 2;
652
0
    }
653
654
    /* init parameterBand2hybridBandOffset table */
655
0
    fdk_sacenc_calcParameterBand2HybridBandOffset(
656
0
        (BOX_SUBBAND_CONFIG)hEnc->nParamBands, hEnc->nHybridBands,
657
0
        hEnc->pParameterBand2HybridBandOffset);
658
659
    /* Fill Setup structure for Space Tree */
660
0
    if (SACENC_OK !=
661
0
        (error = mp4SpaceEnc_FillSpaceTreeSetup(hEnc, &hEnc->spaceTreeSetup))) {
662
0
      goto bail;
663
0
    }
664
665
    /* Init space tree configuration */
666
0
    if (SACENC_OK !=
667
0
        (error = fdk_sacenc_spaceTree_Init(
668
0
             hEnc->hSpaceTree, &hEnc->spaceTreeSetup,
669
0
             hEnc->pParameterBand2HybridBandOffset, hEnc->useFrameKeep))) {
670
0
      goto bail;
671
0
    }
672
673
    /* Get space tree description and resulting number of input/output channels
674
     */
675
0
    {
676
0
      SPACE_TREE_DESCRIPTION spaceTreeDescription;
677
678
0
      if (SACENC_OK != (error = fdk_sacenc_spaceTree_GetDescription(
679
0
                            hEnc->hSpaceTree, &spaceTreeDescription))) {
680
0
        goto bail;
681
0
      }
682
683
0
      hEnc->nInputChannels =
684
0
          spaceTreeDescription.nOutChannels; /* space tree description
685
                                                describes decoder
686
                                                configuration */
687
0
      hEnc->nOutputChannels =
688
0
          spaceTreeDescription.nInChannels; /* space tree description
689
                                               describes decoder
690
                                               configuration */
691
0
    }
692
693
0
    nChInArbDmx = 0;
694
695
    /* INITIALIZATION */
696
0
    for (ch = 0; ch < hEnc->nInputChannels; ch++) {
697
      /* scaling in analysis qmf filterbank (7) */
698
0
      hEnc->pEncoderInputChScale[ch] = 7;
699
700
0
      {
701
        /* additional scaling in qmf prototype filter for low delay */
702
0
        hEnc->pEncoderInputChScale[ch] += 1;
703
0
      }
704
705
0
      { hEnc->pEncoderInputChScale[ch] += DC_FILTER_SF; }
706
0
    } /* nInputChannels */
707
708
    /* Init analysis filterbank */
709
0
    for (ch = 0; ch < hEnc->nInputChannels; ch++) {
710
0
      hEnc->phQmfFiltIn__FDK[ch]->flags =
711
0
          updateQmfFlags(hEnc->phQmfFiltIn__FDK[ch]->flags, !initStatesFlag);
712
713
0
      if (0 != qmfInitAnalysisFilterBank(
714
0
                   hEnc->phQmfFiltIn__FDK[ch],
715
0
                   (FIXP_QAS *)hEnc->phQmfFiltIn__FDK[ch]->FilterStates, 1,
716
0
                   hEnc->nQmfBands, hEnc->nQmfBands, hEnc->nQmfBands,
717
0
                   hEnc->phQmfFiltIn__FDK[ch]->flags)) {
718
0
        error = SACENC_INIT_ERROR;
719
0
        goto bail;
720
0
      }
721
0
    }
722
723
    /* Initialize DC Filter. */
724
0
    {
725
0
      for (ch = 0; ch < hEnc->nInputChannels; ch++) {
726
0
        if (SACENC_OK != (error = fdk_sacenc_initDCFilter(
727
0
                              hEnc->phDCFilterSigIn[ch], hEnc->nSampleRate))) {
728
0
          goto bail;
729
0
        }
730
0
      }
731
0
    }
732
733
    /* Init onset detect. */
734
0
    {
735
      /* init onset detect configuration struct */
736
0
      ONSET_DETECT_CONFIG onsetDetectConfig;
737
0
      onsetDetectConfig.maxTimeSlots = hEnc->nFrameTimeSlots;
738
0
      onsetDetectConfig.lowerBoundOnsetDetection =
739
0
          freq2HybridBand(1725, hEnc->nSampleRate, hEnc->nQmfBands);
740
0
      onsetDetectConfig.upperBoundOnsetDetection = hEnc->nHybridBands;
741
742
0
      for (ch = 0; ch < hEnc->nInputChannels; ch++) {
743
0
        if (SACENC_OK != (error = fdk_sacenc_onsetDetect_Init(
744
0
                              hEnc->phOnset[ch], &onsetDetectConfig, 1))) {
745
0
          goto bail;
746
0
        }
747
0
      }
748
0
    }
749
750
0
    {
751
      /* init windowing */
752
0
      FRAMEWINDOW_CONFIG framewindowConfig;
753
0
      framewindowConfig.nTimeSlotsMax = hEnc->nFrameTimeSlots;
754
0
      framewindowConfig.bFrameKeep = hEnc->useFrameKeep;
755
756
0
      if (SACENC_OK != (error = fdk_sacenc_frameWindow_Init(
757
0
                            hEnc->hFrameWindow, &framewindowConfig))) {
758
0
        goto bail;
759
0
      }
760
0
    }
761
762
    /* Set encoder mode for static gain initialization. */
763
0
    if (SACENC_OK != (error = fdk_sacenc_staticGain_SetEncMode(
764
0
                          hEnc->hStaticGainConfig, hEnc->encMode))) {
765
0
      goto bail;
766
0
    }
767
768
    /* Init static gain. */
769
0
    if (SACENC_OK != (error = fdk_sacenc_staticGain_Init(
770
0
                          hEnc->hStaticGain, hEnc->hStaticGainConfig,
771
0
                          &(hEnc->staticGainScale)))) {
772
0
      goto bail;
773
0
    }
774
775
0
    for (ch = 0; ch < hEnc->nInputChannels; ch++) {
776
0
      hEnc->pEncoderInputChScale[ch] += hEnc->staticGainScale;
777
0
    }
778
779
    /* enhanced downmix for stereo input*/
780
0
    if (hEnc->useTimeDomDownmix != 0) {
781
0
      if (SACENC_OK != (error = fdk_sacenc_init_enhancedTimeDomainDmx(
782
0
                            hEnc->hEnhancedTimeDmx,
783
0
                            fdk_sacenc_getPreGainPtrFDK(hEnc->hStaticGain),
784
0
                            hEnc->staticGainScale,
785
0
                            fdk_sacenc_getPostGainFDK(hEnc->hStaticGain),
786
0
                            hEnc->staticGainScale, hEnc->nFrameLength))) {
787
0
        goto bail;
788
0
      }
789
0
    }
790
791
    /* Create config structure for bitstream formatter including arbitrary
792
     * downmix residual */
793
0
    if (SACENC_OK != (error = fdk_sacenc_initSpatialBitstreamEncoder(
794
0
                          hEnc->hBitstreamFormatter))) {
795
0
      goto bail;
796
0
    }
797
798
0
    if (SACENC_OK != (error = FillSpatialSpecificConfig(
799
0
                          hEnc, fdk_sacenc_getSpatialSpecificConfig(
800
0
                                    hEnc->hBitstreamFormatter)))) {
801
0
      goto bail;
802
0
    }
803
804
0
    if (SACENC_OK !=
805
0
        (error = fdk_sacenc_writeSpatialSpecificConfig(
806
0
             fdk_sacenc_getSpatialSpecificConfig(hEnc->hBitstreamFormatter),
807
0
             hEnc->sscBuf.pSsc, MAX_SSC_BYTES, &hEnc->sscBuf.nSscSizeBits))) {
808
0
      goto bail;
809
0
    }
810
811
    /* init delay compensation with dmx core coder delay; if no core coder is
812
     * used, many other buffers are initialized nevertheless */
813
0
    if (SACENC_OK !=
814
0
        (error = mp4SpaceEnc_InitDelayCompensation(hEnc, dmxDelay))) {
815
0
      goto bail;
816
0
    }
817
818
    /* How much input do we need? */
819
0
    hEnc->nSamplesNext =
820
0
        hEnc->nFrameLength * (hEnc->nInputChannels + nChInArbDmx);
821
0
    hEnc->nSamplesValid = 0;
822
0
  } /* valid handle */
823
824
0
bail:
825
0
  return error;
826
0
}
827
828
static INT getAnalysisLengthTimeSlots(FIXP_WIN *pFrameWindowAna,
829
0
                                      INT nTimeSlots) {
830
0
  int i;
831
0
  for (i = nTimeSlots - 1; i >= 0; i--) {
832
0
    if (pFrameWindowAna[i] != (FIXP_WIN)0) {
833
0
      break;
834
0
    }
835
0
  }
836
0
  nTimeSlots = i + 1;
837
0
  return nTimeSlots;
838
0
}
839
840
0
static INT getAnalysisStartTimeSlot(FIXP_WIN *pFrameWindowAna, INT nTimeSlots) {
841
0
  int startTimeSlot = 0;
842
0
  int i;
843
0
  for (i = 0; i < nTimeSlots; i++) {
844
0
    if (pFrameWindowAna[i] != (FIXP_WIN)0) {
845
0
      break;
846
0
    }
847
0
  }
848
0
  startTimeSlot = i;
849
0
  return startTimeSlot;
850
0
}
851
852
static FDK_SACENC_ERROR __FeedDeinterPreScale(
853
    HANDLE_MP4SPACE_ENCODER hEnc, INT_PCM const *const pSamples,
854
    INT_PCM *const pOutputSamples, INT const nSamples,
855
    UINT const isInputInterleaved, UINT const inputBufferSizePerChannel,
856
0
    UINT *const pnSamplesFed) {
857
0
  FDK_SACENC_ERROR error = SACENC_OK;
858
859
0
  if ((hEnc == NULL) || (pSamples == NULL) || (pnSamplesFed == NULL)) {
860
0
    error = SACENC_INVALID_HANDLE;
861
0
  } else if (nSamples == 0) {
862
0
    error = SACENC_INVALID_CONFIG; /* Flushing not implemented */
863
0
  } else {
864
0
    int ch;
865
0
    const INT nChIn = hEnc->nInputChannels;
866
0
    const INT nChInWithDmx = nChIn;
867
0
    const INT samplesToFeed =
868
0
        FDKmin(nSamples, hEnc->nSamplesNext - hEnc->nSamplesValid);
869
0
    const INT nSamplesPerChannel = samplesToFeed / nChInWithDmx;
870
871
0
    if ((samplesToFeed < 0) || (samplesToFeed % nChInWithDmx != 0) ||
872
0
        (samplesToFeed > nChInWithDmx * (INT)hEnc->nFrameLength)) {
873
0
      error = SACENC_INVALID_CONFIG;
874
0
      goto bail;
875
0
    }
876
0
    int i;
877
878
0
    const INT_PCM *pInput__FDK;
879
0
    const INT_PCM *pInput2__FDK;
880
881
0
    { /* no dmx align = default*/
882
0
      pInput__FDK = pSamples;
883
0
      pInput2__FDK = pSamples + (hEnc->nInputDelay * nChInWithDmx);
884
0
    }
885
886
0
    for (i = 0; i < hEnc->nInputChannels; i++) {
887
0
      hEnc->staticTimeDomainDmxInScale[i] = hEnc->staticGainScale;
888
0
    }
889
890
    /*****        N-channel-input     *****/
891
0
    for (ch = 0; ch < nChIn; ch++) {
892
      /* Write delayed time signal into time signal buffer */
893
0
      FDKmemcpy(&(hEnc->ppTimeSigIn__FDK[ch][0]),
894
0
                &(hEnc->ppTimeSigDelayIn__FDK[ch][0]),
895
0
                hEnc->nSurroundAnalysisBufferDelay * sizeof(INT_PCM));
896
897
0
      if (isInputInterleaved) {
898
        /* Add the new frame de-interleaved. Apply nSurroundAnalysisBufferDelay.
899
         */
900
0
        FDKmemcpy_flex(
901
0
            &(hEnc->ppTimeSigIn__FDK[ch][hEnc->nSurroundAnalysisBufferDelay]),
902
0
            1, pInput__FDK + ch, nChInWithDmx, hEnc->nInputDelay);
903
0
        FDKmemcpy_flex(
904
0
            &(hEnc->ppTimeSigIn__FDK[ch][hEnc->nSurroundAnalysisBufferDelay +
905
0
                                         hEnc->nInputDelay]),
906
0
            1, pInput2__FDK + ch, nChInWithDmx,
907
0
            nSamplesPerChannel - hEnc->nInputDelay);
908
0
      } else {
909
        /* Input is already deinterleaved, just copy */
910
0
        FDKmemcpy(
911
0
            &(hEnc->ppTimeSigIn__FDK[ch][hEnc->nSurroundAnalysisBufferDelay]),
912
0
            pInput__FDK + ch * inputBufferSizePerChannel,
913
0
            hEnc->nInputDelay * sizeof(INT_PCM));
914
0
        FDKmemcpy(
915
0
            &(hEnc->ppTimeSigIn__FDK[ch][hEnc->nSurroundAnalysisBufferDelay +
916
0
                                         hEnc->nInputDelay]),
917
0
            pInput2__FDK + ch * inputBufferSizePerChannel,
918
0
            (nSamplesPerChannel - hEnc->nInputDelay) * sizeof(INT_PCM));
919
0
      }
920
921
      /* Update time signal delay buffer */
922
0
      FDKmemcpy(&(hEnc->ppTimeSigDelayIn__FDK[ch][0]),
923
0
                &(hEnc->ppTimeSigIn__FDK[ch][hEnc->nFrameLength]),
924
0
                hEnc->nSurroundAnalysisBufferDelay * sizeof(INT_PCM));
925
0
    } /* for ch */
926
927
    /*****      No Arbitrary Downmix      *****/
928
    /* "Crude TD Dmx": Time DomainDownmix + NO Arbitrary Downmix, Delay Added at
929
     * pOutputBuffer */
930
0
    if ((hEnc->useTimeDomDownmix > 0)) {
931
0
      if ((hEnc->useTimeDomDownmix == 1) || (hEnc->nInputChannels != 2)) {
932
0
        error = SACENC_INVALID_CONFIG;
933
0
        goto bail;
934
0
      } else {
935
        /* enhanced time domain downmix (for stereo input) */
936
0
        if (hEnc->encMode == SACENC_212) {
937
0
          if (pOutputSamples == NULL) {
938
0
            error = SACENC_INVALID_HANDLE;
939
0
            goto bail;
940
0
          }
941
942
0
          fdk_sacenc_apply_enhancedTimeDomainDmx(
943
0
              hEnc->hEnhancedTimeDmx, hEnc->ppTimeSigIn__FDK, pOutputSamples,
944
0
              hEnc->nSurroundAnalysisBufferDelay);
945
0
        } else {
946
0
          if (&hEnc->ppTimeSigOut__FDK[0][0] == NULL) {
947
0
            error = SACENC_INVALID_HANDLE;
948
0
            goto bail;
949
0
          }
950
951
0
          fdk_sacenc_apply_enhancedTimeDomainDmx(
952
0
              hEnc->hEnhancedTimeDmx, hEnc->ppTimeSigIn__FDK,
953
0
              &hEnc->ppTimeSigOut__FDK[0][0],
954
0
              hEnc->nSurroundAnalysisBufferDelay);
955
0
        }
956
0
      }
957
0
    }
958
959
    /* update number of samples still to process */
960
0
    hEnc->nSamplesValid += samplesToFeed;
961
962
    /*return number of fed samples */
963
0
    *pnSamplesFed = samplesToFeed;
964
0
  }
965
0
bail:
966
0
  return error;
967
0
}
968
969
FDK_SACENC_ERROR FDK_sacenc_encode(const HANDLE_MP4SPACE_ENCODER hMp4SpaceEnc,
970
                                   const FDK_bufDescr *inBufDesc,
971
                                   const FDK_bufDescr *outBufDesc,
972
                                   const SACENC_InArgs *inargs,
973
0
                                   SACENC_OutArgs *outargs) {
974
0
  FDK_SACENC_ERROR error = SACENC_OK;
975
976
0
  const INT_PCM *pInputSamples =
977
0
      (const INT_PCM *)inBufDesc->ppBase[getBufDescIdx(
978
0
          inBufDesc, (FDK_BUF_TYPE_INPUT | FDK_BUF_TYPE_PCM_DATA))];
979
980
0
  INT_PCM *const pOutputSamples = (INT_PCM *)outBufDesc->ppBase[getBufDescIdx(
981
0
      outBufDesc, (FDK_BUF_TYPE_OUTPUT | FDK_BUF_TYPE_PCM_DATA))];
982
983
0
  const int nOutputSamplesBufferSize =
984
0
      outBufDesc->pBufSize[getBufDescIdx(
985
0
          outBufDesc, (FDK_BUF_TYPE_OUTPUT | FDK_BUF_TYPE_PCM_DATA))] /
986
0
      outBufDesc->pEleSize[getBufDescIdx(
987
0
          outBufDesc, (FDK_BUF_TYPE_OUTPUT | FDK_BUF_TYPE_PCM_DATA))];
988
989
0
  if ((hMp4SpaceEnc == NULL) || (pInputSamples == NULL)) {
990
0
    error = SACENC_INVALID_HANDLE;
991
0
  } else {
992
0
    int nOutputSamples;
993
0
    int i, ch, ps, winCnt, ts, slot;
994
0
    INT currTransPos = -1;
995
0
    SPATIALFRAME *pFrameData = NULL;
996
997
    /* Improve Code Readability */
998
0
    const int nChIn = hMp4SpaceEnc->nInputChannels;
999
0
    const int nChInWithDmx = nChIn;
1000
0
    const int nChOut = hMp4SpaceEnc->nOutputChannels;
1001
0
    const int nSamplesPerChannel = inargs->nInputSamples / nChInWithDmx;
1002
0
    const int nOutputSamplesMax = nSamplesPerChannel * nChOut;
1003
0
    const int nFrameTimeSlots = hMp4SpaceEnc->nFrameTimeSlots;
1004
1005
0
    INT encoderInputChScale[SACENC_MAX_INPUT_CHANNELS];
1006
0
    INT nFrameTimeSlotsReduction = 0;
1007
1008
0
    if (hMp4SpaceEnc->encMode == SACENC_212) {
1009
0
      nFrameTimeSlotsReduction = hMp4SpaceEnc->nFrameTimeSlots >> 1;
1010
0
    }
1011
1012
0
    for (i = 0; i < nChIn; i++)
1013
0
      encoderInputChScale[i] = hMp4SpaceEnc->pEncoderInputChScale[i];
1014
1015
    /* Sanity Check */
1016
0
    if ((0 != inargs->nInputSamples % nChInWithDmx)) {
1017
0
      error = SACENC_INVALID_CONFIG;
1018
0
      goto bail;
1019
0
    }
1020
1021
    /*
1022
     * Get Frame Data Handle.
1023
     */
1024
1025
    /* get bitstream handle (for storage of cld's, icc's and so on)
1026
     * get spatialframe 2 frames in the future; NOTE: this is necessary to
1027
     * synchronise spatial data and audio data */
1028
0
    if (NULL == (pFrameData = fdk_sacenc_getSpatialFrame(
1029
0
                     hMp4SpaceEnc->hBitstreamFormatter, WRITE_SPATIALFRAME))) {
1030
0
      error = SACENC_INVALID_HANDLE;
1031
0
      goto bail;
1032
0
    }
1033
1034
    /* Independent Frames Counters*/
1035
0
    if (hMp4SpaceEnc->nDiscardOutFrames >
1036
0
        0) { /* Independent Frames if they should be discarded, Reset Counter*/
1037
0
      hMp4SpaceEnc->independencyCount =
1038
0
          0; /* Reset the counter, first valid frame is an independent one*/
1039
0
      hMp4SpaceEnc->independencyFlag = 1;
1040
0
    } else { /*hMp4SpaceEnc->nDiscardOutFrames == 0*/
1041
0
      hMp4SpaceEnc->independencyFlag =
1042
0
          (hMp4SpaceEnc->independencyCount == 0) ? 1 : 0;
1043
0
      if (hMp4SpaceEnc->independencyFactor > 0) {
1044
0
        hMp4SpaceEnc->independencyCount++;
1045
0
        hMp4SpaceEnc->independencyCount =
1046
0
            hMp4SpaceEnc->independencyCount %
1047
0
            ((int)hMp4SpaceEnc->independencyFactor);
1048
0
      } else { /* independencyFactor == 0 */
1049
0
        hMp4SpaceEnc->independencyCount = -1;
1050
0
      }
1051
0
    }
1052
1053
    /*
1054
     * Time signal preprocessing:
1055
     * - Feed input buffer
1056
     * - Prescale time signal
1057
     * - Apply DC filter on input signal
1058
     */
1059
1060
    /* Feed, Deinterleave, Pre-Scale the input time signals */
1061
0
    if (SACENC_OK !=
1062
0
        (error = __FeedDeinterPreScale(
1063
0
             hMp4SpaceEnc, pInputSamples, pOutputSamples, inargs->nInputSamples,
1064
0
             inargs->isInputInterleaved, inargs->inputBufferSizePerChannel,
1065
0
             &outargs->nSamplesConsumed))) {
1066
0
      goto bail;
1067
0
    }
1068
1069
0
    if (hMp4SpaceEnc->nSamplesNext != hMp4SpaceEnc->nSamplesValid) {
1070
0
      error = SACENC_INVALID_CONFIG;
1071
0
      goto bail;
1072
0
    }
1073
1074
0
    if (hMp4SpaceEnc->encMode == SACENC_212 &&
1075
0
        hMp4SpaceEnc->bEncMode_212_only) {
1076
0
      for (ch = 0; ch < nChIn; ch++) {
1077
0
        for (slot = 0; slot < nFrameTimeSlots; slot++) {
1078
0
          setCplxVec(
1079
0
              hMp4SpaceEnc->pppHybridIn__FDK
1080
0
                  [ch][hMp4SpaceEnc->nUpdateHybridPositionTimeSlots +
1081
0
                       nFrameTimeSlots - nFrameTimeSlotsReduction + slot],
1082
0
              (FIXP_DBL)0, hMp4SpaceEnc->nHybridBands);
1083
0
        }
1084
0
      }
1085
0
    }
1086
1087
    /*
1088
     * Time / Frequency:
1089
     * - T/F audio input channels
1090
     * - T/F arbitrary downmix input channels
1091
     */
1092
0
    for (ch = 0; ch < nChIn; ch++) {
1093
0
      C_AALLOC_SCRATCH_START(pQmfInReal, FIXP_DBL, MAX_QMF_BANDS)
1094
0
      C_AALLOC_SCRATCH_START(pQmfInImag, FIXP_DBL, MAX_QMF_BANDS)
1095
0
      FIXP_GAIN *pPreGain =
1096
0
          fdk_sacenc_getPreGainPtrFDK(hMp4SpaceEnc->hStaticGain);
1097
1098
0
      for (ts = 0; ts < nFrameTimeSlots; ts++) {
1099
0
        FIXP_DBL *pSpecReal;
1100
0
        FIXP_DBL *pSpecImag;
1101
1102
0
        INT_PCM *pTimeIn =
1103
0
            &hMp4SpaceEnc->ppTimeSigIn__FDK[ch][(ts * hMp4SpaceEnc->nQmfBands)];
1104
1105
0
        {
1106
          /* Apply DC filter on input channels */
1107
0
          if (SACENC_OK != (error = fdk_sacenc_applyDCFilter(
1108
0
                                hMp4SpaceEnc->phDCFilterSigIn[ch], pTimeIn,
1109
0
                                pTimeIn, hMp4SpaceEnc->nQmfBands))) {
1110
0
            goto bail;
1111
0
          }
1112
0
        }
1113
1114
        /* QMF filterbank */
1115
0
        C_ALLOC_SCRATCH_START(pWorkBuffer, FIXP_DBL, (MAX_QMF_BANDS << 1));
1116
1117
0
        qmfAnalysisFilteringSlot(hMp4SpaceEnc->phQmfFiltIn__FDK[ch], pQmfInReal,
1118
0
                                 pQmfInImag, pTimeIn, 1, pWorkBuffer);
1119
1120
0
        C_ALLOC_SCRATCH_END(pWorkBuffer, FIXP_DBL, (MAX_QMF_BANDS << 1));
1121
1122
0
        pSpecReal = pQmfInReal;
1123
0
        pSpecImag = pQmfInImag;
1124
1125
        /* Apply pre-scale after filterbank */
1126
0
        if (MAXVAL_GAIN != pPreGain[ch]) {
1127
0
          for (i = 0; i < hMp4SpaceEnc->nHybridBands; i++) {
1128
0
            hMp4SpaceEnc
1129
0
                ->pppHybridIn__FDK[ch]
1130
0
                                  [hMp4SpaceEnc->nAnalysisLookaheadTimeSlots +
1131
0
                                   ts][i]
1132
0
                .v.re = fMult(pSpecReal[i], pPreGain[ch]);
1133
0
            hMp4SpaceEnc
1134
0
                ->pppHybridIn__FDK[ch]
1135
0
                                  [hMp4SpaceEnc->nAnalysisLookaheadTimeSlots +
1136
0
                                   ts][i]
1137
0
                .v.im = fMult(pSpecImag[i], pPreGain[ch]);
1138
0
          }
1139
0
        } else {
1140
0
          for (i = 0; i < hMp4SpaceEnc->nHybridBands; i++) {
1141
0
            hMp4SpaceEnc
1142
0
                ->pppHybridIn__FDK[ch]
1143
0
                                  [hMp4SpaceEnc->nAnalysisLookaheadTimeSlots +
1144
0
                                   ts][i]
1145
0
                .v.re = pSpecReal[i];
1146
0
            hMp4SpaceEnc
1147
0
                ->pppHybridIn__FDK[ch]
1148
0
                                  [hMp4SpaceEnc->nAnalysisLookaheadTimeSlots +
1149
0
                                   ts][i]
1150
0
                .v.im = pSpecImag[i];
1151
0
          }
1152
0
        }
1153
0
      } /* ts */
1154
0
      C_AALLOC_SCRATCH_END(pQmfInImag, FIXP_DBL, MAX_QMF_BANDS)
1155
0
      C_AALLOC_SCRATCH_END(pQmfInReal, FIXP_DBL, MAX_QMF_BANDS)
1156
1157
0
      if (SACENC_OK != error) {
1158
0
        goto bail;
1159
0
      }
1160
0
    } /* ch */
1161
1162
0
    if (hMp4SpaceEnc->encMode == SACENC_212 &&
1163
0
        hMp4SpaceEnc->bEncMode_212_only) {
1164
0
      for (ch = 0; ch < nChIn; ch++) {
1165
0
        for (slot = 0;
1166
0
             slot < (int)(hMp4SpaceEnc->nUpdateHybridPositionTimeSlots +
1167
0
                          nFrameTimeSlots - nFrameTimeSlotsReduction);
1168
0
             slot++) {
1169
0
          copyCplxVec(hMp4SpaceEnc->pppHybridIn__FDK[ch][slot],
1170
0
                      hMp4SpaceEnc->pppHybridInStatic__FDK[ch][slot],
1171
0
                      hMp4SpaceEnc->nHybridBands);
1172
0
        }
1173
0
      }
1174
0
      for (ch = 0; ch < nChIn; ch++) {
1175
0
        for (slot = 0;
1176
0
             slot < (int)(hMp4SpaceEnc->nUpdateHybridPositionTimeSlots +
1177
0
                          nFrameTimeSlots - nFrameTimeSlotsReduction);
1178
0
             slot++) {
1179
0
          copyCplxVec(
1180
0
              hMp4SpaceEnc->pppHybridInStatic__FDK[ch][slot],
1181
0
              hMp4SpaceEnc->pppHybridIn__FDK[ch][nFrameTimeSlots + slot],
1182
0
              hMp4SpaceEnc->nHybridBands);
1183
0
        }
1184
0
      }
1185
0
    }
1186
1187
    /*
1188
     * Onset Detection:
1189
     * - detection of transients
1190
     * - build framing
1191
     */
1192
0
    for (ch = 0; ch < nChIn; ch++) {
1193
0
      if (ch != 3) { /* !LFE */
1194
0
        if (SACENC_OK !=
1195
0
            (error = fdk_sacenc_onsetDetect_Apply(
1196
0
                 hMp4SpaceEnc->phOnset[ch], nFrameTimeSlots,
1197
0
                 hMp4SpaceEnc->nHybridBands,
1198
0
                 &hMp4SpaceEnc->pppHybridIn__FDK
1199
0
                      [ch][hMp4SpaceEnc->nAnalysisLookaheadTimeSlots],
1200
0
                 encoderInputChScale[ch],
1201
0
                 hMp4SpaceEnc->trPrevPos[1], /* contains previous Transient */
1202
0
                 hMp4SpaceEnc->ppTrCurrPos[ch]))) {
1203
0
          goto bail;
1204
0
        }
1205
1206
0
        if ((1) && (hMp4SpaceEnc->useFrameKeep == 0)) {
1207
0
          hMp4SpaceEnc->ppTrCurrPos[ch][0] = -1;
1208
0
        }
1209
1210
        /* Find first Transient Position */
1211
0
        if ((hMp4SpaceEnc->ppTrCurrPos[ch][0] >= 0) &&
1212
0
            ((currTransPos < 0) ||
1213
0
             (hMp4SpaceEnc->ppTrCurrPos[ch][0] < currTransPos))) {
1214
0
          currTransPos = hMp4SpaceEnc->ppTrCurrPos[ch][0];
1215
0
        }
1216
0
      } /* !LFE */
1217
0
    }   /* ch */
1218
1219
0
    if (hMp4SpaceEnc->useFrameKeep == 1) {
1220
0
      if ((currTransPos != -1) || (hMp4SpaceEnc->independencyFlag == 1)) {
1221
0
        hMp4SpaceEnc->avoid_keep = NUM_KEEP_WINDOWS;
1222
0
        currTransPos = -1;
1223
0
      }
1224
0
    }
1225
1226
    /* Save previous Transient Position */
1227
0
    hMp4SpaceEnc->trPrevPos[0] =
1228
0
        FDKmax(-1, hMp4SpaceEnc->trPrevPos[1] - (INT)nFrameTimeSlots);
1229
0
    hMp4SpaceEnc->trPrevPos[1] = currTransPos;
1230
1231
    /* Update Onset Detection Energy Buffer */
1232
0
    for (ch = 0; ch < nChIn; ch++) {
1233
0
      if (SACENC_OK != (error = fdk_sacenc_onsetDetect_Update(
1234
0
                            hMp4SpaceEnc->phOnset[ch], nFrameTimeSlots))) {
1235
0
        goto bail;
1236
0
      }
1237
0
    }
1238
1239
    /* Framing */
1240
0
    if (SACENC_OK !=
1241
0
        (error = fdk_sacenc_frameWindow_GetWindow(
1242
0
             hMp4SpaceEnc->hFrameWindow, hMp4SpaceEnc->trPrevPos,
1243
0
             nFrameTimeSlots, &pFrameData->framingInfo,
1244
0
             hMp4SpaceEnc->pFrameWindowAna__FDK, &hMp4SpaceEnc->frameWinList,
1245
0
             hMp4SpaceEnc->avoid_keep))) {
1246
0
      goto bail;
1247
0
    }
1248
1249
    /*
1250
     * MPS Processing:
1251
     */
1252
0
    for (ps = 0, winCnt = 0; ps < hMp4SpaceEnc->frameWinList.n; ++ps) {
1253
      /* Analysis Windowing */
1254
0
      if (hMp4SpaceEnc->frameWinList.dat[ps].hold == FW_HOLD) {
1255
        /* ************************************** */
1256
        /* ONLY COPY AND HOLD PREVIOUS PARAMETERS */
1257
0
        if (SACENC_OK != (error = fdk_sacenc_duplicateParameterSet(
1258
0
                              &hMp4SpaceEnc->saveFrame, 0, pFrameData, ps))) {
1259
0
          goto bail;
1260
0
        }
1261
1262
0
      } else { /* !FW_HOLD */
1263
        /* ************************************** */
1264
        /* NEW WINDOW */
1265
1266
0
        INT nAnalysisLengthTimeSlots, analysisStartTimeSlot;
1267
1268
0
        nAnalysisLengthTimeSlots = getAnalysisLengthTimeSlots(
1269
0
            hMp4SpaceEnc->pFrameWindowAna__FDK[winCnt],
1270
0
            hMp4SpaceEnc->nAnalysisLengthTimeSlots);
1271
1272
0
        analysisStartTimeSlot =
1273
0
            getAnalysisStartTimeSlot(hMp4SpaceEnc->pFrameWindowAna__FDK[winCnt],
1274
0
                                     hMp4SpaceEnc->nAnalysisLengthTimeSlots);
1275
1276
        /* perform main signal analysis windowing in
1277
         * fdk_sacenc_spaceTree_Apply() */
1278
0
        FIXP_WIN *pFrameWindowAna__FDK =
1279
0
            hMp4SpaceEnc->pFrameWindowAna__FDK[winCnt];
1280
0
        FIXP_DPK ***pppHybridIn__FDK = hMp4SpaceEnc->pppHybridIn__FDK;
1281
0
        FIXP_DPK ***pppProcDataIn__FDK = hMp4SpaceEnc->pppProcDataIn__FDK;
1282
1283
0
        if (hMp4SpaceEnc->encMode == SACENC_212 &&
1284
0
            hMp4SpaceEnc->bEncMode_212_only) {
1285
0
          pppProcDataIn__FDK = pppHybridIn__FDK;
1286
0
        }
1287
1288
0
        if (SACENC_OK !=
1289
0
            (error = fdk_sacenc_spaceTree_Apply(
1290
0
                 hMp4SpaceEnc->hSpaceTree, ps, nChIn, nAnalysisLengthTimeSlots,
1291
0
                 analysisStartTimeSlot, hMp4SpaceEnc->nHybridBands,
1292
0
                 pFrameWindowAna__FDK, pppHybridIn__FDK,
1293
0
                 pppProcDataIn__FDK, /* multi-channel input */
1294
0
                 pFrameData, hMp4SpaceEnc->avoid_keep, encoderInputChScale))) {
1295
0
          goto bail;
1296
0
        }
1297
1298
        /* Save spatial frame for potential hold parameter set */
1299
0
        if (SACENC_OK != (error = fdk_sacenc_duplicateParameterSet(
1300
0
                              pFrameData, ps, &hMp4SpaceEnc->saveFrame, 0))) {
1301
0
          goto bail;
1302
0
        }
1303
1304
0
        ++winCnt;
1305
0
      }
1306
0
      if (hMp4SpaceEnc->avoid_keep > 0) {
1307
0
        hMp4SpaceEnc->avoid_keep--;
1308
0
      }
1309
0
    } /* Loop over Parameter Sets */
1310
    /* ---- End of Processing Loop ---- */
1311
1312
    /*
1313
     * Update hybridInReal/Imag buffer and do the same for arbDmx
1314
     * this means to move the hybrid data of the current frame to the beginning
1315
     * of the 2*nFrameLength-long buffer
1316
     */
1317
0
    if (!(hMp4SpaceEnc->encMode == SACENC_212 &&
1318
0
          hMp4SpaceEnc->bEncMode_212_only)) {
1319
0
      for (ch = 0; ch < nChIn; ch++) { /* for automatic downmix */
1320
0
        for (slot = 0;
1321
0
             slot < (int)(hMp4SpaceEnc->nUpdateHybridPositionTimeSlots +
1322
0
                          nFrameTimeSlots - nFrameTimeSlotsReduction);
1323
0
             slot++) {
1324
0
          copyCplxVec(
1325
0
              hMp4SpaceEnc->pppHybridIn__FDK[ch][slot],
1326
0
              hMp4SpaceEnc->pppHybridIn__FDK[ch][nFrameTimeSlots + slot],
1327
0
              hMp4SpaceEnc->nHybridBands);
1328
0
        }
1329
0
        for (slot = 0; slot < nFrameTimeSlots; slot++) {
1330
0
          setCplxVec(
1331
0
              hMp4SpaceEnc->pppHybridIn__FDK
1332
0
                  [ch][hMp4SpaceEnc->nUpdateHybridPositionTimeSlots +
1333
0
                       nFrameTimeSlots - nFrameTimeSlotsReduction + slot],
1334
0
              (FIXP_DBL)0, hMp4SpaceEnc->nHybridBands);
1335
0
        }
1336
0
      }
1337
0
    }
1338
    /*
1339
     * Spatial Tonality:
1340
     */
1341
0
    {
1342
      /* Smooth config off. */
1343
0
      FDKmemclear(&pFrameData->smgData, sizeof(pFrameData->smgData));
1344
0
    }
1345
1346
    /*
1347
     * Create bitstream
1348
     * - control independecy flag
1349
     * - write spatial frame
1350
     * - return bitstream
1351
     */
1352
0
    UCHAR *pBitstreamDelayBuffer;
1353
1354
0
    if (hMp4SpaceEnc->encMode == SACENC_212) {
1355
      /* no bitstream delay buffer for SACENC_212 mode, write bitstream directly
1356
       * into the sacOutBuffer buffer which is provided by the core routine */
1357
0
      pBitstreamDelayBuffer = (UCHAR *)outBufDesc->ppBase[1];
1358
0
    } else {
1359
      /* bitstream delay is handled in ppBitstreamDelayBuffer buffer */
1360
0
      pBitstreamDelayBuffer =
1361
0
          hMp4SpaceEnc
1362
0
              ->ppBitstreamDelayBuffer[hMp4SpaceEnc->nBitstreamBufferWrite];
1363
0
    }
1364
0
    if (pBitstreamDelayBuffer == NULL) {
1365
0
      error = SACENC_INVALID_HANDLE;
1366
0
      goto bail;
1367
0
    }
1368
1369
0
    pFrameData->bsIndependencyFlag = hMp4SpaceEnc->independencyFlag;
1370
1371
0
    if (SACENC_OK !=
1372
0
        (error = fdk_sacenc_writeSpatialFrame(
1373
0
             pBitstreamDelayBuffer, MAX_MPEGS_BYTES,
1374
0
             &hMp4SpaceEnc->pnOutputBits[hMp4SpaceEnc->nBitstreamBufferWrite],
1375
0
             hMp4SpaceEnc->hBitstreamFormatter))) {
1376
0
      goto bail;
1377
0
    }
1378
1379
    /* return bitstream info */
1380
0
    if ((hMp4SpaceEnc->nDiscardOutFrames == 0) &&
1381
0
        (getBufDescIdx(outBufDesc,
1382
0
                       (FDK_BUF_TYPE_OUTPUT | FDK_BUF_TYPE_BS_DATA)) != -1)) {
1383
0
      const INT idx = getBufDescIdx(
1384
0
          outBufDesc, (FDK_BUF_TYPE_OUTPUT | FDK_BUF_TYPE_BS_DATA));
1385
0
      const INT outBits =
1386
0
          hMp4SpaceEnc->pnOutputBits[hMp4SpaceEnc->nBitstreamBufferRead];
1387
1388
0
      if (((outBits + 7) / 8) >
1389
0
          (INT)(outBufDesc->pBufSize[idx] / outBufDesc->pEleSize[idx])) {
1390
0
        outargs->nOutputBits = 0;
1391
0
        error = SACENC_ENCODE_ERROR;
1392
0
        goto bail;
1393
0
      }
1394
1395
      /* return bitstream buffer, copy delayed bitstream for all configurations
1396
       * except for the SACENC_212 mode */
1397
0
      if (hMp4SpaceEnc->encMode != SACENC_212) {
1398
0
        FDKmemcpy(
1399
0
            outBufDesc->ppBase[idx],
1400
0
            hMp4SpaceEnc
1401
0
                ->ppBitstreamDelayBuffer[hMp4SpaceEnc->nBitstreamBufferRead],
1402
0
            (outBits + 7) / 8);
1403
0
      }
1404
1405
      /* return number of valid bits */
1406
0
      outargs->nOutputBits = outBits;
1407
0
    } else { /* No spatial data should be returned if the current frame is to be
1408
                discarded. */
1409
0
      outargs->nOutputBits = 0;
1410
0
    }
1411
1412
    /* update pointers */
1413
0
    hMp4SpaceEnc->nBitstreamBufferRead =
1414
0
        (hMp4SpaceEnc->nBitstreamBufferRead + 1) %
1415
0
        hMp4SpaceEnc->nBitstreamDelayBuffer;
1416
0
    hMp4SpaceEnc->nBitstreamBufferWrite =
1417
0
        (hMp4SpaceEnc->nBitstreamBufferWrite + 1) %
1418
0
        hMp4SpaceEnc->nBitstreamDelayBuffer;
1419
1420
    /* Set Output Parameters */
1421
0
    nOutputSamples =
1422
0
        (hMp4SpaceEnc->nDiscardOutFrames == 0)
1423
0
            ? (nOutputSamplesMax)
1424
0
            : 0; /* don't output samples in case frames to be discarded */
1425
0
    if (nOutputSamples > nOutputSamplesBufferSize) {
1426
0
      error = SACENC_INVALID_CONFIG;
1427
0
      goto bail;
1428
0
    }
1429
0
    outargs->nOutputSamples = nOutputSamples;
1430
1431
0
    { /* !bQmfOutput */
1432
1433
0
      if (hMp4SpaceEnc->encMode != SACENC_212) {
1434
        /* delay output samples and interleave them */
1435
        /* note: in case of arbitrary downmix this will always be processed,
1436
         * because nOutputSamples != 0, even if bDMXAlign is switched on */
1437
        /* always run copy-func, so nOutputSamplesMax instead of nOutputSamples
1438
         */
1439
0
        for (ch = 0; ch < nChOut; ch++) {
1440
0
          FDKmemcpy_flex(
1441
0
              &hMp4SpaceEnc->pOutputDelayBuffer__FDK
1442
0
                   [ch + (hMp4SpaceEnc->nOutputBufferDelay) * nChOut],
1443
0
              nChOut, hMp4SpaceEnc->ppTimeSigOut__FDK[ch], 1,
1444
0
              nOutputSamplesMax / nChOut);
1445
0
        }
1446
1447
        /* write delayed data in output pcm stream */
1448
        /* always calculate, limiter must have a lookahead!!! */
1449
0
        FDKmemcpy(pOutputSamples, hMp4SpaceEnc->pOutputDelayBuffer__FDK,
1450
0
                  nOutputSamplesMax * sizeof(INT_PCM));
1451
1452
        /* update delay buffer (move back end to the beginning of the buffer) */
1453
0
        FDKmemmove(
1454
0
            hMp4SpaceEnc->pOutputDelayBuffer__FDK,
1455
0
            &hMp4SpaceEnc->pOutputDelayBuffer__FDK[nOutputSamplesMax],
1456
0
            nChOut * (hMp4SpaceEnc->nOutputBufferDelay) * sizeof(INT_PCM));
1457
0
      }
1458
1459
0
      if (hMp4SpaceEnc->useTimeDomDownmix <= 0) {
1460
0
        if (SACENC_OK != (error = fdk_sacenc_staticPostGain_ApplyFDK(
1461
0
                              hMp4SpaceEnc->hStaticGain, pOutputSamples,
1462
0
                              nOutputSamplesMax, 0))) {
1463
0
          goto bail;
1464
0
        }
1465
0
      }
1466
1467
0
    } /* !bQmfOutput */
1468
1469
0
    if (hMp4SpaceEnc->nDiscardOutFrames > 0) {
1470
0
      hMp4SpaceEnc->nDiscardOutFrames--;
1471
0
    }
1472
1473
    /* Invalidate Input Buffer */
1474
0
    hMp4SpaceEnc->nSamplesValid = 0;
1475
1476
0
  } /* valid handle */
1477
0
bail:
1478
0
  return error;
1479
0
}
1480
1481
0
FDK_SACENC_ERROR FDK_sacenc_close(HANDLE_MP4SPACE_ENCODER *phMp4SpaceEnc) {
1482
0
  FDK_SACENC_ERROR error = SACENC_OK;
1483
1484
0
  if (NULL != phMp4SpaceEnc) {
1485
0
    if (NULL != *phMp4SpaceEnc) {
1486
0
      int ch, i;
1487
0
      HANDLE_MP4SPACE_ENCODER const hEnc = *phMp4SpaceEnc;
1488
1489
0
      if (hEnc->pParameterBand2HybridBandOffset != NULL) {
1490
0
        FDK_FREE_MEMORY_1D(hEnc->pParameterBand2HybridBandOffset);
1491
0
      }
1492
      /* Free Analysis Filterbank Structs */
1493
0
      if (hEnc->pEncoderInputChScale != NULL) {
1494
0
        FDK_FREE_MEMORY_1D(hEnc->pEncoderInputChScale);
1495
0
      }
1496
0
      if (hEnc->staticTimeDomainDmxInScale != NULL) {
1497
0
        FDK_FREE_MEMORY_1D(hEnc->staticTimeDomainDmxInScale);
1498
0
      }
1499
0
      if (hEnc->phQmfFiltIn__FDK != NULL) {
1500
0
        for (ch = 0; ch < hEnc->setup.maxChIn; ch++) {
1501
0
          if (hEnc->phQmfFiltIn__FDK[ch] != NULL) {
1502
0
            if (hEnc->phQmfFiltIn__FDK[ch]->FilterStates != NULL) {
1503
0
              FDK_FREE_MEMORY_1D(hEnc->phQmfFiltIn__FDK[ch]->FilterStates);
1504
0
            }
1505
0
            FDK_FREE_MEMORY_1D(hEnc->phQmfFiltIn__FDK[ch]);
1506
0
          }
1507
0
        }
1508
0
        FDK_FREE_MEMORY_1D(hEnc->phQmfFiltIn__FDK);
1509
0
      }
1510
0
      for (ch = 0; ch < hEnc->setup.maxChIn; ch++) {
1511
0
        if (NULL != hEnc->phDCFilterSigIn[ch]) {
1512
0
          fdk_sacenc_destroyDCFilter(&hEnc->phDCFilterSigIn[ch]);
1513
0
        }
1514
0
      }
1515
      /* Close Onset Detection */
1516
0
      for (ch = 0; ch < hEnc->setup.maxChIn; ch++) {
1517
0
        if (NULL != hEnc->phOnset[ch]) {
1518
0
          fdk_sacenc_onsetDetect_Close(&hEnc->phOnset[ch]);
1519
0
        }
1520
0
      }
1521
0
      if (hEnc->ppTrCurrPos) {
1522
0
        FDK_FREE_MEMORY_2D(hEnc->ppTrCurrPos);
1523
0
      }
1524
0
      if (hEnc->hFrameWindow) {
1525
0
        fdk_sacenc_frameWindow_Destroy(&hEnc->hFrameWindow);
1526
0
      }
1527
      /* Close Space Tree */
1528
0
      if (NULL != hEnc->hSpaceTree) {
1529
0
        fdk_sacenc_spaceTree_Close(&hEnc->hSpaceTree);
1530
0
      }
1531
0
      if (NULL != hEnc->hEnhancedTimeDmx) {
1532
0
        fdk_sacenc_close_enhancedTimeDomainDmx(&hEnc->hEnhancedTimeDmx);
1533
0
      }
1534
      /* Close Static Gain */
1535
0
      if (NULL != hEnc->hStaticGain) {
1536
0
        fdk_sacenc_staticGain_Close(&hEnc->hStaticGain);
1537
0
      }
1538
0
      if (NULL != hEnc->hStaticGainConfig) {
1539
0
        fdk_sacenc_staticGain_CloseConfig(&hEnc->hStaticGainConfig);
1540
0
      }
1541
      /* Close Delay*/
1542
0
      if (NULL != hEnc->hDelay) {
1543
0
        fdk_sacenc_delay_Close(&hEnc->hDelay);
1544
0
      }
1545
      /* Delete Bitstream Stuff */
1546
0
      if (NULL != hEnc->hBitstreamFormatter) {
1547
0
        fdk_sacenc_destroySpatialBitstreamEncoder(&(hEnc->hBitstreamFormatter));
1548
0
      }
1549
0
      if (hEnc->pppHybridIn__FDK != NULL) {
1550
0
        if (hEnc->setup.bEncMode_212 == 1) {
1551
0
          FDK_FREE_MEMORY_3D(hEnc->pppHybridIn__FDK);
1552
0
          FDK_FREE_MEMORY_3D(hEnc->pppHybridInStatic__FDK);
1553
0
        } else {
1554
0
          FDK_FREE_MEMORY_3D(hEnc->pppHybridIn__FDK);
1555
0
        }
1556
0
      }
1557
0
      if (hEnc->pppProcDataIn__FDK != NULL) {
1558
0
        FDK_FREE_MEMORY_3D(hEnc->pppProcDataIn__FDK);
1559
0
      }
1560
0
      if (hEnc->pOutputDelayBuffer__FDK != NULL) {
1561
0
        FDK_FREE_MEMORY_1D(hEnc->pOutputDelayBuffer__FDK);
1562
0
      }
1563
0
      if (hEnc->ppTimeSigIn__FDK != NULL) {
1564
0
        { FDK_FREE_MEMORY_2D(hEnc->ppTimeSigIn__FDK); }
1565
0
      }
1566
0
      if (hEnc->ppTimeSigDelayIn__FDK != NULL) {
1567
0
        FDK_FREE_MEMORY_2D(hEnc->ppTimeSigDelayIn__FDK);
1568
0
      }
1569
0
      if (hEnc->ppTimeSigOut__FDK != NULL) {
1570
0
        FDK_FREE_MEMORY_2D(hEnc->ppTimeSigOut__FDK);
1571
0
      }
1572
0
      for (i = 0; i < MAX_NUM_PARAMS; i++) {
1573
0
        if (hEnc->pFrameWindowAna__FDK[i] != NULL) {
1574
0
          FDK_FREE_MEMORY_1D(hEnc->pFrameWindowAna__FDK[i]);
1575
0
        }
1576
0
      }
1577
0
      if (hEnc->pnOutputBits != NULL) {
1578
0
        FDK_FREE_MEMORY_1D(hEnc->pnOutputBits);
1579
0
      }
1580
0
      if (hEnc->ppBitstreamDelayBuffer != NULL) {
1581
0
        FDK_FREE_MEMORY_2D(hEnc->ppBitstreamDelayBuffer);
1582
0
      }
1583
0
      if (hEnc->sscBuf.pSsc != NULL) {
1584
0
        FDK_FREE_MEMORY_1D(hEnc->sscBuf.pSsc);
1585
0
      }
1586
0
      FDK_FREE_MEMORY_1D(*phMp4SpaceEnc);
1587
0
    }
1588
0
  }
1589
1590
0
  return error;
1591
0
}
1592
1593
/*-----------------------------------------------------------------------------
1594
  functionname: mp4SpaceEnc_InitDelayCompensation()
1595
  description:  initialzes delay compensation
1596
  returns:      noError on success, an apropriate error code else
1597
  -----------------------------------------------------------------------------*/
1598
static FDK_SACENC_ERROR mp4SpaceEnc_InitDelayCompensation(
1599
0
    HANDLE_MP4SPACE_ENCODER hMp4SpaceEnc, const INT coreCoderDelay) {
1600
0
  FDK_SACENC_ERROR error = SACENC_OK;
1601
1602
  /* Sanity Check */
1603
0
  if (hMp4SpaceEnc == NULL) {
1604
0
    error = SACENC_INVALID_HANDLE;
1605
0
  } else {
1606
0
    hMp4SpaceEnc->coreCoderDelay = coreCoderDelay;
1607
1608
0
    if (SACENC_OK != (error = fdk_sacenc_delay_Init(
1609
0
                          hMp4SpaceEnc->hDelay, hMp4SpaceEnc->nQmfBands,
1610
0
                          hMp4SpaceEnc->nFrameLength, coreCoderDelay,
1611
0
                          hMp4SpaceEnc->timeAlignment))) {
1612
0
      goto bail;
1613
0
    }
1614
1615
0
    fdk_sacenc_delay_SetDmxAlign(hMp4SpaceEnc->hDelay, 0);
1616
0
    fdk_sacenc_delay_SetTimeDomDmx(
1617
0
        hMp4SpaceEnc->hDelay, (hMp4SpaceEnc->useTimeDomDownmix >= 1) ? 1 : 0);
1618
0
    fdk_sacenc_delay_SetMinimizeDelay(hMp4SpaceEnc->hDelay, 1);
1619
1620
0
    if (SACENC_OK != (error = fdk_sacenc_delay_SubCalulateBufferDelays(
1621
0
                          hMp4SpaceEnc->hDelay))) {
1622
0
      goto bail;
1623
0
    }
1624
1625
    /* init output delay compensation */
1626
0
    hMp4SpaceEnc->nBitstreamDelayBuffer =
1627
0
        fdk_sacenc_delay_GetBitstreamFrameBufferSize(hMp4SpaceEnc->hDelay);
1628
0
    hMp4SpaceEnc->nOutputBufferDelay =
1629
0
        fdk_sacenc_delay_GetOutputAudioBufferDelay(hMp4SpaceEnc->hDelay);
1630
0
    hMp4SpaceEnc->nSurroundAnalysisBufferDelay =
1631
0
        fdk_sacenc_delay_GetSurroundAnalysisBufferDelay(hMp4SpaceEnc->hDelay);
1632
0
    hMp4SpaceEnc->nBitstreamBufferRead = 0;
1633
0
    hMp4SpaceEnc->nBitstreamBufferWrite =
1634
0
        hMp4SpaceEnc->nBitstreamDelayBuffer - 1;
1635
1636
0
    if (hMp4SpaceEnc->encMode == SACENC_212) {
1637
      /* mode 212 expects no bitstream delay */
1638
0
      if (hMp4SpaceEnc->nBitstreamBufferWrite !=
1639
0
          hMp4SpaceEnc->nBitstreamBufferRead) {
1640
0
        error = SACENC_PARAM_ERROR;
1641
0
        goto bail;
1642
0
      }
1643
1644
      /* mode 212 expects no output buffer delay */
1645
0
      if (hMp4SpaceEnc->nOutputBufferDelay != 0) {
1646
0
        error = SACENC_PARAM_ERROR;
1647
0
        goto bail;
1648
0
      }
1649
0
    }
1650
1651
    /*** Input delay to obtain a net encoder delay that is a multiple
1652
    of the used framelength to ensure synchronization of framing
1653
    in artistic down-mix with the corresponding spatial data.      ***/
1654
0
    hMp4SpaceEnc->nDiscardOutFrames =
1655
0
        fdk_sacenc_delay_GetDiscardOutFrames(hMp4SpaceEnc->hDelay);
1656
0
    hMp4SpaceEnc->nInputDelay =
1657
0
        fdk_sacenc_delay_GetDmxAlignBufferDelay(hMp4SpaceEnc->hDelay);
1658
1659
    /* reset independency Flag counter */
1660
0
    hMp4SpaceEnc->independencyCount = 0;
1661
0
    hMp4SpaceEnc->independencyFlag = 1;
1662
1663
0
    int i;
1664
1665
    /* write some parameters to bitstream */
1666
0
    for (i = 0; i < hMp4SpaceEnc->nBitstreamDelayBuffer - 1; i++) {
1667
0
      SPATIALFRAME *pFrameData = NULL;
1668
1669
0
      if (NULL == (pFrameData = fdk_sacenc_getSpatialFrame(
1670
0
                       hMp4SpaceEnc->hBitstreamFormatter, READ_SPATIALFRAME))) {
1671
0
        error = SACENC_INVALID_HANDLE;
1672
0
        goto bail;
1673
0
      }
1674
1675
0
      pFrameData->bsIndependencyFlag = 1;
1676
0
      pFrameData->framingInfo.numParamSets = 1;
1677
0
      pFrameData->framingInfo.bsFramingType = 0;
1678
1679
0
      fdk_sacenc_writeSpatialFrame(
1680
0
          hMp4SpaceEnc->ppBitstreamDelayBuffer[i], MAX_MPEGS_BYTES,
1681
0
          &hMp4SpaceEnc->pnOutputBits[i], hMp4SpaceEnc->hBitstreamFormatter);
1682
0
    }
1683
1684
0
    if ((hMp4SpaceEnc->nInputDelay > MAX_DELAY_INPUT) ||
1685
0
        (hMp4SpaceEnc->nOutputBufferDelay > MAX_DELAY_OUTPUT) ||
1686
0
        (hMp4SpaceEnc->nSurroundAnalysisBufferDelay >
1687
0
         MAX_DELAY_SURROUND_ANALYSIS) ||
1688
0
        (hMp4SpaceEnc->nBitstreamDelayBuffer > MAX_BITSTREAM_DELAY)) {
1689
0
      error = SACENC_INIT_ERROR;
1690
0
      goto bail;
1691
0
    }
1692
0
  }
1693
1694
0
bail:
1695
1696
0
  return error;
1697
0
}
1698
1699
0
static QUANTMODE __mapQuantMode(const MP4SPACEENC_QUANTMODE quantMode) {
1700
0
  QUANTMODE bsQuantMode = QUANTMODE_INVALID;
1701
1702
0
  switch (quantMode) {
1703
0
    case SACENC_QUANTMODE_FINE:
1704
0
      bsQuantMode = QUANTMODE_FINE;
1705
0
      break;
1706
0
    case SACENC_QUANTMODE_EBQ1:
1707
0
      bsQuantMode = QUANTMODE_EBQ1;
1708
0
      break;
1709
0
    case SACENC_QUANTMODE_EBQ2:
1710
0
      bsQuantMode = QUANTMODE_EBQ2;
1711
0
      break;
1712
0
    case SACENC_QUANTMODE_RSVD3:
1713
0
    case SACENC_QUANTMODE_INVALID:
1714
0
    default:
1715
0
      bsQuantMode = QUANTMODE_INVALID;
1716
0
  } /* switch hEnc->quantMode */
1717
1718
0
  return bsQuantMode;
1719
0
}
1720
1721
static FDK_SACENC_ERROR FillSpatialSpecificConfig(
1722
0
    const HANDLE_MP4SPACE_ENCODER hEnc, SPATIALSPECIFICCONFIG *const hSsc) {
1723
0
  FDK_SACENC_ERROR error = SACENC_OK;
1724
1725
0
  if ((NULL == hEnc) || (NULL == hSsc)) {
1726
0
    error = SACENC_INVALID_HANDLE;
1727
0
  } else {
1728
0
    SPACE_TREE_DESCRIPTION spaceTreeDescription;
1729
0
    int i;
1730
1731
    /* Get tree description */
1732
0
    if (SACENC_OK != (error = fdk_sacenc_spaceTree_GetDescription(
1733
0
                          hEnc->hSpaceTree, &spaceTreeDescription))) {
1734
0
      goto bail;
1735
0
    }
1736
1737
    /* Fill SSC */
1738
0
    FDKmemclear(hSsc, sizeof(SPATIALSPECIFICCONFIG)); /* reset */
1739
1740
0
    hSsc->numBands = hEnc->spaceTreeSetup.nParamBands; /* for bsFreqRes */
1741
1742
    /* Fill tree configuration */
1743
0
    hSsc->treeDescription.numOttBoxes = spaceTreeDescription.nOttBoxes;
1744
0
    hSsc->treeDescription.numInChan = spaceTreeDescription.nInChannels;
1745
0
    hSsc->treeDescription.numOutChan = spaceTreeDescription.nOutChannels;
1746
1747
0
    for (i = 0; i < SACENC_MAX_NUM_BOXES; i++) {
1748
0
      hSsc->ottConfig[i].bsOttBands = hSsc->numBands;
1749
0
    }
1750
1751
0
    switch (hEnc->encMode) {
1752
0
      case SACENC_212:
1753
0
        hSsc->bsTreeConfig = TREE_212;
1754
0
        break;
1755
0
      case SACENC_INVALID_MODE:
1756
0
      default:
1757
0
        error = SACENC_INVALID_CONFIG;
1758
0
        goto bail;
1759
0
    }
1760
1761
0
    hSsc->bsSamplingFrequency =
1762
0
        hEnc->nSampleRate; /* for bsSamplingFrequencyIndex */
1763
0
    hSsc->bsFrameLength = hEnc->nFrameTimeSlots - 1;
1764
1765
    /* map decorr type */
1766
0
    if (DECORR_INVALID ==
1767
0
        (hSsc->bsDecorrConfig = mp4SpaceEnc_GetDecorrConfig(hEnc->encMode))) {
1768
0
      error = SACENC_INVALID_CONFIG;
1769
0
      goto bail;
1770
0
    }
1771
1772
    /* map quantMode */
1773
0
    if (QUANTMODE_INVALID ==
1774
0
        (hSsc->bsQuantMode = __mapQuantMode(hEnc->quantMode))) {
1775
0
      error = SACENC_INVALID_CONFIG;
1776
0
      goto bail;
1777
0
    }
1778
1779
    /* Configure Gains*/
1780
0
    hSsc->bsFixedGainDMX = fdk_sacenc_staticGain_GetDmxGain(hEnc->hStaticGain);
1781
0
    hSsc->bsEnvQuantMode = 0;
1782
1783
0
  } /* valid handle */
1784
1785
0
bail:
1786
0
  return error;
1787
0
}
1788
1789
static FDK_SACENC_ERROR mp4SpaceEnc_FillSpaceTreeSetup(
1790
    const HANDLE_MP4SPACE_ENCODER hEnc,
1791
0
    SPACE_TREE_SETUP *const hSpaceTreeSetup) {
1792
0
  FDK_SACENC_ERROR error = SACENC_OK;
1793
1794
  /* Sanity Check */
1795
0
  if (NULL == hEnc || NULL == hSpaceTreeSetup) {
1796
0
    error = SACENC_INVALID_HANDLE;
1797
0
  } else {
1798
0
    QUANTMODE tmpQuantmode = QUANTMODE_INVALID;
1799
1800
    /* map quantMode */
1801
0
    if (QUANTMODE_INVALID == (tmpQuantmode = __mapQuantMode(hEnc->quantMode))) {
1802
0
      error = SACENC_INVALID_CONFIG;
1803
0
      goto bail;
1804
0
    }
1805
1806
0
    hSpaceTreeSetup->nParamBands = hEnc->nParamBands;
1807
0
    hSpaceTreeSetup->bUseCoarseQuantTtoCld = hEnc->useCoarseQuantCld;
1808
0
    hSpaceTreeSetup->bUseCoarseQuantTtoIcc = hEnc->useCoarseQuantIcc;
1809
0
    hSpaceTreeSetup->quantMode = tmpQuantmode;
1810
0
    hSpaceTreeSetup->nHybridBandsMax = hEnc->nHybridBands;
1811
1812
0
    switch (hEnc->encMode) {
1813
0
      case SACENC_212:
1814
0
        hSpaceTreeSetup->mode = SPACETREE_212;
1815
0
        hSpaceTreeSetup->nChannelsInMax = 2;
1816
0
        break;
1817
0
      case SACENC_INVALID_MODE:
1818
0
      default:
1819
0
        error = SACENC_INVALID_CONFIG;
1820
0
        goto bail;
1821
0
    } /* switch hEnc->encMode */
1822
1823
0
  } /* valid handle */
1824
0
bail:
1825
0
  return error;
1826
0
}
1827
1828
FDK_SACENC_ERROR FDK_sacenc_getInfo(const HANDLE_MP4SPACE_ENCODER hMp4SpaceEnc,
1829
0
                                    MP4SPACEENC_INFO *const pInfo) {
1830
0
  FDK_SACENC_ERROR error = SACENC_OK;
1831
1832
0
  if ((NULL == hMp4SpaceEnc) || (NULL == pInfo)) {
1833
0
    error = SACENC_INVALID_HANDLE;
1834
0
  } else {
1835
0
    pInfo->nSampleRate = hMp4SpaceEnc->nSampleRate;
1836
0
    pInfo->nSamplesFrame = hMp4SpaceEnc->nFrameLength;
1837
0
    pInfo->nTotalInputChannels = hMp4SpaceEnc->nInputChannels;
1838
0
    pInfo->nDmxDelay = fdk_sacenc_delay_GetInfoDmxDelay(hMp4SpaceEnc->hDelay);
1839
0
    pInfo->nCodecDelay =
1840
0
        fdk_sacenc_delay_GetInfoCodecDelay(hMp4SpaceEnc->hDelay);
1841
0
    pInfo->nDecoderDelay =
1842
0
        fdk_sacenc_delay_GetInfoDecoderDelay(hMp4SpaceEnc->hDelay);
1843
0
    pInfo->nPayloadDelay =
1844
0
        fdk_sacenc_delay_GetBitstreamFrameBufferSize(hMp4SpaceEnc->hDelay) - 1;
1845
0
    pInfo->nDiscardOutFrames = hMp4SpaceEnc->nDiscardOutFrames;
1846
1847
0
    pInfo->pSscBuf = &hMp4SpaceEnc->sscBuf;
1848
0
  }
1849
0
  return error;
1850
0
}
1851
1852
FDK_SACENC_ERROR FDK_sacenc_setParam(HANDLE_MP4SPACE_ENCODER hMp4SpaceEnc,
1853
                                     const SPACEENC_PARAM param,
1854
0
                                     const UINT value) {
1855
0
  FDK_SACENC_ERROR error = SACENC_OK;
1856
1857
  /* check encoder handle */
1858
0
  if (hMp4SpaceEnc == NULL) {
1859
0
    error = SACENC_INVALID_HANDLE;
1860
0
    goto bail;
1861
0
  }
1862
1863
  /* apply param value */
1864
0
  switch (param) {
1865
0
    case SACENC_LOWDELAY:
1866
0
      if (!((value == 0) || (value == 1) || (value == 2))) {
1867
0
        error = SACENC_INVALID_CONFIG;
1868
0
        break;
1869
0
      }
1870
0
      hMp4SpaceEnc->user.bLdMode = value;
1871
0
      break;
1872
1873
0
    case SACENC_ENC_MODE:
1874
0
      switch ((MP4SPACEENC_MODE)value) {
1875
0
        case SACENC_212:
1876
0
          hMp4SpaceEnc->user.encMode = (MP4SPACEENC_MODE)value;
1877
0
          break;
1878
0
        default:
1879
0
          error = SACENC_INVALID_CONFIG;
1880
0
      }
1881
0
      break;
1882
1883
0
    case SACENC_SAMPLERATE:
1884
0
      if (((int)value < 0) ||
1885
0
          ((int)value > hMp4SpaceEnc->setup.maxSamplingrate)) {
1886
0
        error = SACENC_INVALID_CONFIG;
1887
0
        break;
1888
0
      }
1889
0
      hMp4SpaceEnc->user.sampleRate = value;
1890
0
      break;
1891
1892
0
    case SACENC_FRAME_TIME_SLOTS:
1893
0
      if (((int)value < 0) ||
1894
0
          ((int)value > hMp4SpaceEnc->setup.maxFrameTimeSlots)) {
1895
0
        error = SACENC_INVALID_CONFIG;
1896
0
        break;
1897
0
      }
1898
0
      hMp4SpaceEnc->user.frameTimeSlots = value;
1899
0
      break;
1900
1901
0
    case SACENC_PARAM_BANDS:
1902
0
      switch ((MP4SPACEENC_BANDS_CONFIG)value) {
1903
0
        case SACENC_BANDS_4:
1904
0
        case SACENC_BANDS_5:
1905
0
        case SACENC_BANDS_7:
1906
0
        case SACENC_BANDS_9:
1907
0
        case SACENC_BANDS_12:
1908
0
        case SACENC_BANDS_15:
1909
0
        case SACENC_BANDS_23:
1910
0
          hMp4SpaceEnc->user.nParamBands = (MP4SPACEENC_BANDS_CONFIG)value;
1911
0
          break;
1912
0
        default:
1913
0
          error = SACENC_INVALID_CONFIG;
1914
0
      }
1915
0
      break;
1916
1917
0
    case SACENC_TIME_DOM_DMX:
1918
0
      if (!((value == 0) || (value == 2))) {
1919
0
        error = SACENC_INVALID_CONFIG;
1920
0
        break;
1921
0
      }
1922
0
      hMp4SpaceEnc->user.bTimeDomainDmx = value;
1923
0
      break;
1924
1925
0
    case SACENC_DMX_GAIN:
1926
0
      if (!((value == 0) || (value == 1) || (value == 2) || (value == 3) ||
1927
0
            (value == 4) || (value == 5) || (value == 6) || (value == 7))) {
1928
0
        error = SACENC_INVALID_CONFIG;
1929
0
        break;
1930
0
      }
1931
0
      error = fdk_sacenc_staticGain_SetDmxGain(hMp4SpaceEnc->hStaticGainConfig,
1932
0
                                               (MP4SPACEENC_DMX_GAIN)value);
1933
0
      break;
1934
1935
0
    case SACENC_COARSE_QUANT:
1936
0
      if (!((value == 0) || (value == 1))) {
1937
0
        error = SACENC_INVALID_CONFIG;
1938
0
        break;
1939
0
      }
1940
0
      hMp4SpaceEnc->user.bUseCoarseQuant = value;
1941
0
      break;
1942
1943
0
    case SACENC_QUANT_MODE:
1944
0
      switch ((MP4SPACEENC_QUANTMODE)value) {
1945
0
        case SACENC_QUANTMODE_FINE:
1946
0
        case SACENC_QUANTMODE_EBQ1:
1947
0
        case SACENC_QUANTMODE_EBQ2:
1948
0
          hMp4SpaceEnc->user.quantMode = (MP4SPACEENC_QUANTMODE)value;
1949
0
          break;
1950
0
        default:
1951
0
          error = SACENC_INVALID_CONFIG;
1952
0
      }
1953
0
      break;
1954
1955
0
    case SACENC_TIME_ALIGNMENT:
1956
0
      if ((INT)value < -32768 || (INT)value > 32767) {
1957
0
        error = SACENC_INVALID_CONFIG;
1958
0
        break;
1959
0
      }
1960
0
      hMp4SpaceEnc->user.timeAlignment = value;
1961
0
      break;
1962
1963
0
    case SACENC_INDEPENDENCY_COUNT:
1964
0
      hMp4SpaceEnc->independencyCount = value;
1965
0
      break;
1966
1967
0
    case SACENC_INDEPENDENCY_FACTOR:
1968
0
      hMp4SpaceEnc->user.independencyFactor = value;
1969
0
      break;
1970
1971
0
    default:
1972
0
      error = SACENC_UNSUPPORTED_PARAMETER;
1973
0
      break;
1974
0
  } /* switch(param) */
1975
0
bail:
1976
0
  return error;
1977
0
}
1978
1979
0
FDK_SACENC_ERROR FDK_sacenc_getLibInfo(LIB_INFO *info) {
1980
0
  int i = 0;
1981
1982
0
  if (info == NULL) {
1983
0
    return SACENC_INVALID_HANDLE;
1984
0
  }
1985
1986
0
  FDK_toolsGetLibInfo(info);
1987
1988
  /* search for next free tab */
1989
0
  for (i = 0; i < FDK_MODULE_LAST; i++) {
1990
0
    if (info[i].module_id == FDK_NONE) break;
1991
0
  }
1992
0
  if (i == FDK_MODULE_LAST) {
1993
0
    return SACENC_INIT_ERROR;
1994
0
  }
1995
1996
0
  info[i].module_id = FDK_MPSENC;
1997
0
  info[i].build_date = SACENC_LIB_BUILD_DATE;
1998
0
  info[i].build_time = SACENC_LIB_BUILD_TIME;
1999
0
  info[i].title = SACENC_LIB_TITLE;
2000
0
  info[i].version = LIB_VERSION(SACENC_LIB_VL0, SACENC_LIB_VL1, SACENC_LIB_VL2);
2001
0
  LIB_VERSION_STRING(&info[i]);
2002
2003
  /* Capability flags */
2004
0
  info[i].flags = 0;
2005
  /* End of flags */
2006
2007
0
  return SACENC_OK;
2008
0
}
2009
2010
static DECORRCONFIG mp4SpaceEnc_GetDecorrConfig(
2011
0
    const MP4SPACEENC_MODE encMode) {
2012
0
  DECORRCONFIG decorrConfig = DECORR_INVALID;
2013
2014
  /* set decorrConfig dependent on tree mode */
2015
0
  switch (encMode) {
2016
0
    case SACENC_212:
2017
0
      decorrConfig = DECORR_QMFSPLIT0;
2018
0
      break;
2019
0
    case SACENC_INVALID_MODE:
2020
0
    default:
2021
0
      decorrConfig = DECORR_INVALID;
2022
0
  }
2023
0
  return decorrConfig;
2024
0
}
2025
2026
static FDK_SACENC_ERROR mp4SpaceEnc_InitNumParamBands(
2027
0
    HANDLE_MP4SPACE_ENCODER hEnc, const MP4SPACEENC_BANDS_CONFIG nParamBands) {
2028
0
  FDK_SACENC_ERROR error = SACENC_OK;
2029
2030
  /* Set/Check nParamBands */
2031
0
  int k = 0;
2032
0
  const int n = sizeof(pValidBands_Ld) / sizeof(UCHAR);
2033
0
  const UCHAR *pBands = pValidBands_Ld;
2034
2035
0
  while (k < n && pBands[k] != (UCHAR)nParamBands) ++k;
2036
0
  if (k == n) {
2037
0
    hEnc->nParamBands = SACENC_BANDS_INVALID;
2038
0
  } else {
2039
0
    hEnc->nParamBands = nParamBands;
2040
0
  }
2041
0
  return error;
2042
0
}