/* -----------------------------------------------------------------------------
|
Software License for The Fraunhofer FDK AAC Codec Library for Android
|
|
© Copyright 1995 - 2019 Fraunhofer-Gesellschaft zur Förderung der angewandten
|
Forschung e.V. All rights reserved.
|
|
1. INTRODUCTION
|
The Fraunhofer FDK AAC Codec Library for Android ("FDK AAC Codec") is software
|
that implements the MPEG Advanced Audio Coding ("AAC") encoding and decoding
|
scheme for digital audio. This FDK AAC Codec software is intended to be used on
|
a wide variety of Android devices.
|
|
AAC's HE-AAC and HE-AAC v2 versions are regarded as today's most efficient
|
general perceptual audio codecs. AAC-ELD is considered the best-performing
|
full-bandwidth communications codec by independent studies and is widely
|
deployed. AAC has been standardized by ISO and IEC as part of the MPEG
|
specifications.
|
|
Patent licenses for necessary patent claims for the FDK AAC Codec (including
|
those of Fraunhofer) may be obtained through Via Licensing
|
(www.vialicensing.com) or through the respective patent owners individually for
|
the purpose of encoding or decoding bit streams in products that are compliant
|
with the ISO/IEC MPEG audio standards. Please note that most manufacturers of
|
Android devices already license these patent claims through Via Licensing or
|
directly from the patent owners, and therefore FDK AAC Codec software may
|
already be covered under those patent licenses when it is used for those
|
licensed purposes only.
|
|
Commercially-licensed AAC software libraries, including floating-point versions
|
with enhanced sound quality, are also available from Fraunhofer. Users are
|
encouraged to check the Fraunhofer website for additional applications
|
information and documentation.
|
|
2. COPYRIGHT LICENSE
|
|
Redistribution and use in source and binary forms, with or without modification,
|
are permitted without payment of copyright license fees provided that you
|
satisfy the following conditions:
|
|
You must retain the complete text of this software license in redistributions of
|
the FDK AAC Codec or your modifications thereto in source code form.
|
|
You must retain the complete text of this software license in the documentation
|
and/or other materials provided with redistributions of the FDK AAC Codec or
|
your modifications thereto in binary form. You must make available free of
|
charge copies of the complete source code of the FDK AAC Codec and your
|
modifications thereto to recipients of copies in binary form.
|
|
The name of Fraunhofer may not be used to endorse or promote products derived
|
from this library without prior written permission.
|
|
You may not charge copyright license fees for anyone to use, copy or distribute
|
the FDK AAC Codec software or your modifications thereto.
|
|
Your modified versions of the FDK AAC Codec must carry prominent notices stating
|
that you changed the software and the date of any change. For modified versions
|
of the FDK AAC Codec, the term "Fraunhofer FDK AAC Codec Library for Android"
|
must be replaced by the term "Third-Party Modified Version of the Fraunhofer FDK
|
AAC Codec Library for Android."
|
|
3. NO PATENT LICENSE
|
|
NO EXPRESS OR IMPLIED LICENSES TO ANY PATENT CLAIMS, including without
|
limitation the patents of Fraunhofer, ARE GRANTED BY THIS SOFTWARE LICENSE.
|
Fraunhofer provides no warranty of patent non-infringement with respect to this
|
software.
|
|
You may use this FDK AAC Codec software or modifications thereto only for
|
purposes that are authorized by appropriate patent licenses.
|
|
4. DISCLAIMER
|
|
This FDK AAC Codec software is provided by Fraunhofer on behalf of the copyright
|
holders and contributors "AS IS" and WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES,
|
including but not limited to the implied warranties of merchantability and
|
fitness for a particular purpose. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
|
CONTRIBUTORS BE LIABLE for any direct, indirect, incidental, special, exemplary,
|
or consequential damages, including but not limited to procurement of substitute
|
goods or services; loss of use, data, or profits, or business interruption,
|
however caused and on any theory of liability, whether in contract, strict
|
liability, or tort (including negligence), arising in any way out of the use of
|
this software, even if advised of the possibility of such damage.
|
|
5. CONTACT INFORMATION
|
|
Fraunhofer Institute for Integrated Circuits IIS
|
Attention: Audio and Multimedia Departments - FDK AAC LL
|
Am Wolfsmantel 33
|
91058 Erlangen, Germany
|
|
www.iis.fraunhofer.de/amm
|
amm-info@iis.fraunhofer.de
|
----------------------------------------------------------------------------- */
|
|
/************************* MPEG-D DRC decoder library **************************
|
|
Author(s): Bernhard Neugebauer
|
|
Description: MPEG-D DRC Decoder
|
|
*******************************************************************************/
|
|
#include "drcDec_reader.h"
|
#include "drcDec_gainDecoder.h"
|
#include "FDK_drcDecLib.h"
|
|
#include "drcDec_selectionProcess.h"
|
#include "drcDec_tools.h"
|
|
/* Decoder library info */
|
#define DRCDEC_LIB_VL0 2
|
#define DRCDEC_LIB_VL1 1
|
#define DRCDEC_LIB_VL2 0
|
#define DRCDEC_LIB_TITLE "MPEG-D DRC Decoder Lib"
|
#ifdef __ANDROID__
|
#define DRCDEC_LIB_BUILD_DATE ""
|
#define DRCDEC_LIB_BUILD_TIME ""
|
#else
|
#define DRCDEC_LIB_BUILD_DATE __DATE__
|
#define DRCDEC_LIB_BUILD_TIME __TIME__
|
#endif
|
|
typedef enum {
|
DRC_DEC_NOT_INITIALIZED = 0,
|
DRC_DEC_INITIALIZED,
|
DRC_DEC_NEW_GAIN_PAYLOAD,
|
DRC_DEC_INTERPOLATION_PREPARED
|
} DRC_DEC_STATUS;
|
|
struct s_drc_decoder {
|
DRC_DEC_CODEC_MODE codecMode;
|
DRC_DEC_FUNCTIONAL_RANGE functionalRange;
|
DRC_DEC_STATUS status;
|
|
/* handles of submodules */
|
HANDLE_DRC_GAIN_DECODER hGainDec;
|
HANDLE_DRC_SELECTION_PROCESS hSelectionProc;
|
int selProcInputDiff;
|
|
/* data structs */
|
UNI_DRC_CONFIG uniDrcConfig;
|
LOUDNESS_INFO_SET loudnessInfoSet;
|
UNI_DRC_GAIN uniDrcGain;
|
|
SEL_PROC_OUTPUT selProcOutput;
|
} DRC_DECODER;
|
|
static int isResetNeeded(HANDLE_DRC_DECODER hDrcDec,
|
const SEL_PROC_OUTPUT oldSelProcOutput) {
|
int i, resetNeeded = 0;
|
|
if (hDrcDec->selProcOutput.numSelectedDrcSets !=
|
oldSelProcOutput.numSelectedDrcSets) {
|
resetNeeded = 1;
|
} else {
|
for (i = 0; i < hDrcDec->selProcOutput.numSelectedDrcSets; i++) {
|
if (hDrcDec->selProcOutput.selectedDrcSetIds[i] !=
|
oldSelProcOutput.selectedDrcSetIds[i])
|
resetNeeded = 1;
|
if (hDrcDec->selProcOutput.selectedDownmixIds[i] !=
|
oldSelProcOutput.selectedDownmixIds[i])
|
resetNeeded = 1;
|
}
|
}
|
|
if (hDrcDec->selProcOutput.boost != oldSelProcOutput.boost) resetNeeded = 1;
|
if (hDrcDec->selProcOutput.compress != oldSelProcOutput.compress)
|
resetNeeded = 1;
|
|
/* Note: Changes in downmix matrix are not caught, as they don't affect the
|
* DRC gain decoder */
|
|
return resetNeeded;
|
}
|
|
static void startSelectionProcess(HANDLE_DRC_DECODER hDrcDec) {
|
int uniDrcConfigHasChanged = 0;
|
SEL_PROC_OUTPUT oldSelProcOutput = hDrcDec->selProcOutput;
|
|
if (!hDrcDec->status) return;
|
|
if (hDrcDec->functionalRange & DRC_DEC_SELECTION) {
|
uniDrcConfigHasChanged = hDrcDec->uniDrcConfig.diff;
|
if (hDrcDec->uniDrcConfig.diff || hDrcDec->loudnessInfoSet.diff ||
|
hDrcDec->selProcInputDiff) {
|
/* in case of an error, signal that selection process was not successful
|
*/
|
hDrcDec->selProcOutput.numSelectedDrcSets = 0;
|
|
drcDec_SelectionProcess_Process(
|
hDrcDec->hSelectionProc, &(hDrcDec->uniDrcConfig),
|
&(hDrcDec->loudnessInfoSet), &(hDrcDec->selProcOutput));
|
|
hDrcDec->selProcInputDiff = 0;
|
hDrcDec->uniDrcConfig.diff = 0;
|
hDrcDec->loudnessInfoSet.diff = 0;
|
}
|
}
|
|
if (hDrcDec->functionalRange & DRC_DEC_GAIN) {
|
if (isResetNeeded(hDrcDec, oldSelProcOutput) || uniDrcConfigHasChanged) {
|
drcDec_GainDecoder_Config(hDrcDec->hGainDec, &(hDrcDec->uniDrcConfig),
|
hDrcDec->selProcOutput.numSelectedDrcSets,
|
hDrcDec->selProcOutput.selectedDrcSetIds,
|
hDrcDec->selProcOutput.selectedDownmixIds);
|
}
|
}
|
}
|
|
DRC_DEC_ERROR
|
FDK_drcDec_Open(HANDLE_DRC_DECODER* phDrcDec,
|
const DRC_DEC_FUNCTIONAL_RANGE functionalRange) {
|
DRC_ERROR dErr = DE_OK;
|
DRCDEC_SELECTION_PROCESS_RETURN sErr = DRCDEC_SELECTION_PROCESS_NO_ERROR;
|
HANDLE_DRC_DECODER hDrcDec;
|
|
*phDrcDec = (HANDLE_DRC_DECODER)FDKcalloc(1, sizeof(DRC_DECODER));
|
if (!*phDrcDec) return DRC_DEC_OUT_OF_MEMORY;
|
hDrcDec = *phDrcDec;
|
|
hDrcDec->functionalRange = functionalRange;
|
|
hDrcDec->status = DRC_DEC_NOT_INITIALIZED;
|
hDrcDec->codecMode = DRC_DEC_CODEC_MODE_UNDEFINED;
|
|
if (hDrcDec->functionalRange & DRC_DEC_SELECTION) {
|
sErr = drcDec_SelectionProcess_Create(&(hDrcDec->hSelectionProc));
|
if (sErr) return DRC_DEC_OUT_OF_MEMORY;
|
sErr = drcDec_SelectionProcess_Init(hDrcDec->hSelectionProc);
|
if (sErr) return DRC_DEC_NOT_OK;
|
hDrcDec->selProcInputDiff = 1;
|
}
|
|
if (hDrcDec->functionalRange & DRC_DEC_GAIN) {
|
dErr = drcDec_GainDecoder_Open(&(hDrcDec->hGainDec));
|
if (dErr) return DRC_DEC_OUT_OF_MEMORY;
|
}
|
|
return DRC_DEC_OK;
|
}
|
|
DRC_DEC_ERROR
|
FDK_drcDec_SetCodecMode(HANDLE_DRC_DECODER hDrcDec,
|
const DRC_DEC_CODEC_MODE codecMode) {
|
DRC_ERROR dErr = DE_OK;
|
DRCDEC_SELECTION_PROCESS_RETURN sErr = DRCDEC_SELECTION_PROCESS_NO_ERROR;
|
|
if (hDrcDec == NULL) return DRC_DEC_NOT_OPENED;
|
|
if (hDrcDec->codecMode ==
|
DRC_DEC_CODEC_MODE_UNDEFINED) { /* Set codec mode, if it is set for the
|
first time */
|
hDrcDec->codecMode = codecMode;
|
|
if (hDrcDec->functionalRange & DRC_DEC_SELECTION) {
|
sErr = drcDec_SelectionProcess_SetCodecMode(
|
hDrcDec->hSelectionProc, (SEL_PROC_CODEC_MODE)codecMode);
|
if (sErr) return DRC_DEC_NOT_OK;
|
hDrcDec->selProcInputDiff = 1;
|
}
|
|
if (hDrcDec->functionalRange & DRC_DEC_GAIN) {
|
DELAY_MODE delayMode;
|
int timeDomainSupported;
|
SUBBAND_DOMAIN_MODE subbandDomainSupported;
|
|
switch (hDrcDec->codecMode) {
|
case DRC_DEC_MPEG_4_AAC:
|
case DRC_DEC_MPEG_D_USAC:
|
case DRC_DEC_MPEG_H_3DA:
|
default:
|
delayMode = DM_REGULAR_DELAY;
|
}
|
|
switch (hDrcDec->codecMode) {
|
case DRC_DEC_MPEG_4_AAC:
|
case DRC_DEC_MPEG_D_USAC:
|
timeDomainSupported = 1;
|
subbandDomainSupported = SDM_OFF;
|
break;
|
case DRC_DEC_MPEG_H_3DA:
|
timeDomainSupported = 1;
|
subbandDomainSupported = SDM_STFT256;
|
break;
|
|
case DRC_DEC_TEST_TIME_DOMAIN:
|
timeDomainSupported = 1;
|
subbandDomainSupported = SDM_OFF;
|
break;
|
case DRC_DEC_TEST_QMF_DOMAIN:
|
timeDomainSupported = 0;
|
subbandDomainSupported = SDM_QMF64;
|
break;
|
case DRC_DEC_TEST_STFT_DOMAIN:
|
timeDomainSupported = 0;
|
subbandDomainSupported = SDM_STFT256;
|
break;
|
|
default:
|
timeDomainSupported = 0;
|
subbandDomainSupported = SDM_OFF;
|
}
|
|
dErr = drcDec_GainDecoder_SetCodecDependentParameters(
|
hDrcDec->hGainDec, delayMode, timeDomainSupported,
|
subbandDomainSupported);
|
if (dErr) return DRC_DEC_NOT_OK;
|
}
|
}
|
|
/* Don't allow changing codecMode if it has already been set. */
|
if (hDrcDec->codecMode != codecMode) return DRC_DEC_NOT_OK;
|
|
return DRC_DEC_OK;
|
}
|
|
DRC_DEC_ERROR
|
FDK_drcDec_Init(HANDLE_DRC_DECODER hDrcDec, const int frameSize,
|
const int sampleRate, const int baseChannelCount) {
|
DRC_ERROR dErr = DE_OK;
|
DRCDEC_SELECTION_PROCESS_RETURN sErr = DRCDEC_SELECTION_PROCESS_NO_ERROR;
|
|
if (hDrcDec == NULL || frameSize == 0 || sampleRate == 0 ||
|
baseChannelCount == 0)
|
return DRC_DEC_OK; /* return without doing anything */
|
|
if (hDrcDec->functionalRange & DRC_DEC_SELECTION) {
|
sErr = drcDec_SelectionProcess_SetParam(
|
hDrcDec->hSelectionProc, SEL_PROC_BASE_CHANNEL_COUNT,
|
(FIXP_DBL)baseChannelCount, &(hDrcDec->selProcInputDiff));
|
if (sErr) return DRC_DEC_NOT_OK;
|
sErr = drcDec_SelectionProcess_SetParam(
|
hDrcDec->hSelectionProc, SEL_PROC_SAMPLE_RATE, (FIXP_DBL)sampleRate,
|
&(hDrcDec->selProcInputDiff));
|
if (sErr) return DRC_DEC_NOT_OK;
|
}
|
|
if (hDrcDec->functionalRange & DRC_DEC_GAIN) {
|
dErr = drcDec_GainDecoder_SetParam(hDrcDec->hGainDec, GAIN_DEC_FRAME_SIZE,
|
frameSize);
|
if (dErr) return DRC_DEC_NOT_OK;
|
dErr = drcDec_GainDecoder_SetParam(hDrcDec->hGainDec, GAIN_DEC_SAMPLE_RATE,
|
sampleRate);
|
if (dErr) return DRC_DEC_NOT_OK;
|
dErr = drcDec_GainDecoder_Init(hDrcDec->hGainDec);
|
if (dErr) return DRC_DEC_NOT_OK;
|
}
|
|
hDrcDec->status = DRC_DEC_INITIALIZED;
|
|
startSelectionProcess(hDrcDec);
|
|
return DRC_DEC_OK;
|
}
|
|
DRC_DEC_ERROR
|
FDK_drcDec_Close(HANDLE_DRC_DECODER* phDrcDec) {
|
HANDLE_DRC_DECODER hDrcDec;
|
|
if (phDrcDec == NULL) {
|
return DRC_DEC_OK;
|
}
|
|
hDrcDec = *phDrcDec;
|
|
if (hDrcDec == NULL) return DRC_DEC_NOT_OPENED;
|
|
if (hDrcDec->functionalRange & DRC_DEC_GAIN) {
|
drcDec_GainDecoder_Close(&(hDrcDec->hGainDec));
|
}
|
|
if (hDrcDec->functionalRange & DRC_DEC_SELECTION) {
|
drcDec_SelectionProcess_Delete(&(hDrcDec->hSelectionProc));
|
}
|
|
FDKfree(*phDrcDec);
|
*phDrcDec = NULL;
|
|
return DRC_DEC_OK;
|
}
|
|
DRC_DEC_ERROR
|
FDK_drcDec_SetParam(HANDLE_DRC_DECODER hDrcDec,
|
const DRC_DEC_USERPARAM requestType,
|
const FIXP_DBL requestValue) {
|
DRC_ERROR dErr = DE_OK;
|
DRCDEC_SELECTION_PROCESS_RETURN sErr = DRCDEC_SELECTION_PROCESS_NO_ERROR;
|
int invalidParameter = 0;
|
|
if (hDrcDec == NULL) return DRC_DEC_NOT_OPENED;
|
|
if (hDrcDec->functionalRange & DRC_DEC_GAIN) {
|
switch (requestType) {
|
case DRC_DEC_SAMPLE_RATE:
|
dErr = drcDec_GainDecoder_SetParam(
|
hDrcDec->hGainDec, GAIN_DEC_SAMPLE_RATE, (int)requestValue);
|
if (dErr) return DRC_DEC_PARAM_OUT_OF_RANGE;
|
break;
|
case DRC_DEC_FRAME_SIZE:
|
dErr = drcDec_GainDecoder_SetParam(
|
hDrcDec->hGainDec, GAIN_DEC_FRAME_SIZE, (int)requestValue);
|
if (dErr) return DRC_DEC_PARAM_OUT_OF_RANGE;
|
break;
|
default:
|
invalidParameter |= DRC_DEC_GAIN;
|
}
|
}
|
|
if (hDrcDec->functionalRange & DRC_DEC_SELECTION) {
|
switch (requestType) {
|
case DRC_DEC_BOOST:
|
sErr = drcDec_SelectionProcess_SetParam(hDrcDec->hSelectionProc,
|
SEL_PROC_BOOST, requestValue,
|
&(hDrcDec->selProcInputDiff));
|
if (sErr) return DRC_DEC_PARAM_OUT_OF_RANGE;
|
break;
|
case DRC_DEC_COMPRESS:
|
sErr = drcDec_SelectionProcess_SetParam(hDrcDec->hSelectionProc,
|
SEL_PROC_COMPRESS, requestValue,
|
&(hDrcDec->selProcInputDiff));
|
if (sErr) return DRC_DEC_PARAM_OUT_OF_RANGE;
|
break;
|
case DRC_DEC_LOUDNESS_NORMALIZATION_ON:
|
sErr = drcDec_SelectionProcess_SetParam(
|
hDrcDec->hSelectionProc, SEL_PROC_LOUDNESS_NORMALIZATION_ON,
|
requestValue, &(hDrcDec->selProcInputDiff));
|
if (sErr) return DRC_DEC_PARAM_OUT_OF_RANGE;
|
break;
|
case DRC_DEC_TARGET_LOUDNESS:
|
sErr = drcDec_SelectionProcess_SetParam(
|
hDrcDec->hSelectionProc, SEL_PROC_TARGET_LOUDNESS, requestValue,
|
&(hDrcDec->selProcInputDiff));
|
if (sErr) return DRC_DEC_PARAM_OUT_OF_RANGE;
|
break;
|
case DRC_DEC_EFFECT_TYPE:
|
sErr = drcDec_SelectionProcess_SetParam(
|
hDrcDec->hSelectionProc, SEL_PROC_EFFECT_TYPE, requestValue,
|
&(hDrcDec->selProcInputDiff));
|
if (sErr) return DRC_DEC_PARAM_OUT_OF_RANGE;
|
break;
|
case DRC_DEC_DOWNMIX_ID:
|
sErr = drcDec_SelectionProcess_SetParam(
|
hDrcDec->hSelectionProc, SEL_PROC_DOWNMIX_ID, requestValue,
|
&(hDrcDec->selProcInputDiff));
|
if (sErr) return DRC_DEC_PARAM_OUT_OF_RANGE;
|
break;
|
case DRC_DEC_TARGET_CHANNEL_COUNT_REQUESTED:
|
sErr = drcDec_SelectionProcess_SetParam(
|
hDrcDec->hSelectionProc, SEL_PROC_TARGET_CHANNEL_COUNT,
|
requestValue, &(hDrcDec->selProcInputDiff));
|
if (sErr) return DRC_DEC_PARAM_OUT_OF_RANGE;
|
break;
|
case DRC_DEC_BASE_CHANNEL_COUNT:
|
sErr = drcDec_SelectionProcess_SetParam(
|
hDrcDec->hSelectionProc, SEL_PROC_BASE_CHANNEL_COUNT, requestValue,
|
&(hDrcDec->selProcInputDiff));
|
if (sErr) return DRC_DEC_NOT_OK;
|
break;
|
case DRC_DEC_LOUDNESS_MEASUREMENT_METHOD:
|
sErr = drcDec_SelectionProcess_SetParam(
|
hDrcDec->hSelectionProc, SEL_PROC_LOUDNESS_MEASUREMENT_METHOD,
|
requestValue, &(hDrcDec->selProcInputDiff));
|
if (sErr) return DRC_DEC_PARAM_OUT_OF_RANGE;
|
break;
|
case DRC_DEC_ALBUM_MODE:
|
sErr = drcDec_SelectionProcess_SetParam(
|
hDrcDec->hSelectionProc, SEL_PROC_ALBUM_MODE, requestValue,
|
&(hDrcDec->selProcInputDiff));
|
if (sErr) return DRC_DEC_PARAM_OUT_OF_RANGE;
|
break;
|
default:
|
invalidParameter |= DRC_DEC_SELECTION;
|
}
|
}
|
|
if (invalidParameter == hDrcDec->functionalRange)
|
return DRC_DEC_INVALID_PARAM;
|
|
/* All parameters need a new start of the selection process */
|
startSelectionProcess(hDrcDec);
|
|
return DRC_DEC_OK;
|
}
|
|
LONG FDK_drcDec_GetParam(HANDLE_DRC_DECODER hDrcDec,
|
const DRC_DEC_USERPARAM requestType) {
|
if (hDrcDec == NULL) return DRC_DEC_NOT_OPENED;
|
|
switch (requestType) {
|
case DRC_DEC_BOOST:
|
return (LONG)hDrcDec->selProcOutput.boost;
|
case DRC_DEC_COMPRESS:
|
return (LONG)hDrcDec->selProcOutput.compress;
|
case DRC_DEC_IS_MULTIBAND_DRC_1:
|
return (LONG)bitstreamContainsMultibandDrc(&hDrcDec->uniDrcConfig, 0);
|
case DRC_DEC_IS_MULTIBAND_DRC_2:
|
return (LONG)bitstreamContainsMultibandDrc(&hDrcDec->uniDrcConfig, 0x7F);
|
case DRC_DEC_IS_ACTIVE: {
|
/* MPEG-D DRC is considered active (and overrides MPEG-4 DRC), if
|
* uniDrc payload is present (loudnessInfoSet and/or uniDrcConfig)
|
* at least one of DRC and Loudness Control is switched on */
|
int drcOn = drcDec_SelectionProcess_GetParam(
|
hDrcDec->hSelectionProc, SEL_PROC_DYNAMIC_RANGE_CONTROL_ON);
|
int lnOn = drcDec_SelectionProcess_GetParam(
|
hDrcDec->hSelectionProc, SEL_PROC_LOUDNESS_NORMALIZATION_ON);
|
int uniDrcPayloadPresent =
|
(hDrcDec->loudnessInfoSet.loudnessInfoCount > 0);
|
uniDrcPayloadPresent |=
|
(hDrcDec->loudnessInfoSet.loudnessInfoAlbumCount > 0);
|
uniDrcPayloadPresent |=
|
(hDrcDec->uniDrcConfig.drcInstructionsUniDrcCount > 0);
|
uniDrcPayloadPresent |=
|
(hDrcDec->uniDrcConfig.downmixInstructionsCount > 0);
|
return (LONG)(uniDrcPayloadPresent && (drcOn || lnOn));
|
}
|
case DRC_DEC_TARGET_CHANNEL_COUNT_SELECTED:
|
return (LONG)hDrcDec->selProcOutput.targetChannelCount;
|
default:
|
return 0;
|
}
|
}
|
|
DRC_DEC_ERROR
|
FDK_drcDec_SetInterfaceParameters(HANDLE_DRC_DECODER hDrcDec,
|
HANDLE_UNI_DRC_INTERFACE hUniDrcInterface) {
|
return DRC_DEC_UNSUPPORTED_FUNCTION;
|
}
|
|
DRC_DEC_ERROR
|
FDK_drcDec_SetSelectionProcessMpeghParameters_simple(
|
HANDLE_DRC_DECODER hDrcDec, const int groupPresetIdRequested,
|
const int numGroupIdsRequested, const int* groupIdsRequested) {
|
return DRC_DEC_UNSUPPORTED_FUNCTION;
|
}
|
|
DRC_DEC_ERROR
|
FDK_drcDec_SetDownmixInstructions(HANDLE_DRC_DECODER hDrcDec,
|
const int numDownmixId, const int* downmixId,
|
const int* targetLayout,
|
const int* targetChannelCount) {
|
return DRC_DEC_UNSUPPORTED_FUNCTION;
|
}
|
|
void FDK_drcDec_SetSelectionProcessOutput(
|
HANDLE_DRC_DECODER hDrcDec, HANDLE_SEL_PROC_OUTPUT hSelProcOutput) {}
|
|
HANDLE_SEL_PROC_OUTPUT
|
FDK_drcDec_GetSelectionProcessOutput(HANDLE_DRC_DECODER hDrcDec) {
|
if (hDrcDec == NULL) return NULL;
|
|
return &(hDrcDec->selProcOutput);
|
}
|
|
LONG /* FIXP_DBL, e = 7 */
|
FDK_drcDec_GetGroupLoudness(HANDLE_SEL_PROC_OUTPUT hSelProcOutput,
|
const int groupID, int* groupLoudnessAvailable) {
|
return (LONG)0;
|
}
|
|
void FDK_drcDec_SetChannelGains(HANDLE_DRC_DECODER hDrcDec,
|
const int numChannels, const int frameSize,
|
FIXP_DBL* channelGainDb, FIXP_DBL* audioBuffer,
|
const int audioBufferChannelOffset) {
|
int err;
|
|
if (hDrcDec == NULL) return;
|
|
err = drcDec_GainDecoder_SetLoudnessNormalizationGainDb(
|
hDrcDec->hGainDec, hDrcDec->selProcOutput.loudnessNormalizationGainDb);
|
if (err) return;
|
|
drcDec_GainDecoder_SetChannelGains(hDrcDec->hGainDec, numChannels, frameSize,
|
channelGainDb, audioBufferChannelOffset,
|
audioBuffer);
|
}
|
|
DRC_DEC_ERROR
|
FDK_drcDec_ReadUniDrcConfig(HANDLE_DRC_DECODER hDrcDec,
|
HANDLE_FDK_BITSTREAM hBitstream) {
|
DRC_ERROR dErr = DE_OK;
|
|
if (hDrcDec == NULL) return DRC_DEC_NOT_OPENED;
|
|
if (hDrcDec->codecMode == DRC_DEC_MPEG_D_USAC) {
|
dErr = drcDec_readUniDrcConfig(hBitstream, &(hDrcDec->uniDrcConfig));
|
} else
|
return DRC_DEC_NOT_OK;
|
|
if (dErr) {
|
/* clear config, if parsing error occured */
|
FDKmemclear(&hDrcDec->uniDrcConfig, sizeof(hDrcDec->uniDrcConfig));
|
hDrcDec->uniDrcConfig.diff = 1;
|
}
|
|
startSelectionProcess(hDrcDec);
|
|
return DRC_DEC_OK;
|
}
|
|
DRC_DEC_ERROR
|
FDK_drcDec_ReadDownmixInstructions_Box(HANDLE_DRC_DECODER hDrcDec,
|
HANDLE_FDK_BITSTREAM hBitstream) {
|
DRC_ERROR dErr = DE_OK;
|
|
if (hDrcDec == NULL) return DRC_DEC_NOT_OPENED;
|
|
return DRC_DEC_NOT_OK;
|
|
if (dErr) {
|
/* clear config, if parsing error occurred */
|
FDKmemclear(&hDrcDec->uniDrcConfig.downmixInstructions,
|
sizeof(hDrcDec->uniDrcConfig.downmixInstructions));
|
hDrcDec->uniDrcConfig.downmixInstructionsCount = 0;
|
hDrcDec->uniDrcConfig.downmixInstructionsCountV0 = 0;
|
hDrcDec->uniDrcConfig.downmixInstructionsCountV1 = 0;
|
hDrcDec->uniDrcConfig.diff = 1;
|
}
|
|
startSelectionProcess(hDrcDec);
|
|
return DRC_DEC_OK;
|
}
|
|
DRC_DEC_ERROR
|
FDK_drcDec_ReadUniDrcInstructions_Box(HANDLE_DRC_DECODER hDrcDec,
|
HANDLE_FDK_BITSTREAM hBitstream) {
|
DRC_ERROR dErr = DE_OK;
|
|
if (hDrcDec == NULL) return DRC_DEC_NOT_OPENED;
|
|
return DRC_DEC_NOT_OK;
|
|
if (dErr) {
|
/* clear config, if parsing error occurred */
|
FDKmemclear(&hDrcDec->uniDrcConfig.drcInstructionsUniDrc,
|
sizeof(hDrcDec->uniDrcConfig.drcInstructionsUniDrc));
|
hDrcDec->uniDrcConfig.drcInstructionsUniDrcCount = 0;
|
hDrcDec->uniDrcConfig.drcInstructionsUniDrcCountV0 = 0;
|
hDrcDec->uniDrcConfig.drcInstructionsUniDrcCountV1 = 0;
|
hDrcDec->uniDrcConfig.diff = 1;
|
}
|
|
startSelectionProcess(hDrcDec);
|
|
return DRC_DEC_OK;
|
}
|
|
DRC_DEC_ERROR
|
FDK_drcDec_ReadUniDrcCoefficients_Box(HANDLE_DRC_DECODER hDrcDec,
|
HANDLE_FDK_BITSTREAM hBitstream) {
|
DRC_ERROR dErr = DE_OK;
|
|
if (hDrcDec == NULL) return DRC_DEC_NOT_OPENED;
|
|
return DRC_DEC_NOT_OK;
|
|
if (dErr) {
|
/* clear config, if parsing error occurred */
|
FDKmemclear(&hDrcDec->uniDrcConfig.drcCoefficientsUniDrc,
|
sizeof(hDrcDec->uniDrcConfig.drcCoefficientsUniDrc));
|
hDrcDec->uniDrcConfig.drcCoefficientsUniDrcCount = 0;
|
hDrcDec->uniDrcConfig.drcCoefficientsUniDrcCountV0 = 0;
|
hDrcDec->uniDrcConfig.drcCoefficientsUniDrcCountV1 = 0;
|
hDrcDec->uniDrcConfig.diff = 1;
|
}
|
|
startSelectionProcess(hDrcDec);
|
|
return DRC_DEC_OK;
|
}
|
|
DRC_DEC_ERROR
|
FDK_drcDec_ReadLoudnessInfoSet(HANDLE_DRC_DECODER hDrcDec,
|
HANDLE_FDK_BITSTREAM hBitstream) {
|
DRC_ERROR dErr = DE_OK;
|
|
if (hDrcDec == NULL) return DRC_DEC_NOT_OPENED;
|
|
if (hDrcDec->codecMode == DRC_DEC_MPEG_D_USAC) {
|
dErr = drcDec_readLoudnessInfoSet(hBitstream, &(hDrcDec->loudnessInfoSet));
|
} else
|
return DRC_DEC_NOT_OK;
|
|
if (dErr) {
|
/* clear config, if parsing error occurred */
|
FDKmemclear(&hDrcDec->loudnessInfoSet, sizeof(hDrcDec->loudnessInfoSet));
|
hDrcDec->loudnessInfoSet.diff = 1;
|
}
|
|
startSelectionProcess(hDrcDec);
|
|
return DRC_DEC_OK;
|
}
|
|
DRC_DEC_ERROR
|
FDK_drcDec_ReadLoudnessBox(HANDLE_DRC_DECODER hDrcDec,
|
HANDLE_FDK_BITSTREAM hBitstream) {
|
DRC_ERROR dErr = DE_OK;
|
|
if (hDrcDec == NULL) return DRC_DEC_NOT_OPENED;
|
|
return DRC_DEC_NOT_OK;
|
|
if (dErr) {
|
/* clear config, if parsing error occurred */
|
FDKmemclear(&hDrcDec->loudnessInfoSet, sizeof(hDrcDec->loudnessInfoSet));
|
hDrcDec->loudnessInfoSet.diff = 1;
|
}
|
|
startSelectionProcess(hDrcDec);
|
|
return DRC_DEC_OK;
|
}
|
|
DRC_DEC_ERROR
|
FDK_drcDec_ReadUniDrcGain(HANDLE_DRC_DECODER hDrcDec,
|
HANDLE_FDK_BITSTREAM hBitstream) {
|
DRC_ERROR dErr = DE_OK;
|
|
if (hDrcDec == NULL) return DRC_DEC_NOT_OPENED;
|
if (!hDrcDec->status) {
|
return DRC_DEC_OK;
|
}
|
|
dErr = drcDec_readUniDrcGain(
|
hBitstream, &(hDrcDec->uniDrcConfig),
|
drcDec_GainDecoder_GetFrameSize(hDrcDec->hGainDec),
|
drcDec_GainDecoder_GetDeltaTminDefault(hDrcDec->hGainDec),
|
&(hDrcDec->uniDrcGain));
|
if (dErr) return DRC_DEC_NOT_OK;
|
|
hDrcDec->status = DRC_DEC_NEW_GAIN_PAYLOAD;
|
|
return DRC_DEC_OK;
|
}
|
|
DRC_DEC_ERROR
|
FDK_drcDec_ReadUniDrc(HANDLE_DRC_DECODER hDrcDec,
|
HANDLE_FDK_BITSTREAM hBitstream) {
|
DRC_ERROR dErr = DE_OK;
|
|
if (hDrcDec == NULL) return DRC_DEC_NOT_OPENED;
|
if (!hDrcDec->status) return DRC_DEC_NOT_READY;
|
|
dErr = drcDec_readUniDrc(
|
hBitstream, &(hDrcDec->uniDrcConfig), &(hDrcDec->loudnessInfoSet),
|
drcDec_GainDecoder_GetFrameSize(hDrcDec->hGainDec),
|
drcDec_GainDecoder_GetDeltaTminDefault(hDrcDec->hGainDec),
|
&(hDrcDec->uniDrcGain));
|
|
startSelectionProcess(hDrcDec);
|
if (dErr) return DRC_DEC_NOT_OK;
|
|
hDrcDec->status = DRC_DEC_NEW_GAIN_PAYLOAD;
|
|
return DRC_DEC_OK;
|
}
|
|
DRC_DEC_ERROR
|
FDK_drcDec_Preprocess(HANDLE_DRC_DECODER hDrcDec) {
|
DRC_ERROR dErr = DE_OK;
|
|
if (hDrcDec == NULL) return DRC_DEC_NOT_OPENED;
|
if (!hDrcDec->status) return DRC_DEC_NOT_READY;
|
if (!(hDrcDec->functionalRange & DRC_DEC_GAIN)) return DRC_DEC_NOT_OK;
|
|
if (hDrcDec->status != DRC_DEC_NEW_GAIN_PAYLOAD) {
|
/* no new gain payload was read, e.g. during concalment or flushing.
|
Generate DRC gains based on the stored DRC gains of last frames */
|
drcDec_GainDecoder_Conceal(hDrcDec->hGainDec, &(hDrcDec->uniDrcConfig),
|
&(hDrcDec->uniDrcGain));
|
}
|
|
dErr = drcDec_GainDecoder_Preprocess(
|
hDrcDec->hGainDec, &(hDrcDec->uniDrcGain),
|
hDrcDec->selProcOutput.loudnessNormalizationGainDb,
|
hDrcDec->selProcOutput.boost, hDrcDec->selProcOutput.compress);
|
if (dErr) return DRC_DEC_NOT_OK;
|
hDrcDec->status = DRC_DEC_INTERPOLATION_PREPARED;
|
|
return DRC_DEC_OK;
|
}
|
|
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) {
|
DRC_ERROR dErr = DE_OK;
|
|
if (hDrcDec == NULL) return DRC_DEC_NOT_OPENED;
|
if (!(hDrcDec->functionalRange & DRC_DEC_GAIN)) return DRC_DEC_NOT_OK;
|
if (hDrcDec->status != DRC_DEC_INTERPOLATION_PREPARED)
|
return DRC_DEC_NOT_READY;
|
|
dErr = drcDec_GainDecoder_ProcessTimeDomain(
|
hDrcDec->hGainDec, delaySamples, (GAIN_DEC_LOCATION)drcLocation,
|
channelOffset, drcChannelOffset, numChannelsProcessed,
|
timeDataChannelOffset, realBuffer);
|
if (dErr) return DRC_DEC_NOT_OK;
|
|
return DRC_DEC_OK;
|
}
|
|
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) {
|
DRC_ERROR dErr = DE_OK;
|
|
if (hDrcDec == NULL) return DRC_DEC_NOT_OPENED;
|
if (!(hDrcDec->functionalRange & DRC_DEC_GAIN)) return DRC_DEC_NOT_OK;
|
if (hDrcDec->status != DRC_DEC_INTERPOLATION_PREPARED)
|
return DRC_DEC_NOT_READY;
|
|
dErr = drcDec_GainDecoder_ProcessSubbandDomain(
|
hDrcDec->hGainDec, delaySamples, (GAIN_DEC_LOCATION)drcLocation,
|
channelOffset, drcChannelOffset, numChannelsProcessed,
|
processSingleTimeslot, realBuffer, imagBuffer);
|
if (dErr) return DRC_DEC_NOT_OK;
|
|
return DRC_DEC_OK;
|
}
|
|
DRC_DEC_ERROR
|
FDK_drcDec_ApplyDownmix(HANDLE_DRC_DECODER hDrcDec, int* reverseInChannelMap,
|
int* reverseOutChannelMap, FIXP_DBL* realBuffer,
|
int* pNChannels) {
|
SEL_PROC_OUTPUT* pSelProcOutput = &(hDrcDec->selProcOutput);
|
int baseChCnt = pSelProcOutput->baseChannelCount;
|
int targetChCnt = pSelProcOutput->targetChannelCount;
|
int frameSize, n, ic, oc;
|
FIXP_DBL tmp_out[8];
|
FIXP_DBL* audioChannels[8];
|
|
if (hDrcDec == NULL) return DRC_DEC_NOT_OPENED;
|
if (!(hDrcDec->functionalRange & DRC_DEC_GAIN)) return DRC_DEC_NOT_OK;
|
|
/* only downmix is performed here, no upmix.
|
Downmix is only performed if downmix coefficients are provided.
|
All other cases of downmix and upmix are treated by pcmDmx library. */
|
if (pSelProcOutput->downmixMatrixPresent == 0)
|
return DRC_DEC_OK; /* no downmix */
|
if (targetChCnt >= baseChCnt) return DRC_DEC_OK; /* downmix only */
|
|
/* sanity checks */
|
if (realBuffer == NULL) return DRC_DEC_NOT_OK;
|
if (reverseInChannelMap == NULL) return DRC_DEC_NOT_OK;
|
if (reverseOutChannelMap == NULL) return DRC_DEC_NOT_OK;
|
if (baseChCnt > 8) return DRC_DEC_NOT_OK;
|
if (baseChCnt != *pNChannels) return DRC_DEC_NOT_OK;
|
if (targetChCnt > 8) return DRC_DEC_NOT_OK;
|
|
frameSize = drcDec_GainDecoder_GetFrameSize(hDrcDec->hGainDec);
|
|
for (ic = 0; ic < baseChCnt; ic++) {
|
audioChannels[ic] = &(realBuffer[ic * frameSize]);
|
}
|
|
/* in-place downmix */
|
for (n = 0; n < frameSize; n++) {
|
for (oc = 0; oc < targetChCnt; oc++) {
|
tmp_out[oc] = (FIXP_DBL)0;
|
for (ic = 0; ic < baseChCnt; ic++) {
|
tmp_out[oc] +=
|
fMultDiv2(audioChannels[ic][n],
|
pSelProcOutput->downmixMatrix[reverseInChannelMap[ic]]
|
[reverseOutChannelMap[oc]])
|
<< 3;
|
}
|
}
|
for (oc = 0; oc < targetChCnt; oc++) {
|
if (oc >= baseChCnt) break;
|
audioChannels[oc][n] = tmp_out[oc];
|
}
|
}
|
|
for (oc = targetChCnt; oc < baseChCnt; oc++) {
|
FDKmemset(audioChannels[oc], 0, frameSize * sizeof(FIXP_DBL));
|
}
|
|
*pNChannels = targetChCnt;
|
|
return DRC_DEC_OK;
|
}
|
|
/* Get library info for this module. */
|
DRC_DEC_ERROR
|
FDK_drcDec_GetLibInfo(LIB_INFO* info) {
|
int i;
|
|
if (info == NULL) {
|
return DRC_DEC_INVALID_PARAM;
|
}
|
|
/* Search for next free tab */
|
for (i = 0; i < FDK_MODULE_LAST; i++) {
|
if (info[i].module_id == FDK_NONE) break;
|
}
|
if (i == FDK_MODULE_LAST) {
|
return DRC_DEC_NOT_OK;
|
}
|
|
/* Add the library info */
|
info[i].module_id = FDK_UNIDRCDEC;
|
info[i].version = LIB_VERSION(DRCDEC_LIB_VL0, DRCDEC_LIB_VL1, DRCDEC_LIB_VL2);
|
LIB_VERSION_STRING(info + i);
|
info[i].build_date = DRCDEC_LIB_BUILD_DATE;
|
info[i].build_time = DRCDEC_LIB_BUILD_TIME;
|
info[i].title = DRCDEC_LIB_TITLE;
|
|
return DRC_DEC_OK;
|
}
|