• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* -----------------------------------------------------------------------------
2 Software License for The Fraunhofer FDK AAC Codec Library for Android
3 
4 © Copyright  1995 - 2019 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-D DRC decoder library **************************
96 
97    Author(s):   Bernhard Neugebauer
98 
99    Description: MPEG-D DRC Decoder
100 
101 *******************************************************************************/
102 
103 #include "drcDec_reader.h"
104 #include "drcDec_gainDecoder.h"
105 #include "FDK_drcDecLib.h"
106 
107 #include "drcDec_selectionProcess.h"
108 #include "drcDec_tools.h"
109 
110 /* Decoder library info */
111 #define DRCDEC_LIB_VL0 2
112 #define DRCDEC_LIB_VL1 1
113 #define DRCDEC_LIB_VL2 0
114 #define DRCDEC_LIB_TITLE "MPEG-D DRC Decoder Lib"
115 #ifdef __ANDROID__
116 #define DRCDEC_LIB_BUILD_DATE ""
117 #define DRCDEC_LIB_BUILD_TIME ""
118 #else
119 #define DRCDEC_LIB_BUILD_DATE __DATE__
120 #define DRCDEC_LIB_BUILD_TIME __TIME__
121 #endif
122 
123 typedef enum {
124   DRC_DEC_NOT_INITIALIZED = 0,
125   DRC_DEC_INITIALIZED,
126   DRC_DEC_NEW_GAIN_PAYLOAD,
127   DRC_DEC_INTERPOLATION_PREPARED
128 } DRC_DEC_STATUS;
129 
130 struct s_drc_decoder {
131   DRC_DEC_CODEC_MODE codecMode;
132   DRC_DEC_FUNCTIONAL_RANGE functionalRange;
133   DRC_DEC_STATUS status;
134 
135   /* handles of submodules */
136   HANDLE_DRC_GAIN_DECODER hGainDec;
137   HANDLE_DRC_SELECTION_PROCESS hSelectionProc;
138   int selProcInputDiff;
139 
140   /* data structs */
141   UNI_DRC_CONFIG uniDrcConfig;
142   LOUDNESS_INFO_SET loudnessInfoSet;
143   UNI_DRC_GAIN uniDrcGain;
144 
145   SEL_PROC_OUTPUT selProcOutput;
146 } DRC_DECODER;
147 
_getGainStatus(HANDLE_UNI_DRC_GAIN hUniDrcGain)148 static int _getGainStatus(HANDLE_UNI_DRC_GAIN hUniDrcGain) {
149   return hUniDrcGain->status;
150 }
151 
isResetNeeded(HANDLE_DRC_DECODER hDrcDec,const SEL_PROC_OUTPUT oldSelProcOutput)152 static int isResetNeeded(HANDLE_DRC_DECODER hDrcDec,
153                          const SEL_PROC_OUTPUT oldSelProcOutput) {
154   int i, resetNeeded = 0;
155 
156   if (hDrcDec->selProcOutput.numSelectedDrcSets !=
157       oldSelProcOutput.numSelectedDrcSets) {
158     resetNeeded = 1;
159   } else {
160     for (i = 0; i < hDrcDec->selProcOutput.numSelectedDrcSets; i++) {
161       if (hDrcDec->selProcOutput.selectedDrcSetIds[i] !=
162           oldSelProcOutput.selectedDrcSetIds[i])
163         resetNeeded = 1;
164       if (hDrcDec->selProcOutput.selectedDownmixIds[i] !=
165           oldSelProcOutput.selectedDownmixIds[i])
166         resetNeeded = 1;
167     }
168   }
169 
170   if (hDrcDec->selProcOutput.boost != oldSelProcOutput.boost) resetNeeded = 1;
171   if (hDrcDec->selProcOutput.compress != oldSelProcOutput.compress)
172     resetNeeded = 1;
173 
174   /* Note: Changes in downmix matrix are not caught, as they don't affect the
175    * DRC gain decoder */
176 
177   return resetNeeded;
178 }
179 
startSelectionProcess(HANDLE_DRC_DECODER hDrcDec)180 static void startSelectionProcess(HANDLE_DRC_DECODER hDrcDec) {
181   int uniDrcConfigHasChanged = 0;
182   SEL_PROC_OUTPUT oldSelProcOutput = hDrcDec->selProcOutput;
183 
184   if (!hDrcDec->status) return;
185 
186   if (hDrcDec->functionalRange & DRC_DEC_SELECTION) {
187     uniDrcConfigHasChanged = hDrcDec->uniDrcConfig.diff;
188     if (hDrcDec->uniDrcConfig.diff || hDrcDec->loudnessInfoSet.diff ||
189         hDrcDec->selProcInputDiff) {
190       /* in case of an error, signal that selection process was not successful
191        */
192       hDrcDec->selProcOutput.numSelectedDrcSets = 0;
193 
194       drcDec_SelectionProcess_Process(
195           hDrcDec->hSelectionProc, &(hDrcDec->uniDrcConfig),
196           &(hDrcDec->loudnessInfoSet), &(hDrcDec->selProcOutput));
197 
198       hDrcDec->selProcInputDiff = 0;
199       hDrcDec->uniDrcConfig.diff = 0;
200       hDrcDec->loudnessInfoSet.diff = 0;
201     }
202   }
203 
204   if (hDrcDec->functionalRange & DRC_DEC_GAIN) {
205     if (isResetNeeded(hDrcDec, oldSelProcOutput) || uniDrcConfigHasChanged) {
206       drcDec_GainDecoder_Config(hDrcDec->hGainDec, &(hDrcDec->uniDrcConfig),
207                                 hDrcDec->selProcOutput.numSelectedDrcSets,
208                                 hDrcDec->selProcOutput.selectedDrcSetIds,
209                                 hDrcDec->selProcOutput.selectedDownmixIds);
210     }
211   }
212 }
213 
214 DRC_DEC_ERROR
FDK_drcDec_Open(HANDLE_DRC_DECODER * phDrcDec,const DRC_DEC_FUNCTIONAL_RANGE functionalRange)215 FDK_drcDec_Open(HANDLE_DRC_DECODER* phDrcDec,
216                 const DRC_DEC_FUNCTIONAL_RANGE functionalRange) {
217   DRC_ERROR dErr = DE_OK;
218   DRCDEC_SELECTION_PROCESS_RETURN sErr = DRCDEC_SELECTION_PROCESS_NO_ERROR;
219   HANDLE_DRC_DECODER hDrcDec;
220 
221   *phDrcDec = (HANDLE_DRC_DECODER)FDKcalloc(1, sizeof(DRC_DECODER));
222   if (!*phDrcDec) return DRC_DEC_OUT_OF_MEMORY;
223   hDrcDec = *phDrcDec;
224 
225   hDrcDec->functionalRange = functionalRange;
226 
227   hDrcDec->status = DRC_DEC_NOT_INITIALIZED;
228   hDrcDec->codecMode = DRC_DEC_CODEC_MODE_UNDEFINED;
229 
230   if (hDrcDec->functionalRange & DRC_DEC_SELECTION) {
231     sErr = drcDec_SelectionProcess_Create(&(hDrcDec->hSelectionProc));
232     if (sErr) return DRC_DEC_OUT_OF_MEMORY;
233     sErr = drcDec_SelectionProcess_Init(hDrcDec->hSelectionProc);
234     if (sErr) return DRC_DEC_NOT_OK;
235     hDrcDec->selProcInputDiff = 1;
236   }
237 
238   if (hDrcDec->functionalRange & DRC_DEC_GAIN) {
239     dErr = drcDec_GainDecoder_Open(&(hDrcDec->hGainDec));
240     if (dErr) return DRC_DEC_OUT_OF_MEMORY;
241   }
242 
243   return DRC_DEC_OK;
244 }
245 
246 DRC_DEC_ERROR
FDK_drcDec_SetCodecMode(HANDLE_DRC_DECODER hDrcDec,const DRC_DEC_CODEC_MODE codecMode)247 FDK_drcDec_SetCodecMode(HANDLE_DRC_DECODER hDrcDec,
248                         const DRC_DEC_CODEC_MODE codecMode) {
249   DRC_ERROR dErr = DE_OK;
250   DRCDEC_SELECTION_PROCESS_RETURN sErr = DRCDEC_SELECTION_PROCESS_NO_ERROR;
251 
252   if (hDrcDec == NULL) return DRC_DEC_NOT_OPENED;
253 
254   if (hDrcDec->codecMode ==
255       DRC_DEC_CODEC_MODE_UNDEFINED) { /* Set codec mode, if it is set for the
256                                          first time */
257     hDrcDec->codecMode = codecMode;
258 
259     if (hDrcDec->functionalRange & DRC_DEC_SELECTION) {
260       sErr = drcDec_SelectionProcess_SetCodecMode(
261           hDrcDec->hSelectionProc, (SEL_PROC_CODEC_MODE)codecMode);
262       if (sErr) return DRC_DEC_NOT_OK;
263       hDrcDec->selProcInputDiff = 1;
264     }
265 
266     if (hDrcDec->functionalRange & DRC_DEC_GAIN) {
267       DELAY_MODE delayMode;
268       int timeDomainSupported;
269       SUBBAND_DOMAIN_MODE subbandDomainSupported;
270 
271       switch (hDrcDec->codecMode) {
272         case DRC_DEC_MPEG_4_AAC:
273         case DRC_DEC_MPEG_D_USAC:
274         case DRC_DEC_MPEG_H_3DA:
275         default:
276           delayMode = DM_REGULAR_DELAY;
277       }
278 
279       switch (hDrcDec->codecMode) {
280         case DRC_DEC_MPEG_4_AAC:
281         case DRC_DEC_MPEG_D_USAC:
282           timeDomainSupported = 1;
283           subbandDomainSupported = SDM_OFF;
284           break;
285         case DRC_DEC_MPEG_H_3DA:
286           timeDomainSupported = 1;
287           subbandDomainSupported = SDM_STFT256;
288           break;
289 
290         case DRC_DEC_TEST_TIME_DOMAIN:
291           timeDomainSupported = 1;
292           subbandDomainSupported = SDM_OFF;
293           break;
294         case DRC_DEC_TEST_QMF_DOMAIN:
295           timeDomainSupported = 0;
296           subbandDomainSupported = SDM_QMF64;
297           break;
298         case DRC_DEC_TEST_STFT_DOMAIN:
299           timeDomainSupported = 0;
300           subbandDomainSupported = SDM_STFT256;
301           break;
302 
303         default:
304           timeDomainSupported = 0;
305           subbandDomainSupported = SDM_OFF;
306       }
307 
308       dErr = drcDec_GainDecoder_SetCodecDependentParameters(
309           hDrcDec->hGainDec, delayMode, timeDomainSupported,
310           subbandDomainSupported);
311       if (dErr) return DRC_DEC_NOT_OK;
312     }
313   }
314 
315   /* Don't allow changing codecMode if it has already been set. */
316   if (hDrcDec->codecMode != codecMode) return DRC_DEC_NOT_OK;
317 
318   return DRC_DEC_OK;
319 }
320 
321 DRC_DEC_ERROR
FDK_drcDec_Init(HANDLE_DRC_DECODER hDrcDec,const int frameSize,const int sampleRate,const int baseChannelCount)322 FDK_drcDec_Init(HANDLE_DRC_DECODER hDrcDec, const int frameSize,
323                 const int sampleRate, const int baseChannelCount) {
324   DRC_ERROR dErr = DE_OK;
325   DRCDEC_SELECTION_PROCESS_RETURN sErr = DRCDEC_SELECTION_PROCESS_NO_ERROR;
326 
327   if (hDrcDec == NULL || frameSize == 0 || sampleRate == 0 ||
328       baseChannelCount == 0)
329     return DRC_DEC_OK; /* return without doing anything */
330 
331   if (hDrcDec->functionalRange & DRC_DEC_SELECTION) {
332     sErr = drcDec_SelectionProcess_SetParam(
333         hDrcDec->hSelectionProc, SEL_PROC_BASE_CHANNEL_COUNT,
334         (FIXP_DBL)baseChannelCount, &(hDrcDec->selProcInputDiff));
335     if (sErr) return DRC_DEC_NOT_OK;
336     sErr = drcDec_SelectionProcess_SetParam(
337         hDrcDec->hSelectionProc, SEL_PROC_SAMPLE_RATE, (FIXP_DBL)sampleRate,
338         &(hDrcDec->selProcInputDiff));
339     if (sErr) return DRC_DEC_NOT_OK;
340   }
341 
342   if (hDrcDec->functionalRange & DRC_DEC_GAIN) {
343     dErr = drcDec_GainDecoder_SetParam(hDrcDec->hGainDec, GAIN_DEC_FRAME_SIZE,
344                                        frameSize);
345     if (dErr) return DRC_DEC_NOT_OK;
346     dErr = drcDec_GainDecoder_SetParam(hDrcDec->hGainDec, GAIN_DEC_SAMPLE_RATE,
347                                        sampleRate);
348     if (dErr) return DRC_DEC_NOT_OK;
349     dErr = drcDec_GainDecoder_Init(hDrcDec->hGainDec);
350     if (dErr) return DRC_DEC_NOT_OK;
351   }
352 
353   hDrcDec->status = DRC_DEC_INITIALIZED;
354 
355   startSelectionProcess(hDrcDec);
356 
357   return DRC_DEC_OK;
358 }
359 
360 DRC_DEC_ERROR
FDK_drcDec_Close(HANDLE_DRC_DECODER * phDrcDec)361 FDK_drcDec_Close(HANDLE_DRC_DECODER* phDrcDec) {
362   HANDLE_DRC_DECODER hDrcDec;
363 
364   if (phDrcDec == NULL) {
365     return DRC_DEC_OK;
366   }
367 
368   hDrcDec = *phDrcDec;
369 
370   if (hDrcDec == NULL) return DRC_DEC_NOT_OPENED;
371 
372   if (hDrcDec->functionalRange & DRC_DEC_GAIN) {
373     drcDec_GainDecoder_Close(&(hDrcDec->hGainDec));
374   }
375 
376   if (hDrcDec->functionalRange & DRC_DEC_SELECTION) {
377     drcDec_SelectionProcess_Delete(&(hDrcDec->hSelectionProc));
378   }
379 
380   FDKfree(*phDrcDec);
381   *phDrcDec = NULL;
382 
383   return DRC_DEC_OK;
384 }
385 
386 DRC_DEC_ERROR
FDK_drcDec_SetParam(HANDLE_DRC_DECODER hDrcDec,const DRC_DEC_USERPARAM requestType,const FIXP_DBL requestValue)387 FDK_drcDec_SetParam(HANDLE_DRC_DECODER hDrcDec,
388                     const DRC_DEC_USERPARAM requestType,
389                     const FIXP_DBL requestValue) {
390   DRC_ERROR dErr = DE_OK;
391   DRCDEC_SELECTION_PROCESS_RETURN sErr = DRCDEC_SELECTION_PROCESS_NO_ERROR;
392   int invalidParameter = 0;
393 
394   if (hDrcDec == NULL) return DRC_DEC_NOT_OPENED;
395 
396   if (hDrcDec->functionalRange & DRC_DEC_GAIN) {
397     switch (requestType) {
398       case DRC_DEC_SAMPLE_RATE:
399         dErr = drcDec_GainDecoder_SetParam(
400             hDrcDec->hGainDec, GAIN_DEC_SAMPLE_RATE, (int)requestValue);
401         if (dErr) return DRC_DEC_PARAM_OUT_OF_RANGE;
402         break;
403       case DRC_DEC_FRAME_SIZE:
404         dErr = drcDec_GainDecoder_SetParam(
405             hDrcDec->hGainDec, GAIN_DEC_FRAME_SIZE, (int)requestValue);
406         if (dErr) return DRC_DEC_PARAM_OUT_OF_RANGE;
407         break;
408       default:
409         invalidParameter |= DRC_DEC_GAIN;
410     }
411   }
412 
413   if (hDrcDec->functionalRange & DRC_DEC_SELECTION) {
414     switch (requestType) {
415       case DRC_DEC_BOOST:
416         sErr = drcDec_SelectionProcess_SetParam(hDrcDec->hSelectionProc,
417                                                 SEL_PROC_BOOST, requestValue,
418                                                 &(hDrcDec->selProcInputDiff));
419         if (sErr) return DRC_DEC_PARAM_OUT_OF_RANGE;
420         break;
421       case DRC_DEC_COMPRESS:
422         sErr = drcDec_SelectionProcess_SetParam(hDrcDec->hSelectionProc,
423                                                 SEL_PROC_COMPRESS, requestValue,
424                                                 &(hDrcDec->selProcInputDiff));
425         if (sErr) return DRC_DEC_PARAM_OUT_OF_RANGE;
426         break;
427       case DRC_DEC_LOUDNESS_NORMALIZATION_ON:
428         sErr = drcDec_SelectionProcess_SetParam(
429             hDrcDec->hSelectionProc, SEL_PROC_LOUDNESS_NORMALIZATION_ON,
430             requestValue, &(hDrcDec->selProcInputDiff));
431         if (sErr) return DRC_DEC_PARAM_OUT_OF_RANGE;
432         break;
433       case DRC_DEC_TARGET_LOUDNESS:
434         sErr = drcDec_SelectionProcess_SetParam(
435             hDrcDec->hSelectionProc, SEL_PROC_TARGET_LOUDNESS, requestValue,
436             &(hDrcDec->selProcInputDiff));
437         if (sErr) return DRC_DEC_PARAM_OUT_OF_RANGE;
438         break;
439       case DRC_DEC_EFFECT_TYPE:
440         sErr = drcDec_SelectionProcess_SetParam(
441             hDrcDec->hSelectionProc, SEL_PROC_EFFECT_TYPE, requestValue,
442             &(hDrcDec->selProcInputDiff));
443         if (sErr) return DRC_DEC_PARAM_OUT_OF_RANGE;
444         break;
445       case DRC_DEC_DOWNMIX_ID:
446         sErr = drcDec_SelectionProcess_SetParam(
447             hDrcDec->hSelectionProc, SEL_PROC_DOWNMIX_ID, requestValue,
448             &(hDrcDec->selProcInputDiff));
449         if (sErr) return DRC_DEC_PARAM_OUT_OF_RANGE;
450         break;
451       case DRC_DEC_TARGET_CHANNEL_COUNT_REQUESTED:
452         sErr = drcDec_SelectionProcess_SetParam(
453             hDrcDec->hSelectionProc, SEL_PROC_TARGET_CHANNEL_COUNT,
454             requestValue, &(hDrcDec->selProcInputDiff));
455         if (sErr) return DRC_DEC_PARAM_OUT_OF_RANGE;
456         break;
457       case DRC_DEC_BASE_CHANNEL_COUNT:
458         sErr = drcDec_SelectionProcess_SetParam(
459             hDrcDec->hSelectionProc, SEL_PROC_BASE_CHANNEL_COUNT, requestValue,
460             &(hDrcDec->selProcInputDiff));
461         if (sErr) return DRC_DEC_NOT_OK;
462         break;
463       case DRC_DEC_LOUDNESS_MEASUREMENT_METHOD:
464         sErr = drcDec_SelectionProcess_SetParam(
465             hDrcDec->hSelectionProc, SEL_PROC_LOUDNESS_MEASUREMENT_METHOD,
466             requestValue, &(hDrcDec->selProcInputDiff));
467         if (sErr) return DRC_DEC_PARAM_OUT_OF_RANGE;
468         break;
469       case DRC_DEC_ALBUM_MODE:
470         sErr = drcDec_SelectionProcess_SetParam(
471             hDrcDec->hSelectionProc, SEL_PROC_ALBUM_MODE, requestValue,
472             &(hDrcDec->selProcInputDiff));
473         if (sErr) return DRC_DEC_PARAM_OUT_OF_RANGE;
474         break;
475       default:
476         invalidParameter |= DRC_DEC_SELECTION;
477     }
478   }
479 
480   if (invalidParameter == hDrcDec->functionalRange)
481     return DRC_DEC_INVALID_PARAM;
482 
483   /* All parameters need a new start of the selection process */
484   startSelectionProcess(hDrcDec);
485 
486   return DRC_DEC_OK;
487 }
488 
FDK_drcDec_GetParam(HANDLE_DRC_DECODER hDrcDec,const DRC_DEC_USERPARAM requestType)489 LONG FDK_drcDec_GetParam(HANDLE_DRC_DECODER hDrcDec,
490                          const DRC_DEC_USERPARAM requestType) {
491   if (hDrcDec == NULL) return DRC_DEC_NOT_OPENED;
492 
493   switch (requestType) {
494     case DRC_DEC_BOOST:
495       return (LONG)hDrcDec->selProcOutput.boost;
496     case DRC_DEC_COMPRESS:
497       return (LONG)hDrcDec->selProcOutput.compress;
498     case DRC_DEC_IS_MULTIBAND_DRC_1:
499       return (LONG)bitstreamContainsMultibandDrc(&hDrcDec->uniDrcConfig, 0);
500     case DRC_DEC_IS_MULTIBAND_DRC_2:
501       return (LONG)bitstreamContainsMultibandDrc(&hDrcDec->uniDrcConfig, 0x7F);
502     case DRC_DEC_IS_ACTIVE: {
503       /* MPEG-D DRC is considered active (and overrides MPEG-4 DRC), if
504        * uniDrc payload is present (loudnessInfoSet and/or uniDrcConfig)
505        * at least one of DRC and Loudness Control is switched on */
506       int drcOn = drcDec_SelectionProcess_GetParam(
507           hDrcDec->hSelectionProc, SEL_PROC_DYNAMIC_RANGE_CONTROL_ON);
508       int lnOn = drcDec_SelectionProcess_GetParam(
509           hDrcDec->hSelectionProc, SEL_PROC_LOUDNESS_NORMALIZATION_ON);
510       int uniDrcPayloadPresent =
511           (hDrcDec->loudnessInfoSet.loudnessInfoCount > 0);
512       uniDrcPayloadPresent |=
513           (hDrcDec->loudnessInfoSet.loudnessInfoAlbumCount > 0);
514       uniDrcPayloadPresent |=
515           (hDrcDec->uniDrcConfig.drcInstructionsUniDrcCount > 0);
516       uniDrcPayloadPresent |=
517           (hDrcDec->uniDrcConfig.downmixInstructionsCount > 0);
518       return (LONG)(uniDrcPayloadPresent && (drcOn || lnOn));
519     }
520     case DRC_DEC_TARGET_CHANNEL_COUNT_SELECTED:
521       return (LONG)hDrcDec->selProcOutput.targetChannelCount;
522     case DRC_DEC_OUTPUT_LOUDNESS:
523       return (LONG)hDrcDec->selProcOutput.outputLoudness;
524     default:
525       return 0;
526   }
527 }
528 
529 DRC_DEC_ERROR
FDK_drcDec_SetInterfaceParameters(HANDLE_DRC_DECODER hDrcDec,HANDLE_UNI_DRC_INTERFACE hUniDrcInterface)530 FDK_drcDec_SetInterfaceParameters(HANDLE_DRC_DECODER hDrcDec,
531                                   HANDLE_UNI_DRC_INTERFACE hUniDrcInterface) {
532   return DRC_DEC_UNSUPPORTED_FUNCTION;
533 }
534 
535 DRC_DEC_ERROR
FDK_drcDec_SetSelectionProcessMpeghParameters_simple(HANDLE_DRC_DECODER hDrcDec,const int groupPresetIdRequested,const int numGroupIdsRequested,const int * groupIdsRequested)536 FDK_drcDec_SetSelectionProcessMpeghParameters_simple(
537     HANDLE_DRC_DECODER hDrcDec, const int groupPresetIdRequested,
538     const int numGroupIdsRequested, const int* groupIdsRequested) {
539   return DRC_DEC_UNSUPPORTED_FUNCTION;
540 }
541 
542 DRC_DEC_ERROR
FDK_drcDec_SetDownmixInstructions(HANDLE_DRC_DECODER hDrcDec,const int numDownmixId,const int * downmixId,const int * targetLayout,const int * targetChannelCount)543 FDK_drcDec_SetDownmixInstructions(HANDLE_DRC_DECODER hDrcDec,
544                                   const int numDownmixId, const int* downmixId,
545                                   const int* targetLayout,
546                                   const int* targetChannelCount) {
547   return DRC_DEC_UNSUPPORTED_FUNCTION;
548 }
549 
FDK_drcDec_SetSelectionProcessOutput(HANDLE_DRC_DECODER hDrcDec,HANDLE_SEL_PROC_OUTPUT hSelProcOutput)550 void FDK_drcDec_SetSelectionProcessOutput(
551     HANDLE_DRC_DECODER hDrcDec, HANDLE_SEL_PROC_OUTPUT hSelProcOutput) {}
552 
553 HANDLE_SEL_PROC_OUTPUT
FDK_drcDec_GetSelectionProcessOutput(HANDLE_DRC_DECODER hDrcDec)554 FDK_drcDec_GetSelectionProcessOutput(HANDLE_DRC_DECODER hDrcDec) {
555   if (hDrcDec == NULL) return NULL;
556 
557   return &(hDrcDec->selProcOutput);
558 }
559 
560 LONG /* FIXP_DBL, e = 7 */
FDK_drcDec_GetGroupLoudness(HANDLE_SEL_PROC_OUTPUT hSelProcOutput,const int groupID,int * groupLoudnessAvailable)561 FDK_drcDec_GetGroupLoudness(HANDLE_SEL_PROC_OUTPUT hSelProcOutput,
562                             const int groupID, int* groupLoudnessAvailable) {
563   return (LONG)0;
564 }
565 
FDK_drcDec_SetChannelGains(HANDLE_DRC_DECODER hDrcDec,const int numChannels,const int frameSize,FIXP_DBL * channelGainDb,FIXP_DBL * audioBuffer,const int audioBufferChannelOffset)566 void FDK_drcDec_SetChannelGains(HANDLE_DRC_DECODER hDrcDec,
567                                 const int numChannels, const int frameSize,
568                                 FIXP_DBL* channelGainDb, FIXP_DBL* audioBuffer,
569                                 const int audioBufferChannelOffset) {
570   int err;
571 
572   if (hDrcDec == NULL) return;
573 
574   err = drcDec_GainDecoder_SetLoudnessNormalizationGainDb(
575       hDrcDec->hGainDec, hDrcDec->selProcOutput.loudnessNormalizationGainDb);
576   if (err) return;
577 
578   drcDec_GainDecoder_SetChannelGains(hDrcDec->hGainDec, numChannels, frameSize,
579                                      channelGainDb, audioBufferChannelOffset,
580                                      audioBuffer);
581 }
582 
583 DRC_DEC_ERROR
FDK_drcDec_ReadUniDrcConfig(HANDLE_DRC_DECODER hDrcDec,HANDLE_FDK_BITSTREAM hBitstream)584 FDK_drcDec_ReadUniDrcConfig(HANDLE_DRC_DECODER hDrcDec,
585                             HANDLE_FDK_BITSTREAM hBitstream) {
586   DRC_ERROR dErr = DE_OK;
587 
588   if (hDrcDec == NULL) return DRC_DEC_NOT_OPENED;
589 
590   if (hDrcDec->codecMode == DRC_DEC_MPEG_D_USAC) {
591     dErr = drcDec_readUniDrcConfig(hBitstream, &(hDrcDec->uniDrcConfig));
592   } else
593     return DRC_DEC_NOT_OK;
594 
595   if (dErr) {
596     /* clear config, if parsing error occured */
597     FDKmemclear(&hDrcDec->uniDrcConfig, sizeof(hDrcDec->uniDrcConfig));
598     hDrcDec->uniDrcConfig.diff = 1;
599   }
600 
601   startSelectionProcess(hDrcDec);
602 
603   return DRC_DEC_OK;
604 }
605 
606 DRC_DEC_ERROR
FDK_drcDec_ReadDownmixInstructions_Box(HANDLE_DRC_DECODER hDrcDec,HANDLE_FDK_BITSTREAM hBitstream)607 FDK_drcDec_ReadDownmixInstructions_Box(HANDLE_DRC_DECODER hDrcDec,
608                                        HANDLE_FDK_BITSTREAM hBitstream) {
609   DRC_ERROR dErr = DE_OK;
610 
611   if (hDrcDec == NULL) return DRC_DEC_NOT_OPENED;
612 
613   return DRC_DEC_NOT_OK;
614 
615   if (dErr) {
616     /* clear config, if parsing error occurred */
617     FDKmemclear(&hDrcDec->uniDrcConfig.downmixInstructions,
618                 sizeof(hDrcDec->uniDrcConfig.downmixInstructions));
619     hDrcDec->uniDrcConfig.downmixInstructionsCount = 0;
620     hDrcDec->uniDrcConfig.downmixInstructionsCountV0 = 0;
621     hDrcDec->uniDrcConfig.downmixInstructionsCountV1 = 0;
622     hDrcDec->uniDrcConfig.diff = 1;
623   }
624 
625   startSelectionProcess(hDrcDec);
626 
627   return DRC_DEC_OK;
628 }
629 
630 DRC_DEC_ERROR
FDK_drcDec_ReadUniDrcInstructions_Box(HANDLE_DRC_DECODER hDrcDec,HANDLE_FDK_BITSTREAM hBitstream)631 FDK_drcDec_ReadUniDrcInstructions_Box(HANDLE_DRC_DECODER hDrcDec,
632                                       HANDLE_FDK_BITSTREAM hBitstream) {
633   DRC_ERROR dErr = DE_OK;
634 
635   if (hDrcDec == NULL) return DRC_DEC_NOT_OPENED;
636 
637   return DRC_DEC_NOT_OK;
638 
639   if (dErr) {
640     /* clear config, if parsing error occurred */
641     FDKmemclear(&hDrcDec->uniDrcConfig.drcInstructionsUniDrc,
642                 sizeof(hDrcDec->uniDrcConfig.drcInstructionsUniDrc));
643     hDrcDec->uniDrcConfig.drcInstructionsUniDrcCount = 0;
644     hDrcDec->uniDrcConfig.drcInstructionsUniDrcCountV0 = 0;
645     hDrcDec->uniDrcConfig.drcInstructionsUniDrcCountV1 = 0;
646     hDrcDec->uniDrcConfig.diff = 1;
647   }
648 
649   startSelectionProcess(hDrcDec);
650 
651   return DRC_DEC_OK;
652 }
653 
654 DRC_DEC_ERROR
FDK_drcDec_ReadUniDrcCoefficients_Box(HANDLE_DRC_DECODER hDrcDec,HANDLE_FDK_BITSTREAM hBitstream)655 FDK_drcDec_ReadUniDrcCoefficients_Box(HANDLE_DRC_DECODER hDrcDec,
656                                       HANDLE_FDK_BITSTREAM hBitstream) {
657   DRC_ERROR dErr = DE_OK;
658 
659   if (hDrcDec == NULL) return DRC_DEC_NOT_OPENED;
660 
661   return DRC_DEC_NOT_OK;
662 
663   if (dErr) {
664     /* clear config, if parsing error occurred */
665     FDKmemclear(&hDrcDec->uniDrcConfig.drcCoefficientsUniDrc,
666                 sizeof(hDrcDec->uniDrcConfig.drcCoefficientsUniDrc));
667     hDrcDec->uniDrcConfig.drcCoefficientsUniDrcCount = 0;
668     hDrcDec->uniDrcConfig.drcCoefficientsUniDrcCountV0 = 0;
669     hDrcDec->uniDrcConfig.drcCoefficientsUniDrcCountV1 = 0;
670     hDrcDec->uniDrcConfig.diff = 1;
671   }
672 
673   startSelectionProcess(hDrcDec);
674 
675   return DRC_DEC_OK;
676 }
677 
678 DRC_DEC_ERROR
FDK_drcDec_ReadLoudnessInfoSet(HANDLE_DRC_DECODER hDrcDec,HANDLE_FDK_BITSTREAM hBitstream)679 FDK_drcDec_ReadLoudnessInfoSet(HANDLE_DRC_DECODER hDrcDec,
680                                HANDLE_FDK_BITSTREAM hBitstream) {
681   DRC_ERROR dErr = DE_OK;
682 
683   if (hDrcDec == NULL) return DRC_DEC_NOT_OPENED;
684 
685   if (hDrcDec->codecMode == DRC_DEC_MPEG_D_USAC) {
686     dErr = drcDec_readLoudnessInfoSet(hBitstream, &(hDrcDec->loudnessInfoSet));
687   } else
688     return DRC_DEC_NOT_OK;
689 
690   if (dErr) {
691     /* clear config, if parsing error occurred */
692     FDKmemclear(&hDrcDec->loudnessInfoSet, sizeof(hDrcDec->loudnessInfoSet));
693     hDrcDec->loudnessInfoSet.diff = 1;
694   }
695 
696   startSelectionProcess(hDrcDec);
697 
698   return DRC_DEC_OK;
699 }
700 
701 DRC_DEC_ERROR
FDK_drcDec_ReadLoudnessBox(HANDLE_DRC_DECODER hDrcDec,HANDLE_FDK_BITSTREAM hBitstream)702 FDK_drcDec_ReadLoudnessBox(HANDLE_DRC_DECODER hDrcDec,
703                            HANDLE_FDK_BITSTREAM hBitstream) {
704   DRC_ERROR dErr = DE_OK;
705 
706   if (hDrcDec == NULL) return DRC_DEC_NOT_OPENED;
707 
708   return DRC_DEC_NOT_OK;
709 
710   if (dErr) {
711     /* clear config, if parsing error occurred */
712     FDKmemclear(&hDrcDec->loudnessInfoSet, sizeof(hDrcDec->loudnessInfoSet));
713     hDrcDec->loudnessInfoSet.diff = 1;
714   }
715 
716   startSelectionProcess(hDrcDec);
717 
718   return DRC_DEC_OK;
719 }
720 
721 DRC_DEC_ERROR
FDK_drcDec_ReadUniDrcGain(HANDLE_DRC_DECODER hDrcDec,HANDLE_FDK_BITSTREAM hBitstream)722 FDK_drcDec_ReadUniDrcGain(HANDLE_DRC_DECODER hDrcDec,
723                           HANDLE_FDK_BITSTREAM hBitstream) {
724   DRC_ERROR dErr = DE_OK;
725 
726   if (hDrcDec == NULL) return DRC_DEC_NOT_OPENED;
727   if (!hDrcDec->status) {
728     return DRC_DEC_OK;
729   }
730 
731   dErr = drcDec_readUniDrcGain(
732       hBitstream, &(hDrcDec->uniDrcConfig),
733       drcDec_GainDecoder_GetFrameSize(hDrcDec->hGainDec),
734       drcDec_GainDecoder_GetDeltaTminDefault(hDrcDec->hGainDec),
735       &(hDrcDec->uniDrcGain));
736   if (dErr) return DRC_DEC_NOT_OK;
737 
738   if (_getGainStatus(&(hDrcDec->uniDrcGain))) {
739     hDrcDec->status = DRC_DEC_NEW_GAIN_PAYLOAD;
740   }
741 
742   return DRC_DEC_OK;
743 }
744 
745 DRC_DEC_ERROR
FDK_drcDec_ReadUniDrc(HANDLE_DRC_DECODER hDrcDec,HANDLE_FDK_BITSTREAM hBitstream)746 FDK_drcDec_ReadUniDrc(HANDLE_DRC_DECODER hDrcDec,
747                       HANDLE_FDK_BITSTREAM hBitstream) {
748   DRC_ERROR dErr = DE_OK;
749 
750   if (hDrcDec == NULL) return DRC_DEC_NOT_OPENED;
751   if (!hDrcDec->status) return DRC_DEC_NOT_READY;
752 
753   dErr = drcDec_readUniDrc(
754       hBitstream, &(hDrcDec->uniDrcConfig), &(hDrcDec->loudnessInfoSet),
755       drcDec_GainDecoder_GetFrameSize(hDrcDec->hGainDec),
756       drcDec_GainDecoder_GetDeltaTminDefault(hDrcDec->hGainDec),
757       &(hDrcDec->uniDrcGain));
758 
759   startSelectionProcess(hDrcDec);
760   if (dErr) return DRC_DEC_NOT_OK;
761 
762   if (_getGainStatus(&(hDrcDec->uniDrcGain))) {
763     hDrcDec->status = DRC_DEC_NEW_GAIN_PAYLOAD;
764   }
765 
766   return DRC_DEC_OK;
767 }
768 
769 DRC_DEC_ERROR
FDK_drcDec_Preprocess(HANDLE_DRC_DECODER hDrcDec)770 FDK_drcDec_Preprocess(HANDLE_DRC_DECODER hDrcDec) {
771   DRC_ERROR dErr = DE_OK;
772 
773   if (hDrcDec == NULL) return DRC_DEC_NOT_OPENED;
774   if (!hDrcDec->status) return DRC_DEC_NOT_READY;
775   if (!(hDrcDec->functionalRange & DRC_DEC_GAIN)) return DRC_DEC_NOT_OK;
776 
777   if (hDrcDec->status != DRC_DEC_NEW_GAIN_PAYLOAD) {
778     /* no new gain payload was read, e.g. during concalment or flushing.
779        Generate DRC gains based on the stored DRC gains of last frames */
780     drcDec_GainDecoder_Conceal(hDrcDec->hGainDec, &(hDrcDec->uniDrcConfig),
781                                &(hDrcDec->uniDrcGain));
782   }
783 
784   dErr = drcDec_GainDecoder_Preprocess(
785       hDrcDec->hGainDec, &(hDrcDec->uniDrcGain),
786       hDrcDec->selProcOutput.loudnessNormalizationGainDb,
787       hDrcDec->selProcOutput.boost, hDrcDec->selProcOutput.compress);
788   if (dErr) return DRC_DEC_NOT_OK;
789   hDrcDec->status = DRC_DEC_INTERPOLATION_PREPARED;
790 
791   return DRC_DEC_OK;
792 }
793 
794 DRC_DEC_ERROR
FDK_drcDec_ProcessTime(HANDLE_DRC_DECODER hDrcDec,const int delaySamples,const DRC_DEC_LOCATION drcLocation,const int channelOffset,const int drcChannelOffset,const int numChannelsProcessed,FIXP_DBL * realBuffer,const int timeDataChannelOffset)795 FDK_drcDec_ProcessTime(HANDLE_DRC_DECODER hDrcDec, const int delaySamples,
796                        const DRC_DEC_LOCATION drcLocation,
797                        const int channelOffset, const int drcChannelOffset,
798                        const int numChannelsProcessed, FIXP_DBL* realBuffer,
799                        const int timeDataChannelOffset) {
800   DRC_ERROR dErr = DE_OK;
801 
802   if (hDrcDec == NULL) return DRC_DEC_NOT_OPENED;
803   if (!(hDrcDec->functionalRange & DRC_DEC_GAIN)) return DRC_DEC_NOT_OK;
804   if (hDrcDec->status != DRC_DEC_INTERPOLATION_PREPARED)
805     return DRC_DEC_NOT_READY;
806 
807   dErr = drcDec_GainDecoder_ProcessTimeDomain(
808       hDrcDec->hGainDec, delaySamples, (GAIN_DEC_LOCATION)drcLocation,
809       channelOffset, drcChannelOffset, numChannelsProcessed,
810       timeDataChannelOffset, realBuffer);
811   if (dErr) return DRC_DEC_NOT_OK;
812 
813   return DRC_DEC_OK;
814 }
815 
816 DRC_DEC_ERROR
FDK_drcDec_ProcessFreq(HANDLE_DRC_DECODER hDrcDec,const int delaySamples,const DRC_DEC_LOCATION drcLocation,const int channelOffset,const int drcChannelOffset,const int numChannelsProcessed,const int processSingleTimeslot,FIXP_DBL ** realBuffer,FIXP_DBL ** imagBuffer)817 FDK_drcDec_ProcessFreq(HANDLE_DRC_DECODER hDrcDec, const int delaySamples,
818                        const DRC_DEC_LOCATION drcLocation,
819                        const int channelOffset, const int drcChannelOffset,
820                        const int numChannelsProcessed,
821                        const int processSingleTimeslot, FIXP_DBL** realBuffer,
822                        FIXP_DBL** imagBuffer) {
823   DRC_ERROR dErr = DE_OK;
824 
825   if (hDrcDec == NULL) return DRC_DEC_NOT_OPENED;
826   if (!(hDrcDec->functionalRange & DRC_DEC_GAIN)) return DRC_DEC_NOT_OK;
827   if (hDrcDec->status != DRC_DEC_INTERPOLATION_PREPARED)
828     return DRC_DEC_NOT_READY;
829 
830   dErr = drcDec_GainDecoder_ProcessSubbandDomain(
831       hDrcDec->hGainDec, delaySamples, (GAIN_DEC_LOCATION)drcLocation,
832       channelOffset, drcChannelOffset, numChannelsProcessed,
833       processSingleTimeslot, realBuffer, imagBuffer);
834   if (dErr) return DRC_DEC_NOT_OK;
835 
836   return DRC_DEC_OK;
837 }
838 
839 DRC_DEC_ERROR
FDK_drcDec_ApplyDownmix(HANDLE_DRC_DECODER hDrcDec,int * reverseInChannelMap,int * reverseOutChannelMap,FIXP_DBL * realBuffer,int * pNChannels)840 FDK_drcDec_ApplyDownmix(HANDLE_DRC_DECODER hDrcDec, int* reverseInChannelMap,
841                         int* reverseOutChannelMap, FIXP_DBL* realBuffer,
842                         int* pNChannels) {
843   SEL_PROC_OUTPUT* pSelProcOutput = &(hDrcDec->selProcOutput);
844   int baseChCnt = pSelProcOutput->baseChannelCount;
845   int targetChCnt = pSelProcOutput->targetChannelCount;
846   int frameSize, n, ic, oc;
847   FIXP_DBL tmp_out[8];
848   FIXP_DBL* audioChannels[8];
849 
850   if (hDrcDec == NULL) return DRC_DEC_NOT_OPENED;
851   if (!(hDrcDec->functionalRange & DRC_DEC_GAIN)) return DRC_DEC_NOT_OK;
852 
853   /* only downmix is performed here, no upmix.
854      Downmix is only performed if downmix coefficients are provided.
855      All other cases of downmix and upmix are treated by pcmDmx library. */
856   if (pSelProcOutput->downmixMatrixPresent == 0)
857     return DRC_DEC_OK;                             /* no downmix */
858   if (targetChCnt >= baseChCnt) return DRC_DEC_OK; /* downmix only */
859 
860   /* sanity checks */
861   if (realBuffer == NULL) return DRC_DEC_NOT_OK;
862   if (reverseInChannelMap == NULL) return DRC_DEC_NOT_OK;
863   if (reverseOutChannelMap == NULL) return DRC_DEC_NOT_OK;
864   if (baseChCnt > 8) return DRC_DEC_NOT_OK;
865   if (baseChCnt != *pNChannels) return DRC_DEC_NOT_OK;
866   if (targetChCnt > 8) return DRC_DEC_NOT_OK;
867 
868   frameSize = drcDec_GainDecoder_GetFrameSize(hDrcDec->hGainDec);
869 
870   for (ic = 0; ic < baseChCnt; ic++) {
871     audioChannels[ic] = &(realBuffer[ic * frameSize]);
872   }
873 
874   /* in-place downmix */
875   for (n = 0; n < frameSize; n++) {
876     for (oc = 0; oc < targetChCnt; oc++) {
877       tmp_out[oc] = (FIXP_DBL)0;
878       for (ic = 0; ic < baseChCnt; ic++) {
879         tmp_out[oc] +=
880             fMultDiv2(audioChannels[ic][n],
881                       pSelProcOutput->downmixMatrix[reverseInChannelMap[ic]]
882                                                    [reverseOutChannelMap[oc]])
883             << 3;
884       }
885     }
886     for (oc = 0; oc < targetChCnt; oc++) {
887       if (oc >= baseChCnt) break;
888       audioChannels[oc][n] = tmp_out[oc];
889     }
890   }
891 
892   for (oc = targetChCnt; oc < baseChCnt; oc++) {
893     FDKmemset(audioChannels[oc], 0, frameSize * sizeof(FIXP_DBL));
894   }
895 
896   *pNChannels = targetChCnt;
897 
898   return DRC_DEC_OK;
899 }
900 
901 /* Get library info for this module. */
902 DRC_DEC_ERROR
FDK_drcDec_GetLibInfo(LIB_INFO * info)903 FDK_drcDec_GetLibInfo(LIB_INFO* info) {
904   int i;
905 
906   if (info == NULL) {
907     return DRC_DEC_INVALID_PARAM;
908   }
909 
910   /* Search for next free tab */
911   for (i = 0; i < FDK_MODULE_LAST; i++) {
912     if (info[i].module_id == FDK_NONE) break;
913   }
914   if (i == FDK_MODULE_LAST) {
915     return DRC_DEC_NOT_OK;
916   }
917 
918   /* Add the library info */
919   info[i].module_id = FDK_UNIDRCDEC;
920   info[i].version = LIB_VERSION(DRCDEC_LIB_VL0, DRCDEC_LIB_VL1, DRCDEC_LIB_VL2);
921   LIB_VERSION_STRING(info + i);
922   info[i].build_date = DRCDEC_LIB_BUILD_DATE;
923   info[i].build_time = DRCDEC_LIB_BUILD_TIME;
924   info[i].title = DRCDEC_LIB_TITLE;
925 
926   return DRC_DEC_OK;
927 }
928