diff options
Diffstat (limited to 'libAACdec')
-rw-r--r-- | libAACdec/include/aacdecoder_lib.h | 123 | ||||
-rw-r--r-- | libAACdec/src/aac_ram.cpp | 8 | ||||
-rw-r--r-- | libAACdec/src/aac_rom.cpp | 50 | ||||
-rw-r--r-- | libAACdec/src/aac_rom.h | 9 | ||||
-rw-r--r-- | libAACdec/src/aacdec_drc.cpp | 104 | ||||
-rw-r--r-- | libAACdec/src/aacdec_drc.h | 17 | ||||
-rw-r--r-- | libAACdec/src/aacdec_drc_types.h | 4 | ||||
-rw-r--r-- | libAACdec/src/aacdecoder.cpp | 188 | ||||
-rw-r--r-- | libAACdec/src/aacdecoder.h | 29 | ||||
-rw-r--r-- | libAACdec/src/aacdecoder_lib.cpp | 165 | ||||
-rw-r--r-- | libAACdec/src/conceal.cpp | 15 |
11 files changed, 549 insertions, 163 deletions
diff --git a/libAACdec/include/aacdecoder_lib.h b/libAACdec/include/aacdecoder_lib.h index 60efe8d..a0c0854 100644 --- a/libAACdec/include/aacdecoder_lib.h +++ b/libAACdec/include/aacdecoder_lib.h @@ -144,10 +144,9 @@ to allocate memory for the required structures, and the corresponding mpegFileRe files and to de-allocate associated structures. mpegFileRead_Open() tries to detect the bitstream format and in case of MPEG-4 file format or Raw Packets file format (a Fraunhofer IIS proprietary format) reads the Audio Specific Config data (ASC). An unsuccessful attempt to recognize the bitstream format requires the user to -provide this information manually (see \ref CommandLineUsage). For any other bitstream formats that are -usually applicable in streaming applications, the decoder itself will try to synchronize and parse the given -bitstream fragment using the FDK transport library. Hence, for streaming applications (without file access) -this step is not necessary. +provide this information manually. For any other bitstream formats that are usually applicable in streaming +applications, the decoder itself will try to synchronize and parse the given bitstream fragment using the +FDK transport library. Hence, for streaming applications (without file access) this step is not necessary. -# Call aacDecoder_Open() to open and retrieve a handle to a new AAC decoder instance. \dontinclude main.cpp @@ -430,21 +429,68 @@ typedef enum { typedef enum { AAC_PCM_OUTPUT_INTERLEAVED = 0x0000, /*!< PCM output mode (1: interleaved (default); 0: not interleaved). */ - AAC_PCM_OUTPUT_CHANNELS = 0x0001, /*!< Number of PCM output channels (if different from encoded audio channels, downmixing or - upmixing is applied). \n - -1: Disable up-/downmixing. The decoder output contains the same number of channels as the - encoded bitstream. \n - 1: The decoder performs a mono matrix mix-down if the encoded audio channels are greater - than one. Thus it ouputs always exact one channel. \n - 2: The decoder performs a stereo matrix mix-down if the encoded audio channels are greater - than two. If the encoded audio channels are smaller than two the decoder duplicates the - output. Thus it ouputs always exact two channels. \n */ - AAC_PCM_DUAL_CHANNEL_OUTPUT_MODE = 0x0002, /*!< Defines how the decoder processes two channel signals: - 0: Leave both signals as they are (default). - 1: Create a dual mono output signal from channel 1. - 2: Create a dual mono output signal from channel 2. + AAC_PCM_DUAL_CHANNEL_OUTPUT_MODE = 0x0002, /*!< Defines how the decoder processes two channel signals: \n + 0: Leave both signals as they are (default). \n + 1: Create a dual mono output signal from channel 1. \n + 2: Create a dual mono output signal from channel 2. \n 3: Create a dual mono output signal by mixing both channels (L' = R' = 0.5*Ch1 + 0.5*Ch2). */ AAC_PCM_OUTPUT_CHANNEL_MAPPING = 0x0003, /*!< Output buffer channel ordering. 0: MPEG PCE style order, 1: WAV file channel order (default). */ + AAC_PCM_LIMITER_ENABLE = 0x0004, /*!< Enable signal level limiting. \n + -1: Auto-config. Enable limiter for all non-lowdelay configurations by default. \n + 0: Disable limiter in general. \n + 1: Enable limiter always. + It is recommended to call the decoder with a AACDEC_CLRHIST flag to reset all states when + the limiter switch is changed explicitly. */ + AAC_PCM_LIMITER_ATTACK_TIME = 0x0005, /*!< Signal level limiting attack time in ms. + Default confguration is 15 ms. Adjustable range from 1 ms to 15 ms. */ + AAC_PCM_LIMITER_RELEAS_TIME = 0x0006, /*!< Signal level limiting release time in ms. + Default configuration is 50 ms. Adjustable time must be larger than 0 ms. */ + AAC_PCM_MIN_OUTPUT_CHANNELS = 0x0011, /*!< Minimum number of PCM output channels. If higher than the number of encoded audio channels, + a simple channel extension is applied. \n + -1, 0: Disable channel extenstion feature. The decoder output contains the same number of + channels as the encoded bitstream. \n + 1: This value is currently needed only together with the mix-down feature. See + ::AAC_PCM_MAX_OUTPUT_CHANNELS and note 2 below. \n + 2: Encoded mono signals will be duplicated to achieve a 2/0/0.0 channel output + configuration. \n + 6: The decoder trys to reorder encoded signals with less than six channels to achieve + a 3/0/2.1 channel output signal. Missing channels will be filled with a zero signal. + If reordering is not possible the empty channels will simply be appended. Only + available if instance is configured to support multichannel output. \n + 8: The decoder trys to reorder encoded signals with less than eight channels to + achieve a 3/0/4.1 channel output signal. Missing channels will be filled with a + zero signal. If reordering is not possible the empty channels will simply be + appended. Only available if instance is configured to support multichannel output.\n + NOTE: \n + 1. The channel signalling (CStreamInfo::pChannelType and CStreamInfo::pChannelIndices) + will not be modified. Added empty channels will be signalled with channel type + AUDIO_CHANNEL_TYPE::ACT_NONE. \n + 2. If the parameter value is greater than that of ::AAC_PCM_MAX_OUTPUT_CHANNELS both will + be set to the same value. \n + 3. This parameter does not affect MPEG Surround processing. */ + AAC_PCM_MAX_OUTPUT_CHANNELS = 0x0012, /*!< Maximum number of PCM output channels. If lower than the number of encoded audio channels, + downmixing is applied accordingly. If dedicated metadata is available in the stream it + will be used to achieve better mixing results. \n + -1, 0: Disable downmixing feature. The decoder output contains the same number of channels + as the encoded bitstream. \n + 1: All encoded audio configurations with more than one channel will be mixed down to + one mono output signal. \n + 2: The decoder performs a stereo mix-down if the number encoded audio channels is + greater than two. \n + 6: If the number of encoded audio channels is greater than six the decoder performs a + mix-down to meet the target output configuration of 3/0/2.1 channels. Only + available if instance is configured to support multichannel output. \n + 8: This value is currently needed only together with the channel extension feature. + See ::AAC_PCM_MIN_OUTPUT_CHANNELS and note 2 below. Only available if instance is + configured to support multichannel output. \n + NOTE: \n + 1. Down-mixing of any seven or eight channel configuration not defined in ISO/IEC 14496-3 + PDAM 4 is not supported by this software version. \n + 2. If the parameter value is greater than zero but smaller than ::AAC_PCM_MIN_OUTPUT_CHANNELS + both will be set to same value. \n + 3. The operating mode of the MPEG Surround module will be set accordingly. \n + 4. Setting this param with any value will disable the binaural processing of the MPEG + Surround module (::AAC_MPEGS_BINAURAL_ENABLE=0). */ AAC_CONCEAL_METHOD = 0x0100, /*!< Error concealment: Processing method. \n 0: Spectral muting. \n @@ -485,18 +531,18 @@ typedef enum */ typedef struct { - /* These three members are the only really relevant ones for the user. */ + /* These five members are the only really relevant ones for the user. */ INT sampleRate; /*!< The samplerate in Hz of the fully decoded PCM audio signal (after SBR processing). */ INT frameSize; /*!< The frame size of the decoded PCM audio signal. \n 1024 or 960 for AAC-LC \n 2048 or 1920 for HE-AAC (v2) \n 512 or 480 for AAC-LD and AAC-ELD */ INT numChannels; /*!< The number of output audio channels in the decoded and interleaved PCM audio signal. */ - AUDIO_CHANNEL_TYPE *pChannelType; /*!< Audio channel type of each output audio channel. */ - UCHAR *pChannelIndices; /*!< Audio channel index for each output audio channel. + AUDIO_CHANNEL_TYPE *pChannelType; /*!< Audio channel type of each output audio channel. */ + UCHAR *pChannelIndices; /*!< Audio channel index for each output audio channel. See ISO/IEC 13818-7:2005(E), 8.5.3.2 Explicit channel mapping using a program_config_element() */ /* Decoder internal members. */ - INT aacSampleRate; /*!< sampling rate in Hz without SBR (from configuration info). */ + INT aacSampleRate; /*!< Sampling rate in Hz without SBR (from configuration info). */ INT profile; /*!< MPEG-2 profile (from file header) (-1: not applicable (e. g. MPEG-4)). */ AUDIO_OBJECT_TYPE aot; /*!< Audio Object Type (from ASC): is set to the appropriate value for MPEG-2 bitstreams (e. g. 2 for AAC-LC). */ INT channelConfig; /*!< Channel configuration (0: PCE defined, 1: mono, 2: stereo, ... */ @@ -509,7 +555,9 @@ typedef struct AUDIO_OBJECT_TYPE extAot; /*!< Extension Audio Object Type (from ASC) */ INT extSamplingRate; /*!< Extension sampling rate in Hz (from ASC) */ - UINT flags; /*!< Copy if internal flags. Only to be written by the decoder, and only to be read externally. */ + UINT outputDelay; /*!< The number of samples the output is additionally delayed by the decoder. */ + + UINT flags; /*!< Copy of internal flags. Only to be written by the decoder, and only to be read externally. */ SCHAR epConfig; /*!< epConfig level (from ASC): only level 0 supported, -1 means no ER (e. g. AOT=2, MPEG-2 AAC, etc.) */ @@ -522,10 +570,25 @@ typedef struct UINT numTotalAccessUnits; /*!< This is the number of total access units that have passed through the decoder. */ UINT numBadAccessUnits; /*!< This is the number of total access units that were considered with errors from numTotalBytes. */ + /* Metadata */ + SCHAR drcProgRefLev; /*!< DRC program reference level. Defines the reference level below full-scale. + It is quantized in steps of 0.25dB. The valid values range from 0 (0 dBFS) to 127 (-31.75 dBFS). + It is used to reflect the average loudness of the audio in LKFS accoring to ITU-R BS 1770. + If no level has been found in the bitstream the value is -1. */ + SCHAR drcPresMode; /*!< DRC presentation mode. According to ETSI TS 101 154, this field indicates whether + light (MPEG-4 Dynamic Range Control tool) or heavy compression (DVB heavy compression) + dynamic range control shall take priority on the outputs. + For details, see ETSI TS 101 154, table C.33. Possible values are: \n + -1: No corresponding metadata found in the bitstream \n + 0: DRC presentation mode not indicated \n + 1: DRC presentation mode 1 \n + 2: DRC presentation mode 2 \n + 3: Reserved */ + } CStreamInfo; -typedef struct AAC_DECODER_INSTANCE *HANDLE_AACDECODER; +typedef struct AAC_DECODER_INSTANCE *HANDLE_AACDECODER; /*!< Pointer to a AAC decoder instance. */ #ifdef __cplusplus extern "C" @@ -634,11 +697,15 @@ aacDecoder_Fill ( HANDLE_AACDECODER self, const UINT bufferSize[], UINT *bytesValid ); -#define AACDEC_CONCEAL 1 /*!< Flag for aacDecoder_DecodeFrame(): do not consider new input data. Do concealment. */ -#define AACDEC_FLUSH 2 /*!< Flag for aacDecoder_DecodeFrame(): Do not consider new input data. Flush filterbanks (output delayed audio). */ -#define AACDEC_INTR 4 /*!< Flag for aacDecoder_DecodeFrame(): Signal an input bit stream data discontinuity. Resync any internals as necessary. */ -#define AACDEC_CLRHIST 8 /*!< Flag for aacDecoder_DecodeFrame(): Clear all signal delay lines and history buffers. - Caution: This can cause discontinuities in the output signal. */ +#define AACDEC_CONCEAL 1 /*!< Flag for aacDecoder_DecodeFrame(): Trigger the built-in error concealment module \ + to generate a substitute signal for one lost frame. New input data will not be + considered. */ +#define AACDEC_FLUSH 2 /*!< Flag for aacDecoder_DecodeFrame(): Flush all filterbanks to get all delayed audio \ + without having new input data. Thus new input data will not be considered.*/ +#define AACDEC_INTR 4 /*!< Flag for aacDecoder_DecodeFrame(): Signal an input bit stream data discontinuity. \ + Resync any internals as necessary. */ +#define AACDEC_CLRHIST 8 /*!< Flag for aacDecoder_DecodeFrame(): Clear all signal delay lines and history buffers.\ + CAUTION: This can cause discontinuities in the output signal. */ /** * \brief Decode one audio frame diff --git a/libAACdec/src/aac_ram.cpp b/libAACdec/src/aac_ram.cpp index a38f57c..1ff289b 100644 --- a/libAACdec/src/aac_ram.cpp +++ b/libAACdec/src/aac_ram.cpp @@ -108,15 +108,15 @@ C_ALLOC_MEM(AacDecoder, AAC_DECODER_INSTANCE, 1) /*! The structure CAacDecoderStaticChannelInfo contains the static sideinfo which is needed for the decoding of one aac channel. <br> Dimension: #AacDecoderChannels */ -C_ALLOC_MEM2(AacDecoderStaticChannelInfo, CAacDecoderStaticChannelInfo, 1, (6)) +C_ALLOC_MEM2(AacDecoderStaticChannelInfo, CAacDecoderStaticChannelInfo, 1, (8)) /*! The structure CAacDecoderChannelInfo contains the dynamic sideinfo which is needed for the decoding of one aac channel. <br> Dimension: #AacDecoderChannels */ -C_ALLOC_MEM2(AacDecoderChannelInfo, CAacDecoderChannelInfo, 1, (6)) +C_AALLOC_MEM2(AacDecoderChannelInfo, CAacDecoderChannelInfo, 1, (8)) /*! Overlap buffer */ -C_ALLOC_MEM2(OverlapBuffer, FIXP_DBL, OverlapBufferSize, (6)) +C_ALLOC_MEM2(OverlapBuffer, FIXP_DBL, OverlapBufferSize, (8)) C_ALLOC_MEM(DrcInfo, CDrcInfo, 1) @@ -128,7 +128,7 @@ C_ALLOC_MEM(DrcInfo, CDrcInfo, 1) Dynamic memory areas, might be reused in other algorithm sections, e.g. the sbr decoder */ -C_ALLOC_MEM_OVERLAY(WorkBufferCore2, FIXP_DBL, ((6)*1024), SECT_DATA_L2, WORKBUFFER2_TAG) +C_ALLOC_MEM_OVERLAY(WorkBufferCore2, FIXP_DBL, ((8)*1024), SECT_DATA_L2, WORKBUFFER2_TAG) C_ALLOC_MEM_OVERLAY(WorkBufferCore1, CWorkBufferCore1, 1, SECT_DATA_L1, WORKBUFFER1_TAG) diff --git a/libAACdec/src/aac_rom.cpp b/libAACdec/src/aac_rom.cpp index fa04c42..607cb3b 100644 --- a/libAACdec/src/aac_rom.cpp +++ b/libAACdec/src/aac_rom.cpp @@ -1777,42 +1777,62 @@ const FIXP_TCC FDKaacDec_tnsCoeff4 [16] = }; /* MPEG like mapping (no change). */ -const UCHAR channelMappingTablePassthrough[8][8] = +const UCHAR channelMappingTablePassthrough[15][8] = { + { 0, 1, 2, 3, 4, 5, 6, 7}, /* fallback */ { 0, 1,255,255,255,255,255,255}, /* mono / PS */ { 0, 1,255,255,255,255,255,255}, /* stereo */ { 0, 1, 2,255,255,255,255,255}, /* 3ch */ { 0, 1, 2, 3,255,255,255,255}, /* 4ch */ { 0, 1, 2, 3, 4,255,255,255}, /* 5ch */ { 0, 1, 2, 3, 4, 5,255,255}, /* 5.1ch */ - { 0, 1, 2, 3, 4, 5, 6, 7}, /* 7ch */ - { 0, 1, 2, 3, 4, 5, 6, 7} /* 7.1ch */ + { 0, 1, 2, 3, 4, 5, 6, 7}, /* 7.1 front */ + { 0, 1, 2, 3, 4, 5, 6, 7}, /* reserved */ + { 0, 1, 2, 3, 4, 5, 6, 7}, /* reserved */ + { 0, 1, 2, 3, 4, 5, 6, 7}, /* reserved */ + { 0, 1, 2, 3, 4, 5, 6,255}, /* 6.1ch */ + { 0, 1, 2, 3, 4, 5, 6, 7}, /* 7.1 rear */ + { 0, 1, 2, 3, 4, 5, 6, 7}, /* reserved */ + { 0, 1, 2, 3, 4, 5, 6, 7} /* 7.1 top */ }; /* WAV file like mapping (from MPEG mapping). */ -const UCHAR channelMappingTableWAV[8][8] = +const UCHAR channelMappingTableWAV[15][8] = { + { 0, 1, 2, 3, 4, 5, 6, 7}, /* fallback */ { 0, 1,255,255,255,255,255,255}, /* mono / PS */ { 0, 1,255,255,255,255,255,255}, /* stereo */ { 2, 0, 1,255,255,255,255,255}, /* 3ch */ { 2, 0, 1, 3,255,255,255,255}, /* 4ch */ { 2, 0, 1, 3, 4,255,255,255}, /* 5ch */ { 2, 0, 1, 4, 5, 3,255,255}, /* 5.1ch */ - { 0, 1, 2, 3, 4, 5, 6, 7}, /* 7ch */ - { 2, 0, 1, 6, 7, 4, 5, 3} /* 7.1ch */ + { 2, 6, 7, 0, 1, 4, 5, 3}, /* 7.1 front */ + { 0, 1, 2, 3, 4, 5, 6, 7}, /* reserved */ + { 0, 1, 2, 3, 4, 5, 6, 7}, /* reserved */ + { 0, 1, 2, 3, 4, 5, 6, 7}, /* reserved */ + { 2, 0, 1, 4, 5, 6, 3,255}, /* 6.1ch */ + { 2, 0, 1, 6, 7, 4, 5, 3}, /* 7.1 rear */ + { 0, 1, 2, 3, 4, 5, 6, 7}, /* reserved */ + { 2, 0, 1, 4, 5, 3, 6, 7} /* 7.1 top */ }; /* Lookup tables for elements in ER bitstream */ -const MP4_ELEMENT_ID elementsTab[8][7] = +const MP4_ELEMENT_ID elementsTab[15][7] = { - {ID_SCE, ID_EXT, ID_END, ID_NONE, ID_NONE,ID_NONE,ID_NONE }, /* 1 channel */ - {ID_CPE, ID_EXT, ID_END, ID_NONE, ID_NONE,ID_NONE,ID_NONE } /* 2 channels */ - , - {ID_SCE, ID_CPE, ID_EXT, ID_END, ID_NONE,ID_NONE,ID_NONE }, /* 3 channels */ - {ID_SCE, ID_CPE, ID_SCE, ID_EXT, ID_END, ID_NONE,ID_NONE }, /* 4 channels */ - {ID_SCE, ID_CPE, ID_CPE, ID_EXT, ID_END, ID_NONE,ID_NONE }, /* 5 channels */ - {ID_SCE, ID_CPE, ID_CPE, ID_LFE, ID_EXT, ID_END, ID_NONE }, /* 6 channels */ - {ID_SCE, ID_CPE, ID_CPE, ID_CPE, ID_LFE, ID_EXT, ID_END} /* 8 channels */ + /* 1 */ { ID_SCE, ID_EXT, ID_END, ID_NONE, ID_NONE, ID_NONE, ID_NONE }, /* 1 channel */ + /* 2 */ { ID_CPE, ID_EXT, ID_END, ID_NONE, ID_NONE, ID_NONE, ID_NONE } /* 2 channels */ + /* 3 */ ,{ ID_SCE, ID_CPE, ID_EXT, ID_END, ID_NONE, ID_NONE, ID_NONE }, /* 3 channels */ + /* 4 */ { ID_SCE, ID_CPE, ID_SCE, ID_EXT, ID_END, ID_NONE, ID_NONE }, /* 4 channels */ + /* 5 */ { ID_SCE, ID_CPE, ID_CPE, ID_EXT, ID_END, ID_NONE, ID_NONE }, /* 5 channels */ + /* 6 */ { ID_SCE, ID_CPE, ID_CPE, ID_LFE, ID_EXT, ID_END, ID_NONE } /* 6 channels */ + /* 7 */ ,{ ID_SCE, ID_CPE, ID_CPE, ID_CPE, ID_LFE, ID_EXT, ID_END }, /* 8 channels */ + /* 8 */ { ID_NONE, ID_NONE, ID_NONE, ID_NONE, ID_NONE, ID_NONE, ID_NONE }, /* reserved */ + /* 9 */ { ID_NONE, ID_NONE, ID_NONE, ID_NONE, ID_NONE, ID_NONE, ID_NONE }, /* reserved */ + /* 10 */ { ID_NONE, ID_NONE, ID_NONE, ID_NONE, ID_NONE, ID_NONE, ID_NONE }, /* reserved */ + /* 11 */ { ID_SCE, ID_CPE, ID_CPE, ID_SCE, ID_LFE, ID_EXT, ID_END }, /* 7 channels */ + /* 12 */ { ID_SCE, ID_CPE, ID_CPE, ID_CPE, ID_LFE, ID_EXT, ID_END }, /* 8 channels */ + /* 13 */ { ID_NONE, ID_NONE, ID_NONE, ID_NONE, ID_NONE, ID_NONE, ID_NONE }, /* reserved */ + /* 14 */ { ID_SCE, ID_CPE, ID_CPE, ID_LFE, ID_CPE, ID_EXT, ID_END } /* 8 channels */ }; /*! Random sign bit used for concealment diff --git a/libAACdec/src/aac_rom.h b/libAACdec/src/aac_rom.h index 536d184..f314a2d 100644 --- a/libAACdec/src/aac_rom.h +++ b/libAACdec/src/aac_rom.h @@ -177,11 +177,12 @@ extern const USHORT randomSign[AAC_NF_NO_RANDOM_VAL/16]; extern const FIXP_DBL pow2_div24minus1[47]; extern const int offsetTab[2][16]; -/* Channel mapping indices for time domain I/O. First dimension is channel count-1. */ -extern const UCHAR channelMappingTablePassthrough[8][8]; -extern const UCHAR channelMappingTableWAV[8][8]; +/* Channel mapping indices for time domain I/O. + The first dimension is the channel configuration index. */ +extern const UCHAR channelMappingTablePassthrough[15][8]; +extern const UCHAR channelMappingTableWAV[15][8]; /* Lookup tables for elements in ER bitstream */ -extern const MP4_ELEMENT_ID elementsTab[8][7]; +extern const MP4_ELEMENT_ID elementsTab[15][7]; #endif /* #ifndef AAC_ROM_H */ diff --git a/libAACdec/src/aacdec_drc.cpp b/libAACdec/src/aacdec_drc.cpp index 2666454..0c33a2b 100644 --- a/libAACdec/src/aacdec_drc.cpp +++ b/libAACdec/src/aacdec_drc.cpp @@ -130,7 +130,6 @@ void aacDecoder_drcInit ( /* init control fields */ self->enable = 0; self->numThreads = 0; - self->digitalNorm = 0; /* init params */ pParams = &self->params; @@ -139,12 +138,15 @@ void aacDecoder_drcInit ( pParams->usrCut = FL2FXCONST_DBL(0.0f); pParams->boost = FL2FXCONST_DBL(0.0f); pParams->usrBoost = FL2FXCONST_DBL(0.0f); - pParams->targetRefLevel = AACDEC_DRC_DEFAULT_REF_LEVEL; + pParams->targetRefLevel = -1; pParams->expiryFrame = AACDEC_DRC_DFLT_EXPIRY_FRAMES; + pParams->applyDigitalNorm = 0; pParams->applyHeavyCompression = 0; /* initial program ref level = target ref level */ self->progRefLevel = pParams->targetRefLevel; + self->progRefLevelPresent = 0; + self->presMode = -1; } @@ -222,11 +224,12 @@ AAC_DECODER_ERROR aacDecoder_drcSetParam ( return AAC_DEC_INVALID_HANDLE; } if (value < 0) { - self->digitalNorm = 0; + self->params.applyDigitalNorm = 0; + self->params.targetRefLevel = -1; } else { /* ref_level must be between 0 and MAX_REFERENCE_LEVEL, inclusive */ - self->digitalNorm = 1; + self->params.applyDigitalNorm = 1; if (self->params.targetRefLevel != (SCHAR)value) { self->params.targetRefLevel = (SCHAR)value; self->progRefLevel = (SCHAR)value; /* Always set the program reference level equal to the @@ -234,6 +237,16 @@ AAC_DECODER_ERROR aacDecoder_drcSetParam ( } } break; + case APPLY_NORMALIZATION: + if (value < 0 || value > 1) { + return AAC_DEC_SET_PARAM_FAIL; + } + if (self == NULL) { + return AAC_DEC_INVALID_HANDLE; + } + /* Store new parameter value */ + self->params.applyDigitalNorm = (UCHAR)value; + break; case APPLY_HEAVY_COMPRESSION: if (value < 0 || value > 1) { return AAC_DEC_SET_PARAM_FAIL; @@ -278,7 +291,7 @@ AAC_DECODER_ERROR aacDecoder_drcSetParam ( self->enable = ( (self->params.boost > (FIXP_DBL)0) || (self->params.cut > (FIXP_DBL)0) || (self->params.applyHeavyCompression != 0) - || (self->digitalNorm == 1) ); + || (self->params.targetRefLevel >= 0) ); return ErrorStatus; @@ -539,7 +552,7 @@ static int aacDecoder_drcReadCompression ( UINT payloadPosition ) { int bitCnt = 0; - int dmxLevelsPresent, compressionPresent; + int dmxLevelsPresent, extensionPresent, compressionPresent; int coarseGrainTcPresent, fineGrainTcPresent; /* Move to the beginning of the DRC payload field */ @@ -561,8 +574,9 @@ static int aacDecoder_drcReadCompression ( return 0; } FDKreadBits(bs, 2); /* dolby_surround_mode */ - FDKreadBits(bs, 2); /* presentation_mode */ - if (FDKreadBits(bs, 2) != 0) { /* reserved, set to 0 */ + pDrcBs->presMode = FDKreadBits(bs, 2); /* presentation_mode */ + FDKreadBits(bs, 1); /* stereo_downmix_mode */ + if (FDKreadBits(bs, 1) != 0) { /* reserved, set to 0 */ return 0; } @@ -571,9 +585,7 @@ static int aacDecoder_drcReadCompression ( return 0; } dmxLevelsPresent = FDKreadBits(bs, 1); /* downmixing_levels_MPEG4_status */ - if (FDKreadBits(bs, 1) != 0) { /* reserved, set to 0 */ - return 0; - } + extensionPresent = FDKreadBits(bs, 1); /* ancillary_data_extension_status; */ compressionPresent = FDKreadBits(bs, 1); /* audio_coding_mode_and_compression status */ coarseGrainTcPresent = FDKreadBits(bs, 1); /* coarse_grain_timecode_status */ fineGrainTcPresent = FDKreadBits(bs, 1); /* fine_grain_timecode_status */ @@ -631,6 +643,19 @@ static int aacDecoder_drcReadCompression ( bitCnt += 16; } + /* Read extension just to get the right amount of bits. */ + if (extensionPresent) { + int extBits = 8; + + FDKreadBits(bs, 1); /* reserved, set to 0 */ + if (FDKreadBits(bs, 1)) extBits += 8; /* ext_downmixing_levels_status */ + if (FDKreadBits(bs, 1)) extBits += 16; /* ext_downmixing_global_gains_status */ + if (FDKreadBits(bs, 1)) extBits += 8; /* ext_downmixing_lfe_level_status */ + + FDKpushFor(bs, extBits - 4); /* skip the extension payload remainder. */ + bitCnt += extBits; + } + return (bitCnt); } @@ -780,9 +805,15 @@ static int aacDecoder_drcExtractAndMap ( */ if (pThreadBs->progRefLevel >= 0) { self->progRefLevel = pThreadBs->progRefLevel; + self->progRefLevelPresent = 1; self->prlExpiryCount = 0; /* Got a new value -> Reset counter */ } + if (drcPayloadType == DVB_DRC_ANC_DATA) { + /* Announce the presentation mode of this valid thread. */ + self->presMode = pThreadBs->presMode; + } + /* SCE, CPE and LFE */ for (ch = 0; ch < validChannels; ch++) { int mapedChannel = channelMapping[ch]; @@ -802,6 +833,7 @@ static int aacDecoder_drcExtractAndMap ( if ( (pParams->expiryFrame > 0) && (self->prlExpiryCount++ > pParams->expiryFrame) ) { /* The program reference level is too old, so set it back to the target level. */ + self->progRefLevelPresent = 0; self->progRefLevel = pParams->targetRefLevel; self->prlExpiryCount = 0; } @@ -815,6 +847,7 @@ void aacDecoder_drcApply ( void *pSbrDec, CAacDecoderChannelInfo *pAacDecoderChannelInfo, CDrcChannelData *pDrcChData, + FIXP_DBL *extGain, int ch, /* needed only for SBR */ int aacFrameSize, int bSbrPresent ) @@ -826,8 +859,8 @@ void aacDecoder_drcApply ( FIXP_DBL max_mantissa; INT max_exponent; - FIXP_DBL norm_mantissa = FL2FXCONST_DBL(0.0f); - INT norm_exponent = 0; + FIXP_DBL norm_mantissa = FL2FXCONST_DBL(0.5f); + INT norm_exponent = 1; FIXP_DBL fact_mantissa[MAX_DRC_BANDS]; INT fact_exponent[MAX_DRC_BANDS]; @@ -849,6 +882,15 @@ void aacDecoder_drcApply ( if (!self->enable) { sbrDecoder_drcDisable( (HANDLE_SBRDECODER)pSbrDec, ch ); + if (extGain != NULL) { + INT gainScale = (INT)*extGain; + /* The gain scaling must be passed to the function in the buffer pointed on by extGain. */ + if (gainScale >= 0 && gainScale <= DFRACT_BITS) { + *extGain = scaleValue(norm_mantissa, norm_exponent-gainScale); + } else { + FDK_ASSERT(0); + } + } return; } @@ -864,7 +906,7 @@ void aacDecoder_drcApply ( reduced DAC SNR (if signal is attenuated) or clipping (if signal is boosted) */ - if (self->digitalNorm == 1) + if (pParams->targetRefLevel >= 0) { /* 0.5^((targetRefLevel - progRefLevel)/24) */ norm_mantissa = fLdPow( @@ -874,7 +916,18 @@ void aacDecoder_drcApply ( 3, &norm_exponent ); } - else { + /* Always export the normalization gain (if possible). */ + if (extGain != NULL) { + INT gainScale = (INT)*extGain; + /* The gain scaling must be passed to the function in the buffer pointed on by extGain. */ + if (gainScale >= 0 && gainScale <= DFRACT_BITS) { + *extGain = scaleValue(norm_mantissa, norm_exponent-gainScale); + } else { + FDK_ASSERT(0); + } + } + if (self->params.applyDigitalNorm == 0) { + /* Reset normalization gain since this module must not apply it */ norm_mantissa = FL2FXCONST_DBL(0.5f); norm_exponent = 1; } @@ -1112,3 +1165,24 @@ int aacDecoder_drcEpilog ( return err; } +/* + * Export relevant metadata info from bitstream payload. + */ +void aacDecoder_drcGetInfo ( + HANDLE_AAC_DRC self, + SCHAR *pPresMode, + SCHAR *pProgRefLevel ) +{ + if (self != NULL) { + if (pPresMode != NULL) { + *pPresMode = self->presMode; + } + if (pProgRefLevel != NULL) { + if (self->progRefLevelPresent) { + *pProgRefLevel = self->progRefLevel; + } else { + *pProgRefLevel = -1; + } + } + } +} diff --git a/libAACdec/src/aacdec_drc.h b/libAACdec/src/aacdec_drc.h index 2ebae2c..c850aa5 100644 --- a/libAACdec/src/aacdec_drc.h +++ b/libAACdec/src/aacdec_drc.h @@ -98,7 +98,6 @@ amm-info@iis.fraunhofer.de #include "channel.h" #include "FDK_bitstream.h" -#define AACDEC_DRC_DEFAULT_REF_LEVEL ( 108 ) /* -27 dB below full scale (typical for movies) */ #define AACDEC_DRC_DFLT_EXPIRY_FRAMES ( 50 ) /* Default DRC data expiry time in AAC frames */ /** @@ -111,6 +110,7 @@ typedef enum TARGET_REF_LEVEL, DRC_BS_DELAY, DRC_DATA_EXPIRY_FRAME, + APPLY_NORMALIZATION, APPLY_HEAVY_COMPRESSION } AACDEC_DRC_PARAM; @@ -149,6 +149,8 @@ int aacDecoder_drcProlog ( * \param pSbrDec pointer to SBR decoder instance * \param pAacDecoderChannelInfo AAC decoder channel instance to be processed * \param pDrcDat DRC channel data + * \param extGain Pointer to a FIXP_DBL where a externally applyable gain will be stored into (independently on whether it will be apply internally or not). + * At function call the buffer must hold the scale (0 >= scale < DFRACT_BITS) to be applied on the gain value. * \param ch channel index * \param aacFrameSize AAC frame size * \param bSbrPresent flag indicating that SBR is present, in which case DRC is handed over to the SBR instance pSbrDec @@ -158,6 +160,7 @@ void aacDecoder_drcApply ( void *pSbrDec, CAacDecoderChannelInfo *pAacDecoderChannelInfo, CDrcChannelData *pDrcDat, + FIXP_DBL *extGain, int ch, int aacFrameSize, int bSbrPresent ); @@ -170,5 +173,17 @@ int aacDecoder_drcEpilog ( UCHAR channelMapping[], int validChannels ); +/** + * \brief Get metadata information found in bitstream. + * \param self DRC module instance handle. + * \param pPresMode Pointer to field where the presentation mode will be written to. + * \param pProgRefLevel Pointer to field where the program reference level will be written to. + * \return Nothing. + */ +void aacDecoder_drcGetInfo ( + HANDLE_AAC_DRC self, + SCHAR *pPresMode, + SCHAR *pProgRefLevel ); + #endif /* AACDEC_DRC_H */ diff --git a/libAACdec/src/aacdec_drc_types.h b/libAACdec/src/aacdec_drc_types.h index 1b5cd76..4c6d163 100644 --- a/libAACdec/src/aacdec_drc_types.h +++ b/libAACdec/src/aacdec_drc_types.h @@ -124,6 +124,7 @@ typedef struct { UINT excludedChnsMask; SCHAR progRefLevel; + SCHAR presMode; /* Presentation mode: 0 (not indicated), 1, 2, and 3 (reserved). */ SCHAR pceInstanceTag; CDrcChannelData channelData; @@ -140,6 +141,7 @@ typedef struct UINT expiryFrame; SCHAR targetRefLevel; UCHAR bsDelayEnable; + UCHAR applyDigitalNorm; UCHAR applyHeavyCompression; } CDrcParams; @@ -155,9 +157,11 @@ typedef struct USHORT numPayloads; /* The number of DRC data payload elements found within frame */ USHORT numThreads; /* The number of DRC data threads extracted from the found payload elements */ SCHAR progRefLevel; /* Program reference level for all channels */ + UCHAR progRefLevelPresent; /* Program reference level found in bitstream */ UINT prlExpiryCount; /* Counter that can be used to monitor the life time of the program reference level. */ + SCHAR presMode; /* Presentation mode as defined in ETSI TS 101 154 */ UCHAR dvbAncDataAvailable; /* Flag that indicates whether DVB ancillary data is present or not */ UINT dvbAncDataPosition; /* Used to store the DVB ancillary data payload position in the bitstream (only one per frame) */ UINT drcPayloadPosition[MAX_DRC_THREADS]; /* Used to store the DRC payload positions in the bitstream */ diff --git a/libAACdec/src/aacdecoder.cpp b/libAACdec/src/aacdecoder.cpp index 3a2a561..e19c501 100644 --- a/libAACdec/src/aacdecoder.cpp +++ b/libAACdec/src/aacdecoder.cpp @@ -338,17 +338,22 @@ AAC_DECODER_ERROR CAacDecoder_AncDataParse ( \return Error code */ static AAC_DECODER_ERROR CDataStreamElement_Read ( + HANDLE_AACDECODER self, HANDLE_FDK_BITSTREAM bs, - CAncData *ancData, - HANDLE_AAC_DRC hDrcInfo, - HANDLE_TRANSPORTDEC pTp, UCHAR *elementInstanceTag, UINT alignmentAnchor ) { + HANDLE_TRANSPORTDEC pTp; + CAncData *ancData; AAC_DECODER_ERROR error = AAC_DEC_OK; - UINT dataStart; + UINT dataStart, dseBits; int dataByteAlignFlag, count; + FDK_ASSERT(self != NULL); + + ancData = &self->ancData; + pTp = self->hInput; + int crcReg = transportDec_CrcStartReg(pTp, 0); /* Element Instance Tag */ @@ -361,6 +366,7 @@ static AAC_DECODER_ERROR CDataStreamElement_Read ( if (count == 255) { count += FDKreadBits(bs,8); /* EscCount */ } + dseBits = count*8; if (dataByteAlignFlag) { FDKbyteAlign(bs, alignmentAnchor); @@ -372,19 +378,29 @@ static AAC_DECODER_ERROR CDataStreamElement_Read ( transportDec_CrcEndReg(pTp, crcReg); { - INT readBits, dataBits = count<<3; - /* Move to the beginning of the data junk */ FDKpushBack(bs, dataStart-FDKgetValidBits(bs)); /* Read Anc data if available */ - readBits = aacDecoder_drcMarkPayload( hDrcInfo, bs, DVB_DRC_ANC_DATA ); + aacDecoder_drcMarkPayload( self->hDrcInfo, bs, DVB_DRC_ANC_DATA ); + } + + { + PCMDMX_ERROR dmxErr = PCMDMX_OK; + + /* Move to the beginning of the data junk */ + FDKpushBack(bs, dataStart-FDKgetValidBits(bs)); - if (readBits != dataBits) { - /* Move to the end again. */ - FDKpushBiDirectional(bs, FDKgetValidBits(bs)-dataStart+dataBits); + /* Read DMX meta-data */ + dmxErr = pcmDmx_Parse ( + self->hPcmUtils, + bs, + dseBits, + 0 /* not mpeg2 */ ); } - } + + /* Move to the very end of the element. */ + FDKpushBiDirectional(bs, FDKgetValidBits(bs)-dataStart+dseBits); return error; } @@ -701,6 +717,12 @@ void CStreamInfoInit(CStreamInfo *pStreamInfo) pStreamInfo->numChannels = 0; pStreamInfo->sampleRate = 0; pStreamInfo->frameSize = 0; + + pStreamInfo->outputDelay = 0; + + /* DRC */ + pStreamInfo->drcProgRefLev = -1; /* set program reference level to not indicated */ + pStreamInfo->drcPresMode = -1; /* default: presentation mode not indicated */ } /*! @@ -774,7 +796,7 @@ LINKSPEC_CPP void CAacDecoder_Close(HANDLE_AACDECODER self) if (self == NULL) return; - for (ch=0; ch<(6); ch++) { + for (ch=0; ch<(8); ch++) { if (self->pAacDecoderStaticChannelInfo[ch] != NULL) { if (self->pAacDecoderStaticChannelInfo[ch]->pOverlapBuffer != NULL) { FreeOverlapBuffer (&self->pAacDecoderStaticChannelInfo[ch]->pOverlapBuffer); @@ -851,18 +873,19 @@ LINKSPEC_CPP AAC_DECODER_ERROR CAacDecoder_Init(HANDLE_AACDECODER self, const CS /* valid number of channels -> copy program config element (PCE) from ASC */ FDKmemcpy(&self->pce, &asc->m_progrConfigElement, sizeof(CProgramConfig)); /* Built element table */ - el = CProgramConfig_GetElementTable(&asc->m_progrConfigElement, self->elements, 7); - for (; el<7; el++) { + el = CProgramConfig_GetElementTable(&asc->m_progrConfigElement, self->elements, (8), &self->chMapIndex); + for (; el<(8); el++) { self->elements[el] = ID_NONE; } } else { return AAC_DEC_UNSUPPORTED_CHANNELCONFIG; } } else { + self->chMapIndex = 0; if (transportDec_GetFormat(self->hInput) == TT_MP4_ADTS) { /* set default max_channels for memory allocation because in implicit channel mapping mode we don't know the actual number of channels until we processed at least one raw_data_block(). */ - ascChannels = (6); + ascChannels = (8); } else { return AAC_DEC_UNSUPPORTED_CHANNELCONFIG; } @@ -874,26 +897,34 @@ LINKSPEC_CPP AAC_DECODER_ERROR CAacDecoder_Init(HANDLE_AACDECODER self, const CS case 1: case 2: case 3: case 4: case 5: case 6: ascChannels = asc->m_channelConfiguration; break; - case 7: + case 11: + ascChannels = 7; + break; + case 7: case 12: case 14: ascChannels = 8; break; default: return AAC_DEC_UNSUPPORTED_CHANNELCONFIG; } + if (ascChannels > (8)) { + return AAC_DEC_UNSUPPORTED_CHANNELCONFIG; + } + /* Initialize constant mappings for channel config 1-7 */ if (asc->m_channelConfiguration > 0) { int el; - FDKmemcpy(self->elements, elementsTab[asc->m_channelConfiguration-1], sizeof(MP4_ELEMENT_ID)*FDKmin(7,7)); - for (el=7; el<7; el++) { + FDKmemcpy(self->elements, elementsTab[asc->m_channelConfiguration-1], sizeof(MP4_ELEMENT_ID)*FDKmin(7,(8))); + for (el=7; el<(8); el++) { self->elements[el] = ID_NONE; } for (ch=0; ch<ascChannels; ch++) { self->chMapping[ch] = ch; } - for (; ch<(6); ch++) { + for (; ch<(8); ch++) { self->chMapping[ch] = 255; } + self->chMapIndex = asc->m_channelConfiguration; } #ifdef TP_PCE_ENABLE else { @@ -909,9 +940,6 @@ LINKSPEC_CPP AAC_DECODER_ERROR CAacDecoder_Init(HANDLE_AACDECODER self, const CS self->streamInfo.channelConfig = asc->m_channelConfiguration; - if (ascChannels > (6)) { - return AAC_DEC_UNSUPPORTED_CHANNELCONFIG; - } if (self->streamInfo.aot != asc->m_aot) { self->streamInfo.aot = asc->m_aot; ascChanged = 1; @@ -1096,6 +1124,7 @@ LINKSPEC_CPP AAC_DECODER_ERROR CAacDecoder_DecodeFrame( MP4_ELEMENT_ID type = ID_NONE; /* Current element type */ INT aacChannels=0; /* Channel counter for channels found in the bitstream */ + int chOutMapIdx; /* Output channel mapping index (see comment below) */ INT auStartAnchor = (INT)FDKgetValidBits(bs); /* AU start bit buffer position for AU byte alignment */ @@ -1119,12 +1148,12 @@ LINKSPEC_CPP AAC_DECODER_ERROR CAacDecoder_DecodeFrame( if (self->streamInfo.channelConfig == 0) { /* Init Channel/Element mapping table */ - for (ch=0; ch<(6); ch++) { + for (ch=0; ch<(8); ch++) { self->chMapping[ch] = 255; } if (!CProgramConfig_IsValid(pce)) { int el; - for (el=0; el<7; el++) { + for (el=0; el<(8); el++) { self->elements[el] = ID_NONE; } } @@ -1161,11 +1190,8 @@ LINKSPEC_CPP AAC_DECODER_ERROR CAacDecoder_DecodeFrame( CConcealment_InitChannelData(&self->pAacDecoderStaticChannelInfo[ch]->concealmentInfo, &self->concealCommonData, self->streamInfo.aacSamplesPerFrame ); - /* Clear concealment buffers to get rid of the complete history */ - FDKmemclear(self->pAacDecoderStaticChannelInfo[ch]->concealmentInfo.spectralCoefficient, 1024 * sizeof(FIXP_CNCL)); - FDKmemclear(self->pAacDecoderStaticChannelInfo[ch]->concealmentInfo.specScale, 8 * sizeof(SHORT)); /* Clear overlap-add buffers to avoid clicks. */ - FDKmemclear(self->pAacDecoderStaticChannelInfo[ch]->IMdct.overlap.freq, OverlapBufferSize*sizeof(FIXP_DBL)); + FDKmemclear(self->pAacDecoderStaticChannelInfo[ch]->pOverlapBuffer, OverlapBufferSize*sizeof(FIXP_DBL)); } } @@ -1378,10 +1404,8 @@ LINKSPEC_CPP AAC_DECODER_ERROR CAacDecoder_DecodeFrame( { UCHAR element_instance_tag; - CDataStreamElement_Read( bs, - &self->ancData, - self->hDrcInfo, - self->hInput, + CDataStreamElement_Read( self, + bs, &element_instance_tag, auStartAnchor ); @@ -1401,29 +1425,6 @@ LINKSPEC_CPP AAC_DECODER_ERROR CAacDecoder_DecodeFrame( //self->frameOK = 0; } } - - { - UCHAR *pDvbAncData = NULL; - AAC_DECODER_ERROR ancErr; - int ancIndex; - int dvbAncDataSize = 0; - - /* Ask how many anc data elements are in buffer */ - ancIndex = self->ancData.nrElements - 1; - /* Get the last one (if available) */ - ancErr = CAacDecoder_AncDataGet( &self->ancData, - ancIndex, - &pDvbAncData, - &dvbAncDataSize ); - - if (ancErr == AAC_DEC_OK) { - pcmDmx_ReadDvbAncData ( - self->hPcmUtils, - pDvbAncData, - dvbAncDataSize, - 0 /* not mpeg2 */ ); - } - } break; #ifdef TP_PCE_ENABLE @@ -1442,9 +1443,9 @@ LINKSPEC_CPP AAC_DECODER_ERROR CAacDecoder_DecodeFrame( } else if ( result > 1 ) { /* Built element table */ - int elIdx = CProgramConfig_GetElementTable(pce, self->elements, 7); + int elIdx = CProgramConfig_GetElementTable(pce, self->elements, (8), &self->chMapIndex); /* Reset the remaining tabs */ - for ( ; elIdx<7; elIdx++) { + for ( ; elIdx<(8); elIdx++) { self->elements[elIdx] = ID_NONE; } /* Make new number of channel persistant */ @@ -1510,10 +1511,19 @@ LINKSPEC_CPP AAC_DECODER_ERROR CAacDecoder_DecodeFrame( break; } } - if (err == SBRDEC_OK) { + switch (err) { + case SBRDEC_PARSE_ERROR: + /* Can not go on parsing because we do not + know the length of the SBR extension data. */ + FDKpushFor(bs, bitCnt); + bitCnt = 0; + break; + case SBRDEC_OK: self->sbrEnabled = 1; - } else { + break; + default: self->frameOK = 0; + break; } } @@ -1603,13 +1613,17 @@ LINKSPEC_CPP AAC_DECODER_ERROR CAacDecoder_DecodeFrame( self->frameOK=0; } - /* store or restore the number of channels */ + /* store or restore the number of channels and the corresponding info */ if ( self->frameOK && !(flags &(AACDEC_CONCEAL|AACDEC_FLUSH)) ) { - self->concealChannels = aacChannels; /* store */ + self->aacChannelsPrev = aacChannels; /* store */ + FDKmemcpy(self->channelTypePrev, self->channelType, (8)*sizeof(AUDIO_CHANNEL_TYPE)); /* store */ + FDKmemcpy(self->channelIndicesPrev, self->channelIndices, (8)*sizeof(UCHAR)); /* store */ self->sbrEnabledPrev = self->sbrEnabled; } else { if (self->aacChannels > 0) { - aacChannels = self->concealChannels; /* restore */ + aacChannels = self->aacChannelsPrev; /* restore */ + FDKmemcpy(self->channelType, self->channelTypePrev, (8)*sizeof(AUDIO_CHANNEL_TYPE)); /* restore */ + FDKmemcpy(self->channelIndices, self->channelIndicesPrev, (8)*sizeof(UCHAR)); /* restore */ self->sbrEnabled = self->sbrEnabledPrev; } } @@ -1632,12 +1646,31 @@ LINKSPEC_CPP AAC_DECODER_ERROR CAacDecoder_DecodeFrame( return ErrorStatus; } + /* Setup the output channel mapping. The table below shows the four possibilities: + * # | chCfg | PCE | cChCfg | chOutMapIdx + * ---+-------+-----+--------+------------------ + * 1 | > 0 | no | - | chCfg + * 2 | 0 | yes | > 0 | cChCfg + * 3 | 0 | yes | 0 | aacChannels || 0 + * 4 | 0 | no | - | aacChannels || 0 + * ---+-------+-----+--------+------------------ + * Where chCfg is the channel configuration index from ASC and cChCfg is a corresponding chCfg + * derived from a given PCE. The variable aacChannels represents the number of channel found + * during bitstream decoding. Due to the structure of the mapping table it can only be used for + * mapping if its value is smaller than 7. Otherwise we use the fallback (0) which is a simple + * pass-through. The possibility #4 should appear only with MPEG-2 (ADTS) streams. This is + * mode is called "implicit channel mapping". + */ + chOutMapIdx = ((self->chMapIndex==0) && (aacChannels<7)) ? aacChannels : self->chMapIndex; + /* Inverse transform */ { int stride, offset, c; + /* Turn on/off DRC modules level normalization in digital domain depending on the limiter status. */ + aacDecoder_drcSetParam( self->hDrcInfo, APPLY_NORMALIZATION, (self->limiterEnableCurr) ? 0 : 1 ); /* Extract DRC control data and map it to channels (without bitstream delay) */ aacDecoder_drcProlog ( self->hDrcInfo, @@ -1663,13 +1696,18 @@ LINKSPEC_CPP AAC_DECODER_ERROR CAacDecoder_DecodeFrame( /* Setup offset and stride for time buffer traversal. */ if (interleaved) { stride = aacChannels; - offset = self->channelOutputMapping[aacChannels-1][c]; + offset = self->channelOutputMapping[chOutMapIdx][c]; } else { stride = 1; - offset = self->channelOutputMapping[aacChannels-1][c] * self->streamInfo.aacSamplesPerFrame; + offset = self->channelOutputMapping[chOutMapIdx][c] * self->streamInfo.aacSamplesPerFrame; } + if ( flags&AACDEC_FLUSH ) { + /* Clear pAacDecoderChannelInfo->pSpectralCoefficient because with AACDEC_FLUSH set it contains undefined data. */ + FDKmemclear(pAacDecoderChannelInfo->pSpectralCoefficient, sizeof(FIXP_DBL)*self->streamInfo.aacSamplesPerFrame); + } + /* Conceal defective spectral data */ @@ -1688,12 +1726,15 @@ LINKSPEC_CPP AAC_DECODER_ERROR CAacDecoder_DecodeFrame( /* Reset DRC control data for this channel */ aacDecoder_drcInitChannelData ( &self->pAacDecoderStaticChannelInfo[c]->drcData ); } + /* The DRC module demands to be called with the gain field holding the gain scale. */ + self->extGain[0] = (FIXP_DBL)TDL_GAIN_SCALING; /* DRC processing */ aacDecoder_drcApply ( self->hDrcInfo, self->hSbrDecoder, pAacDecoderChannelInfo, &self->pAacDecoderStaticChannelInfo[c]->drcData, + self->extGain, c, self->streamInfo.aacSamplesPerFrame, self->sbrEnabled @@ -1711,6 +1752,7 @@ LINKSPEC_CPP AAC_DECODER_ERROR CAacDecoder_DecodeFrame( (self->frameOK && !(flags&AACDEC_CONCEAL)), self->aacCommonData.workBufferCore1->mdctOutTemp ); + self->extGainDelay = self->streamInfo.aacSamplesPerFrame; break; case AACDEC_RENDER_ELDFB: CBlock_FrequencyToTimeLowDelay( @@ -1720,6 +1762,7 @@ LINKSPEC_CPP AAC_DECODER_ERROR CAacDecoder_DecodeFrame( self->streamInfo.aacSamplesPerFrame, stride ); + self->extGainDelay = (self->streamInfo.aacSamplesPerFrame*2 - self->streamInfo.aacSamplesPerFrame/2 - 1)/2; break; default: ErrorStatus = AAC_DEC_UNKNOWN; @@ -1743,11 +1786,20 @@ LINKSPEC_CPP AAC_DECODER_ERROR CAacDecoder_DecodeFrame( ); } + /* Add additional concealment delay */ + self->streamInfo.outputDelay += CConcealment_GetDelay(&self->concealCommonData) * self->streamInfo.aacSamplesPerFrame; + + /* Map DRC data to StreamInfo structure */ + aacDecoder_drcGetInfo ( + self->hDrcInfo, + &self->streamInfo.drcPresMode, + &self->streamInfo.drcProgRefLev + ); /* Reorder channel type information tables. */ { - AUDIO_CHANNEL_TYPE types[(6)]; - UCHAR idx[(6)]; + AUDIO_CHANNEL_TYPE types[(8)]; + UCHAR idx[(8)]; int c; FDK_ASSERT(sizeof(self->channelType) == sizeof(types)); @@ -1757,8 +1809,8 @@ LINKSPEC_CPP AAC_DECODER_ERROR CAacDecoder_DecodeFrame( FDKmemcpy(idx, self->channelIndices, sizeof(idx)); for (c=0; c<aacChannels; c++) { - self->channelType[self->channelOutputMapping[aacChannels-1][c]] = types[c]; - self->channelIndices[self->channelOutputMapping[aacChannels-1][c]] = idx[c]; + self->channelType[self->channelOutputMapping[chOutMapIdx][c]] = types[c]; + self->channelIndices[self->channelOutputMapping[chOutMapIdx][c]] = idx[c]; } } diff --git a/libAACdec/src/aacdecoder.h b/libAACdec/src/aacdecoder.h index 16351e6..3541773 100644 --- a/libAACdec/src/aacdecoder.h +++ b/libAACdec/src/aacdecoder.h @@ -111,6 +111,7 @@ amm-info@iis.fraunhofer.de #include "aacdec_drc.h" #include "pcmutils_lib.h" + #include "limiter.h" /* Capabilities flags */ @@ -176,27 +177,31 @@ struct AAC_DECODER_INSTANCE { UINT flags; /*!< Flags for internal decoder use. DO NOT USE self::streaminfo::flags ! */ - MP4_ELEMENT_ID elements[7]; /*!< Table where the element Id's are listed */ - UCHAR elTags[7]; /*!< Table where the elements id Tags are listed */ - UCHAR chMapping[(6)]; /*!< Table of MPEG canonical order to bitstream channel order mapping. */ + MP4_ELEMENT_ID elements[(8)]; /*!< Table where the element Id's are listed */ + UCHAR elTags[(8)]; /*!< Table where the elements id Tags are listed */ + UCHAR chMapping[(8)]; /*!< Table of MPEG canonical order to bitstream channel order mapping. */ - AUDIO_CHANNEL_TYPE channelType[(6)]; /*!< Audio channel type of each output audio channel (from 0 upto numChannels). */ - UCHAR channelIndices[(6)]; /*!< Audio channel index for each output audio channel (from 0 upto numChannels). */ + AUDIO_CHANNEL_TYPE channelType[(8)]; /*!< Audio channel type of each output audio channel (from 0 upto numChannels). */ + UCHAR channelIndices[(8)]; /*!< Audio channel index for each output audio channel (from 0 upto numChannels). */ /* See ISO/IEC 13818-7:2005(E), 8.5.3.2 Explicit channel mapping using a program_config_element() */ const UCHAR (*channelOutputMapping)[8]; /*!< Table for MPEG canonical order to output channel order mapping. */ - + UCHAR chMapIndex; /*!< Index to access one line of the channelOutputMapping table. This is required + because not all 8 channel configurations have the same output mapping. */ CProgramConfig pce; CStreamInfo streamInfo; /*!< pointer to StreamInfo data (read from the bitstream) */ - CAacDecoderChannelInfo *pAacDecoderChannelInfo[(6)]; /*!< Temporal channel memory */ - CAacDecoderStaticChannelInfo *pAacDecoderStaticChannelInfo[(6)]; /*!< Persistent channel memory */ + CAacDecoderChannelInfo *pAacDecoderChannelInfo[(8)]; /*!< Temporal channel memory */ + CAacDecoderStaticChannelInfo *pAacDecoderStaticChannelInfo[(8)]; /*!< Persistent channel memory */ CAacDecoderCommonData aacCommonData; /*!< Temporal shared data for all channels hooked into pAacDecoderChannelInfo */ CConcealParams concealCommonData; - INT concealChannels; + + INT aacChannelsPrev; /*!< The amount of AAC core channels of the last successful decode call. */ + AUDIO_CHANNEL_TYPE channelTypePrev[(8)]; /*!< Array holding the channelType values of the last successful decode call. */ + UCHAR channelIndicesPrev[(8)]; /*!< Array holding the channelIndices values of the last successful decode call. */ HANDLE_SBRDECODER hSbrDecoder; /*!< SBR decoder handle. */ @@ -214,6 +219,12 @@ struct AAC_DECODER_INSTANCE { CAncData ancData; /*!< structure to handle ancillary data */ HANDLE_PCM_DOWNMIX hPcmUtils; /*!< privat data for the PCM utils. */ + TDLimiterPtr hLimiter; /*!< Handle of time domain limiter. */ + UCHAR limiterEnableUser; /*!< The limiter configuration requested by the library user */ + UCHAR limiterEnableCurr; /*!< The current limiter configuration. */ + + FIXP_DBL extGain[1]; /*!< Gain that must be applied to the output signal. */ + UINT extGainDelay; /*!< Delay that must be accounted for extGain. */ }; diff --git a/libAACdec/src/aacdecoder_lib.cpp b/libAACdec/src/aacdecoder_lib.cpp index ec8f41e..82f85ab 100644 --- a/libAACdec/src/aacdecoder_lib.cpp +++ b/libAACdec/src/aacdecoder_lib.cpp @@ -110,7 +110,7 @@ amm-info@iis.fraunhofer.de /* Decoder library info */ #define AACDECODER_LIB_VL0 2 #define AACDECODER_LIB_VL1 5 -#define AACDECODER_LIB_VL2 5 +#define AACDECODER_LIB_VL2 10 #define AACDECODER_LIB_TITLE "AAC Decoder Lib" #define AACDECODER_LIB_BUILD_DATE __DATE__ #define AACDECODER_LIB_BUILD_TIME __TIME__ @@ -397,12 +397,14 @@ aacDecoder_SetParam ( const HANDLE_AACDECODER self, /*!< Handle of the decode CConcealParams *pConcealData = NULL; HANDLE_AAC_DRC hDrcInfo = NULL; HANDLE_PCM_DOWNMIX hPcmDmx = NULL; + TDLimiterPtr hPcmTdl = NULL; /* check decoder handle */ if (self != NULL) { pConcealData = &self->concealCommonData; hDrcInfo = self->hDrcInfo; hPcmDmx = self->hPcmUtils; + hPcmTdl = self->hLimiter; } else { errorStatus = AAC_DEC_INVALID_HANDLE; } @@ -420,8 +422,8 @@ aacDecoder_SetParam ( const HANDLE_AACDECODER self, /*!< Handle of the decode self->outputInterleaved = value; break; - case AAC_PCM_OUTPUT_CHANNELS: - if (value < -1 || value > (6)) { + case AAC_PCM_MIN_OUTPUT_CHANNELS: + if (value < -1 || value > (8)) { return AAC_DEC_SET_PARAM_FAIL; } { @@ -429,7 +431,30 @@ aacDecoder_SetParam ( const HANDLE_AACDECODER self, /*!< Handle of the decode err = pcmDmx_SetParam ( hPcmDmx, - NUMBER_OF_OUTPUT_CHANNELS, + MIN_NUMBER_OF_OUTPUT_CHANNELS, + value ); + + switch (err) { + case PCMDMX_OK: + break; + case PCMDMX_INVALID_HANDLE: + return AAC_DEC_INVALID_HANDLE; + default: + return AAC_DEC_SET_PARAM_FAIL; + } + } + break; + + case AAC_PCM_MAX_OUTPUT_CHANNELS: + if (value < -1 || value > (8)) { + return AAC_DEC_SET_PARAM_FAIL; + } + { + PCMDMX_ERROR err; + + err = pcmDmx_SetParam ( + hPcmDmx, + MAX_NUMBER_OF_OUTPUT_CHANNELS, value ); switch (err) { @@ -449,7 +474,7 @@ aacDecoder_SetParam ( const HANDLE_AACDECODER self, /*!< Handle of the decode err = pcmDmx_SetParam ( hPcmDmx, - DUAL_CHANNEL_DOWNMIX_MODE, + DMX_DUAL_CHANNEL_MODE, value ); switch (err) { @@ -463,6 +488,47 @@ aacDecoder_SetParam ( const HANDLE_AACDECODER self, /*!< Handle of the decode } break; + + case AAC_PCM_LIMITER_ENABLE: + if (value < -1 || value > 1) { + return AAC_DEC_SET_PARAM_FAIL; + } + if (self == NULL) { + return AAC_DEC_INVALID_HANDLE; + } + self->limiterEnableUser = value; + break; + + case AAC_PCM_LIMITER_ATTACK_TIME: + if (value <= 0) { /* module function converts value to unsigned */ + return AAC_DEC_SET_PARAM_FAIL; + } + switch (setLimiterAttack(hPcmTdl, value)) { + case TDLIMIT_OK: + break; + case TDLIMIT_INVALID_HANDLE: + return AAC_DEC_INVALID_HANDLE; + case TDLIMIT_INVALID_PARAMETER: + default: + return AAC_DEC_SET_PARAM_FAIL; + } + break; + + case AAC_PCM_LIMITER_RELEAS_TIME: + if (value <= 0) { /* module function converts value to unsigned */ + return AAC_DEC_SET_PARAM_FAIL; + } + switch (setLimiterRelease(hPcmTdl, value)) { + case TDLIMIT_OK: + break; + case TDLIMIT_INVALID_HANDLE: + return AAC_DEC_INVALID_HANDLE; + case TDLIMIT_INVALID_PARAMETER: + default: + return AAC_DEC_SET_PARAM_FAIL; + } + break; + case AAC_PCM_OUTPUT_CHANNEL_MAPPING: switch (value) { case 0: @@ -609,6 +675,14 @@ LINKSPEC_CPP HANDLE_AACDECODER aacDecoder_Open(TRANSPORT_TYPE transportFmt, UINT goto bail; } + aacDec->hLimiter = createLimiter(TDL_ATTACK_DEFAULT_MS, TDL_RELEASE_DEFAULT_MS, SAMPLE_MAX, (8), 96000); + if (NULL == aacDec->hLimiter) { + err = -1; + goto bail; + } + aacDec->limiterEnableUser = (UCHAR)-1; + aacDec->limiterEnableCurr = 0; + /* Assure that all modules have same delay */ @@ -768,6 +842,7 @@ LINKSPEC_CPP AAC_DECODER_ERROR aacDecoder_DecodeFrame( /* Signal bit stream interruption to other modules if required. */ if ( fTpInterruption || (flags & (AACDEC_INTR|AACDEC_CLRHIST)) ) { + sbrDecoder_SetParam(self->hSbrDecoder, SBR_CLEAR_HISTORY, (flags&AACDEC_CLRHIST)); aacDecoder_SignalInterruption(self); if ( ! (flags & AACDEC_INTR) ) { ErrorStatus = AAC_DEC_TRANSPORT_SYNC_ERROR; @@ -783,6 +858,19 @@ LINKSPEC_CPP AAC_DECODER_ERROR aacDecoder_DecodeFrame( self->streamInfo.numBadBytes = 0; self->streamInfo.numTotalBytes = 0; } + /* Reset the output delay field. The modules will add their figures one after another. */ + self->streamInfo.outputDelay = 0; + + if (self->limiterEnableUser==(UCHAR)-1) { + /* Enbale limiter for all non-lowdelay AOT's. */ + self->limiterEnableCurr = ( self->flags & (AC_LD|AC_ELD) ) ? 0 : 1; + } + else { + /* Use limiter configuration as requested. */ + self->limiterEnableCurr = self->limiterEnableUser; + } + /* reset limiter gain on a per frame basis */ + self->extGain[0] = FL2FXCONST_DBL(1.0f/(float)(1<<TDL_GAIN_SCALING)); ErrorStatus = CAacDecoder_DecodeFrame(self, @@ -825,11 +913,15 @@ LINKSPEC_CPP AAC_DECODER_ERROR aacDecoder_DecodeFrame( if (self->sbrEnabled) { SBR_ERROR sbrError = SBRDEC_OK; + int chOutMapIdx = ((self->chMapIndex==0) && (self->streamInfo.numChannels<7)) ? self->streamInfo.numChannels : self->chMapIndex; /* set params */ sbrDecoder_SetParam ( self->hSbrDecoder, SBR_SYSTEM_BITSTREAM_DELAY, self->sbrParams.bsDelay); + sbrDecoder_SetParam ( self->hSbrDecoder, + SBR_FLUSH_DATA, + (flags & AACDEC_FLUSH) ); if ( self->streamInfo.aot == AOT_ER_AAC_ELD ) { /* Configure QMF */ @@ -838,7 +930,16 @@ LINKSPEC_CPP AAC_DECODER_ERROR aacDecoder_DecodeFrame( (self->flags & AC_LD_MPS) ? 1 : 0 ); } + { + PCMDMX_ERROR dmxErr; + INT maxOutCh = 0; + dmxErr = pcmDmx_GetParam(self->hPcmUtils, MAX_NUMBER_OF_OUTPUT_CHANNELS, &maxOutCh); + if ( (dmxErr == PCMDMX_OK) && (maxOutCh == 1) ) { + /* Disable PS processing if we have to create a mono output signal. */ + self->psPossible = 0; + } + } /* apply SBR processing */ @@ -846,23 +947,29 @@ LINKSPEC_CPP AAC_DECODER_ERROR aacDecoder_DecodeFrame( pTimeData, &self->streamInfo.numChannels, &self->streamInfo.sampleRate, - self->channelOutputMapping[self->streamInfo.numChannels-1], + self->channelOutputMapping[chOutMapIdx], interleaved, self->frameOK, &self->psPossible); if (sbrError == SBRDEC_OK) { + #define UPS_SCALE 2 /* Maximum upsampling factor is 4 (CELP+SBR) */ + FIXP_DBL upsampleFactor = FL2FXCONST_DBL(1.0f/(1<<UPS_SCALE)); /* Update data in streaminfo structure. Assume that the SBR upsampling factor is either 1 or 2 */ self->flags |= AC_SBR_PRESENT; if (self->streamInfo.aacSampleRate != self->streamInfo.sampleRate) { if (self->streamInfo.frameSize == 768) { - self->streamInfo.frameSize = (self->streamInfo.aacSamplesPerFrame * 8) / 3; + upsampleFactor = FL2FXCONST_DBL(8.0f/(3<<UPS_SCALE)); } else { - self->streamInfo.frameSize = self->streamInfo.aacSamplesPerFrame << 1; + upsampleFactor = FL2FXCONST_DBL(2.0f/(1<<UPS_SCALE)); } } + /* Apply upsampling factor to both the core frame length and the core delay */ + self->streamInfo.frameSize = (INT)fMult((FIXP_DBL)self->streamInfo.aacSamplesPerFrame<<UPS_SCALE, upsampleFactor); + self->streamInfo.outputDelay = (UINT)(INT)fMult((FIXP_DBL)self->streamInfo.outputDelay<<UPS_SCALE, upsampleFactor); + self->streamInfo.outputDelay += sbrDecoder_GetDelay( self->hSbrDecoder ); if (self->psPossible) { self->flags |= AC_PS_PRESENT; @@ -870,19 +977,20 @@ LINKSPEC_CPP AAC_DECODER_ERROR aacDecoder_DecodeFrame( self->channelType[1] = ACT_FRONT; self->channelIndices[0] = 0; self->channelIndices[1] = 1; - } else { - self->flags &= ~AC_PS_PRESENT; } } } + { + INT pcmLimiterScale = 0; + PCMDMX_ERROR dmxErr = PCMDMX_OK; if ( flags & (AACDEC_INTR | AACDEC_CLRHIST) ) { /* delete data from the past (e.g. mixdown coeficients) */ pcmDmx_Reset( self->hPcmUtils, PCMDMX_RESET_BS_DATA ); } /* do PCM post processing */ - pcmDmx_ApplyFrame ( + dmxErr = pcmDmx_ApplyFrame ( self->hPcmUtils, pTimeData, self->streamInfo.frameSize, @@ -890,9 +998,39 @@ LINKSPEC_CPP AAC_DECODER_ERROR aacDecoder_DecodeFrame( interleaved, self->channelType, self->channelIndices, - self->channelOutputMapping + self->channelOutputMapping, + (self->limiterEnableCurr) ? &pcmLimiterScale : NULL ); + if (dmxErr == PCMDMX_INVALID_MODE) { + /* Announce the framework that the current combination of channel configuration and downmix + * settings are not know to produce a predictable behavior and thus maybe produce strange output. */ + ErrorStatus = AAC_DEC_DECODE_FRAME_ERROR; + } + if ( flags & AACDEC_CLRHIST ) { + /* Delete the delayed signal. */ + resetLimiter(self->hLimiter); + } + if (self->limiterEnableCurr) + { + /* Set actual signal parameters */ + setLimiterNChannels(self->hLimiter, self->streamInfo.numChannels); + setLimiterSampleRate(self->hLimiter, self->streamInfo.sampleRate); + + applyLimiter( + self->hLimiter, + pTimeData, + self->extGain, + &pcmLimiterScale, + 1, + self->extGainDelay, + self->streamInfo.frameSize + ); + + /* Announce the additional limiter output delay */ + self->streamInfo.outputDelay += getLimiterDelay(self->hLimiter); + } + } /* Signal interruption to take effect in next frame. */ @@ -917,6 +1055,9 @@ LINKSPEC_CPP void aacDecoder_Close ( HANDLE_AACDECODER self ) return; + if (self->hLimiter != NULL) { + destroyLimiter(self->hLimiter); + } if (self->hPcmUtils != NULL) { pcmDmx_Close( &self->hPcmUtils ); diff --git a/libAACdec/src/conceal.cpp b/libAACdec/src/conceal.cpp index c26051c..1c313ef 100644 --- a/libAACdec/src/conceal.cpp +++ b/libAACdec/src/conceal.cpp @@ -762,7 +762,6 @@ int CConcealment_UpdateState( hConcealmentInfo, frameOk ); - if ( !frameOk ) { /* Create data for signal rendering according to the selected concealment method and decoder operating mode. */ @@ -775,11 +774,13 @@ int { default: case ConcealMethodMute: - /* Mute spectral data in case of errors */ - FDKmemclear(pAacDecoderChannelInfo->pSpectralCoefficient, samplesPerFrame * sizeof(FIXP_DBL)); - /* Set last window shape */ - pAacDecoderChannelInfo->icsInfo.WindowShape = hConcealmentInfo->windowShape; - appliedProcessing = 1; + if (!frameOk) { + /* Mute spectral data in case of errors */ + FDKmemclear(pAacDecoderChannelInfo->pSpectralCoefficient, samplesPerFrame * sizeof(FIXP_DBL)); + /* Set last window shape */ + pAacDecoderChannelInfo->icsInfo.WindowShape = hConcealmentInfo->windowShape; + appliedProcessing = 1; + } break; case ConcealMethodNoise: @@ -801,7 +802,7 @@ int pSamplingRateInfo, samplesPerFrame, 0, /* don't use tonal improvement */ - 0); + frameOk); break; } |