diff options
author | Matthias P. Braendli <matthias.braendli@mpb.li> | 2019-11-11 11:38:02 +0100 |
---|---|---|
committer | Matthias P. Braendli <matthias.braendli@mpb.li> | 2019-11-11 11:38:02 +0100 |
commit | 0e5af65c467b2423a0b857ae3ad98c91acc1e190 (patch) | |
tree | d07f69550d8886271e44fe79c4dcfb299cafbd38 /fdk-aac/libDRCdec/src/FDK_drcDecLib.cpp | |
parent | efe406d9724f959c8bc2a31802559ca6d41fd897 (diff) | |
download | ODR-AudioEnc-0e5af65c467b2423a0b857ae3ad98c91acc1e190.tar.gz ODR-AudioEnc-0e5af65c467b2423a0b857ae3ad98c91acc1e190.tar.bz2 ODR-AudioEnc-0e5af65c467b2423a0b857ae3ad98c91acc1e190.zip |
Include patched FDK-AAC in the repository
The initial idea was to get the DAB+ patch into upstream, but since
that follows the android source releases, there is no place for a custom
DAB+ patch there.
So instead of having to maintain a patched fdk-aac that has to have the
same .so version as the distribution package on which it is installed,
we prefer having a separate fdk-aac-dab library to avoid collision.
At that point, there's no reason to keep fdk-aac in a separate
repository, as odr-audioenc is the only tool that needs DAB+ encoding
support. Including it here simplifies installation, and makes it
consistent with toolame-dab, also shipped in this repository.
DAB+ decoding support (needed by ODR-SourceCompanion, dablin, etisnoop,
welle.io and others) can be done using upstream FDK-AAC.
Diffstat (limited to 'fdk-aac/libDRCdec/src/FDK_drcDecLib.cpp')
-rw-r--r-- | fdk-aac/libDRCdec/src/FDK_drcDecLib.cpp | 891 |
1 files changed, 891 insertions, 0 deletions
diff --git a/fdk-aac/libDRCdec/src/FDK_drcDecLib.cpp b/fdk-aac/libDRCdec/src/FDK_drcDecLib.cpp new file mode 100644 index 0000000..b29b79d --- /dev/null +++ b/fdk-aac/libDRCdec/src/FDK_drcDecLib.cpp @@ -0,0 +1,891 @@ +/* ----------------------------------------------------------------------------- +Software License for The Fraunhofer FDK AAC Codec Library for Android + +© Copyright 1995 - 2018 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 DRC_DEC_ERROR startSelectionProcess(HANDLE_DRC_DECODER hDrcDec) { + DRC_ERROR dErr = DE_OK; + DRCDEC_SELECTION_PROCESS_RETURN sErr = DRCDEC_SELECTION_PROCESS_NO_ERROR; + int uniDrcConfigHasChanged = 0; + SEL_PROC_OUTPUT oldSelProcOutput = hDrcDec->selProcOutput; + + if (!hDrcDec->status) return DRC_DEC_NOT_READY; + + 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; + + sErr = drcDec_SelectionProcess_Process( + hDrcDec->hSelectionProc, &(hDrcDec->uniDrcConfig), + &(hDrcDec->loudnessInfoSet), &(hDrcDec->selProcOutput)); + if (sErr) return DRC_DEC_OK; + + hDrcDec->selProcInputDiff = 0; + hDrcDec->uniDrcConfig.diff = 0; + hDrcDec->loudnessInfoSet.diff = 0; + } + } + + if (hDrcDec->functionalRange & DRC_DEC_GAIN) { + if (isResetNeeded(hDrcDec, oldSelProcOutput) || uniDrcConfigHasChanged) { + dErr = + drcDec_GainDecoder_Config(hDrcDec->hGainDec, &(hDrcDec->uniDrcConfig), + hDrcDec->selProcOutput.numSelectedDrcSets, + hDrcDec->selProcOutput.selectedDrcSetIds, + hDrcDec->selProcOutput.selectedDownmixIds); + if (dErr) return DRC_DEC_OK; + } + } + return DRC_DEC_OK; +} + +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_Init(hDrcDec->hGainDec, frameSize, sampleRate); + 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) { + DRCDEC_SELECTION_PROCESS_RETURN sErr = DRCDEC_SELECTION_PROCESS_NO_ERROR; + + if (hDrcDec == NULL) return DRC_DEC_NOT_OPENED; + + if (hDrcDec->functionalRange == DRC_DEC_GAIN) + return DRC_DEC_NOT_OK; /* not supported for DRC_DEC_GAIN. All parameters are + handed over to selection process lib. */ + + 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; + default: + 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)); + if (dErr) return DRC_DEC_NOT_OK; + + startSelectionProcess(hDrcDec); + + 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; +} |