Commit 6ccecbc4 authored by Martin Storsjo's avatar Martin Storsjo

Merge remote-tracking branch 'aosp/master'

parents ce186344 d149516e
...@@ -53,6 +53,11 @@ LOCAL_C_INCLUDES := \ ...@@ -53,6 +53,11 @@ LOCAL_C_INCLUDES := \
$(LOCAL_PATH)/libSBRdec/include \ $(LOCAL_PATH)/libSBRdec/include \
$(LOCAL_PATH)/libSBRenc/include $(LOCAL_PATH)/libSBRenc/include
# In tpdec_asc.cpp: address of array 'pPce->FrontElementIsCpe'
# will always evaluate to 'true'.
LOCAL_CLANG_CPPFLAGS += \
-Wno-pointer-bool-conversion
LOCAL_MODULE:= libFraunhoferAAC LOCAL_MODULE:= libFraunhoferAAC
include $(BUILD_STATIC_LIBRARY) include $(BUILD_STATIC_LIBRARY)
...@@ -144,10 +144,9 @@ to allocate memory for the required structures, and the corresponding mpegFileRe ...@@ -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 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 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 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 provide this information manually. For any other bitstream formats that are usually applicable in streaming
usually applicable in streaming applications, the decoder itself will try to synchronize and parse the given applications, the decoder itself will try to synchronize and parse the given bitstream fragment using the
bitstream fragment using the FDK transport library. Hence, for streaming applications (without file access) FDK transport library. Hence, for streaming applications (without file access) this step is not necessary.
this step is not necessary.
-# Call aacDecoder_Open() to open and retrieve a handle to a new AAC decoder instance. -# Call aacDecoder_Open() to open and retrieve a handle to a new AAC decoder instance.
\dontinclude main.cpp \dontinclude main.cpp
...@@ -430,21 +429,68 @@ typedef enum { ...@@ -430,21 +429,68 @@ typedef enum {
typedef enum typedef enum
{ {
AAC_PCM_OUTPUT_INTERLEAVED = 0x0000, /*!< PCM output mode (1: interleaved (default); 0: not interleaved). */ 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 AAC_PCM_DUAL_CHANNEL_OUTPUT_MODE = 0x0002, /*!< Defines how the decoder processes two channel signals: \n
upmixing is applied). \n 0: Leave both signals as they are (default). \n
-1: Disable up-/downmixing. The decoder output contains the same number of channels as the 1: Create a dual mono output signal from channel 1. \n
encoded bitstream. \n 2: Create a dual mono output signal from channel 2. \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.
3: Create a dual mono output signal by mixing both channels (L' = R' = 0.5*Ch1 + 0.5*Ch2). */ 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_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 AAC_CONCEAL_METHOD = 0x0100, /*!< Error concealment: Processing method. \n
0: Spectral muting. \n 0: Spectral muting. \n
...@@ -485,18 +531,18 @@ typedef enum ...@@ -485,18 +531,18 @@ typedef enum
*/ */
typedef struct 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 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 INT frameSize; /*!< The frame size of the decoded PCM audio signal. \n
1024 or 960 for AAC-LC \n 1024 or 960 for AAC-LC \n
2048 or 1920 for HE-AAC (v2) \n 2048 or 1920 for HE-AAC (v2) \n
512 or 480 for AAC-LD and AAC-ELD */ 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. */ 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. */ AUDIO_CHANNEL_TYPE *pChannelType; /*!< Audio channel type of each output audio channel. */
UCHAR *pChannelIndices; /*!< Audio channel index for 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() */ See ISO/IEC 13818-7:2005(E), 8.5.3.2 Explicit channel mapping using a program_config_element() */
/* Decoder internal members. */ /* 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)). */ 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). */ 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, ... */ INT channelConfig; /*!< Channel configuration (0: PCE defined, 1: mono, 2: stereo, ... */
...@@ -509,7 +555,9 @@ typedef struct ...@@ -509,7 +555,9 @@ typedef struct
AUDIO_OBJECT_TYPE extAot; /*!< Extension Audio Object Type (from ASC) */ AUDIO_OBJECT_TYPE extAot; /*!< Extension Audio Object Type (from ASC) */
INT extSamplingRate; /*!< Extension sampling rate in Hz (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.) */ 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 ...@@ -522,10 +570,25 @@ typedef struct
UINT numTotalAccessUnits; /*!< This is the number of total access units that have passed through the decoder. */ 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. */ 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; } CStreamInfo;
typedef struct AAC_DECODER_INSTANCE *HANDLE_AACDECODER; typedef struct AAC_DECODER_INSTANCE *HANDLE_AACDECODER; /*!< Pointer to a AAC decoder instance. */
#ifdef __cplusplus #ifdef __cplusplus
extern "C" extern "C"
...@@ -634,11 +697,15 @@ aacDecoder_Fill ( HANDLE_AACDECODER self, ...@@ -634,11 +697,15 @@ aacDecoder_Fill ( HANDLE_AACDECODER self,
const UINT bufferSize[], const UINT bufferSize[],
UINT *bytesValid ); UINT *bytesValid );
#define AACDEC_CONCEAL 1 /*!< Flag for aacDecoder_DecodeFrame(): do not consider new input data. Do concealment. */ #define AACDEC_CONCEAL 1 /*!< Flag for aacDecoder_DecodeFrame(): Trigger the built-in error concealment module \
#define AACDEC_FLUSH 2 /*!< Flag for aacDecoder_DecodeFrame(): Do not consider new input data. Flush filterbanks (output delayed audio). */ to generate a substitute signal for one lost frame. New input data will not be
#define AACDEC_INTR 4 /*!< Flag for aacDecoder_DecodeFrame(): Signal an input bit stream data discontinuity. Resync any internals as necessary. */ considered. */
#define AACDEC_CLRHIST 8 /*!< Flag for aacDecoder_DecodeFrame(): Clear all signal delay lines and history buffers. #define AACDEC_FLUSH 2 /*!< Flag for aacDecoder_DecodeFrame(): Flush all filterbanks to get all delayed audio \
Caution: This can cause discontinuities in the output signal. */ 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 * \brief Decode one audio frame
......
...@@ -108,15 +108,15 @@ C_ALLOC_MEM(AacDecoder, AAC_DECODER_INSTANCE, 1) ...@@ -108,15 +108,15 @@ C_ALLOC_MEM(AacDecoder, AAC_DECODER_INSTANCE, 1)
/*! The structure CAacDecoderStaticChannelInfo contains the static sideinfo which is needed /*! The structure CAacDecoderStaticChannelInfo contains the static sideinfo which is needed
for the decoding of one aac channel. <br> for the decoding of one aac channel. <br>
Dimension: #AacDecoderChannels */ 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 /*! The structure CAacDecoderChannelInfo contains the dynamic sideinfo which is needed
for the decoding of one aac channel. <br> for the decoding of one aac channel. <br>
Dimension: #AacDecoderChannels */ Dimension: #AacDecoderChannels */
C_ALLOC_MEM2(AacDecoderChannelInfo, CAacDecoderChannelInfo, 1, (6)) C_AALLOC_MEM2(AacDecoderChannelInfo, CAacDecoderChannelInfo, 1, (8))
/*! Overlap buffer */ /*! Overlap buffer */
C_ALLOC_MEM2(OverlapBuffer, FIXP_DBL, OverlapBufferSize, (6)) C_ALLOC_MEM2(OverlapBuffer, FIXP_DBL, OverlapBufferSize, (8))
C_ALLOC_MEM(DrcInfo, CDrcInfo, 1) C_ALLOC_MEM(DrcInfo, CDrcInfo, 1)
...@@ -128,7 +128,7 @@ 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, Dynamic memory areas, might be reused in other algorithm sections,
e.g. the sbr decoder 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) C_ALLOC_MEM_OVERLAY(WorkBufferCore1, CWorkBufferCore1, 1, SECT_DATA_L1, WORKBUFFER1_TAG)
......
...@@ -1777,42 +1777,62 @@ const FIXP_TCC FDKaacDec_tnsCoeff4 [16] = ...@@ -1777,42 +1777,62 @@ const FIXP_TCC FDKaacDec_tnsCoeff4 [16] =
}; };
/* MPEG like mapping (no change). */ /* 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}, /* mono / PS */
{ 0, 1,255,255,255,255,255,255}, /* stereo */ { 0, 1,255,255,255,255,255,255}, /* stereo */
{ 0, 1, 2,255,255,255,255,255}, /* 3ch */ { 0, 1, 2,255,255,255,255,255}, /* 3ch */
{ 0, 1, 2, 3,255,255,255,255}, /* 4ch */ { 0, 1, 2, 3,255,255,255,255}, /* 4ch */
{ 0, 1, 2, 3, 4,255,255,255}, /* 5ch */ { 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,255,255}, /* 5.1ch */
{ 0, 1, 2, 3, 4, 5, 6, 7}, /* 7ch */ { 0, 1, 2, 3, 4, 5, 6, 7}, /* 7.1 front */
{ 0, 1, 2, 3, 4, 5, 6, 7} /* 7.1ch */ { 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). */ /* 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}, /* mono / PS */
{ 0, 1,255,255,255,255,255,255}, /* stereo */ { 0, 1,255,255,255,255,255,255}, /* stereo */
{ 2, 0, 1,255,255,255,255,255}, /* 3ch */ { 2, 0, 1,255,255,255,255,255}, /* 3ch */
{ 2, 0, 1, 3,255,255,255,255}, /* 4ch */ { 2, 0, 1, 3,255,255,255,255}, /* 4ch */
{ 2, 0, 1, 3, 4,255,255,255}, /* 5ch */ { 2, 0, 1, 3, 4,255,255,255}, /* 5ch */
{ 2, 0, 1, 4, 5, 3,255,255}, /* 5.1ch */ { 2, 0, 1, 4, 5, 3,255,255}, /* 5.1ch */
{ 0, 1, 2, 3, 4, 5, 6, 7}, /* 7ch */ { 2, 6, 7, 0, 1, 4, 5, 3}, /* 7.1 front */
{ 2, 0, 1, 6, 7, 4, 5, 3} /* 7.1ch */ { 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 */ /* 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 */ /* 1 */ { 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 */ /* 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 */
{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 */
{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 */
{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 */
{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 */
{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 /*! Random sign bit used for concealment
......
...@@ -177,11 +177,12 @@ extern const USHORT randomSign[AAC_NF_NO_RANDOM_VAL/16]; ...@@ -177,11 +177,12 @@ extern const USHORT randomSign[AAC_NF_NO_RANDOM_VAL/16];
extern const FIXP_DBL pow2_div24minus1[47]; extern const FIXP_DBL pow2_div24minus1[47];
extern const int offsetTab[2][16]; extern const int offsetTab[2][16];
/* Channel mapping indices for time domain I/O. First dimension is channel count-1. */ /* Channel mapping indices for time domain I/O.
extern const UCHAR channelMappingTablePassthrough[8][8]; The first dimension is the channel configuration index. */
extern const UCHAR channelMappingTableWAV[8][8]; extern const UCHAR channelMappingTablePassthrough[15][8];
extern const UCHAR channelMappingTableWAV[15][8];
/* Lookup tables for elements in ER bitstream */ /* 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 */ #endif /* #ifndef AAC_ROM_H */
...@@ -130,7 +130,6 @@ void aacDecoder_drcInit ( ...@@ -130,7 +130,6 @@ void aacDecoder_drcInit (
/* init control fields */ /* init control fields */
self->enable = 0; self->enable = 0;
self->numThreads = 0; self->numThreads = 0;
self->digitalNorm = 0;
/* init params */ /* init params */
pParams = &self->params; pParams = &self->params;
...@@ -139,12 +138,15 @@ void aacDecoder_drcInit ( ...@@ -139,12 +138,15 @@ void aacDecoder_drcInit (
pParams->usrCut = FL2FXCONST_DBL(0.0f); pParams->usrCut = FL2FXCONST_DBL(0.0f);
pParams->boost = FL2FXCONST_DBL(0.0f); pParams->boost = FL2FXCONST_DBL(0.0f);
pParams->usrBoost = 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->expiryFrame = AACDEC_DRC_DFLT_EXPIRY_FRAMES;
pParams->applyDigitalNorm = 0;
pParams->applyHeavyCompression = 0; pParams->applyHeavyCompression = 0;
/* initial program ref level = target ref level */ /* initial program ref level = target ref level */
self->progRefLevel = pParams->targetRefLevel; self->progRefLevel = pParams->targetRefLevel;
self->progRefLevelPresent = 0;
self->presMode = -1;
} }
...@@ -222,11 +224,12 @@ AAC_DECODER_ERROR aacDecoder_drcSetParam ( ...@@ -222,11 +224,12 @@ AAC_DECODER_ERROR aacDecoder_drcSetParam (
return AAC_DEC_INVALID_HANDLE; return AAC_DEC_INVALID_HANDLE;
} }
if (value < 0) { if (value < 0) {
self->digitalNorm = 0; self->params.applyDigitalNorm = 0;
self->params.targetRefLevel = -1;
} }
else { else {
/* ref_level must be between 0 and MAX_REFERENCE_LEVEL, inclusive */ /* ref_level must be between 0 and MAX_REFERENCE_LEVEL, inclusive */
self->digitalNorm = 1; self->params.applyDigitalNorm = 1;
if (self->params.targetRefLevel != (SCHAR)value) { if (self->params.targetRefLevel != (SCHAR)value) {
self->params.targetRefLevel = (SCHAR)value; self->params.targetRefLevel = (SCHAR)value;
self->progRefLevel = (SCHAR)value; /* Always set the program reference level equal to the self->progRefLevel = (SCHAR)value; /* Always set the program reference level equal to the
...@@ -234,6 +237,16 @@ AAC_DECODER_ERROR aacDecoder_drcSetParam ( ...@@ -234,6 +237,16 @@ AAC_DECODER_ERROR aacDecoder_drcSetParam (
} }
} }
break; 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: case APPLY_HEAVY_COMPRESSION:
if (value < 0 || value > 1) { if (value < 0 || value > 1) {
return AAC_DEC_SET_PARAM_FAIL; return AAC_DEC_SET_PARAM_FAIL;
...@@ -278,7 +291,7 @@ AAC_DECODER_ERROR aacDecoder_drcSetParam ( ...@@ -278,7 +291,7 @@ AAC_DECODER_ERROR aacDecoder_drcSetParam (
self->enable = ( (self->params.boost > (FIXP_DBL)0) self->enable = ( (self->params.boost > (FIXP_DBL)0)
|| (self->params.cut > (FIXP_DBL)0) || (self->params.cut > (FIXP_DBL)0)
|| (self->params.applyHeavyCompression != 0) || (self->params.applyHeavyCompression != 0)
|| (self->digitalNorm == 1) ); || (self->params.targetRefLevel >= 0) );
return ErrorStatus; return ErrorStatus;
...@@ -539,7 +552,7 @@ static int aacDecoder_drcReadCompression ( ...@@ -539,7 +552,7 @@ static int aacDecoder_drcReadCompression (
UINT payloadPosition ) UINT payloadPosition )
{ {
int bitCnt = 0; int bitCnt = 0;
int dmxLevelsPresent, compressionPresent; int dmxLevelsPresent, extensionPresent, compressionPresent;
int coarseGrainTcPresent, fineGrainTcPresent; int coarseGrainTcPresent, fineGrainTcPresent;
/* Move to the beginning of the DRC payload field */ /* Move to the beginning of the DRC payload field */
...@@ -561,8 +574,9 @@ static int aacDecoder_drcReadCompression ( ...@@ -561,8 +574,9 @@ static int aacDecoder_drcReadCompression (
return 0; return 0;
} }
FDKreadBits(bs, 2); /* dolby_surround_mode */ FDKreadBits(bs, 2); /* dolby_surround_mode */
FDKreadBits(bs, 2); /* presentation_mode */ pDrcBs->presMode = FDKreadBits(bs, 2); /* presentation_mode */
if (FDKreadBits(bs, 2) != 0) { /* reserved, set to 0 */ FDKreadBits(bs, 1); /* stereo_downmix_mode */
if (FDKreadBits(bs, 1) != 0) { /* reserved, set to 0 */
return 0; return 0;
} }
...@@ -571,9 +585,7 @@ static int aacDecoder_drcReadCompression ( ...@@ -571,9 +585,7 @@ static int aacDecoder_drcReadCompression (
return 0; return 0;
} }
dmxLevelsPresent = FDKreadBits(bs, 1); /* downmixing_levels_MPEG4_status */ dmxLevelsPresent = FDKreadBits(bs, 1); /* downmixing_levels_MPEG4_status */
if (FDKreadBits(bs, 1) != 0) { /* reserved, set to 0 */ extensionPresent = FDKreadBits(bs, 1); /* ancillary_data_extension_status; */
return 0;
}
compressionPresent = FDKreadBits(bs, 1); /* audio_coding_mode_and_compression status */ compressionPresent = FDKreadBits(bs, 1); /* audio_coding_mode_and_compression status */
coarseGrainTcPresent = FDKreadBits(bs, 1); /* coarse_grain_timecode_status */ coarseGrainTcPresent = FDKreadBits(bs, 1); /* coarse_grain_timecode_status */
fineGrainTcPresent = FDKreadBits(bs, 1); /* fine_grain_timecode_status */ fineGrainTcPresent = FDKreadBits(bs, 1); /* fine_grain_timecode_status */
...@@ -631,6 +643,19 @@ static int aacDecoder_drcReadCompression ( ...@@ -631,6 +643,19 @@ static int aacDecoder_drcReadCompression (
bitCnt += 16; 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); return (bitCnt);
} }
...@@ -780,9 +805,15 @@ static int aacDecoder_drcExtractAndMap ( ...@@ -780,9 +805,15 @@ static int aacDecoder_drcExtractAndMap (
*/ */
if (pThreadBs->progRefLevel >= 0) { if (pThreadBs->progRefLevel >= 0) {
self->progRefLevel = pThreadBs->progRefLevel; self->progRefLevel = pThreadBs->progRefLevel;
self->progRefLevelPresent = 1;
self->prlExpiryCount = 0; /* Got a new value -> Reset counter */ 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 */ /* SCE, CPE and LFE */
for (ch = 0; ch < validChannels; ch++) { for (ch = 0; ch < validChannels; ch++) {
int mapedChannel = channelMapping[ch]; int mapedChannel = channelMapping[ch];
...@@ -802,6 +833,7 @@ static int aacDecoder_drcExtractAndMap ( ...@@ -802,6 +833,7 @@ static int aacDecoder_drcExtractAndMap (
if ( (pParams->expiryFrame > 0) if ( (pParams->expiryFrame > 0)
&& (self->prlExpiryCount++ > pParams->expiryFrame) ) && (self->prlExpiryCount++ > pParams->expiryFrame) )
{ /* The program reference level is too old, so set it back to the target level. */ { /* The program reference level is too old, so set it back to the target level. */
self->progRefLevelPresent = 0;
self->progRefLevel = pParams->targetRefLevel; self->progRefLevel = pParams->targetRefLevel;
self->prlExpiryCount = 0; self->prlExpiryCount = 0;
} }
...@@ -815,6 +847,7 @@ void aacDecoder_drcApply ( ...@@ -815,6 +847,7 @@ void aacDecoder_drcApply (
void *pSbrDec, void *pSbrDec,
CAacDecoderChannelInfo *pAacDecoderChannelInfo, CAacDecoderChannelInfo *pAacDecoderChannelInfo,
CDrcChannelData *pDrcChData, CDrcChannelData *pDrcChData,
FIXP_DBL *extGain,
int ch, /* needed only for SBR */ int ch, /* needed only for SBR */
int aacFrameSize, int aacFrameSize,
int bSbrPresent ) int bSbrPresent )
...@@ -826,8 +859,8 @@ void aacDecoder_drcApply ( ...@@ -826,8 +859,8 @@ void aacDecoder_drcApply (
FIXP_DBL max_mantissa; FIXP_DBL max_mantissa;
INT max_exponent; INT max_exponent;
FIXP_DBL norm_mantissa = FL2FXCONST_DBL(0.0f); FIXP_DBL norm_mantissa = FL2FXCONST_DBL(0.5f);
INT norm_exponent = 0; INT norm_exponent = 1;
FIXP_DBL fact_mantissa[MAX_DRC_BANDS]; FIXP_DBL fact_mantissa[MAX_DRC_BANDS];
INT fact_exponent[MAX_DRC_BANDS]; INT fact_exponent[MAX_DRC_BANDS];
...@@ -849,6 +882,15 @@ void aacDecoder_drcApply ( ...@@ -849,6 +882,15 @@ void aacDecoder_drcApply (
if (!self->enable) { if (!self->enable) {
sbrDecoder_drcDisable( (HANDLE_SBRDECODER)pSbrDec, ch ); 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; return;
} }
...@@ -864,7 +906,7 @@ void aacDecoder_drcApply ( ...@@ -864,7 +906,7 @@ void aacDecoder_drcApply (
reduced DAC SNR (if signal is attenuated) or clipping (if signal is reduced DAC SNR (if signal is attenuated) or clipping (if signal is
boosted) */ boosted) */
if (self->digitalNorm == 1) if (pParams->targetRefLevel >= 0)
{ {
/* 0.5^((targetRefLevel - progRefLevel)/24) */ /* 0.5^((targetRefLevel - progRefLevel)/24) */
norm_mantissa = fLdPow( norm_mantissa = fLdPow(
...@@ -874,7 +916,18 @@ void aacDecoder_drcApply ( ...@@ -874,7 +916,18 @@ void aacDecoder_drcApply (
3, 3,
&norm_exponent ); &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_mantissa = FL2FXCONST_DBL(0.5f);
norm_exponent = 1; norm_exponent = 1;
} }
...@@ -1112,3 +1165,24 @@ int aacDecoder_drcEpilog ( ...@@ -1112,3 +1165,24 @@ int aacDecoder_drcEpilog (
return err; 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;
}
}
}
}
...@@ -98,7 +98,6 @@ amm-info@iis.fraunhofer.de ...@@ -98,7 +98,6 @@ amm-info@iis.fraunhofer.de
#include "channel.h" #include "channel.h"
#include "FDK_bitstream.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 */ #define AACDEC_DRC_DFLT_EXPIRY_FRAMES ( 50 ) /* Default DRC data expiry time in AAC frames */
/** /**
...@@ -111,6 +110,7 @@ typedef enum ...@@ -111,6 +110,7 @@ typedef enum
TARGET_REF_LEVEL, TARGET_REF_LEVEL,
DRC_BS_DELAY, DRC_BS_DELAY,
DRC_DATA_EXPIRY_FRAME, DRC_DATA_EXPIRY_FRAME,
APPLY_NORMALIZATION,
APPLY_HEAVY_COMPRESSION APPLY_HEAVY_COMPRESSION
} AACDEC_DRC_PARAM; } AACDEC_DRC_PARAM;
...@@ -149,6 +149,8 @@ int aacDecoder_drcProlog ( ...@@ -149,6 +149,8 @@ int aacDecoder_drcProlog (
* \param pSbrDec pointer to SBR decoder instance * \param pSbrDec pointer to SBR decoder instance
* \param pAacDecoderChannelInfo AAC decoder channel instance to be processed * \param pAacDecoderChannelInfo AAC decoder channel instance to be processed
* \param pDrcDat DRC channel data * \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 ch channel index
* \param aacFrameSize AAC frame size * \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 * \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 ( ...@@ -158,6 +160,7 @@ void aacDecoder_drcApply (
void *pSbrDec, void *pSbrDec,
CAacDecoderChannelInfo *pAacDecoderChannelInfo, CAacDecoderChannelInfo *pAacDecoderChannelInfo,
CDrcChannelData *pDrcDat, CDrcChannelData *pDrcDat,
FIXP_DBL *extGain,
int ch, int ch,
int aacFrameSize, int aacFrameSize,
int bSbrPresent ); int bSbrPresent );
...@@ -170,5 +173,17 @@ int aacDecoder_drcEpilog ( ...@@ -170,5 +173,17 @@ int aacDecoder_drcEpilog (
UCHAR channelMapping[], UCHAR channelMapping[],
int validChannels ); 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 */ #endif /* AACDEC_DRC_H */
...@@ -124,6 +124,7 @@ typedef struct ...@@ -124,6 +124,7 @@ typedef struct
{ {
UINT excludedChnsMask; UINT excludedChnsMask;
SCHAR progRefLevel; SCHAR progRefLevel;
SCHAR presMode; /* Presentation mode: 0 (not indicated), 1, 2, and 3 (reserved). */
SCHAR pceInstanceTag; SCHAR pceInstanceTag;
CDrcChannelData channelData; CDrcChannelData channelData;
...@@ -140,6 +141,7 @@ typedef struct ...@@ -140,6 +141,7 @@ typedef struct
UINT expiryFrame; UINT expiryFrame;
SCHAR targetRefLevel; SCHAR targetRefLevel;
UCHAR bsDelayEnable; UCHAR bsDelayEnable;
UCHAR applyDigitalNorm;
UCHAR applyHeavyCompression; UCHAR applyHeavyCompression;
} CDrcParams; } CDrcParams;
...@@ -155,9 +157,11 @@ typedef struct ...@@ -155,9 +157,11 @@ typedef struct
USHORT numPayloads; /* The number of DRC data payload elements found within frame */ 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 */ USHORT numThreads; /* The number of DRC data threads extracted from the found payload elements */
SCHAR progRefLevel; /* Program reference level for all channels */ 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. */ 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 */ 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 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 */ UINT drcPayloadPosition[MAX_DRC_THREADS]; /* Used to store the DRC payload positions in the bitstream */
......
...@@ -338,17 +338,22 @@ AAC_DECODER_ERROR CAacDecoder_AncDataParse ( ...@@ -338,17 +338,22 @@ AAC_DECODER_ERROR CAacDecoder_AncDataParse (
\return Error code \return Error code
*/ */
static AAC_DECODER_ERROR CDataStreamElement_Read ( static AAC_DECODER_ERROR CDataStreamElement_Read (
HANDLE_AACDECODER self,
HANDLE_FDK_BITSTREAM bs, HANDLE_FDK_BITSTREAM bs,
CAncData *ancData,
HANDLE_AAC_DRC hDrcInfo,
HANDLE_TRANSPORTDEC pTp,
UCHAR *elementInstanceTag, UCHAR *elementInstanceTag,
UINT alignmentAnchor ) UINT alignmentAnchor )
{ {
HANDLE_TRANSPORTDEC pTp;
CAncData *ancData;
AAC_DECODER_ERROR error = AAC_DEC_OK; AAC_DECODER_ERROR error = AAC_DEC_OK;
UINT dataStart; UINT dataStart, dseBits;
int dataByteAlignFlag, count; int dataByteAlignFlag, count;
FDK_ASSERT(self != NULL);
ancData = &self->ancData;
pTp = self->hInput;
int crcReg = transportDec_CrcStartReg(pTp, 0); int crcReg = transportDec_CrcStartReg(pTp, 0);
/* Element Instance Tag */ /* Element Instance Tag */
...@@ -361,6 +366,7 @@ static AAC_DECODER_ERROR CDataStreamElement_Read ( ...@@ -361,6 +366,7 @@ static AAC_DECODER_ERROR CDataStreamElement_Read (
if (count == 255) { if (count == 255) {
count += FDKreadBits(bs,8); /* EscCount */ count += FDKreadBits(bs,8); /* EscCount */
} }
dseBits = count*8;
if (dataByteAlignFlag) { if (dataByteAlignFlag) {
FDKbyteAlign(bs, alignmentAnchor); FDKbyteAlign(bs, alignmentAnchor);
...@@ -372,19 +378,29 @@ static AAC_DECODER_ERROR CDataStreamElement_Read ( ...@@ -372,19 +378,29 @@ static AAC_DECODER_ERROR CDataStreamElement_Read (
transportDec_CrcEndReg(pTp, crcReg); transportDec_CrcEndReg(pTp, crcReg);
{ {
INT readBits, dataBits = count<<3;
/* Move to the beginning of the data junk */ /* Move to the beginning of the data junk */
FDKpushBack(bs, dataStart-FDKgetValidBits(bs)); FDKpushBack(bs, dataStart-FDKgetValidBits(bs));
/* Read Anc data if available */ /* 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) { /* Read DMX meta-data */
/* Move to the end again. */ dmxErr = pcmDmx_Parse (
FDKpushBiDirectional(bs, FDKgetValidBits(bs)-dataStart+dataBits); self->hPcmUtils,
bs,
dseBits,
0 /* not mpeg2 */ );
} }
}
/* Move to the very end of the element. */
FDKpushBiDirectional(bs, FDKgetValidBits(bs)-dataStart+dseBits);
return error; return error;
} }
...@@ -701,6 +717,12 @@ void CStreamInfoInit(CStreamInfo *pStreamInfo) ...@@ -701,6 +717,12 @@ void CStreamInfoInit(CStreamInfo *pStreamInfo)
pStreamInfo->numChannels = 0; pStreamInfo->numChannels = 0;
pStreamInfo->sampleRate = 0; pStreamInfo->sampleRate = 0;
pStreamInfo->frameSize = 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) ...@@ -774,7 +796,7 @@ LINKSPEC_CPP void CAacDecoder_Close(HANDLE_AACDECODER self)
if (self == NULL) if (self == NULL)
return; return;
for (ch=0; ch<(6); ch++) { for (ch=0; ch<(8); ch++) {
if (self->pAacDecoderStaticChannelInfo[ch] != NULL) { if (self->pAacDecoderStaticChannelInfo[ch] != NULL) {
if (self->pAacDecoderStaticChannelInfo[ch]->pOverlapBuffer != NULL) { if (self->pAacDecoderStaticChannelInfo[ch]->pOverlapBuffer != NULL) {
FreeOverlapBuffer (&self->pAacDecoderStaticChannelInfo[ch]->pOverlapBuffer); FreeOverlapBuffer (&self->pAacDecoderStaticChannelInfo[ch]->pOverlapBuffer);
...@@ -851,18 +873,19 @@ LINKSPEC_CPP AAC_DECODER_ERROR CAacDecoder_Init(HANDLE_AACDECODER self, const CS ...@@ -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 */ /* valid number of channels -> copy program config element (PCE) from ASC */
FDKmemcpy(&self->pce, &asc->m_progrConfigElement, sizeof(CProgramConfig)); FDKmemcpy(&self->pce, &asc->m_progrConfigElement, sizeof(CProgramConfig));
/* Built element table */ /* Built element table */
el = CProgramConfig_GetElementTable(&asc->m_progrConfigElement, self->elements, 7); el = CProgramConfig_GetElementTable(&asc->m_progrConfigElement, self->elements, (8), &self->chMapIndex);
for (; el<7; el++) { for (; el<(8); el++) {
self->elements[el] = ID_NONE; self->elements[el] = ID_NONE;
} }
} else { } else {
return AAC_DEC_UNSUPPORTED_CHANNELCONFIG; return AAC_DEC_UNSUPPORTED_CHANNELCONFIG;
} }
} else { } else {
self->chMapIndex = 0;
if (transportDec_GetFormat(self->hInput) == TT_MP4_ADTS) { if (transportDec_GetFormat(self->hInput) == TT_MP4_ADTS) {
/* set default max_channels for memory allocation because in implicit channel mapping mode /* 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(). */ we don't know the actual number of channels until we processed at least one raw_data_block(). */
ascChannels = (6); ascChannels = (8);
} else { } else {
return AAC_DEC_UNSUPPORTED_CHANNELCONFIG; return AAC_DEC_UNSUPPORTED_CHANNELCONFIG;
} }
...@@ -874,26 +897,34 @@ LINKSPEC_CPP AAC_DECODER_ERROR CAacDecoder_Init(HANDLE_AACDECODER self, const CS ...@@ -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: case 1: case 2: case 3: case 4: case 5: case 6:
ascChannels = asc->m_channelConfiguration; ascChannels = asc->m_channelConfiguration;
break; break;
case 7: case 11:
ascChannels = 7;
break;
case 7: case 12: case 14:
ascChannels = 8; ascChannels = 8;
break; break;
default: default:
return AAC_DEC_UNSUPPORTED_CHANNELCONFIG; return AAC_DEC_UNSUPPORTED_CHANNELCONFIG;
} }
if (ascChannels > (8)) {
return AAC_DEC_UNSUPPORTED_CHANNELCONFIG;
}
/* Initialize constant mappings for channel config 1-7 */ /* Initialize constant mappings for channel config 1-7 */
if (asc->m_channelConfiguration > 0) { if (asc->m_channelConfiguration > 0) {
int el; int el;
FDKmemcpy(self->elements, elementsTab[asc->m_channelConfiguration-1], sizeof(MP4_ELEMENT_ID)*FDKmin(7,7)); FDKmemcpy(self->elements, elementsTab[asc->m_channelConfiguration-1], sizeof(MP4_ELEMENT_ID)*FDKmin(7,(8)));
for (el=7; el<7; el++) { for (el=7; el<(8); el++) {
self->elements[el] = ID_NONE; self->elements[el] = ID_NONE;
} }
for (ch=0; ch<ascChannels; ch++) { for (ch=0; ch<ascChannels; ch++) {
self->chMapping[ch] = ch; self->chMapping[ch] = ch;
} }
for (; ch<(6); ch++) { for (; ch<(8); ch++) {
self->chMapping[ch] = 255; self->chMapping[ch] = 255;
} }
self->chMapIndex = asc->m_channelConfiguration;
} }
#ifdef TP_PCE_ENABLE #ifdef TP_PCE_ENABLE
else { else {
...@@ -909,9 +940,6 @@ LINKSPEC_CPP AAC_DECODER_ERROR CAacDecoder_Init(HANDLE_AACDECODER self, const CS ...@@ -909,9 +940,6 @@ LINKSPEC_CPP AAC_DECODER_ERROR CAacDecoder_Init(HANDLE_AACDECODER self, const CS
self->streamInfo.channelConfig = asc->m_channelConfiguration; self->streamInfo.channelConfig = asc->m_channelConfiguration;
if (ascChannels > (6)) {
return AAC_DEC_UNSUPPORTED_CHANNELCONFIG;
}
if (self->streamInfo.aot != asc->m_aot) { if (self->streamInfo.aot != asc->m_aot) {
self->streamInfo.aot = asc->m_aot; self->streamInfo.aot = asc->m_aot;
ascChanged = 1; ascChanged = 1;
...@@ -1096,6 +1124,7 @@ LINKSPEC_CPP AAC_DECODER_ERROR CAacDecoder_DecodeFrame( ...@@ -1096,6 +1124,7 @@ LINKSPEC_CPP AAC_DECODER_ERROR CAacDecoder_DecodeFrame(
MP4_ELEMENT_ID type = ID_NONE; /* Current element type */ MP4_ELEMENT_ID type = ID_NONE; /* Current element type */
INT aacChannels=0; /* Channel counter for channels found in the bitstream */ 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 */ 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( ...@@ -1119,12 +1148,12 @@ LINKSPEC_CPP AAC_DECODER_ERROR CAacDecoder_DecodeFrame(
if (self->streamInfo.channelConfig == 0) { if (self->streamInfo.channelConfig == 0) {
/* Init Channel/Element mapping table */ /* Init Channel/Element mapping table */
for (ch=0; ch<(6); ch++) { for (ch=0; ch<(8); ch++) {
self->chMapping[ch] = 255; self->chMapping[ch] = 255;
} }
if (!CProgramConfig_IsValid(pce)) { if (!CProgramConfig_IsValid(pce)) {
int el; int el;
for (el=0; el<7; el++) { for (el=0; el<(8); el++) {
self->elements[el] = ID_NONE; self->elements[el] = ID_NONE;
} }
} }
...@@ -1161,11 +1190,8 @@ LINKSPEC_CPP AAC_DECODER_ERROR CAacDecoder_DecodeFrame( ...@@ -1161,11 +1190,8 @@ LINKSPEC_CPP AAC_DECODER_ERROR CAacDecoder_DecodeFrame(
CConcealment_InitChannelData(&self->pAacDecoderStaticChannelInfo[ch]->concealmentInfo, CConcealment_InitChannelData(&self->pAacDecoderStaticChannelInfo[ch]->concealmentInfo,
&self->concealCommonData, &self->concealCommonData,
self->streamInfo.aacSamplesPerFrame ); 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. */ /* 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( ...@@ -1378,10 +1404,8 @@ LINKSPEC_CPP AAC_DECODER_ERROR CAacDecoder_DecodeFrame(
{ {
UCHAR element_instance_tag; UCHAR element_instance_tag;
CDataStreamElement_Read( bs, CDataStreamElement_Read( self,
&self->ancData, bs,
self->hDrcInfo,
self->hInput,
&element_instance_tag, &element_instance_tag,
auStartAnchor ); auStartAnchor );
...@@ -1401,29 +1425,6 @@ LINKSPEC_CPP AAC_DECODER_ERROR CAacDecoder_DecodeFrame( ...@@ -1401,29 +1425,6 @@ LINKSPEC_CPP AAC_DECODER_ERROR CAacDecoder_DecodeFrame(
//self->frameOK = 0; //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; break;
#ifdef TP_PCE_ENABLE #ifdef TP_PCE_ENABLE
...@@ -1442,9 +1443,9 @@ LINKSPEC_CPP AAC_DECODER_ERROR CAacDecoder_DecodeFrame( ...@@ -1442,9 +1443,9 @@ LINKSPEC_CPP AAC_DECODER_ERROR CAacDecoder_DecodeFrame(
} }
else if ( result > 1 ) { else if ( result > 1 ) {
/* Built element table */ /* 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 */ /* Reset the remaining tabs */
for ( ; elIdx<7; elIdx++) { for ( ; elIdx<(8); elIdx++) {
self->elements[elIdx] = ID_NONE; self->elements[elIdx] = ID_NONE;
} }
/* Make new number of channel persistant */ /* Make new number of channel persistant */
...@@ -1510,10 +1511,19 @@ LINKSPEC_CPP AAC_DECODER_ERROR CAacDecoder_DecodeFrame( ...@@ -1510,10 +1511,19 @@ LINKSPEC_CPP AAC_DECODER_ERROR CAacDecoder_DecodeFrame(
break; 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; self->sbrEnabled = 1;
} else { break;
default:
self->frameOK = 0; self->frameOK = 0;
break;
} }
} }
...@@ -1603,13 +1613,17 @@ LINKSPEC_CPP AAC_DECODER_ERROR CAacDecoder_DecodeFrame( ...@@ -1603,13 +1613,17 @@ LINKSPEC_CPP AAC_DECODER_ERROR CAacDecoder_DecodeFrame(
self->frameOK=0; 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)) ) { 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; self->sbrEnabledPrev = self->sbrEnabled;
} else { } else {
if (self->aacChannels > 0) { 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; self->sbrEnabled = self->sbrEnabledPrev;
} }
} }
...@@ -1632,12 +1646,31 @@ LINKSPEC_CPP AAC_DECODER_ERROR CAacDecoder_DecodeFrame( ...@@ -1632,12 +1646,31 @@ LINKSPEC_CPP AAC_DECODER_ERROR CAacDecoder_DecodeFrame(
return ErrorStatus; 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 Inverse transform
*/ */
{ {
int stride, offset, c; 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) */ /* Extract DRC control data and map it to channels (without bitstream delay) */
aacDecoder_drcProlog ( aacDecoder_drcProlog (
self->hDrcInfo, self->hDrcInfo,
...@@ -1663,13 +1696,18 @@ LINKSPEC_CPP AAC_DECODER_ERROR CAacDecoder_DecodeFrame( ...@@ -1663,13 +1696,18 @@ LINKSPEC_CPP AAC_DECODER_ERROR CAacDecoder_DecodeFrame(
/* Setup offset and stride for time buffer traversal. */ /* Setup offset and stride for time buffer traversal. */
if (interleaved) { if (interleaved) {
stride = aacChannels; stride = aacChannels;
offset = self->channelOutputMapping[aacChannels-1][c]; offset = self->channelOutputMapping[chOutMapIdx][c];
} else { } else {
stride = 1; 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 Conceal defective spectral data
*/ */
...@@ -1688,12 +1726,15 @@ LINKSPEC_CPP AAC_DECODER_ERROR CAacDecoder_DecodeFrame( ...@@ -1688,12 +1726,15 @@ LINKSPEC_CPP AAC_DECODER_ERROR CAacDecoder_DecodeFrame(
/* Reset DRC control data for this channel */ /* Reset DRC control data for this channel */
aacDecoder_drcInitChannelData ( &self->pAacDecoderStaticChannelInfo[c]->drcData ); 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 */ /* DRC processing */
aacDecoder_drcApply ( aacDecoder_drcApply (
self->hDrcInfo, self->hDrcInfo,
self->hSbrDecoder, self->hSbrDecoder,
pAacDecoderChannelInfo, pAacDecoderChannelInfo,
&self->pAacDecoderStaticChannelInfo[c]->drcData, &self->pAacDecoderStaticChannelInfo[c]->drcData,
self->extGain,
c, c,
self->streamInfo.aacSamplesPerFrame, self->streamInfo.aacSamplesPerFrame,
self->sbrEnabled self->sbrEnabled
...@@ -1711,6 +1752,7 @@ LINKSPEC_CPP AAC_DECODER_ERROR CAacDecoder_DecodeFrame( ...@@ -1711,6 +1752,7 @@ LINKSPEC_CPP AAC_DECODER_ERROR CAacDecoder_DecodeFrame(
(self->frameOK && !(flags&AACDEC_CONCEAL)), (self->frameOK && !(flags&AACDEC_CONCEAL)),
self->aacCommonData.workBufferCore1->mdctOutTemp self->aacCommonData.workBufferCore1->mdctOutTemp
); );
self->extGainDelay = self->streamInfo.aacSamplesPerFrame;
break; break;
case AACDEC_RENDER_ELDFB: case AACDEC_RENDER_ELDFB:
CBlock_FrequencyToTimeLowDelay( CBlock_FrequencyToTimeLowDelay(
...@@ -1720,6 +1762,7 @@ LINKSPEC_CPP AAC_DECODER_ERROR CAacDecoder_DecodeFrame( ...@@ -1720,6 +1762,7 @@ LINKSPEC_CPP AAC_DECODER_ERROR CAacDecoder_DecodeFrame(
self->streamInfo.aacSamplesPerFrame, self->streamInfo.aacSamplesPerFrame,
stride stride
); );
self->extGainDelay = (self->streamInfo.aacSamplesPerFrame*2 - self->streamInfo.aacSamplesPerFrame/2 - 1)/2;
break; break;
default: default:
ErrorStatus = AAC_DEC_UNKNOWN; ErrorStatus = AAC_DEC_UNKNOWN;
...@@ -1743,11 +1786,20 @@ LINKSPEC_CPP AAC_DECODER_ERROR CAacDecoder_DecodeFrame( ...@@ -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. */ /* Reorder channel type information tables. */
{ {
AUDIO_CHANNEL_TYPE types[(6)]; AUDIO_CHANNEL_TYPE types[(8)];
UCHAR idx[(6)]; UCHAR idx[(8)];
int c; int c;
FDK_ASSERT(sizeof(self->channelType) == sizeof(types)); FDK_ASSERT(sizeof(self->channelType) == sizeof(types));
...@@ -1757,8 +1809,8 @@ LINKSPEC_CPP AAC_DECODER_ERROR CAacDecoder_DecodeFrame( ...@@ -1757,8 +1809,8 @@ LINKSPEC_CPP AAC_DECODER_ERROR CAacDecoder_DecodeFrame(
FDKmemcpy(idx, self->channelIndices, sizeof(idx)); FDKmemcpy(idx, self->channelIndices, sizeof(idx));
for (c=0; c<aacChannels; c++) { for (c=0; c<aacChannels; c++) {
self->channelType[self->channelOutputMapping[aacChannels-1][c]] = types[c]; self->channelType[self->channelOutputMapping[chOutMapIdx][c]] = types[c];
self->channelIndices[self->channelOutputMapping[aacChannels-1][c]] = idx[c]; self->channelIndices[self->channelOutputMapping[chOutMapIdx][c]] = idx[c];
} }
} }
......
...@@ -111,6 +111,7 @@ amm-info@iis.fraunhofer.de ...@@ -111,6 +111,7 @@ amm-info@iis.fraunhofer.de
#include "aacdec_drc.h" #include "aacdec_drc.h"
#include "pcmutils_lib.h" #include "pcmutils_lib.h"
#include "limiter.h"
/* Capabilities flags */ /* Capabilities flags */
...@@ -176,27 +177,31 @@ struct AAC_DECODER_INSTANCE { ...@@ -176,27 +177,31 @@ struct AAC_DECODER_INSTANCE {
UINT flags; /*!< Flags for internal decoder use. DO NOT USE self::streaminfo::flags ! */ 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 */ MP4_ELEMENT_ID elements[(8)]; /*!< Table where the element Id's are listed */
UCHAR elTags[7]; /*!< Table where the elements id Tags are listed */ UCHAR elTags[(8)]; /*!< Table where the elements id Tags are listed */
UCHAR chMapping[(6)]; /*!< Table of MPEG canonical order to bitstream channel order mapping. */ 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). */ AUDIO_CHANNEL_TYPE channelType[(8)]; /*!< 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). */ 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() */ /* 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. */ 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; CProgramConfig pce;
CStreamInfo streamInfo; /*!< pointer to StreamInfo data (read from the bitstream) */ CStreamInfo streamInfo; /*!< pointer to StreamInfo data (read from the bitstream) */
CAacDecoderChannelInfo *pAacDecoderChannelInfo[(6)]; /*!< Temporal channel memory */ CAacDecoderChannelInfo *pAacDecoderChannelInfo[(8)]; /*!< Temporal channel memory */
CAacDecoderStaticChannelInfo *pAacDecoderStaticChannelInfo[(6)]; /*!< Persistent channel memory */ CAacDecoderStaticChannelInfo *pAacDecoderStaticChannelInfo[(8)]; /*!< Persistent channel memory */
CAacDecoderCommonData aacCommonData; /*!< Temporal shared data for all channels hooked into pAacDecoderChannelInfo */ CAacDecoderCommonData aacCommonData; /*!< Temporal shared data for all channels hooked into pAacDecoderChannelInfo */
CConcealParams concealCommonData; 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. */ HANDLE_SBRDECODER hSbrDecoder; /*!< SBR decoder handle. */
...@@ -214,6 +219,12 @@ struct AAC_DECODER_INSTANCE { ...@@ -214,6 +219,12 @@ struct AAC_DECODER_INSTANCE {
CAncData ancData; /*!< structure to handle ancillary data */ CAncData ancData; /*!< structure to handle ancillary data */
HANDLE_PCM_DOWNMIX hPcmUtils; /*!< privat data for the PCM utils. */ 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. */
}; };
......
...@@ -110,7 +110,7 @@ amm-info@iis.fraunhofer.de ...@@ -110,7 +110,7 @@ amm-info@iis.fraunhofer.de
/* Decoder library info */ /* Decoder library info */
#define AACDECODER_LIB_VL0 2 #define AACDECODER_LIB_VL0 2
#define AACDECODER_LIB_VL1 5 #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_TITLE "AAC Decoder Lib"
#define AACDECODER_LIB_BUILD_DATE __DATE__ #define AACDECODER_LIB_BUILD_DATE __DATE__
#define AACDECODER_LIB_BUILD_TIME __TIME__ #define AACDECODER_LIB_BUILD_TIME __TIME__
...@@ -397,12 +397,14 @@ aacDecoder_SetParam ( const HANDLE_AACDECODER self, /*!< Handle of the decode ...@@ -397,12 +397,14 @@ aacDecoder_SetParam ( const HANDLE_AACDECODER self, /*!< Handle of the decode
CConcealParams *pConcealData = NULL; CConcealParams *pConcealData = NULL;
HANDLE_AAC_DRC hDrcInfo = NULL; HANDLE_AAC_DRC hDrcInfo = NULL;
HANDLE_PCM_DOWNMIX hPcmDmx = NULL; HANDLE_PCM_DOWNMIX hPcmDmx = NULL;
TDLimiterPtr hPcmTdl = NULL;
/* check decoder handle */ /* check decoder handle */
if (self != NULL) { if (self != NULL) {
pConcealData = &self->concealCommonData; pConcealData = &self->concealCommonData;
hDrcInfo = self->hDrcInfo; hDrcInfo = self->hDrcInfo;
hPcmDmx = self->hPcmUtils; hPcmDmx = self->hPcmUtils;
hPcmTdl = self->hLimiter;
} else { } else {
errorStatus = AAC_DEC_INVALID_HANDLE; errorStatus = AAC_DEC_INVALID_HANDLE;
} }
...@@ -420,8 +422,8 @@ aacDecoder_SetParam ( const HANDLE_AACDECODER self, /*!< Handle of the decode ...@@ -420,8 +422,8 @@ aacDecoder_SetParam ( const HANDLE_AACDECODER self, /*!< Handle of the decode
self->outputInterleaved = value; self->outputInterleaved = value;
break; break;
case AAC_PCM_OUTPUT_CHANNELS: case AAC_PCM_MIN_OUTPUT_CHANNELS:
if (value < -1 || value > (6)) { if (value < -1 || value > (8)) {
return AAC_DEC_SET_PARAM_FAIL; return AAC_DEC_SET_PARAM_FAIL;
} }
{ {
...@@ -429,7 +431,30 @@ aacDecoder_SetParam ( const HANDLE_AACDECODER self, /*!< Handle of the decode ...@@ -429,7 +431,30 @@ aacDecoder_SetParam ( const HANDLE_AACDECODER self, /*!< Handle of the decode
err = pcmDmx_SetParam ( err = pcmDmx_SetParam (
hPcmDmx, 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 ); value );
switch (err) { switch (err) {
...@@ -449,7 +474,7 @@ aacDecoder_SetParam ( const HANDLE_AACDECODER self, /*!< Handle of the decode ...@@ -449,7 +474,7 @@ aacDecoder_SetParam ( const HANDLE_AACDECODER self, /*!< Handle of the decode
err = pcmDmx_SetParam ( err = pcmDmx_SetParam (
hPcmDmx, hPcmDmx,
DUAL_CHANNEL_DOWNMIX_MODE, DMX_DUAL_CHANNEL_MODE,
value ); value );
switch (err) { switch (err) {
...@@ -463,6 +488,47 @@ aacDecoder_SetParam ( const HANDLE_AACDECODER self, /*!< Handle of the decode ...@@ -463,6 +488,47 @@ aacDecoder_SetParam ( const HANDLE_AACDECODER self, /*!< Handle of the decode
} }
break; 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: case AAC_PCM_OUTPUT_CHANNEL_MAPPING:
switch (value) { switch (value) {
case 0: case 0:
...@@ -609,6 +675,14 @@ LINKSPEC_CPP HANDLE_AACDECODER aacDecoder_Open(TRANSPORT_TYPE transportFmt, UINT ...@@ -609,6 +675,14 @@ LINKSPEC_CPP HANDLE_AACDECODER aacDecoder_Open(TRANSPORT_TYPE transportFmt, UINT
goto bail; 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 */ /* Assure that all modules have same delay */
...@@ -768,6 +842,7 @@ LINKSPEC_CPP AAC_DECODER_ERROR aacDecoder_DecodeFrame( ...@@ -768,6 +842,7 @@ LINKSPEC_CPP AAC_DECODER_ERROR aacDecoder_DecodeFrame(
/* Signal bit stream interruption to other modules if required. */ /* Signal bit stream interruption to other modules if required. */
if ( fTpInterruption || (flags & (AACDEC_INTR|AACDEC_CLRHIST)) ) if ( fTpInterruption || (flags & (AACDEC_INTR|AACDEC_CLRHIST)) )
{ {
sbrDecoder_SetParam(self->hSbrDecoder, SBR_CLEAR_HISTORY, (flags&AACDEC_CLRHIST));
aacDecoder_SignalInterruption(self); aacDecoder_SignalInterruption(self);
if ( ! (flags & AACDEC_INTR) ) { if ( ! (flags & AACDEC_INTR) ) {
ErrorStatus = AAC_DEC_TRANSPORT_SYNC_ERROR; ErrorStatus = AAC_DEC_TRANSPORT_SYNC_ERROR;
...@@ -783,6 +858,19 @@ LINKSPEC_CPP AAC_DECODER_ERROR aacDecoder_DecodeFrame( ...@@ -783,6 +858,19 @@ LINKSPEC_CPP AAC_DECODER_ERROR aacDecoder_DecodeFrame(
self->streamInfo.numBadBytes = 0; self->streamInfo.numBadBytes = 0;
self->streamInfo.numTotalBytes = 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, ErrorStatus = CAacDecoder_DecodeFrame(self,
...@@ -825,11 +913,15 @@ LINKSPEC_CPP AAC_DECODER_ERROR aacDecoder_DecodeFrame( ...@@ -825,11 +913,15 @@ LINKSPEC_CPP AAC_DECODER_ERROR aacDecoder_DecodeFrame(
if (self->sbrEnabled) if (self->sbrEnabled)
{ {
SBR_ERROR sbrError = SBRDEC_OK; SBR_ERROR sbrError = SBRDEC_OK;
int chOutMapIdx = ((self->chMapIndex==0) && (self->streamInfo.numChannels<7)) ? self->streamInfo.numChannels : self->chMapIndex;
/* set params */ /* set params */
sbrDecoder_SetParam ( self->hSbrDecoder, sbrDecoder_SetParam ( self->hSbrDecoder,
SBR_SYSTEM_BITSTREAM_DELAY, SBR_SYSTEM_BITSTREAM_DELAY,
self->sbrParams.bsDelay); self->sbrParams.bsDelay);
sbrDecoder_SetParam ( self->hSbrDecoder,
SBR_FLUSH_DATA,
(flags & AACDEC_FLUSH) );
if ( self->streamInfo.aot == AOT_ER_AAC_ELD ) { if ( self->streamInfo.aot == AOT_ER_AAC_ELD ) {
/* Configure QMF */ /* Configure QMF */
...@@ -838,7 +930,16 @@ LINKSPEC_CPP AAC_DECODER_ERROR aacDecoder_DecodeFrame( ...@@ -838,7 +930,16 @@ LINKSPEC_CPP AAC_DECODER_ERROR aacDecoder_DecodeFrame(
(self->flags & AC_LD_MPS) ? 1 : 0 ); (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 */ /* apply SBR processing */
...@@ -846,23 +947,29 @@ LINKSPEC_CPP AAC_DECODER_ERROR aacDecoder_DecodeFrame( ...@@ -846,23 +947,29 @@ LINKSPEC_CPP AAC_DECODER_ERROR aacDecoder_DecodeFrame(
pTimeData, pTimeData,
&self->streamInfo.numChannels, &self->streamInfo.numChannels,
&self->streamInfo.sampleRate, &self->streamInfo.sampleRate,
self->channelOutputMapping[self->streamInfo.numChannels-1], self->channelOutputMapping[chOutMapIdx],
interleaved, interleaved,
self->frameOK, self->frameOK,
&self->psPossible); &self->psPossible);
if (sbrError == SBRDEC_OK) { 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 */ /* Update data in streaminfo structure. Assume that the SBR upsampling factor is either 1 or 2 */
self->flags |= AC_SBR_PRESENT; self->flags |= AC_SBR_PRESENT;
if (self->streamInfo.aacSampleRate != self->streamInfo.sampleRate) { if (self->streamInfo.aacSampleRate != self->streamInfo.sampleRate) {
if (self->streamInfo.frameSize == 768) { if (self->streamInfo.frameSize == 768) {
self->streamInfo.frameSize = (self->streamInfo.aacSamplesPerFrame * 8) / 3; upsampleFactor = FL2FXCONST_DBL(8.0f/(3<<UPS_SCALE));
} else { } 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) { if (self->psPossible) {
self->flags |= AC_PS_PRESENT; self->flags |= AC_PS_PRESENT;
...@@ -870,19 +977,20 @@ LINKSPEC_CPP AAC_DECODER_ERROR aacDecoder_DecodeFrame( ...@@ -870,19 +977,20 @@ LINKSPEC_CPP AAC_DECODER_ERROR aacDecoder_DecodeFrame(
self->channelType[1] = ACT_FRONT; self->channelType[1] = ACT_FRONT;
self->channelIndices[0] = 0; self->channelIndices[0] = 0;
self->channelIndices[1] = 1; self->channelIndices[1] = 1;
} else {
self->flags &= ~AC_PS_PRESENT;
} }
} }
} }
{
INT pcmLimiterScale = 0;
PCMDMX_ERROR dmxErr = PCMDMX_OK;
if ( flags & (AACDEC_INTR | AACDEC_CLRHIST) ) { if ( flags & (AACDEC_INTR | AACDEC_CLRHIST) ) {
/* delete data from the past (e.g. mixdown coeficients) */ /* delete data from the past (e.g. mixdown coeficients) */
pcmDmx_Reset( self->hPcmUtils, PCMDMX_RESET_BS_DATA ); pcmDmx_Reset( self->hPcmUtils, PCMDMX_RESET_BS_DATA );
} }
/* do PCM post processing */ /* do PCM post processing */
pcmDmx_ApplyFrame ( dmxErr = pcmDmx_ApplyFrame (
self->hPcmUtils, self->hPcmUtils,
pTimeData, pTimeData,
self->streamInfo.frameSize, self->streamInfo.frameSize,
...@@ -890,9 +998,39 @@ LINKSPEC_CPP AAC_DECODER_ERROR aacDecoder_DecodeFrame( ...@@ -890,9 +998,39 @@ LINKSPEC_CPP AAC_DECODER_ERROR aacDecoder_DecodeFrame(
interleaved, interleaved,
self->channelType, self->channelType,
self->channelIndices, 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. */ /* Signal interruption to take effect in next frame. */
...@@ -917,6 +1055,9 @@ LINKSPEC_CPP void aacDecoder_Close ( HANDLE_AACDECODER self ) ...@@ -917,6 +1055,9 @@ LINKSPEC_CPP void aacDecoder_Close ( HANDLE_AACDECODER self )
return; return;
if (self->hLimiter != NULL) {
destroyLimiter(self->hLimiter);
}
if (self->hPcmUtils != NULL) { if (self->hPcmUtils != NULL) {
pcmDmx_Close( &self->hPcmUtils ); pcmDmx_Close( &self->hPcmUtils );
......
...@@ -762,7 +762,6 @@ int ...@@ -762,7 +762,6 @@ int
CConcealment_UpdateState( hConcealmentInfo, CConcealment_UpdateState( hConcealmentInfo,
frameOk ); frameOk );
if ( !frameOk )
{ {
/* Create data for signal rendering according to the selected concealment method and decoder operating mode. */ /* Create data for signal rendering according to the selected concealment method and decoder operating mode. */
...@@ -775,11 +774,13 @@ int ...@@ -775,11 +774,13 @@ int
{ {
default: default:
case ConcealMethodMute: case ConcealMethodMute:
/* Mute spectral data in case of errors */ if (!frameOk) {
FDKmemclear(pAacDecoderChannelInfo->pSpectralCoefficient, samplesPerFrame * sizeof(FIXP_DBL)); /* Mute spectral data in case of errors */
/* Set last window shape */ FDKmemclear(pAacDecoderChannelInfo->pSpectralCoefficient, samplesPerFrame * sizeof(FIXP_DBL));
pAacDecoderChannelInfo->icsInfo.WindowShape = hConcealmentInfo->windowShape; /* Set last window shape */
appliedProcessing = 1; pAacDecoderChannelInfo->icsInfo.WindowShape = hConcealmentInfo->windowShape;
appliedProcessing = 1;
}
break; break;
case ConcealMethodNoise: case ConcealMethodNoise:
...@@ -801,7 +802,7 @@ int ...@@ -801,7 +802,7 @@ int
pSamplingRateInfo, pSamplingRateInfo,
samplesPerFrame, samplesPerFrame,
0, /* don't use tonal improvement */ 0, /* don't use tonal improvement */
0); frameOk);
break; break;
} }
......
...@@ -215,7 +215,7 @@ amm-info@iis.fraunhofer.de ...@@ -215,7 +215,7 @@ amm-info@iis.fraunhofer.de
#else #else
#error >>>> Please set architecture characterization defines for your platform (FDK_HIGH_PERFORMANCE)! <<<< #warning >>>> Please set architecture characterization defines for your platform (FDK_HIGH_PERFORMANCE)! <<<<
#endif /* Architecture switches */ #endif /* Architecture switches */
......
...@@ -96,7 +96,7 @@ amm-info@iis.fraunhofer.de ...@@ -96,7 +96,7 @@ amm-info@iis.fraunhofer.de
#if defined(__CC_ARM) || defined(__arm__) || defined(_M_ARM) /* cppp replaced: elif */ #if defined(__CC_ARM) || defined(__arm__) || defined(_M_ARM) /* cppp replaced: elif */
#include "arm/cplx_mul.h" #include "arm/cplx_mul.h"
#elif defined(__GNUC__) && defined(__mips__) /* cppp replaced: elif */ #elif defined(__GNUC__) && defined(__mips__) && __mips_isa_rev < 6
#include "mips/cplx_mul.h" #include "mips/cplx_mul.h"
#endif /* #if defined all cores: bfin, arm, etc. */ #endif /* #if defined all cores: bfin, arm, etc. */
......
...@@ -89,7 +89,7 @@ amm-info@iis.fraunhofer.de ...@@ -89,7 +89,7 @@ amm-info@iis.fraunhofer.de
******************************************************************************/ ******************************************************************************/
#if defined(__GNUC__) && defined(__mips__) #if defined(__GNUC__) && defined(__mips__) && __mips_isa_rev < 6
//#define FUNCTION_cplxMultDiv2_32x16 //#define FUNCTION_cplxMultDiv2_32x16
......
...@@ -146,12 +146,15 @@ typedef struct ...@@ -146,12 +146,15 @@ typedef struct
UCHAR FrontElementIsCpe[PC_FSB_CHANNELS_MAX]; UCHAR FrontElementIsCpe[PC_FSB_CHANNELS_MAX];
UCHAR FrontElementTagSelect[PC_FSB_CHANNELS_MAX]; UCHAR FrontElementTagSelect[PC_FSB_CHANNELS_MAX];
UCHAR FrontElementHeightInfo[PC_FSB_CHANNELS_MAX];
UCHAR SideElementIsCpe[PC_FSB_CHANNELS_MAX]; UCHAR SideElementIsCpe[PC_FSB_CHANNELS_MAX];
UCHAR SideElementTagSelect[PC_FSB_CHANNELS_MAX]; UCHAR SideElementTagSelect[PC_FSB_CHANNELS_MAX];
UCHAR SideElementHeightInfo[PC_FSB_CHANNELS_MAX];
UCHAR BackElementIsCpe[PC_FSB_CHANNELS_MAX]; UCHAR BackElementIsCpe[PC_FSB_CHANNELS_MAX];
UCHAR BackElementTagSelect[PC_FSB_CHANNELS_MAX]; UCHAR BackElementTagSelect[PC_FSB_CHANNELS_MAX];
UCHAR BackElementHeightInfo[PC_FSB_CHANNELS_MAX];
UCHAR LfeElementTagSelect[PC_LFE_CHANNELS_MAX]; UCHAR LfeElementTagSelect[PC_LFE_CHANNELS_MAX];
...@@ -324,16 +327,23 @@ int getSamplingRateIndex( UINT samplingRate ) ...@@ -324,16 +327,23 @@ int getSamplingRateIndex( UINT samplingRate )
*/ */
static inline int getNumberOfTotalChannels(int channelConfig) static inline int getNumberOfTotalChannels(int channelConfig)
{ {
if (channelConfig > 0 && channelConfig < 8) switch (channelConfig) {
return (channelConfig == 7)?8:channelConfig; case 1: case 2: case 3:
else case 4: case 5: case 6:
return channelConfig;
case 7: case 12: case 14:
return 8;
case 11:
return 7;
default:
return 0; return 0;
}
} }
static inline static inline
int getNumberOfEffectiveChannels(const int channelConfig) int getNumberOfEffectiveChannels(const int channelConfig)
{ { /* index: 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15 */
const int n[] = {0,1,2,3,4,5,5,7}; const int n[] = {0,1,2,3,4,5,5,7,0,0, 0, 6, 7, 0, 7, 0};
return n[channelConfig]; return n[channelConfig];
} }
......
...@@ -151,6 +151,7 @@ typedef enum { ...@@ -151,6 +151,7 @@ typedef enum {
#define PC_ASSOCDATA_MAX 8 #define PC_ASSOCDATA_MAX 8
#define PC_CCEL_MAX 16 /* CC elements */ #define PC_CCEL_MAX 16 /* CC elements */
#define PC_COMMENTLENGTH 256 #define PC_COMMENTLENGTH 256
#define PC_NUM_HEIGHT_LAYER 3
/*! /*!
...@@ -239,14 +240,20 @@ int CProgramConfig_LookupElement( ...@@ -239,14 +240,20 @@ int CProgramConfig_LookupElement(
); );
/** /**
* \brief Get table of elements in canonical order. * \brief Get table of elements in canonical order from a
* \param pPce A valid program config structure. * give program config field.
* \param table An array where the element IDs are stored. * \param pPce A valid program config structure.
* \return Total element count including all SCE, CPE and LFE. * \param table An array where the element IDs are stored.
* \param elListSize The length of the table array.
* \param pChMapIdx Pointer to a field receiving the corresponding
* implicit channel configuration index of the given
* PCE. If none can be found it receives the value 0.
* \return Total element count including all SCE, CPE and LFE.
*/ */
int CProgramConfig_GetElementTable( const CProgramConfig *pPce, int CProgramConfig_GetElementTable( const CProgramConfig *pPce,
MP4_ELEMENT_ID table[], MP4_ELEMENT_ID table[],
const INT elListSize ); const INT elListSize,
UCHAR *pChMapIdx );
/** /**
* \brief Initialize a given AudioSpecificConfig structure. * \brief Initialize a given AudioSpecificConfig structure.
......
...@@ -90,6 +90,9 @@ amm-info@iis.fraunhofer.de ...@@ -90,6 +90,9 @@ amm-info@iis.fraunhofer.de
#include "tpdec_lib.h" #include "tpdec_lib.h"
#include "tp_data.h" #include "tp_data.h"
#ifdef TP_PCE_ENABLE
#include "FDK_crc.h"
#endif
void CProgramConfig_Reset(CProgramConfig *pPce) void CProgramConfig_Reset(CProgramConfig *pPce)
...@@ -111,13 +114,75 @@ int CProgramConfig_IsValid ( const CProgramConfig *pPce ) ...@@ -111,13 +114,75 @@ int CProgramConfig_IsValid ( const CProgramConfig *pPce )
} }
#ifdef TP_PCE_ENABLE #ifdef TP_PCE_ENABLE
#define PCE_HEIGHT_EXT_SYNC ( 0xAC )
/*
* Read the extension for height info.
* return 0 if successfull or -1 if the CRC failed.
*/
static
int CProgramConfig_ReadHeightExt(
CProgramConfig *pPce,
HANDLE_FDK_BITSTREAM bs,
int * const bytesAvailable,
const UINT alignmentAnchor
)
{
int err = 0;
FDK_CRCINFO crcInfo; /* CRC state info */
INT crcReg;
FDKcrcInit(&crcInfo, 0x07, 0xFF, 8);
crcReg = FDKcrcStartReg(&crcInfo, bs, 0);
UINT startAnchor = FDKgetValidBits(bs);
FDK_ASSERT(pPce != NULL);
FDK_ASSERT(bs != NULL);
FDK_ASSERT(bytesAvailable != NULL);
if ( (startAnchor >= 24) && (*bytesAvailable >= 3)
&& (FDKreadBits(bs,8) == PCE_HEIGHT_EXT_SYNC) )
{
int i;
for (i=0; i < pPce->NumFrontChannelElements; i++)
{
pPce->FrontElementHeightInfo[i] = (UCHAR) FDKreadBits(bs,2);
}
for (i=0; i < pPce->NumSideChannelElements; i++)
{
pPce->SideElementHeightInfo[i] = (UCHAR) FDKreadBits(bs,2);
}
for (i=0; i < pPce->NumBackChannelElements; i++)
{
pPce->BackElementHeightInfo[i] = (UCHAR) FDKreadBits(bs,2);
}
FDKbyteAlign(bs, alignmentAnchor);
FDKcrcEndReg(&crcInfo, bs, crcReg);
if ((USHORT)FDKreadBits(bs,8) != FDKcrcGetCRC(&crcInfo)) {
/* CRC failed */
err = -1;
}
}
else {
/* No valid extension data found -> restore the initial bitbuffer state */
FDKpushBack(bs, startAnchor - FDKgetValidBits(bs));
}
/* Always report the bytes read. */
*bytesAvailable -= (startAnchor - FDKgetValidBits(bs)) >> 3;
return (err);
}
void CProgramConfig_Read( void CProgramConfig_Read(
CProgramConfig *pPce, CProgramConfig *pPce,
HANDLE_FDK_BITSTREAM bs, HANDLE_FDK_BITSTREAM bs,
UINT alignmentAnchor UINT alignmentAnchor
) )
{ {
int i; int i, err = 0;
int commentBytes;
pPce->NumEffectiveChannels = 0; pPce->NumEffectiveChannels = 0;
pPce->NumChannels = 0; pPce->NumChannels = 0;
...@@ -190,8 +255,12 @@ void CProgramConfig_Read( ...@@ -190,8 +255,12 @@ void CProgramConfig_Read(
FDKbyteAlign(bs, alignmentAnchor); FDKbyteAlign(bs, alignmentAnchor);
pPce->CommentFieldBytes = (UCHAR) FDKreadBits(bs,8); pPce->CommentFieldBytes = (UCHAR) FDKreadBits(bs,8);
commentBytes = pPce->CommentFieldBytes;
/* Search for height info extension and read it if available */
err = CProgramConfig_ReadHeightExt( pPce, bs, &commentBytes, alignmentAnchor );
for (i=0; i < pPce->CommentFieldBytes; i++) for (i=0; i < commentBytes; i++)
{ {
UCHAR text; UCHAR text;
...@@ -203,7 +272,7 @@ void CProgramConfig_Read( ...@@ -203,7 +272,7 @@ void CProgramConfig_Read(
} }
} }
pPce->isValid = 1; pPce->isValid = (err) ? 0 : 1;
} }
/* /*
...@@ -235,6 +304,10 @@ int CProgramConfig_Compare ( const CProgramConfig * const pPce1, ...@@ -235,6 +304,10 @@ int CProgramConfig_Compare ( const CProgramConfig * const pPce1,
} else { } else {
int el, numCh1 = 0, numCh2 = 0; int el, numCh1 = 0, numCh2 = 0;
for (el = 0; el < pPce1->NumFrontChannelElements; el += 1) { for (el = 0; el < pPce1->NumFrontChannelElements; el += 1) {
if (pPce1->FrontElementHeightInfo[el] != pPce2->FrontElementHeightInfo[el]) {
result = 2; /* different height info */
break;
}
numCh1 += pPce1->FrontElementIsCpe[el] ? 2 : 1; numCh1 += pPce1->FrontElementIsCpe[el] ? 2 : 1;
numCh2 += pPce2->FrontElementIsCpe[el] ? 2 : 1; numCh2 += pPce2->FrontElementIsCpe[el] ? 2 : 1;
} }
...@@ -248,6 +321,10 @@ int CProgramConfig_Compare ( const CProgramConfig * const pPce1, ...@@ -248,6 +321,10 @@ int CProgramConfig_Compare ( const CProgramConfig * const pPce1,
} else { } else {
int el, numCh1 = 0, numCh2 = 0; int el, numCh1 = 0, numCh2 = 0;
for (el = 0; el < pPce1->NumSideChannelElements; el += 1) { for (el = 0; el < pPce1->NumSideChannelElements; el += 1) {
if (pPce1->SideElementHeightInfo[el] != pPce2->SideElementHeightInfo[el]) {
result = 2; /* different height info */
break;
}
numCh1 += pPce1->SideElementIsCpe[el] ? 2 : 1; numCh1 += pPce1->SideElementIsCpe[el] ? 2 : 1;
numCh2 += pPce2->SideElementIsCpe[el] ? 2 : 1; numCh2 += pPce2->SideElementIsCpe[el] ? 2 : 1;
} }
...@@ -261,6 +338,10 @@ int CProgramConfig_Compare ( const CProgramConfig * const pPce1, ...@@ -261,6 +338,10 @@ int CProgramConfig_Compare ( const CProgramConfig * const pPce1,
} else { } else {
int el, numCh1 = 0, numCh2 = 0; int el, numCh1 = 0, numCh2 = 0;
for (el = 0; el < pPce1->NumBackChannelElements; el += 1) { for (el = 0; el < pPce1->NumBackChannelElements; el += 1) {
if (pPce1->BackElementHeightInfo[el] != pPce2->BackElementHeightInfo[el]) {
result = 2; /* different height info */
break;
}
numCh1 += pPce1->BackElementIsCpe[el] ? 2 : 1; numCh1 += pPce1->BackElementIsCpe[el] ? 2 : 1;
numCh2 += pPce2->BackElementIsCpe[el] ? 2 : 1; numCh2 += pPce2->BackElementIsCpe[el] ? 2 : 1;
} }
...@@ -290,6 +371,44 @@ void CProgramConfig_GetDefault( CProgramConfig *pPce, ...@@ -290,6 +371,44 @@ void CProgramConfig_GetDefault( CProgramConfig *pPce,
switch (channelConfig) { switch (channelConfig) {
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
case 32: /* 7.1 side channel configuration as defined in FDK_audio.h */
pPce->NumFrontChannelElements = 2;
pPce->FrontElementIsCpe[0] = 0;
pPce->FrontElementIsCpe[1] = 1;
pPce->NumSideChannelElements = 1;
pPce->SideElementIsCpe[0] = 1;
pPce->NumBackChannelElements = 1;
pPce->BackElementIsCpe[0] = 1;
pPce->NumLfeChannelElements = 1;
pPce->NumChannels = 8;
pPce->NumEffectiveChannels = 7;
pPce->isValid = 1;
break;
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
case 12: /* 3/0/4.1ch surround back */
pPce->BackElementIsCpe[1] = 1;
pPce->NumChannels += 1;
pPce->NumEffectiveChannels += 1;
case 11: /* 3/0/3.1ch */
pPce->NumFrontChannelElements += 2;
pPce->FrontElementIsCpe[0] = 0;
pPce->FrontElementIsCpe[1] = 1;
pPce->NumBackChannelElements += 2;
pPce->BackElementIsCpe[0] = 1;
pPce->BackElementIsCpe[1] += 0;
pPce->NumLfeChannelElements += 1;
pPce->NumChannels += 7;
pPce->NumEffectiveChannels += 6;
pPce->isValid = 1;
break;
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
case 14: /* 2/0/0-3/0/2-0.1ch front height */
pPce->FrontElementHeightInfo[2] = 1; /* Top speaker */
case 7: /* 5/0/2.1ch front */
pPce->NumFrontChannelElements += 1;
pPce->FrontElementIsCpe[2] = 1;
pPce->NumChannels += 2;
pPce->NumEffectiveChannels += 2;
case 6: /* 3/0/2.1ch */ case 6: /* 3/0/2.1ch */
pPce->NumLfeChannelElements += 1; pPce->NumLfeChannelElements += 1;
pPce->NumChannels += 1; pPce->NumChannels += 1;
...@@ -348,10 +467,11 @@ void CProgramConfig_GetDefault( CProgramConfig *pPce, ...@@ -348,10 +467,11 @@ void CProgramConfig_GetDefault( CProgramConfig *pPce,
/** /**
* \brief get implicit audio channel type for given channelConfig and MPEG ordered channel index * \brief get implicit audio channel type for given channelConfig and MPEG ordered channel index
* \param channelConfig MPEG channelConfiguration from 1 upto 7 * \param channelConfig MPEG channelConfiguration from 1 upto 14
* \param index MPEG channel order index * \param index MPEG channel order index
* \return audio channel type. * \return audio channel type.
*/ */
static
void getImplicitAudioChannelTypeAndIndex( void getImplicitAudioChannelTypeAndIndex(
AUDIO_CHANNEL_TYPE *chType, AUDIO_CHANNEL_TYPE *chType,
UCHAR *chIndex, UCHAR *chIndex,
...@@ -364,9 +484,9 @@ void getImplicitAudioChannelTypeAndIndex( ...@@ -364,9 +484,9 @@ void getImplicitAudioChannelTypeAndIndex(
*chIndex = index; *chIndex = index;
} else { } else {
switch (channelConfig) { switch (channelConfig) {
case MODE_1_2_1: case 4: /* SCE, CPE, SCE */
case MODE_1_2_2: case 5: /* SCE, CPE, CPE */
case MODE_1_2_2_1: case 6: /* SCE, CPE, CPE, LFE */
switch (index) { switch (index) {
case 3: case 3:
case 4: case 4:
...@@ -379,12 +499,12 @@ void getImplicitAudioChannelTypeAndIndex( ...@@ -379,12 +499,12 @@ void getImplicitAudioChannelTypeAndIndex(
break; break;
} }
break; break;
case MODE_1_2_2_2_1: case 7: /* SCE,CPE,CPE,CPE,LFE */
switch (index) { switch (index) {
case 3: case 3:
case 4: case 4:
*chType = ACT_SIDE; *chType = ACT_FRONT;
*chIndex = index - 3; *chIndex = index;
break; break;
case 5: case 5:
case 6: case 6:
...@@ -397,6 +517,42 @@ void getImplicitAudioChannelTypeAndIndex( ...@@ -397,6 +517,42 @@ void getImplicitAudioChannelTypeAndIndex(
break; break;
} }
break; break;
case 11: /* SCE,CPE,CPE,SCE,LFE */
if (index < 6) {
*chType = ACT_BACK;
*chIndex = index - 3;
} else {
*chType = ACT_LFE;
*chIndex = 0;
}
break;
case 12: /* SCE,CPE,CPE,CPE,LFE */
if (index < 7) {
*chType = ACT_BACK;
*chIndex = index - 3;
} else {
*chType = ACT_LFE;
*chIndex = 0;
}
break;
case 14: /* SCE,CPE,CPE,LFE,CPE */
switch (index) {
case 3:
case 4:
*chType = ACT_BACK;
*chIndex = index - 3;
break;
case 5:
*chType = ACT_LFE;
*chIndex = 0;
break;
case 6:
case 7:
*chType = ACT_FRONT_TOP;
*chIndex = index - 6; /* handle the top layer independently */
break;
}
break;
default: default:
*chType = ACT_NONE; *chType = ACT_NONE;
break; break;
...@@ -467,7 +623,24 @@ int CProgramConfig_LookupElement( ...@@ -467,7 +623,24 @@ int CProgramConfig_LookupElement(
else { else {
/* Accept the additional channel(s), only if the tag is in the lists */ /* Accept the additional channel(s), only if the tag is in the lists */
int isCpe = 0, i; int isCpe = 0, i;
int cc = 0, fc = 0, sc = 0, bc = 0, lc = 0, ec = 0; /* Channel and element counters */ /* Element counter */
int ec[PC_NUM_HEIGHT_LAYER] = {0};
/* Channel counters */
int cc[PC_NUM_HEIGHT_LAYER] = {0};
int fc[PC_NUM_HEIGHT_LAYER] = {0};
int sc[PC_NUM_HEIGHT_LAYER] = {0};
int bc[PC_NUM_HEIGHT_LAYER] = {0};
int lc = 0;;
/* General MPEG (PCE) composition rules:
- Over all:
<normal height channels><top height channels><bottom height channels>
- Within each height layer:
<front channels><side channels><back channels>
- Exception:
The LFE channels have no height info and thus they are arranged at the very
end of the normal height layer channels.
*/
switch (elType) switch (elType)
{ {
...@@ -476,87 +649,206 @@ int CProgramConfig_LookupElement( ...@@ -476,87 +649,206 @@ int CProgramConfig_LookupElement(
case ID_SCE: case ID_SCE:
/* search in front channels */ /* search in front channels */
for (i = 0; i < pPce->NumFrontChannelElements; i++) { for (i = 0; i < pPce->NumFrontChannelElements; i++) {
int heightLayer = pPce->FrontElementHeightInfo[i];
if (isCpe == pPce->FrontElementIsCpe[i] && pPce->FrontElementTagSelect[i] == tag) { if (isCpe == pPce->FrontElementIsCpe[i] && pPce->FrontElementTagSelect[i] == tag) {
chMapping[cc] = channelIdx; int h, elIdx = ec[heightLayer], chIdx = cc[heightLayer];
chType[cc] = ACT_FRONT; AUDIO_CHANNEL_TYPE aChType = (AUDIO_CHANNEL_TYPE)((heightLayer<<4) | ACT_FRONT);
chIndex[cc] = fc; for (h = heightLayer-1; h >= 0; h-=1) {
int el;
/* Count front channels/elements */
for (el = 0; el < pPce->NumFrontChannelElements; el+=1) {
if (pPce->FrontElementHeightInfo[el] == h) {
elIdx += 1;
chIdx += (pPce->FrontElementIsCpe[el]) ? 2 : 1;
}
}
/* Count side channels/elements */
for (el = 0; el < pPce->NumSideChannelElements; el+=1) {
if (pPce->SideElementHeightInfo[el] == h) {
elIdx += 1;
chIdx += (pPce->SideElementIsCpe[el]) ? 2 : 1;
}
}
/* Count back channels/elements */
for (el = 0; el < pPce->NumBackChannelElements; el+=1) {
if (pPce->BackElementHeightInfo[el] == h) {
elIdx += 1;
chIdx += (pPce->BackElementIsCpe[el]) ? 2 : 1;
}
}
if (h == 0) { /* normal height */
elIdx += pPce->NumLfeChannelElements;
chIdx += pPce->NumLfeChannelElements;
}
}
chMapping[chIdx] = channelIdx;
chType[chIdx] = aChType;
chIndex[chIdx] = fc[heightLayer];
if (isCpe) { if (isCpe) {
chMapping[cc+1] = channelIdx+1; chMapping[chIdx+1] = channelIdx+1;
chType[cc+1] = ACT_FRONT; chType[chIdx+1] = aChType;
chIndex[cc+1] = fc+1; chIndex[chIdx+1] = fc[heightLayer]+1;
} }
*elMapping = ec; *elMapping = elIdx;
return 1; return 1;
} }
ec++; ec[heightLayer] += 1;
if (pPce->FrontElementIsCpe[i]) { if (pPce->FrontElementIsCpe[i]) {
cc+=2; fc+=2; cc[heightLayer] += 2;
fc[heightLayer] += 2;
} else { } else {
cc++; fc++; cc[heightLayer] += 1;
fc[heightLayer] += 1;
} }
} }
/* search in side channels */ /* search in side channels */
for (i = 0; i < pPce->NumSideChannelElements; i++) { for (i = 0; i < pPce->NumSideChannelElements; i++) {
int heightLayer = pPce->SideElementHeightInfo[i];
if (isCpe == pPce->SideElementIsCpe[i] && pPce->SideElementTagSelect[i] == tag) { if (isCpe == pPce->SideElementIsCpe[i] && pPce->SideElementTagSelect[i] == tag) {
chMapping[cc] = channelIdx; int h, elIdx = ec[heightLayer], chIdx = cc[heightLayer];
chType[cc] = ACT_SIDE; AUDIO_CHANNEL_TYPE aChType = (AUDIO_CHANNEL_TYPE)((heightLayer<<4) | ACT_SIDE);
chIndex[cc] = sc; for (h = heightLayer-1; h >= 0; h-=1) {
int el;
/* Count front channels/elements */
for (el = 0; el < pPce->NumFrontChannelElements; el+=1) {
if (pPce->FrontElementHeightInfo[el] == h) {
elIdx += 1;
chIdx += (pPce->FrontElementIsCpe[el]) ? 2 : 1;
}
}
/* Count side channels/elements */
for (el = 0; el < pPce->NumSideChannelElements; el+=1) {
if (pPce->SideElementHeightInfo[el] == h) {
elIdx += 1;
chIdx += (pPce->SideElementIsCpe[el]) ? 2 : 1;
}
}
/* Count back channels/elements */
for (el = 0; el < pPce->NumBackChannelElements; el+=1) {
if (pPce->BackElementHeightInfo[el] == h) {
elIdx += 1;
chIdx += (pPce->BackElementIsCpe[el]) ? 2 : 1;
}
}
if (h == 0) { /* LFE channels belong to the normal height layer */
elIdx += pPce->NumLfeChannelElements;
chIdx += pPce->NumLfeChannelElements;
}
}
chMapping[chIdx] = channelIdx;
chType[chIdx] = aChType;
chIndex[chIdx] = sc[heightLayer];
if (isCpe) { if (isCpe) {
chMapping[cc+1] = channelIdx+1; chMapping[chIdx+1] = channelIdx+1;
chType[cc+1] = ACT_SIDE; chType[chIdx+1] = aChType;
chIndex[cc+1] = sc+1; chIndex[chIdx+1] = sc[heightLayer]+1;
} }
*elMapping = ec; *elMapping = elIdx;
return 1; return 1;
} }
ec++; ec[heightLayer] += 1;
if (pPce->SideElementIsCpe[i]) { if (pPce->SideElementIsCpe[i]) {
cc+=2; sc+=2; cc[heightLayer] += 2;
sc[heightLayer] += 2;
} else { } else {
cc++; sc++; cc[heightLayer] += 1;
sc[heightLayer] += 1;
} }
} }
/* search in back channels */ /* search in back channels */
for (i = 0; i < pPce->NumBackChannelElements; i++) { for (i = 0; i < pPce->NumBackChannelElements; i++) {
int heightLayer = pPce->BackElementHeightInfo[i];
if (isCpe == pPce->BackElementIsCpe[i] && pPce->BackElementTagSelect[i] == tag) { if (isCpe == pPce->BackElementIsCpe[i] && pPce->BackElementTagSelect[i] == tag) {
chMapping[cc] = channelIdx; int h, elIdx = ec[heightLayer], chIdx = cc[heightLayer];
chType[cc] = ACT_BACK; AUDIO_CHANNEL_TYPE aChType = (AUDIO_CHANNEL_TYPE)((heightLayer<<4) | ACT_BACK);
chIndex[cc] = bc; for (h = heightLayer-1; h >= 0; h-=1) {
int el;
/* Count front channels/elements */
for (el = 0; el < pPce->NumFrontChannelElements; el+=1) {
if (pPce->FrontElementHeightInfo[el] == h) {
elIdx += 1;
chIdx += (pPce->FrontElementIsCpe[el]) ? 2 : 1;
}
}
/* Count side channels/elements */
for (el = 0; el < pPce->NumSideChannelElements; el+=1) {
if (pPce->SideElementHeightInfo[el] == h) {
elIdx += 1;
chIdx += (pPce->SideElementIsCpe[el]) ? 2 : 1;
}
}
/* Count back channels/elements */
for (el = 0; el < pPce->NumBackChannelElements; el+=1) {
if (pPce->BackElementHeightInfo[el] == h) {
elIdx += 1;
chIdx += (pPce->BackElementIsCpe[el]) ? 2 : 1;
}
}
if (h == 0) { /* normal height */
elIdx += pPce->NumLfeChannelElements;
chIdx += pPce->NumLfeChannelElements;
}
}
chMapping[chIdx] = channelIdx;
chType[chIdx] = aChType;
chIndex[chIdx] = bc[heightLayer];
if (isCpe) { if (isCpe) {
chMapping[cc+1] = channelIdx+1; chMapping[chIdx+1] = channelIdx+1;
chType[cc+1] = ACT_BACK; chType[chIdx+1] = aChType;
chIndex[cc+1] = bc+1; chIndex[chIdx+1] = bc[heightLayer]+1;
} }
*elMapping = ec; *elMapping = elIdx;
return 1; return 1;
} }
ec++; ec[heightLayer] += 1;
if (pPce->BackElementIsCpe[i]) { if (pPce->BackElementIsCpe[i]) {
cc+=2; bc+=2; cc[heightLayer] += 2;
bc[heightLayer] += 2;
} else { } else {
cc++; bc++; cc[heightLayer] += 1;
bc[heightLayer] += 1;
} }
} }
break; break;
case ID_LFE: case ID_LFE:
/* Initialize channel counter and element counter */ { /* Unfortunately we have to go through all normal height
cc = pPce->NumEffectiveChannels; layer elements to get the position of the LFE channels.
ec = pPce->NumFrontChannelElements+ pPce->NumSideChannelElements + pPce->NumBackChannelElements; Start with counting the front channels/elements at normal height */
for (i = 0; i < pPce->NumFrontChannelElements; i+=1) {
int heightLayer = pPce->FrontElementHeightInfo[i];
ec[heightLayer] += 1;
cc[heightLayer] += (pPce->FrontElementIsCpe[i]) ? 2 : 1;
}
/* Count side channels/elements at normal height */
for (i = 0; i < pPce->NumSideChannelElements; i+=1) {
int heightLayer = pPce->SideElementHeightInfo[i];
ec[heightLayer] += 1;
cc[heightLayer] += (pPce->SideElementIsCpe[i]) ? 2 : 1;
}
/* Count back channels/elements at normal height */
for (i = 0; i < pPce->NumBackChannelElements; i+=1) {
int heightLayer = pPce->BackElementHeightInfo[i];
ec[heightLayer] += 1;
cc[heightLayer] += (pPce->BackElementIsCpe[i]) ? 2 : 1;
}
/* search in lfe channels */ /* search in lfe channels */
for (i = 0; i < pPce->NumLfeChannelElements; i++) { for (i = 0; i < pPce->NumLfeChannelElements; i++) {
int elIdx = ec[0]; /* LFE channels belong to the normal height layer */
int chIdx = cc[0];
if ( pPce->LfeElementTagSelect[i] == tag ) { if ( pPce->LfeElementTagSelect[i] == tag ) {
chMapping[cc] = channelIdx; chMapping[chIdx] = channelIdx;
*elMapping = ec; *elMapping = elIdx;
chType[cc] = ACT_LFE; chType[chIdx] = ACT_LFE;
chIndex[cc] = lc; chIndex[chIdx] = lc;
return 1; return 1;
} }
ec++; ec[0] += 1;
cc++; cc[0] += 1;
lc++; lc += 1;
} }
break; } break;
/* Non audio elements */ /* Non audio elements */
case ID_CCE: case ID_CCE:
...@@ -590,13 +882,19 @@ int CProgramConfig_LookupElement( ...@@ -590,13 +882,19 @@ int CProgramConfig_LookupElement(
int CProgramConfig_GetElementTable( int CProgramConfig_GetElementTable(
const CProgramConfig *pPce, const CProgramConfig *pPce,
MP4_ELEMENT_ID elList[], MP4_ELEMENT_ID elList[],
const INT elListSize const INT elListSize,
UCHAR *pChMapIdx
) )
{ {
int i, el = 0; int i, el = 0;
if ( elListSize FDK_ASSERT(elList != NULL);
< pPce->NumFrontChannelElements + pPce->NumSideChannelElements + pPce->NumBackChannelElements + pPce->NumLfeChannelElements FDK_ASSERT(pChMapIdx != NULL);
*pChMapIdx = 0;
if ( elListSize
< pPce->NumFrontChannelElements + pPce->NumSideChannelElements + pPce->NumBackChannelElements + pPce->NumLfeChannelElements
) )
{ {
return 0; return 0;
...@@ -623,6 +921,47 @@ int CProgramConfig_GetElementTable( ...@@ -623,6 +921,47 @@ int CProgramConfig_GetElementTable(
} }
/* Find an corresponding channel configuration if possible */
switch (pPce->NumChannels) {
case 1: case 2: case 3: case 4: case 5: case 6:
/* One and two channels have no alternatives. The other ones are mapped directly to the
corresponding channel config. Because of legacy reasons or for lack of alternative mappings. */
*pChMapIdx = pPce->NumChannels;
break;
case 7:
{
C_ALLOC_SCRATCH_START(tmpPce, CProgramConfig, 1);
/* Create a PCE for the config to test ... */
CProgramConfig_GetDefault(tmpPce, 11);
/* ... and compare it with the given one. */
*pChMapIdx = (!(CProgramConfig_Compare(pPce, tmpPce)&0xE)) ? 11 : 0;
/* If compare result is 0 or 1 we can be sure that it is channel config 11. */
C_ALLOC_SCRATCH_END(tmpPce, CProgramConfig, 1);
}
break;
case 8:
{ /* Try the four possible 7.1ch configurations. One after the other. */
UCHAR testCfg[4] = { 32, 14, 12, 7};
C_ALLOC_SCRATCH_START(tmpPce, CProgramConfig, 1);
for (i=0; i<4; i+=1) {
/* Create a PCE for the config to test ... */
CProgramConfig_GetDefault(tmpPce, testCfg[i]);
/* ... and compare it with the given one. */
if (!(CProgramConfig_Compare(pPce, tmpPce)&0xE)) {
/* If the compare result is 0 or 1 than the two channel configurations match. */
/* Explicit mapping of 7.1 side channel configuration to 7.1 rear channel mapping. */
*pChMapIdx = (testCfg[i]==32) ? 12 : testCfg[i];
}
}
C_ALLOC_SCRATCH_END(tmpPce, CProgramConfig, 1);
}
break;
default:
/* The PCE does not match any predefined channel configuration. */
*pChMapIdx = 0;
break;
}
return el; return el;
} }
#endif #endif
...@@ -714,7 +1053,7 @@ TRANSPORTDEC_ERROR GaSpecificConfig_Parse( CSGaSpecificConfig *self, ...@@ -714,7 +1053,7 @@ TRANSPORTDEC_ERROR GaSpecificConfig_Parse( CSGaSpecificConfig *self,
#ifdef TP_ELD_ENABLE #ifdef TP_ELD_ENABLE
static INT ld_sbr_header( const CSAudioSpecificConfig *asc, static INT ld_sbr_header( const CSAudioSpecificConfig *asc,
HANDLE_FDK_BITSTREAM hBs, HANDLE_FDK_BITSTREAM hBs,
CSTpCallBacks *cb ) CSTpCallBacks *cb )
{ {
const int channelConfiguration = asc->m_channelConfiguration; const int channelConfiguration = asc->m_channelConfiguration;
...@@ -728,6 +1067,8 @@ static INT ld_sbr_header( const CSAudioSpecificConfig *asc, ...@@ -728,6 +1067,8 @@ static INT ld_sbr_header( const CSAudioSpecificConfig *asc,
} }
switch ( channelConfiguration ) { switch ( channelConfiguration ) {
case 14:
case 12:
case 7: case 7:
error |= cb->cbSbr(cb->cbSbrData, hBs, asc->m_samplingFrequency, asc->m_extensionSamplingFrequency, asc->m_samplesPerFrame, AOT_ER_AAC_ELD, ID_CPE, i++); error |= cb->cbSbr(cb->cbSbrData, hBs, asc->m_samplingFrequency, asc->m_extensionSamplingFrequency, asc->m_samplesPerFrame, AOT_ER_AAC_ELD, ID_CPE, i++);
case 6: case 6:
...@@ -737,6 +1078,8 @@ static INT ld_sbr_header( const CSAudioSpecificConfig *asc, ...@@ -737,6 +1078,8 @@ static INT ld_sbr_header( const CSAudioSpecificConfig *asc,
error |= cb->cbSbr(cb->cbSbrData, hBs, asc->m_samplingFrequency, asc->m_extensionSamplingFrequency, asc->m_samplesPerFrame, AOT_ER_AAC_ELD, ID_CPE, i++); error |= cb->cbSbr(cb->cbSbrData, hBs, asc->m_samplingFrequency, asc->m_extensionSamplingFrequency, asc->m_samplesPerFrame, AOT_ER_AAC_ELD, ID_CPE, i++);
break; break;
case 11:
error |= cb->cbSbr(cb->cbSbrData, hBs, asc->m_samplingFrequency, asc->m_extensionSamplingFrequency, asc->m_samplesPerFrame, AOT_ER_AAC_ELD, ID_CPE, i++);
case 4: case 4:
error |= cb->cbSbr(cb->cbSbrData, hBs, asc->m_samplingFrequency, asc->m_extensionSamplingFrequency, asc->m_samplesPerFrame, AOT_ER_AAC_ELD, ID_CPE, i++); error |= cb->cbSbr(cb->cbSbrData, hBs, asc->m_samplingFrequency, asc->m_extensionSamplingFrequency, asc->m_samplesPerFrame, AOT_ER_AAC_ELD, ID_CPE, i++);
error |= cb->cbSbr(cb->cbSbrData, hBs, asc->m_samplingFrequency, asc->m_extensionSamplingFrequency, asc->m_samplesPerFrame, AOT_ER_AAC_ELD, ID_SCE, i++); error |= cb->cbSbr(cb->cbSbrData, hBs, asc->m_samplingFrequency, asc->m_extensionSamplingFrequency, asc->m_samplesPerFrame, AOT_ER_AAC_ELD, ID_SCE, i++);
...@@ -802,24 +1145,6 @@ TRANSPORTDEC_ERROR EldSpecificConfig_Parse( ...@@ -802,24 +1145,6 @@ TRANSPORTDEC_ERROR EldSpecificConfig_Parse(
} }
switch (eldExtType) { switch (eldExtType) {
case ELDEXT_LDSAC:
esc->m_useLdQmfTimeAlign = 1;
if (cb->cbSsc != NULL) {
ErrorStatus = (TRANSPORTDEC_ERROR)cb->cbSsc(
cb->cbSscData,
hBs,
asc->m_aot,
asc->m_samplingFrequency,
1, /* muxMode */
len
);
} else {
ErrorStatus = TRANSPORTDEC_UNSUPPORTED_FORMAT;
}
if (ErrorStatus != TRANSPORTDEC_OK) {
goto bail;
}
break;
default: default:
for(cnt=0; cnt<len; cnt++) { for(cnt=0; cnt<len; cnt++) {
FDKreadBits(hBs, 8 ); FDKreadBits(hBs, 8 );
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
/* library info */ /* library info */
#define TP_LIB_VL0 2 #define TP_LIB_VL0 2
#define TP_LIB_VL1 3 #define TP_LIB_VL1 3
#define TP_LIB_VL2 3 #define TP_LIB_VL2 4
#define TP_LIB_TITLE "MPEG Transport" #define TP_LIB_TITLE "MPEG Transport"
#define TP_LIB_BUILD_DATE __DATE__ #define TP_LIB_BUILD_DATE __DATE__
#define TP_LIB_BUILD_TIME __TIME__ #define TP_LIB_BUILD_TIME __TIME__
...@@ -146,12 +146,15 @@ typedef struct ...@@ -146,12 +146,15 @@ typedef struct
UCHAR FrontElementIsCpe[PC_FSB_CHANNELS_MAX]; UCHAR FrontElementIsCpe[PC_FSB_CHANNELS_MAX];
UCHAR FrontElementTagSelect[PC_FSB_CHANNELS_MAX]; UCHAR FrontElementTagSelect[PC_FSB_CHANNELS_MAX];
UCHAR FrontElementHeightInfo[PC_FSB_CHANNELS_MAX];
UCHAR SideElementIsCpe[PC_FSB_CHANNELS_MAX]; UCHAR SideElementIsCpe[PC_FSB_CHANNELS_MAX];
UCHAR SideElementTagSelect[PC_FSB_CHANNELS_MAX]; UCHAR SideElementTagSelect[PC_FSB_CHANNELS_MAX];
UCHAR SideElementHeightInfo[PC_FSB_CHANNELS_MAX];
UCHAR BackElementIsCpe[PC_FSB_CHANNELS_MAX]; UCHAR BackElementIsCpe[PC_FSB_CHANNELS_MAX];
UCHAR BackElementTagSelect[PC_FSB_CHANNELS_MAX]; UCHAR BackElementTagSelect[PC_FSB_CHANNELS_MAX];
UCHAR BackElementHeightInfo[PC_FSB_CHANNELS_MAX];
UCHAR LfeElementTagSelect[PC_LFE_CHANNELS_MAX]; UCHAR LfeElementTagSelect[PC_LFE_CHANNELS_MAX];
...@@ -324,16 +327,23 @@ int getSamplingRateIndex( UINT samplingRate ) ...@@ -324,16 +327,23 @@ int getSamplingRateIndex( UINT samplingRate )
*/ */
static inline int getNumberOfTotalChannels(int channelConfig) static inline int getNumberOfTotalChannels(int channelConfig)
{ {
if (channelConfig > 0 && channelConfig < 8) switch (channelConfig) {
return (channelConfig == 7)?8:channelConfig; case 1: case 2: case 3:
else case 4: case 5: case 6:
return channelConfig;
case 7: case 12: case 14:
return 8;
case 11:
return 7;
default:
return 0; return 0;
}
} }
static inline static inline
int getNumberOfEffectiveChannels(const int channelConfig) int getNumberOfEffectiveChannels(const int channelConfig)
{ { /* index: 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15 */
const int n[] = {0,1,2,3,4,5,5,7}; const int n[] = {0,1,2,3,4,5,5,7,0,0, 0, 6, 7, 0, 7, 0};
return n[channelConfig]; return n[channelConfig];
} }
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
/* library info */ /* library info */
#define TP_LIB_VL0 2 #define TP_LIB_VL0 2
#define TP_LIB_VL1 3 #define TP_LIB_VL1 3
#define TP_LIB_VL2 3 #define TP_LIB_VL2 4
#define TP_LIB_TITLE "MPEG Transport" #define TP_LIB_TITLE "MPEG Transport"
#define TP_LIB_BUILD_DATE __DATE__ #define TP_LIB_BUILD_DATE __DATE__
#define TP_LIB_BUILD_TIME __TIME__ #define TP_LIB_BUILD_TIME __TIME__
/* -----------------------------------------------------------------------------------------------------------
Software License for The Fraunhofer FDK AAC Codec Library for Android
© Copyright 1995 - 2013 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
----------------------------------------------------------------------------------------------------------- */
/************************ FDK PCM postprocessor module *********************
Author(s): Matthias Neusinger
Description: Hard limiter for clipping prevention
*******************************************************************************/
#ifndef _LIMITER_H_
#define _LIMITER_H_
#include "common_fix.h"
#define TDL_ATTACK_DEFAULT_MS (15) /* default attack time in ms */
#define TDL_RELEASE_DEFAULT_MS (50) /* default release time in ms */
#define TDL_GAIN_SCALING (15) /* scaling of gain value. */
#ifdef __cplusplus
extern "C" {
#endif
typedef enum {
TDLIMIT_OK = 0,
__error_codes_start = -100,
TDLIMIT_INVALID_HANDLE,
TDLIMIT_INVALID_PARAMETER,
__error_codes_end
} TDLIMITER_ERROR;
struct TDLimiter;
typedef struct TDLimiter* TDLimiterPtr;
/******************************************************************************
* createLimiter *
* maxAttackMs: maximum and initial attack/lookahead time in milliseconds *
* releaseMs: release time in milliseconds (90% time constant) *
* threshold: limiting threshold *
* maxChannels: maximum and initial number of channels *
* maxSampleRate: maximum and initial sampling rate in Hz *
* returns: limiter handle *
******************************************************************************/
TDLimiterPtr createLimiter(unsigned int maxAttackMs,
unsigned int releaseMs,
INT_PCM threshold,
unsigned int maxChannels,
unsigned int maxSampleRate);
/******************************************************************************
* resetLimiter *
* limiter: limiter handle *
* returns: error code *
******************************************************************************/
TDLIMITER_ERROR resetLimiter(TDLimiterPtr limiter);
/******************************************************************************
* destroyLimiter *
* limiter: limiter handle *
* returns: error code *
******************************************************************************/
TDLIMITER_ERROR destroyLimiter(TDLimiterPtr limiter);
/******************************************************************************
* applyLimiter *
* limiter: limiter handle *
* pGain : pointer to gains to be applied to the signal before limiting, *
* which are downscaled by TDL_GAIN_SCALING bit. *
* These gains are delayed by gain_delay, and smoothed. *
* Smoothing is done by a butterworth lowpass filter with a cutoff *
* frequency which is fixed with respect to the sampling rate. *
* It is a substitute for the smoothing due to windowing and *
* overlap/add, if a gain is applied in frequency domain. *
* gain_scale: pointer to scaling exponents to be applied to the signal before *
* limiting, without delay and without smoothing *
* gain_size: number of elements in pGain, currently restricted to 1 *
* gain_delay: delay [samples] with which the gains in pGain shall be applied *
* gain_delay <= nSamples *
* samples: input/output buffer containing interleaved samples *
* precision of output will be DFRACT_BITS-TDL_GAIN_SCALING bits *
* nSamples: number of samples per channel *
* returns: error code *
******************************************************************************/
TDLIMITER_ERROR applyLimiter(TDLimiterPtr limiter,
INT_PCM* samples,
FIXP_DBL* pGain,
const INT* gain_scale,
const UINT gain_size,
const UINT gain_delay,
const UINT nSamples);
/******************************************************************************
* getLimiterDelay *
* limiter: limiter handle *
* returns: exact delay caused by the limiter in samples *
******************************************************************************/
unsigned int getLimiterDelay(TDLimiterPtr limiter);
/******************************************************************************
* setLimiterNChannels *
* limiter: limiter handle *
* nChannels: number of channels ( <= maxChannels specified on create) *
* returns: error code *
******************************************************************************/
TDLIMITER_ERROR setLimiterNChannels(TDLimiterPtr limiter, unsigned int nChannels);
/******************************************************************************
* setLimiterSampleRate *
* limiter: limiter handle *
* sampleRate: sampling rate in Hz ( <= maxSampleRate specified on create) *
* returns: error code *
******************************************************************************/
TDLIMITER_ERROR setLimiterSampleRate(TDLimiterPtr limiter, unsigned int sampleRate);
/******************************************************************************
* setLimiterAttack *
* limiter: limiter handle *
* attackMs: attack time in ms ( <= maxAttackMs specified on create) *
* returns: error code *
******************************************************************************/
TDLIMITER_ERROR setLimiterAttack(TDLimiterPtr limiter, unsigned int attackMs);
/******************************************************************************
* setLimiterRelease *
* limiter: limiter handle *
* releaseMs: release time in ms *
* returns: error code *
******************************************************************************/
TDLIMITER_ERROR setLimiterRelease(TDLimiterPtr limiter, unsigned int releaseMs);
/******************************************************************************
* setLimiterThreshold *
* limiter: limiter handle *
* threshold: limiter threshold *
* returns: error code *
******************************************************************************/
TDLIMITER_ERROR setLimiterThreshold(TDLimiterPtr limiter, INT_PCM threshold);
#ifdef __cplusplus
}
#endif
#endif //#ifndef _LIMITER_H_
...@@ -95,69 +95,88 @@ amm-info@iis.fraunhofer.de ...@@ -95,69 +95,88 @@ amm-info@iis.fraunhofer.de
#include "machine_type.h" #include "machine_type.h"
#include "common_fix.h" #include "common_fix.h"
#include "FDK_audio.h" #include "FDK_audio.h"
#include "FDK_bitstream.h"
/* ------------------------ *
* MODULE SETTINGS: *
* ------------------------ */
/* #define PCM_UPMIX_ENABLE */ /*!< Generally enable up mixing. */
#define PCM_DOWNMIX_ENABLE /*!< Generally enable down mixing. */
#define DVB_MIXDOWN_ENABLE /*!< Enable this to support DVB ancillary data for encoder
assisted downmixing of MPEG-4 AAC and
MPEG-1/2 layer 2 streams. PCM_DOWNMIX_ENABLE has to
be enabled, too! */
#define MPEG_PCE_MIXDOWN_ENABLE /*!< Enable this to support MPEG matrix mixdown with a
coefficient carried in the PCE. PCM_DOWNMIX_ENABLE
has to be enabled, too! */
/* #define ARIB_MIXDOWN_ENABLE */ /*!< Enable modifications to the MPEG PCE mixdown method
to fulfill ARIB standard. MPEG_PCE_MIXDOWN_ENABLE has
to be set. */
/* ------------------------ * /* ------------------------ *
* ERROR CODES: * * ERROR CODES: *
* ------------------------ */ * ------------------------ */
typedef enum typedef enum
{ {
PCMDMX_OK = 0x0, /*!< No error happened. */ PCMDMX_OK = 0x0, /*!< No error happened. */
PCMDMX_OUT_OF_MEMORY = 0x2, /*!< Not enough memory to set up an instance of the module. */
PCMDMX_UNKNOWN = 0x5, /*!< Error condition is of unknown reason, or from a third pcm_dmx_fatal_error_start,
party module. */ PCMDMX_OUT_OF_MEMORY = 0x2, /*!< Not enough memory to set up an instance of the module. */
PCMDMX_INVALID_HANDLE, /*!< The given instance handle is not valid. */ PCMDMX_UNKNOWN = 0x5, /*!< Error condition is of unknown reason, or from a third
PCMDMX_INVALID_ARGUMENT, /*!< One of the parameters handed over is invalid. */ party module. */
PCMDMX_INVALID_CH_CONFIG, /*!< The given channel configuration is not supported and pcm_dmx_fatal_error_end,
thus no processing was performed. */
PCMDMX_INVALID_MODE, /*!< The set configuration/mode is not applicable. */ PCMDMX_INVALID_HANDLE, /*!< The given instance handle is not valid. */
PCMDMX_UNKNOWN_PARAM, /*!< The handed parameter is not known/supported. */ PCMDMX_INVALID_ARGUMENT, /*!< One of the parameters handed over is invalid. */
PCMDMX_UNABLE_TO_SET_PARAM, /*!< Unable to set the specific parameter. Most probably PCMDMX_INVALID_CH_CONFIG, /*!< The given channel configuration is not supported and thus
the value ist out of range. */ no processing was performed. */
PCMDMX_CORRUPT_ANC_DATA /*!< The read ancillary data was corrupt. */ PCMDMX_INVALID_MODE, /*!< The set configuration/mode is not applicable. */
PCMDMX_UNKNOWN_PARAM, /*!< The handed parameter is not known/supported. */
PCMDMX_UNABLE_TO_SET_PARAM, /*!< Unable to set the specific parameter. Most probably the
value ist out of range. */
PCMDMX_CORRUPT_ANC_DATA /*!< The read ancillary data was corrupt. */
} PCMDMX_ERROR; } PCMDMX_ERROR;
/** Macro to identify fatal errors. */
#define PCMDMX_IS_FATAL_ERROR(err) ( (((err)>=pcm_dmx_fatal_error_start) && ((err)<=pcm_dmx_fatal_error_end)) ? 1 : 0)
/* ------------------------ * /* ------------------------ *
* RUNTIME PARAMS: * * RUNTIME PARAMS: *
* ------------------------ */ * ------------------------ */
typedef enum typedef enum
{ {
DMX_BS_DATA_EXPIRY_FRAME, /*!< The number of frames without new metadata that have to DMX_BS_DATA_EXPIRY_FRAME, /*!< The number of frames without new metadata that have to go
go by before the bitstream data expires. The value 0 by before the bitstream data expires. The value 0 disables
disables expiry. */ expiry. */
DMX_BS_DATA_DELAY, /*!< The number of delay frames of the output samples DMX_BS_DATA_DELAY, /*!< The number of delay frames of the output samples compared
compared to the bitstream data. */ to the bitstream data. */
NUMBER_OF_OUTPUT_CHANNELS , /*!< The number of output channels (equals the number of MIN_NUMBER_OF_OUTPUT_CHANNELS, /*!< The minimum number of output channels. For all input
channels processed by the audio output setup). */ configurations that have less than the given channels the
DUAL_CHANNEL_DOWNMIX_MODE /*!< Downmix mode for two channel audio data. */ module will modify the output automatically to obtain the
given number of output channels. Mono signals will be
duplicated. If more than two output channels are desired
the module just adds empty channels. The parameter value
must be either -1, 0, 1, 2, 6 or 8. If the value is
greater than zero and exceeds the value of parameter
MAX_NUMBER_OF_OUTPUT_CHANNELS the latter will be set to
the same value. Both values -1 and 0 disable the feature. */
MAX_NUMBER_OF_OUTPUT_CHANNELS, /*!< The maximum number of output channels. For all input
configurations that have more than the given channels the
module will apply a mixdown automatically to obtain the
given number of output channels. The value must be either
-1, 0, 1, 2, 6 or 8. If it is greater than zero and lower
or equal than the value of MIN_NUMBER_OF_OUTPUT_CHANNELS
parameter the latter will be set to the same value.
The values -1 and 0 disable the feature. */
DMX_DUAL_CHANNEL_MODE, /*!< Downmix mode for two channel audio data. */
DMX_PSEUDO_SURROUND_MODE /*!< Defines how module handles pseudo surround compatible
signals. See PSEUDO_SURROUND_MODE type for details. */
} PCMDMX_PARAM; } PCMDMX_PARAM;
/* Parameter value types */
typedef enum typedef enum
{ {
STEREO_MODE = 0x0, /*!< Leave stereo signals as they are. */ NEVER_DO_PS_DMX = -1, /*!< Never create a pseudo surround compatible downmix. */
CH1_MODE = 0x1, /*!< Create a dual mono output signal from channel 1. */ AUTO_PS_DMX = 0, /*!< Create a pseudo surround compatible downmix only if
CH2_MODE = 0x2, /*!< Create a dual mono output signal from channel 2. */ signalled in bitstreams meta data. (Default) */
MIXED_MODE = 0x3 /*!< Create a dual mono output signal by mixing the two channels. */ FORCE_PS_DMX = 1 /*!< Always create a pseudo surround compatible downmix.
CAUTION: This can lead to excessive signal cancellations
and signal level differences for non-compatible signals. */
} PSEUDO_SURROUND_MODE;
typedef enum
{
STEREO_MODE = 0x0, /*!< Leave stereo signals as they are. */
CH1_MODE = 0x1, /*!< Create a dual mono output signal from channel 1. */
CH2_MODE = 0x2, /*!< Create a dual mono output signal from channel 2. */
MIXED_MODE = 0x3 /*!< Create a dual mono output signal by mixing the two
channels. */
} DUAL_CHANNEL_MODE; } DUAL_CHANNEL_MODE;
...@@ -178,7 +197,7 @@ extern "C" ...@@ -178,7 +197,7 @@ extern "C"
/** Open and initialize an instance of the PCM downmix module /** Open and initialize an instance of the PCM downmix module
* @param [out] Pointer to a buffer receiving the handle of the new instance. * @param [out] Pointer to a buffer receiving the handle of the new instance.
* @returns Returns an error code. * @returns Returns an error code.
**/ **/
PCMDMX_ERROR pcmDmx_Open ( PCMDMX_ERROR pcmDmx_Open (
HANDLE_PCM_DOWNMIX *pSelf HANDLE_PCM_DOWNMIX *pSelf
...@@ -188,20 +207,46 @@ PCMDMX_ERROR pcmDmx_Open ( ...@@ -188,20 +207,46 @@ PCMDMX_ERROR pcmDmx_Open (
* @param [in] Handle of PCM downmix instance. * @param [in] Handle of PCM downmix instance.
* @param [in] Parameter to be set. * @param [in] Parameter to be set.
* @param [in] Parameter value. * @param [in] Parameter value.
* @returns Returns an error code. * @returns Returns an error code.
**/ **/
PCMDMX_ERROR pcmDmx_SetParam ( PCMDMX_ERROR pcmDmx_SetParam (
HANDLE_PCM_DOWNMIX self, HANDLE_PCM_DOWNMIX self,
PCMDMX_PARAM param, const PCMDMX_PARAM param,
UINT value const INT value
);
/** Get one parameter value of one PCM downmix module instance.
* @param [in] Handle of PCM downmix module instance.
* @param [in] Parameter to be set.
* @param [out] Pointer to buffer receiving the parameter value.
* @returns Returns an error code.
**/
PCMDMX_ERROR pcmDmx_GetParam (
HANDLE_PCM_DOWNMIX self,
const PCMDMX_PARAM param,
INT * const pValue
); );
/** Read the ancillary data transported in DSEs of DVB streams with MPEG-4 content /** Read downmix meta-data directly from a given bitstream.
* @param [in] Handle of PCM downmix instance.
* @param [in] Handle of FDK bitstream buffer.
* @param [in] Length of ancillary data in bits.
* @param [in] Flag indicating wheter the ancillary data is from a MPEG-1/2 or an MPEG-4 stream.
* @returns Returns an error code.
**/
PCMDMX_ERROR pcmDmx_Parse (
HANDLE_PCM_DOWNMIX self,
HANDLE_FDK_BITSTREAM hBitStream,
UINT ancDataBits,
int isMpeg2
);
/** Read downmix meta-data from a given data buffer.
* @param [in] Handle of PCM downmix instance. * @param [in] Handle of PCM downmix instance.
* @param [in] Pointer to ancillary data buffer. * @param [in] Pointer to ancillary data buffer.
* @param [in] Size of ancillary data. * @param [in] Size of ancillary data in bytes.
* @param [in] Flag indicating wheter the ancillary data is from a MPEG-1/2 or an MPEG-4 stream. * @param [in] Flag indicating wheter the ancillary data is from a MPEG-1/2 or an MPEG-4 stream.
* @returns Returns an error code. * @returns Returns an error code.
**/ **/
PCMDMX_ERROR pcmDmx_ReadDvbAncData ( PCMDMX_ERROR pcmDmx_ReadDvbAncData (
HANDLE_PCM_DOWNMIX self, HANDLE_PCM_DOWNMIX self,
...@@ -211,12 +256,11 @@ PCMDMX_ERROR pcmDmx_ReadDvbAncData ( ...@@ -211,12 +256,11 @@ PCMDMX_ERROR pcmDmx_ReadDvbAncData (
); );
/** Set the matrix mixdown information extracted from the PCE of an AAC bitstream. /** Set the matrix mixdown information extracted from the PCE of an AAC bitstream.
* Note: Call only if matrix_mixdown_idx_present is true.
* @param [in] Handle of PCM downmix instance. * @param [in] Handle of PCM downmix instance.
* @param [in] Matrix mixdown index present flag extracted from PCE. * @param [in] Matrix mixdown index present flag extracted from PCE.
* @param [in] The 2 bit matrix mixdown index extracted from PCE. * @param [in] The 2 bit matrix mixdown index extracted from PCE.
* @param [in] The pseudo surround enable flag extracted from PCE. * @param [in] The pseudo surround enable flag extracted from PCE.
* @returns Returns an error code. * @returns Returns an error code.
**/ **/
PCMDMX_ERROR pcmDmx_SetMatrixMixdownFromPce ( PCMDMX_ERROR pcmDmx_SetMatrixMixdownFromPce (
HANDLE_PCM_DOWNMIX self, HANDLE_PCM_DOWNMIX self,
...@@ -235,34 +279,42 @@ PCMDMX_ERROR pcmDmx_Reset ( ...@@ -235,34 +279,42 @@ PCMDMX_ERROR pcmDmx_Reset (
UINT flags UINT flags
); );
/** Apply down or up mixing. /** Create a mixdown, bypass or extend the output signal depending on the modules settings and the
* respective given input configuration.
* *
* \param [in] Handle of PCM downmix module instance. * \param [in] Handle of PCM downmix module instance.
* \param [inout] Pointer to time buffer with decoded PCM samples. * \param [inout] Pointer to time buffer with decoded PCM samples.
* \param [in] Pointer where the amount of output samples is returned into. * \param [in] The I/O block size which is the number of samples per channel.
* \param [inout] Pointer where the amount of output channels is returned into. * \param [inout] Pointer to buffer that holds the number of input channels and where the
* \param [in] Flag which indicates if output time data are writtern interleaved or as subsequent blocks. * amount of output channels is written to.
* \param [inout] Array were the corresponding channel type for each output audio channel is stored into. * \param [in] Flag which indicates if output time data is writtern interleaved or as
* \param [inout] Array were the corresponding channel type index for each output audio channel is stored into. * subsequent blocks.
* \param [in] Array containing the output channel mapping to be used (From MPEG PCE ordering to whatever is required). * \param [inout] Array were the corresponding channel type for each output audio channel is
* * stored into.
* @returns Returns an error code. * \param [inout] Array were the corresponding channel type index for each output audio channel
* is stored into.
* \param [in] Array containing the output channel mapping to be used (from MPEG PCE ordering
* to whatever is required).
* \param [out] Pointer on a field receiving the scale factor that has to be applied on all
* samples afterwards. If the handed pointer is NULL the final scaling is done
* internally.
* @returns Returns an error code.
**/ **/
PCMDMX_ERROR pcmDmx_ApplyFrame ( PCMDMX_ERROR pcmDmx_ApplyFrame (
HANDLE_PCM_DOWNMIX self, HANDLE_PCM_DOWNMIX self,
INT_PCM *pPcmBuf, INT_PCM *pPcmBuf,
UINT frameSize, UINT frameSize,
INT *nChannels, INT *nChannels,
int fInterleaved, int fInterleaved,
AUDIO_CHANNEL_TYPE channelType[], AUDIO_CHANNEL_TYPE channelType[],
UCHAR channelIndices[], UCHAR channelIndices[],
const UCHAR channelMapping[][8] const UCHAR channelMapping[][8],
INT *pDmxOutScale
); );
/** Close an instance of the PCM downmix module. /** Close an instance of the PCM downmix module.
* @param [inout] Pointer to a buffer containing the handle of the instance. * @param [inout] Pointer to a buffer containing the handle of the instance.
* @returns Returns an error code. * @returns Returns an error code.
**/ **/
PCMDMX_ERROR pcmDmx_Close ( PCMDMX_ERROR pcmDmx_Close (
HANDLE_PCM_DOWNMIX *pSelf HANDLE_PCM_DOWNMIX *pSelf
...@@ -270,7 +322,7 @@ PCMDMX_ERROR pcmDmx_Close ( ...@@ -270,7 +322,7 @@ PCMDMX_ERROR pcmDmx_Close (
/** Get library info for this module. /** Get library info for this module.
* @param [out] Pointer to an allocated LIB_INFO structure. * @param [out] Pointer to an allocated LIB_INFO structure.
* @returns Returns an error code. * @returns Returns an error code.
*/ */
PCMDMX_ERROR pcmDmx_GetLibInfo( LIB_INFO *info ); PCMDMX_ERROR pcmDmx_GetLibInfo( LIB_INFO *info );
......
/* -----------------------------------------------------------------------------------------------------------
Software License for The Fraunhofer FDK AAC Codec Library for Android
© Copyright 1995 - 2013 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
----------------------------------------------------------------------------------------------------------- */
/************************ FDK PCM postprocessor module *********************
Author(s): Matthias Neusinger
Description: Hard limiter for clipping prevention
*******************************************************************************/
#include "limiter.h"
struct TDLimiter {
unsigned int attack;
FIXP_DBL attackConst, releaseConst;
unsigned int attackMs, releaseMs, maxAttackMs;
FIXP_PCM threshold;
unsigned int channels, maxChannels;
unsigned int sampleRate, maxSampleRate;
FIXP_DBL cor, max;
FIXP_DBL* maxBuf;
FIXP_DBL* delayBuf;
unsigned int maxBufIdx, delayBufIdx;
FIXP_DBL smoothState0;
FIXP_DBL minGain;
FIXP_DBL additionalGainPrev;
FIXP_DBL additionalGainFilterState;
FIXP_DBL additionalGainFilterState1;
};
/* create limiter */
TDLimiterPtr createLimiter(
unsigned int maxAttackMs,
unsigned int releaseMs,
INT_PCM threshold,
unsigned int maxChannels,
unsigned int maxSampleRate
)
{
TDLimiterPtr limiter = NULL;
unsigned int attack, release;
FIXP_DBL attackConst, releaseConst, exponent;
INT e_ans;
/* calc attack and release time in samples */
attack = (unsigned int)(maxAttackMs * maxSampleRate / 1000);
release = (unsigned int)(releaseMs * maxSampleRate / 1000);
/* alloc limiter struct */
limiter = (TDLimiterPtr)FDKcalloc(1, sizeof(struct TDLimiter));
if (!limiter) return NULL;
/* alloc max and delay buffers */
limiter->maxBuf = (FIXP_DBL*)FDKcalloc(attack + 1, sizeof(FIXP_DBL));
limiter->delayBuf = (FIXP_DBL*)FDKcalloc(attack * maxChannels, sizeof(FIXP_DBL));
if (!limiter->maxBuf || !limiter->delayBuf) {
destroyLimiter(limiter);
return NULL;
}
/* attackConst = pow(0.1, 1.0 / (attack + 1)) */
exponent = invFixp(attack+1);
attackConst = fPow(FL2FXCONST_DBL(0.1f), 0, exponent, 0, &e_ans);
attackConst = scaleValue(attackConst, e_ans);
/* releaseConst = (float)pow(0.1, 1.0 / (release + 1)) */
exponent = invFixp(release + 1);
releaseConst = fPow(FL2FXCONST_DBL(0.1f), 0, exponent, 0, &e_ans);
releaseConst = scaleValue(releaseConst, e_ans);
/* init parameters */
limiter->attackMs = maxAttackMs;
limiter->maxAttackMs = maxAttackMs;
limiter->releaseMs = releaseMs;
limiter->attack = attack;
limiter->attackConst = attackConst;
limiter->releaseConst = releaseConst;
limiter->threshold = (FIXP_PCM)threshold;
limiter->channels = maxChannels;
limiter->maxChannels = maxChannels;
limiter->sampleRate = maxSampleRate;
limiter->maxSampleRate = maxSampleRate;
resetLimiter(limiter);
return limiter;
}
/* reset limiter */
TDLIMITER_ERROR resetLimiter(TDLimiterPtr limiter)
{
if (limiter != NULL) {
limiter->maxBufIdx = 0;
limiter->delayBufIdx = 0;
limiter->max = (FIXP_DBL)0;
limiter->cor = FL2FXCONST_DBL(1.0f/(1<<1));
limiter->smoothState0 = FL2FXCONST_DBL(1.0f/(1<<1));
limiter->minGain = FL2FXCONST_DBL(1.0f/(1<<1));
limiter->additionalGainPrev = FL2FXCONST_DBL(1.0f/(1<<TDL_GAIN_SCALING));
limiter->additionalGainFilterState = FL2FXCONST_DBL(1.0f/(1<<TDL_GAIN_SCALING));
limiter->additionalGainFilterState1 = FL2FXCONST_DBL(1.0f/(1<<TDL_GAIN_SCALING));
FDKmemset(limiter->maxBuf, 0, (limiter->attack + 1) * sizeof(FIXP_DBL) );
FDKmemset(limiter->delayBuf, 0, limiter->attack * limiter->channels * sizeof(FIXP_DBL) );
}
else {
return TDLIMIT_INVALID_HANDLE;
}
return TDLIMIT_OK;
}
/* destroy limiter */
TDLIMITER_ERROR destroyLimiter(TDLimiterPtr limiter)
{
if (limiter != NULL) {
FDKfree(limiter->maxBuf);
FDKfree(limiter->delayBuf);
FDKfree(limiter);
}
else {
return TDLIMIT_INVALID_HANDLE;
}
return TDLIMIT_OK;
}
/* apply limiter */
TDLIMITER_ERROR applyLimiter(TDLimiterPtr limiter,
INT_PCM* samples,
FIXP_DBL* pGain,
const INT* gain_scale,
const UINT gain_size,
const UINT gain_delay,
const UINT nSamples)
{
unsigned int i, j;
FIXP_PCM tmp1, tmp2;
FIXP_DBL tmp, old, gain, additionalGain, additionalGainUnfiltered;
FIXP_DBL minGain = FL2FXCONST_DBL(1.0f/(1<<1));
FDK_ASSERT(gain_size == 1);
FDK_ASSERT(gain_delay <= nSamples);
if ( limiter == NULL ) return TDLIMIT_INVALID_HANDLE;
{
unsigned int channels = limiter->channels;
unsigned int attack = limiter->attack;
FIXP_DBL attackConst = limiter->attackConst;
FIXP_DBL releaseConst = limiter->releaseConst;
FIXP_DBL threshold = FX_PCM2FX_DBL(limiter->threshold)>>TDL_GAIN_SCALING;
FIXP_DBL max = limiter->max;
FIXP_DBL* maxBuf = limiter->maxBuf;
unsigned int maxBufIdx = limiter->maxBufIdx;
FIXP_DBL cor = limiter->cor;
FIXP_DBL* delayBuf = limiter->delayBuf;
unsigned int delayBufIdx = limiter->delayBufIdx;
FIXP_DBL smoothState0 = limiter->smoothState0;
FIXP_DBL additionalGainSmoothState = limiter->additionalGainFilterState;
FIXP_DBL additionalGainSmoothState1 = limiter->additionalGainFilterState1;
for (i = 0; i < nSamples; i++) {
if (i < gain_delay) {
additionalGainUnfiltered = limiter->additionalGainPrev;
} else {
additionalGainUnfiltered = pGain[0];
}
/* Smooth additionalGain */
/* [b,a] = butter(1, 0.01) */
static const FIXP_SGL b[] = { FL2FXCONST_SGL(0.015466*2.0), FL2FXCONST_SGL( 0.015466*2.0) };
static const FIXP_SGL a[] = { FL2FXCONST_SGL(1.000000), FL2FXCONST_SGL(-0.96907) };
/* [b,a] = butter(1, 0.001) */
//static const FIXP_SGL b[] = { FL2FXCONST_SGL(0.0015683*2.0), FL2FXCONST_SGL( 0.0015683*2.0) };
//static const FIXP_SGL a[] = { FL2FXCONST_SGL(1.0000000), FL2FXCONST_SGL(-0.99686) };
additionalGain = - fMult(additionalGainSmoothState, a[1]) + fMultDiv2( additionalGainUnfiltered, b[0]) + fMultDiv2(additionalGainSmoothState1, b[1]);
additionalGainSmoothState1 = additionalGainUnfiltered;
additionalGainSmoothState = additionalGain;
/* Apply the additional scaling that has no delay and no smoothing */
if (gain_scale[0] > 0) {
additionalGain <<= gain_scale[0];
} else {
additionalGain >>= gain_scale[0];
}
/* get maximum absolute sample value of all channels, including the additional gain. */
tmp1 = (FIXP_PCM)0;
for (j = 0; j < channels; j++) {
tmp2 = (FIXP_PCM)samples[i * channels + j];
if (tmp2 == (FIXP_PCM)SAMPLE_MIN) /* protect fAbs from -1.0 value */
tmp2 = (FIXP_PCM)(SAMPLE_MIN+1);
tmp1 = fMax(tmp1, fAbs(tmp2));
}
tmp = SATURATE_LEFT_SHIFT(fMultDiv2(tmp1, additionalGain), 1, DFRACT_BITS);
/* set threshold as lower border to save calculations in running maximum algorithm */
tmp = fMax(tmp, threshold);
/* running maximum */
old = maxBuf[maxBufIdx];
maxBuf[maxBufIdx] = tmp;
if (tmp >= max) {
/* new sample is greater than old maximum, so it is the new maximum */
max = tmp;
}
else if (old < max) {
/* maximum does not change, as the sample, which has left the window was
not the maximum */
}
else {
/* the old maximum has left the window, we have to search the complete
buffer for the new max */
max = maxBuf[0];
for (j = 1; j <= attack; j++) {
if (maxBuf[j] > max) max = maxBuf[j];
}
}
maxBufIdx++;
if (maxBufIdx >= attack+1) maxBufIdx = 0;
/* calc gain */
/* gain is downscaled by one, so that gain = 1.0 can be represented */
if (max > threshold) {
gain = fDivNorm(threshold, max)>>1;
}
else {
gain = FL2FXCONST_DBL(1.0f/(1<<1));
}
/* gain smoothing, method: TDL_EXPONENTIAL */
/* first order IIR filter with attack correction to avoid overshoots */
/* correct the 'aiming' value of the exponential attack to avoid the remaining overshoot */
if (gain < smoothState0) {
cor = fMin(cor, fMultDiv2((gain - fMultDiv2(FL2FXCONST_SGL(0.1f*(1<<1)),smoothState0)), FL2FXCONST_SGL(1.11111111f/(1<<1)))<<2);
}
else {
cor = gain;
}
/* smoothing filter */
if (cor < smoothState0) {
smoothState0 = fMult(attackConst,(smoothState0 - cor)) + cor; /* attack */
smoothState0 = fMax(smoothState0, gain); /* avoid overshooting target */
}
else {
/* sign inversion twice to round towards +infinity,
so that gain can converge to 1.0 again,
for bit-identical output when limiter is not active */
smoothState0 = -fMult(releaseConst,-(smoothState0 - cor)) + cor; /* release */
}
gain = smoothState0;
/* lookahead delay, apply gain */
for (j = 0; j < channels; j++) {
tmp = delayBuf[delayBufIdx * channels + j];
delayBuf[delayBufIdx * channels + j] = fMult((FIXP_PCM)samples[i * channels + j], additionalGain);
/* Apply gain to delayed signal */
if (gain < FL2FXCONST_DBL(1.0f/(1<<1)))
tmp = fMult(tmp,gain<<1);
samples[i * channels + j] = FX_DBL2FX_PCM((FIXP_DBL)SATURATE_LEFT_SHIFT(tmp,TDL_GAIN_SCALING,DFRACT_BITS));
}
delayBufIdx++;
if (delayBufIdx >= attack) delayBufIdx = 0;
/* save minimum gain factor */
if (gain < minGain) minGain = gain;
}
limiter->max = max;
limiter->maxBufIdx = maxBufIdx;
limiter->cor = cor;
limiter->delayBufIdx = delayBufIdx;
limiter->smoothState0 = smoothState0;
limiter->additionalGainFilterState = additionalGainSmoothState;
limiter->additionalGainFilterState1 = additionalGainSmoothState1;
limiter->minGain = minGain;
limiter->additionalGainPrev = pGain[0];
return TDLIMIT_OK;
}
}
/* get delay in samples */
unsigned int getLimiterDelay(TDLimiterPtr limiter)
{
FDK_ASSERT(limiter != NULL);
return limiter->attack;
}
/* set number of channels */
TDLIMITER_ERROR setLimiterNChannels(TDLimiterPtr limiter, unsigned int nChannels)
{
if ( limiter == NULL ) return TDLIMIT_INVALID_HANDLE;
if (nChannels > limiter->maxChannels) return TDLIMIT_INVALID_PARAMETER;
limiter->channels = nChannels;
//resetLimiter(limiter);
return TDLIMIT_OK;
}
/* set sampling rate */
TDLIMITER_ERROR setLimiterSampleRate(TDLimiterPtr limiter, unsigned int sampleRate)
{
unsigned int attack, release;
FIXP_DBL attackConst, releaseConst, exponent;
INT e_ans;
if ( limiter == NULL ) return TDLIMIT_INVALID_HANDLE;
if (sampleRate > limiter->maxSampleRate) return TDLIMIT_INVALID_PARAMETER;
/* update attack and release time in samples */
attack = (unsigned int)(limiter->attackMs * sampleRate / 1000);
release = (unsigned int)(limiter->releaseMs * sampleRate / 1000);
/* attackConst = pow(0.1, 1.0 / (attack + 1)) */
exponent = invFixp(attack+1);
attackConst = fPow(FL2FXCONST_DBL(0.1f), 0, exponent, 0, &e_ans);
attackConst = scaleValue(attackConst, e_ans);
/* releaseConst = (float)pow(0.1, 1.0 / (release + 1)) */
exponent = invFixp(release + 1);
releaseConst = fPow(FL2FXCONST_DBL(0.1f), 0, exponent, 0, &e_ans);
releaseConst = scaleValue(releaseConst, e_ans);
limiter->attack = attack;
limiter->attackConst = attackConst;
limiter->releaseConst = releaseConst;
limiter->sampleRate = sampleRate;
/* reset */
//resetLimiter(limiter);
return TDLIMIT_OK;
}
/* set attack time */
TDLIMITER_ERROR setLimiterAttack(TDLimiterPtr limiter, unsigned int attackMs)
{
unsigned int attack;
FIXP_DBL attackConst, exponent;
INT e_ans;
if ( limiter == NULL ) return TDLIMIT_INVALID_HANDLE;
if (attackMs > limiter->maxAttackMs) return TDLIMIT_INVALID_PARAMETER;
/* calculate attack time in samples */
attack = (unsigned int)(attackMs * limiter->sampleRate / 1000);
/* attackConst = pow(0.1, 1.0 / (attack + 1)) */
exponent = invFixp(attack+1);
attackConst = fPow(FL2FXCONST_DBL(0.1f), 0, exponent, 0, &e_ans);
attackConst = scaleValue(attackConst, e_ans);
limiter->attack = attack;
limiter->attackConst = attackConst;
limiter->attackMs = attackMs;
return TDLIMIT_OK;
}
/* set release time */
TDLIMITER_ERROR setLimiterRelease(TDLimiterPtr limiter, unsigned int releaseMs)
{
unsigned int release;
FIXP_DBL releaseConst, exponent;
INT e_ans;
if ( limiter == NULL ) return TDLIMIT_INVALID_HANDLE;
/* calculate release time in samples */
release = (unsigned int)(releaseMs * limiter->sampleRate / 1000);
/* releaseConst = (float)pow(0.1, 1.0 / (release + 1)) */
exponent = invFixp(release + 1);
releaseConst = fPow(FL2FXCONST_DBL(0.1f), 0, exponent, 0, &e_ans);
releaseConst = scaleValue(releaseConst, e_ans);
limiter->releaseConst = releaseConst;
limiter->releaseMs = releaseMs;
return TDLIMIT_OK;
}
/* set limiter threshold */
TDLIMITER_ERROR setLimiterThreshold(TDLimiterPtr limiter, INT_PCM threshold)
{
if ( limiter == NULL ) return TDLIMIT_INVALID_HANDLE;
limiter->threshold = (FIXP_PCM)threshold;
return TDLIMIT_OK;
}
This source diff could not be displayed because it is too large. You can view the blob instead.
...@@ -145,6 +145,8 @@ typedef enum ...@@ -145,6 +145,8 @@ typedef enum
SBR_SYSTEM_BITSTREAM_DELAY, /*!< System: Switch to enable an additional SBR bitstream delay of one frame. */ SBR_SYSTEM_BITSTREAM_DELAY, /*!< System: Switch to enable an additional SBR bitstream delay of one frame. */
SBR_QMF_MODE, /*!< Set QMF mode, either complex or low power. */ SBR_QMF_MODE, /*!< Set QMF mode, either complex or low power. */
SBR_LD_QMF_TIME_ALIGN, /*!< Set QMF type, either LD-MPS or CLDFB. Relevant for ELD streams only. */ SBR_LD_QMF_TIME_ALIGN, /*!< Set QMF type, either LD-MPS or CLDFB. Relevant for ELD streams only. */
SBR_FLUSH_DATA, /*!< Set internal state to flush the decoder with the next process call. */
SBR_CLEAR_HISTORY, /*!< Clear all internal states (delay lines, QMF states, ...). */
SBR_BS_INTERRUPTION /*!< Signal bit stream interruption. Value is ignored. */ SBR_BS_INTERRUPTION /*!< Signal bit stream interruption. Value is ignored. */
} SBRDEC_PARAM; } SBRDEC_PARAM;
...@@ -308,7 +310,7 @@ SBR_ERROR sbrDecoder_Apply ( HANDLE_SBRDECODER self, ...@@ -308,7 +310,7 @@ SBR_ERROR sbrDecoder_Apply ( HANDLE_SBRDECODER self,
INT_PCM *timeData, INT_PCM *timeData,
int *numChannels, int *numChannels,
int *sampleRate, int *sampleRate,
const UCHAR channelMapping[(6)], const UCHAR channelMapping[(8)],
const int interleaved, const int interleaved,
const int coreDecodedOk, const int coreDecodedOk,
UCHAR *psDecoded ); UCHAR *psDecoded );
...@@ -329,6 +331,13 @@ SBR_ERROR sbrDecoder_Close ( HANDLE_SBRDECODER *self ); ...@@ -329,6 +331,13 @@ SBR_ERROR sbrDecoder_Close ( HANDLE_SBRDECODER *self );
*/ */
INT sbrDecoder_GetLibInfo( LIB_INFO *info ); INT sbrDecoder_GetLibInfo( LIB_INFO *info );
/**
* \brief Determine the modules output signal delay in samples.
* \param self SBR decoder handle.
* \return The number of samples signal delay added by the module.
*/
UINT sbrDecoder_GetDelay( const HANDLE_SBRDECODER self );
#ifdef __cplusplus #ifdef __cplusplus
} }
......
...@@ -179,6 +179,9 @@ typedef FREQ_BAND_DATA *HANDLE_FREQ_BAND_DATA; ...@@ -179,6 +179,9 @@ typedef FREQ_BAND_DATA *HANDLE_FREQ_BAND_DATA;
#define SBRDEC_LOW_POWER 16 /* Flag indicating that Low Power QMF mode shall be used. */ #define SBRDEC_LOW_POWER 16 /* Flag indicating that Low Power QMF mode shall be used. */
#define SBRDEC_PS_DECODED 32 /* Flag indicating that PS was decoded and rendered. */ #define SBRDEC_PS_DECODED 32 /* Flag indicating that PS was decoded and rendered. */
#define SBRDEC_LD_MPS_QMF 512 /* Flag indicating that the LD-MPS QMF shall be used. */ #define SBRDEC_LD_MPS_QMF 512 /* Flag indicating that the LD-MPS QMF shall be used. */
#define SBRDEC_DOWNSAMPLE 8192 /* Flag indicating that the downsampling mode is used. */
#define SBRDEC_FLUSH 16384 /* Flag is used to flush all elements in use. */
#define SBRDEC_FORCE_RESET 32768 /* Flag is used to force a reset of all elements in use. */
#define SBRDEC_HDR_STAT_RESET 1 #define SBRDEC_HDR_STAT_RESET 1
#define SBRDEC_HDR_STAT_UPDATE 2 #define SBRDEC_HDR_STAT_UPDATE 2
......
...@@ -107,19 +107,19 @@ amm-info@iis.fraunhofer.de ...@@ -107,19 +107,19 @@ amm-info@iis.fraunhofer.de
/*! SBR Decoder main structure */ /*! SBR Decoder main structure */
C_ALLOC_MEM(Ram_SbrDecoder, struct SBR_DECODER_INSTANCE, 1) C_ALLOC_MEM(Ram_SbrDecoder, struct SBR_DECODER_INSTANCE, 1)
/*! SBR Decoder element data <br> /*! SBR Decoder element data <br>
Dimension: (4) */ Dimension: (8) */
C_ALLOC_MEM2(Ram_SbrDecElement, SBR_DECODER_ELEMENT, 1, (4)) C_ALLOC_MEM2(Ram_SbrDecElement, SBR_DECODER_ELEMENT, 1, (8))
/*! SBR Decoder individual channel data <br> /*! SBR Decoder individual channel data <br>
Dimension: (6) */ Dimension: (8) */
C_ALLOC_MEM2(Ram_SbrDecChannel, SBR_CHANNEL, 1, (6)+1) C_ALLOC_MEM2(Ram_SbrDecChannel, SBR_CHANNEL, 1, (8)+1)
/*! Filter states for QMF-synthesis. <br> /*! Filter states for QMF-synthesis. <br>
Dimension: #(6) * (#QMF_FILTER_STATE_SYN_SIZE-#(64)) */ Dimension: #(8) * (#QMF_FILTER_STATE_SYN_SIZE-#(64)) */
C_AALLOC_MEM2_L(Ram_sbr_QmfStatesSynthesis, FIXP_QSS, (640)-(64), (6)+1, SECT_DATA_L1) C_AALLOC_MEM2_L(Ram_sbr_QmfStatesSynthesis, FIXP_QSS, (640)-(64), (8)+1, SECT_DATA_L1)
/*! Delayed spectral data needed for the dynamic framing of SBR. /*! Delayed spectral data needed for the dynamic framing of SBR.
For mp3PRO, 1/3 of a frame is buffered (#(6) 6) */ For mp3PRO, 1/3 of a frame is buffered (#(6) 6) */
C_AALLOC_MEM2(Ram_sbr_OverlapBuffer, FIXP_DBL, 2 * (6) * (64), (6)+1) C_AALLOC_MEM2(Ram_sbr_OverlapBuffer, FIXP_DBL, 2 * (6) * (64), (8)+1)
/*! Static Data of PS */ /*! Static Data of PS */
......
...@@ -118,8 +118,8 @@ typedef struct ...@@ -118,8 +118,8 @@ typedef struct
struct SBR_DECODER_INSTANCE struct SBR_DECODER_INSTANCE
{ {
SBR_DECODER_ELEMENT *pSbrElement[(4)]; SBR_DECODER_ELEMENT *pSbrElement[(8)];
SBR_HEADER_DATA sbrHeader[(4)][(1)+1]; /* Sbr header for each individual channel of an element */ SBR_HEADER_DATA sbrHeader[(8)][(1)+1]; /* Sbr header for each individual channel of an element */
FIXP_DBL *workBuffer1; FIXP_DBL *workBuffer1;
FIXP_DBL *workBuffer2; FIXP_DBL *workBuffer2;
......
...@@ -95,7 +95,7 @@ amm-info@iis.fraunhofer.de ...@@ -95,7 +95,7 @@ amm-info@iis.fraunhofer.de
#define SBRDEC_MAX_DRC_CHANNELS (6) #define SBRDEC_MAX_DRC_CHANNELS (8)
#define SBRDEC_MAX_DRC_BANDS ( 16 ) #define SBRDEC_MAX_DRC_BANDS ( 16 )
typedef struct typedef struct
......
...@@ -137,7 +137,7 @@ amm-info@iis.fraunhofer.de ...@@ -137,7 +137,7 @@ amm-info@iis.fraunhofer.de
/* Decoder library info */ /* Decoder library info */
#define SBRDECODER_LIB_VL0 2 #define SBRDECODER_LIB_VL0 2
#define SBRDECODER_LIB_VL1 2 #define SBRDECODER_LIB_VL1 2
#define SBRDECODER_LIB_VL2 3 #define SBRDECODER_LIB_VL2 6
#define SBRDECODER_LIB_TITLE "SBR Decoder" #define SBRDECODER_LIB_TITLE "SBR Decoder"
#define SBRDECODER_LIB_BUILD_DATE __DATE__ #define SBRDECODER_LIB_BUILD_DATE __DATE__
#define SBRDECODER_LIB_BUILD_TIME __TIME__ #define SBRDECODER_LIB_BUILD_TIME __TIME__
...@@ -251,8 +251,10 @@ SBR_ERROR sbrDecoder_ResetElement ( ...@@ -251,8 +251,10 @@ SBR_ERROR sbrDecoder_ResetElement (
if ( sampleRateIn == sampleRateOut ) { if ( sampleRateIn == sampleRateOut ) {
synDownsampleFac = 2; synDownsampleFac = 2;
self->flags |= SBRDEC_DOWNSAMPLE;
} else { } else {
synDownsampleFac = 1; synDownsampleFac = 1;
self->flags &= ~SBRDEC_DOWNSAMPLE;
} }
self->synDownsampleFac = synDownsampleFac; self->synDownsampleFac = synDownsampleFac;
...@@ -428,7 +430,7 @@ SBR_ERROR sbrDecoder_InitElement ( ...@@ -428,7 +430,7 @@ SBR_ERROR sbrDecoder_InitElement (
int nSbrElementsStart = self->numSbrElements; int nSbrElementsStart = self->numSbrElements;
/* Check core codec AOT */ /* Check core codec AOT */
if (! sbrDecoder_isCoreCodecValid(coreCodec) || elementIndex >= (4)) { if (! sbrDecoder_isCoreCodecValid(coreCodec) || elementIndex >= (8)) {
sbrError = SBRDEC_UNSUPPORTED_CONFIG; sbrError = SBRDEC_UNSUPPORTED_CONFIG;
goto bail; goto bail;
} }
...@@ -444,6 +446,7 @@ SBR_ERROR sbrDecoder_InitElement ( ...@@ -444,6 +446,7 @@ SBR_ERROR sbrDecoder_InitElement (
&& self->coreCodec == coreCodec && self->coreCodec == coreCodec
&& self->pSbrElement[elementIndex] != NULL && self->pSbrElement[elementIndex] != NULL
&& self->pSbrElement[elementIndex]->elementID == elementID && self->pSbrElement[elementIndex]->elementID == elementID
&& !(self->flags & SBRDEC_FORCE_RESET)
) )
{ {
/* Nothing to do */ /* Nothing to do */
...@@ -550,8 +553,9 @@ bail: ...@@ -550,8 +553,9 @@ bail:
if (nSbrElementsStart < self->numSbrElements) { if (nSbrElementsStart < self->numSbrElements) {
/* Free the memory allocated for this element */ /* Free the memory allocated for this element */
sbrDecoder_DestroyElement( self, elementIndex ); sbrDecoder_DestroyElement( self, elementIndex );
} else if (self->pSbrElement[elementIndex] != NULL) { } else if ( (self->pSbrElement[elementIndex] != NULL)
/* Set error flag to trigger concealment */ && (elementIndex < (8)))
{ /* Set error flag to trigger concealment */
self->pSbrElement[elementIndex]->frameErrorFlag[self->pSbrElement[elementIndex]->useFrameSlot] = 1; self->pSbrElement[elementIndex]->frameErrorFlag[self->pSbrElement[elementIndex]->useFrameSlot] = 1;
} }
} }
...@@ -615,7 +619,7 @@ INT sbrDecoder_Header ( ...@@ -615,7 +619,7 @@ INT sbrDecoder_Header (
SBR_ERROR sbrError = SBRDEC_OK; SBR_ERROR sbrError = SBRDEC_OK;
int headerIndex; int headerIndex;
if ( self == NULL || elementIndex > (4) ) if ( self == NULL || elementIndex > (8) )
{ {
return SBRDEC_UNSUPPORTED_CONFIG; return SBRDEC_UNSUPPORTED_CONFIG;
} }
...@@ -728,6 +732,24 @@ SBR_ERROR sbrDecoder_SetParam (HANDLE_SBRDECODER self, ...@@ -728,6 +732,24 @@ SBR_ERROR sbrDecoder_SetParam (HANDLE_SBRDECODER self,
} }
} }
break; break;
case SBR_FLUSH_DATA:
if (value != 0) {
if (self == NULL) {
errorStatus = SBRDEC_NOT_INITIALIZED;
} else {
self->flags |= SBRDEC_FLUSH;
}
}
break;
case SBR_CLEAR_HISTORY:
if (value != 0) {
if (self == NULL) {
errorStatus = SBRDEC_NOT_INITIALIZED;
} else {
self->flags |= SBRDEC_FORCE_RESET;
}
}
break;
case SBR_BS_INTERRUPTION: case SBR_BS_INTERRUPTION:
{ {
int elementIndex; int elementIndex;
...@@ -738,7 +760,8 @@ SBR_ERROR sbrDecoder_SetParam (HANDLE_SBRDECODER self, ...@@ -738,7 +760,8 @@ SBR_ERROR sbrDecoder_SetParam (HANDLE_SBRDECODER self,
} }
/* Loop over SBR elements */ /* Loop over SBR elements */
for (elementIndex = 0; elementIndex < self->numSbrElements; elementIndex++) for (elementIndex = 0; elementIndex < self->numSbrElements; elementIndex++) {
if (self->pSbrElement[elementIndex] != NULL)
{ {
HANDLE_SBR_HEADER_DATA hSbrHeader; HANDLE_SBR_HEADER_DATA hSbrHeader;
int headerIndex = getHeaderSlot(self->pSbrElement[elementIndex]->useFrameSlot, int headerIndex = getHeaderSlot(self->pSbrElement[elementIndex]->useFrameSlot,
...@@ -750,7 +773,7 @@ SBR_ERROR sbrDecoder_SetParam (HANDLE_SBRDECODER self, ...@@ -750,7 +773,7 @@ SBR_ERROR sbrDecoder_SetParam (HANDLE_SBRDECODER self,
This switches off bitstream parsing until a new header arrives. */ This switches off bitstream parsing until a new header arrives. */
hSbrHeader->syncState = UPSAMPLING; hSbrHeader->syncState = UPSAMPLING;
hSbrHeader->status |= SBRDEC_HDR_STAT_UPDATE; hSbrHeader->status |= SBRDEC_HDR_STAT_UPDATE;
} } }
} }
break; break;
default: default:
...@@ -767,7 +790,7 @@ SBRDEC_DRC_CHANNEL * sbrDecoder_drcGetChannel( const HANDLE_SBRDECODER self, con ...@@ -767,7 +790,7 @@ SBRDEC_DRC_CHANNEL * sbrDecoder_drcGetChannel( const HANDLE_SBRDECODER self, con
SBRDEC_DRC_CHANNEL *pSbrDrcChannelData = NULL; SBRDEC_DRC_CHANNEL *pSbrDrcChannelData = NULL;
int elementIndex, elChanIdx=0, numCh=0; int elementIndex, elChanIdx=0, numCh=0;
for (elementIndex = 0; (elementIndex < (4)) && (numCh <= channel); elementIndex++) for (elementIndex = 0; (elementIndex < (8)) && (numCh <= channel); elementIndex++)
{ {
SBR_DECODER_ELEMENT *pSbrElement = self->pSbrElement[elementIndex]; SBR_DECODER_ELEMENT *pSbrElement = self->pSbrElement[elementIndex];
int c, elChannels; int c, elChannels;
...@@ -829,7 +852,7 @@ SBR_ERROR sbrDecoder_drcFeedChannel ( HANDLE_SBRDECODER self, ...@@ -829,7 +852,7 @@ SBR_ERROR sbrDecoder_drcFeedChannel ( HANDLE_SBRDECODER self,
if (self == NULL) { if (self == NULL) {
return SBRDEC_NOT_INITIALIZED; return SBRDEC_NOT_INITIALIZED;
} }
if (ch > (6) || pNextFact_mag == NULL) { if (ch > (8) || pNextFact_mag == NULL) {
return SBRDEC_SET_PARAM_FAIL; return SBRDEC_SET_PARAM_FAIL;
} }
...@@ -874,7 +897,7 @@ void sbrDecoder_drcDisable ( HANDLE_SBRDECODER self, ...@@ -874,7 +897,7 @@ void sbrDecoder_drcDisable ( HANDLE_SBRDECODER self,
SBRDEC_DRC_CHANNEL *pSbrDrcChannelData = NULL; SBRDEC_DRC_CHANNEL *pSbrDrcChannelData = NULL;
if ( (self == NULL) if ( (self == NULL)
|| (ch > (6)) || (ch > (8))
|| (self->numSbrElements == 0) || (self->numSbrElements == 0)
|| (self->numSbrChannels == 0) ) { || (self->numSbrChannels == 0) ) {
return; return;
...@@ -1119,6 +1142,10 @@ SBR_ERROR sbrDecoder_Parse( ...@@ -1119,6 +1142,10 @@ SBR_ERROR sbrDecoder_Parse(
} }
} }
} }
} else {
/* The returned bit count will not be the actual payload size since we did not
parse the frame data. Return an error so that the caller can react respectively. */
errorStatus = SBRDEC_PARSE_ERROR;
} }
if (!fDoDecodeSbrData) { if (!fDoDecodeSbrData) {
...@@ -1198,6 +1225,15 @@ sbrDecoder_DecodeElement ( ...@@ -1198,6 +1225,15 @@ sbrDecoder_DecodeElement (
int stereo = (hSbrElement->elementID == ID_CPE) ? 1 : 0; int stereo = (hSbrElement->elementID == ID_CPE) ? 1 : 0;
int numElementChannels = hSbrElement->nChannels; /* Number of channels of the current SBR element */ int numElementChannels = hSbrElement->nChannels; /* Number of channels of the current SBR element */
if (self->flags & SBRDEC_FLUSH) {
/* Move frame pointer to the next slot which is up to be decoded/applied next */
hSbrElement->useFrameSlot = (hSbrElement->useFrameSlot+1) % (self->numDelayFrames+1);
/* Update header and frame data pointer because they have already been set */
hSbrHeader = &self->sbrHeader[elementIndex][hSbrElement->useHeaderSlot[hSbrElement->useFrameSlot]];
hFrameDataLeft = &hSbrElement->pSbrChannel[0]->frameData[hSbrElement->useFrameSlot];
hFrameDataRight = &hSbrElement->pSbrChannel[1]->frameData[hSbrElement->useFrameSlot];
}
/* Update the header error flag */ /* Update the header error flag */
hSbrHeader->frameErrorFlag = hSbrElement->frameErrorFlag[hSbrElement->useFrameSlot]; hSbrHeader->frameErrorFlag = hSbrElement->frameErrorFlag[hSbrElement->useFrameSlot];
...@@ -1375,7 +1411,7 @@ SBR_ERROR sbrDecoder_Apply ( HANDLE_SBRDECODER self, ...@@ -1375,7 +1411,7 @@ SBR_ERROR sbrDecoder_Apply ( HANDLE_SBRDECODER self,
INT_PCM *timeData, INT_PCM *timeData,
int *numChannels, int *numChannels,
int *sampleRate, int *sampleRate,
const UCHAR channelMapping[(6)], const UCHAR channelMapping[(8)],
const int interleaved, const int interleaved,
const int coreDecodedOk, const int coreDecodedOk,
UCHAR *psDecoded ) UCHAR *psDecoded )
...@@ -1472,6 +1508,10 @@ SBR_ERROR sbrDecoder_Apply ( HANDLE_SBRDECODER self, ...@@ -1472,6 +1508,10 @@ SBR_ERROR sbrDecoder_Apply ( HANDLE_SBRDECODER self,
/* Clear reset and flush flag because everything seems to be done successfully. */
self->flags &= ~SBRDEC_FORCE_RESET;
self->flags &= ~SBRDEC_FLUSH;
bail: bail:
return errorStatus; return errorStatus;
...@@ -1496,7 +1536,7 @@ SBR_ERROR sbrDecoder_Close ( HANDLE_SBRDECODER *pSelf ) ...@@ -1496,7 +1536,7 @@ SBR_ERROR sbrDecoder_Close ( HANDLE_SBRDECODER *pSelf )
FreeRam_SbrDecWorkBuffer2(&self->workBuffer2); FreeRam_SbrDecWorkBuffer2(&self->workBuffer2);
} }
for (i = 0; i < (4); i++) { for (i = 0; i < (8); i++) {
sbrDecoder_DestroyElement( self, i ); sbrDecoder_DestroyElement( self, i );
} }
...@@ -1544,3 +1584,34 @@ INT sbrDecoder_GetLibInfo( LIB_INFO *info ) ...@@ -1544,3 +1584,34 @@ INT sbrDecoder_GetLibInfo( LIB_INFO *info )
return 0; return 0;
} }
UINT sbrDecoder_GetDelay( const HANDLE_SBRDECODER self )
{
UINT outputDelay = 0;
if ( self != NULL) {
UINT flags = self->flags;
/* See chapter 1.6.7.2 of ISO/IEC 14496-3 for the GA-SBR figures below. */
/* Are we initialized? */
if ( (self->numSbrChannels > 0)
&& (self->numSbrElements > 0) )
{
/* Add QMF synthesis delay */
if ( (flags & SBRDEC_ELD_GRID)
&& IS_LOWDELAY(self->coreCodec) ) {
/* Low delay SBR: */
{
outputDelay += (flags & SBRDEC_DOWNSAMPLE) ? 32 : 64; /* QMF synthesis */
}
}
else if (!IS_USAC(self->coreCodec)) {
/* By the method of elimination this is the GA (AAC-LC, HE-AAC, ...) branch: */
outputDelay += (flags & SBRDEC_DOWNSAMPLE) ? 481 : 962;
}
}
}
return (outputDelay);
}
...@@ -232,6 +232,14 @@ typedef enum ...@@ -232,6 +232,14 @@ typedef enum
} AUDIO_OBJECT_TYPE; } AUDIO_OBJECT_TYPE;
#define IS_USAC(aot) \
((aot) == AOT_USAC \
|| (aot) == AOT_RSVD50)
#define IS_LOWDELAY(aot) \
((aot) == AOT_ER_AAC_LD \
|| (aot) == AOT_ER_AAC_ELD)
/** Channel Mode ( 1-7 equals MPEG channel configurations, others are arbitrary). */ /** Channel Mode ( 1-7 equals MPEG channel configurations, others are arbitrary). */
typedef enum { typedef enum {
MODE_INVALID = -1, MODE_INVALID = -1,
...@@ -263,17 +271,29 @@ typedef enum { ...@@ -263,17 +271,29 @@ typedef enum {
} CHANNEL_MODE; } CHANNEL_MODE;
/** Speaker description tags */ /**
* Speaker description tags.
* Do not change the enumeration values unless it keeps the following segmentation:
* - Bit 0-3: Horizontal postion (0: none, 1: front, 2: side, 3: back, 4: lfe)
* - Bit 4-7: Vertical position (0: normal, 1: top, 2: bottom)
*/
typedef enum { typedef enum {
ACT_NONE, ACT_NONE = 0x00,
ACT_FRONT, ACT_FRONT = 0x01, /*!< Front speaker position (at normal height) */
ACT_SIDE, ACT_SIDE = 0x02, /*!< Side speaker position (at normal height) */
ACT_BACK, ACT_BACK = 0x03, /*!< Back speaker position (at normal height) */
ACT_LFE, ACT_LFE = 0x04, /*!< Low frequency effect speaker postion (front) */
ACT_FRONT_TOP,
ACT_SIDE_TOP, ACT_TOP = 0x10, /*!< Top speaker area (for combination with speaker positions) */
ACT_BACK_TOP, ACT_FRONT_TOP = 0x11, /*!< Top front speaker = (ACT_FRONT|ACT_TOP) */
ACT_TOP /* Ts */ ACT_SIDE_TOP = 0x12, /*!< Top side speaker = (ACT_SIDE |ACT_TOP) */
ACT_BACK_TOP = 0x13, /*!< Top back speaker = (ACT_BACK |ACT_TOP) */
ACT_BOTTOM = 0x20, /*!< Bottom speaker area (for combination with speaker positions) */
ACT_FRONT_BOTTOM = 0x21, /*!< Bottom front speaker = (ACT_FRONT|ACT_BOTTOM) */
ACT_SIDE_BOTTOM = 0x22, /*!< Bottom side speaker = (ACT_SIDE |ACT_BOTTOM) */
ACT_BACK_BOTTOM = 0x23 /*!< Bottom back speaker = (ACT_BACK |ACT_BOTTOM) */
} AUDIO_CHANNEL_TYPE; } AUDIO_CHANNEL_TYPE;
typedef enum typedef enum
......
...@@ -99,7 +99,7 @@ amm-info@iis.fraunhofer.de ...@@ -99,7 +99,7 @@ amm-info@iis.fraunhofer.de
/* library info */ /* library info */
#define SYS_LIB_VL0 1 #define SYS_LIB_VL0 1
#define SYS_LIB_VL1 3 #define SYS_LIB_VL1 3
#define SYS_LIB_VL2 4 #define SYS_LIB_VL2 6
#define SYS_LIB_TITLE "System Integration Library" #define SYS_LIB_TITLE "System Integration Library"
#define SYS_LIB_BUILD_DATE __DATE__ #define SYS_LIB_BUILD_DATE __DATE__
#define SYS_LIB_BUILD_TIME __TIME__ #define SYS_LIB_BUILD_TIME __TIME__
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment