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 := \
$(LOCAL_PATH)/libSBRdec/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
include $(BUILD_STATIC_LIBRARY)
......@@ -144,10 +144,9 @@ to allocate memory for the required structures, and the corresponding mpegFileRe
files and to de-allocate associated structures. mpegFileRead_Open() tries to detect the bitstream format and
in case of MPEG-4 file format or Raw Packets file format (a Fraunhofer IIS proprietary format) reads the Audio
Specific Config data (ASC). An unsuccessful attempt to recognize the bitstream format requires the user to
provide this information manually (see \ref CommandLineUsage). For any other bitstream formats that are
usually applicable in streaming applications, the decoder itself will try to synchronize and parse the given
bitstream fragment using the FDK transport library. Hence, for streaming applications (without file access)
this step is not necessary.
provide this information manually. For any other bitstream formats that are usually applicable in streaming
applications, the decoder itself will try to synchronize and parse the given bitstream fragment using the
FDK transport library. Hence, for streaming applications (without file access) this step is not necessary.
-# Call aacDecoder_Open() to open and retrieve a handle to a new AAC decoder instance.
\dontinclude main.cpp
......@@ -430,21 +429,68 @@ typedef enum {
typedef enum
{
AAC_PCM_OUTPUT_INTERLEAVED = 0x0000, /*!< PCM output mode (1: interleaved (default); 0: not interleaved). */
AAC_PCM_OUTPUT_CHANNELS = 0x0001, /*!< Number of PCM output channels (if different from encoded audio channels, downmixing or
upmixing is applied). \n
-1: Disable up-/downmixing. The decoder output contains the same number of channels as the
encoded bitstream. \n
1: The decoder performs a mono matrix mix-down if the encoded audio channels are greater
than one. Thus it ouputs always exact one channel. \n
2: The decoder performs a stereo matrix mix-down if the encoded audio channels are greater
than two. If the encoded audio channels are smaller than two the decoder duplicates the
output. Thus it ouputs always exact two channels. \n */
AAC_PCM_DUAL_CHANNEL_OUTPUT_MODE = 0x0002, /*!< Defines how the decoder processes two channel signals:
0: Leave both signals as they are (default).
1: Create a dual mono output signal from channel 1.
2: Create a dual mono output signal from channel 2.
AAC_PCM_DUAL_CHANNEL_OUTPUT_MODE = 0x0002, /*!< Defines how the decoder processes two channel signals: \n
0: Leave both signals as they are (default). \n
1: Create a dual mono output signal from channel 1. \n
2: Create a dual mono output signal from channel 2. \n
3: Create a dual mono output signal by mixing both channels (L' = R' = 0.5*Ch1 + 0.5*Ch2). */
AAC_PCM_OUTPUT_CHANNEL_MAPPING = 0x0003, /*!< Output buffer channel ordering. 0: MPEG PCE style order, 1: WAV file channel order (default). */
AAC_PCM_LIMITER_ENABLE = 0x0004, /*!< Enable signal level limiting. \n
-1: Auto-config. Enable limiter for all non-lowdelay configurations by default. \n
0: Disable limiter in general. \n
1: Enable limiter always.
It is recommended to call the decoder with a AACDEC_CLRHIST flag to reset all states when
the limiter switch is changed explicitly. */
AAC_PCM_LIMITER_ATTACK_TIME = 0x0005, /*!< Signal level limiting attack time in ms.
Default confguration is 15 ms. Adjustable range from 1 ms to 15 ms. */
AAC_PCM_LIMITER_RELEAS_TIME = 0x0006, /*!< Signal level limiting release time in ms.
Default configuration is 50 ms. Adjustable time must be larger than 0 ms. */
AAC_PCM_MIN_OUTPUT_CHANNELS = 0x0011, /*!< Minimum number of PCM output channels. If higher than the number of encoded audio channels,
a simple channel extension is applied. \n
-1, 0: Disable channel extenstion feature. The decoder output contains the same number of
channels as the encoded bitstream. \n
1: This value is currently needed only together with the mix-down feature. See
::AAC_PCM_MAX_OUTPUT_CHANNELS and note 2 below. \n
2: Encoded mono signals will be duplicated to achieve a 2/0/0.0 channel output
configuration. \n
6: The decoder trys to reorder encoded signals with less than six channels to achieve
a 3/0/2.1 channel output signal. Missing channels will be filled with a zero signal.
If reordering is not possible the empty channels will simply be appended. Only
available if instance is configured to support multichannel output. \n
8: The decoder trys to reorder encoded signals with less than eight channels to
achieve a 3/0/4.1 channel output signal. Missing channels will be filled with a
zero signal. If reordering is not possible the empty channels will simply be
appended. Only available if instance is configured to support multichannel output.\n
NOTE: \n
1. The channel signalling (CStreamInfo::pChannelType and CStreamInfo::pChannelIndices)
will not be modified. Added empty channels will be signalled with channel type
AUDIO_CHANNEL_TYPE::ACT_NONE. \n
2. If the parameter value is greater than that of ::AAC_PCM_MAX_OUTPUT_CHANNELS both will
be set to the same value. \n
3. This parameter does not affect MPEG Surround processing. */
AAC_PCM_MAX_OUTPUT_CHANNELS = 0x0012, /*!< Maximum number of PCM output channels. If lower than the number of encoded audio channels,
downmixing is applied accordingly. If dedicated metadata is available in the stream it
will be used to achieve better mixing results. \n
-1, 0: Disable downmixing feature. The decoder output contains the same number of channels
as the encoded bitstream. \n
1: All encoded audio configurations with more than one channel will be mixed down to
one mono output signal. \n
2: The decoder performs a stereo mix-down if the number encoded audio channels is
greater than two. \n
6: If the number of encoded audio channels is greater than six the decoder performs a
mix-down to meet the target output configuration of 3/0/2.1 channels. Only
available if instance is configured to support multichannel output. \n
8: This value is currently needed only together with the channel extension feature.
See ::AAC_PCM_MIN_OUTPUT_CHANNELS and note 2 below. Only available if instance is
configured to support multichannel output. \n
NOTE: \n
1. Down-mixing of any seven or eight channel configuration not defined in ISO/IEC 14496-3
PDAM 4 is not supported by this software version. \n
2. If the parameter value is greater than zero but smaller than ::AAC_PCM_MIN_OUTPUT_CHANNELS
both will be set to same value. \n
3. The operating mode of the MPEG Surround module will be set accordingly. \n
4. Setting this param with any value will disable the binaural processing of the MPEG
Surround module (::AAC_MPEGS_BINAURAL_ENABLE=0). */
AAC_CONCEAL_METHOD = 0x0100, /*!< Error concealment: Processing method. \n
0: Spectral muting. \n
......@@ -485,7 +531,7 @@ typedef enum
*/
typedef struct
{
/* These three members are the only really relevant ones for the user. */
/* These five members are the only really relevant ones for the user. */
INT sampleRate; /*!< The samplerate in Hz of the fully decoded PCM audio signal (after SBR processing). */
INT frameSize; /*!< The frame size of the decoded PCM audio signal. \n
1024 or 960 for AAC-LC \n
......@@ -496,7 +542,7 @@ typedef struct
UCHAR *pChannelIndices; /*!< Audio channel index for each output audio channel.
See ISO/IEC 13818-7:2005(E), 8.5.3.2 Explicit channel mapping using a program_config_element() */
/* Decoder internal members. */
INT aacSampleRate; /*!< sampling rate in Hz without SBR (from configuration info). */
INT aacSampleRate; /*!< Sampling rate in Hz without SBR (from configuration info). */
INT profile; /*!< MPEG-2 profile (from file header) (-1: not applicable (e. g. MPEG-4)). */
AUDIO_OBJECT_TYPE aot; /*!< Audio Object Type (from ASC): is set to the appropriate value for MPEG-2 bitstreams (e. g. 2 for AAC-LC). */
INT channelConfig; /*!< Channel configuration (0: PCE defined, 1: mono, 2: stereo, ... */
......@@ -509,7 +555,9 @@ typedef struct
AUDIO_OBJECT_TYPE extAot; /*!< Extension Audio Object Type (from ASC) */
INT extSamplingRate; /*!< Extension sampling rate in Hz (from ASC) */
UINT flags; /*!< Copy if internal flags. Only to be written by the decoder, and only to be read externally. */
UINT outputDelay; /*!< The number of samples the output is additionally delayed by the decoder. */
UINT flags; /*!< Copy of internal flags. Only to be written by the decoder, and only to be read externally. */
SCHAR epConfig; /*!< epConfig level (from ASC): only level 0 supported, -1 means no ER (e. g. AOT=2, MPEG-2 AAC, etc.) */
......@@ -522,10 +570,25 @@ typedef struct
UINT numTotalAccessUnits; /*!< This is the number of total access units that have passed through the decoder. */
UINT numBadAccessUnits; /*!< This is the number of total access units that were considered with errors from numTotalBytes. */
/* Metadata */
SCHAR drcProgRefLev; /*!< DRC program reference level. Defines the reference level below full-scale.
It is quantized in steps of 0.25dB. The valid values range from 0 (0 dBFS) to 127 (-31.75 dBFS).
It is used to reflect the average loudness of the audio in LKFS accoring to ITU-R BS 1770.
If no level has been found in the bitstream the value is -1. */
SCHAR drcPresMode; /*!< DRC presentation mode. According to ETSI TS 101 154, this field indicates whether
light (MPEG-4 Dynamic Range Control tool) or heavy compression (DVB heavy compression)
dynamic range control shall take priority on the outputs.
For details, see ETSI TS 101 154, table C.33. Possible values are: \n
-1: No corresponding metadata found in the bitstream \n
0: DRC presentation mode not indicated \n
1: DRC presentation mode 1 \n
2: DRC presentation mode 2 \n
3: Reserved */
} CStreamInfo;
typedef struct AAC_DECODER_INSTANCE *HANDLE_AACDECODER;
typedef struct AAC_DECODER_INSTANCE *HANDLE_AACDECODER; /*!< Pointer to a AAC decoder instance. */
#ifdef __cplusplus
extern "C"
......@@ -634,11 +697,15 @@ aacDecoder_Fill ( HANDLE_AACDECODER self,
const UINT bufferSize[],
UINT *bytesValid );
#define AACDEC_CONCEAL 1 /*!< Flag for aacDecoder_DecodeFrame(): do not consider new input data. Do concealment. */
#define AACDEC_FLUSH 2 /*!< Flag for aacDecoder_DecodeFrame(): Do not consider new input data. Flush filterbanks (output delayed audio). */
#define AACDEC_INTR 4 /*!< Flag for aacDecoder_DecodeFrame(): Signal an input bit stream data discontinuity. Resync any internals as necessary. */
#define AACDEC_CLRHIST 8 /*!< Flag for aacDecoder_DecodeFrame(): Clear all signal delay lines and history buffers.
Caution: This can cause discontinuities in the output signal. */
#define AACDEC_CONCEAL 1 /*!< Flag for aacDecoder_DecodeFrame(): Trigger the built-in error concealment module \
to generate a substitute signal for one lost frame. New input data will not be
considered. */
#define AACDEC_FLUSH 2 /*!< Flag for aacDecoder_DecodeFrame(): Flush all filterbanks to get all delayed audio \
without having new input data. Thus new input data will not be considered.*/
#define AACDEC_INTR 4 /*!< Flag for aacDecoder_DecodeFrame(): Signal an input bit stream data discontinuity. \
Resync any internals as necessary. */
#define AACDEC_CLRHIST 8 /*!< Flag for aacDecoder_DecodeFrame(): Clear all signal delay lines and history buffers.\
CAUTION: This can cause discontinuities in the output signal. */
/**
* \brief Decode one audio frame
......
......@@ -108,15 +108,15 @@ C_ALLOC_MEM(AacDecoder, AAC_DECODER_INSTANCE, 1)
/*! The structure CAacDecoderStaticChannelInfo contains the static sideinfo which is needed
for the decoding of one aac channel. <br>
Dimension: #AacDecoderChannels */
C_ALLOC_MEM2(AacDecoderStaticChannelInfo, CAacDecoderStaticChannelInfo, 1, (6))
C_ALLOC_MEM2(AacDecoderStaticChannelInfo, CAacDecoderStaticChannelInfo, 1, (8))
/*! The structure CAacDecoderChannelInfo contains the dynamic sideinfo which is needed
for the decoding of one aac channel. <br>
Dimension: #AacDecoderChannels */
C_ALLOC_MEM2(AacDecoderChannelInfo, CAacDecoderChannelInfo, 1, (6))
C_AALLOC_MEM2(AacDecoderChannelInfo, CAacDecoderChannelInfo, 1, (8))
/*! Overlap buffer */
C_ALLOC_MEM2(OverlapBuffer, FIXP_DBL, OverlapBufferSize, (6))
C_ALLOC_MEM2(OverlapBuffer, FIXP_DBL, OverlapBufferSize, (8))
C_ALLOC_MEM(DrcInfo, CDrcInfo, 1)
......@@ -128,7 +128,7 @@ C_ALLOC_MEM(DrcInfo, CDrcInfo, 1)
Dynamic memory areas, might be reused in other algorithm sections,
e.g. the sbr decoder
*/
C_ALLOC_MEM_OVERLAY(WorkBufferCore2, FIXP_DBL, ((6)*1024), SECT_DATA_L2, WORKBUFFER2_TAG)
C_ALLOC_MEM_OVERLAY(WorkBufferCore2, FIXP_DBL, ((8)*1024), SECT_DATA_L2, WORKBUFFER2_TAG)
C_ALLOC_MEM_OVERLAY(WorkBufferCore1, CWorkBufferCore1, 1, SECT_DATA_L1, WORKBUFFER1_TAG)
......
......@@ -1777,42 +1777,62 @@ const FIXP_TCC FDKaacDec_tnsCoeff4 [16] =
};
/* MPEG like mapping (no change). */
const UCHAR channelMappingTablePassthrough[8][8] =
const UCHAR channelMappingTablePassthrough[15][8] =
{
{ 0, 1, 2, 3, 4, 5, 6, 7}, /* fallback */
{ 0, 1,255,255,255,255,255,255}, /* mono / PS */
{ 0, 1,255,255,255,255,255,255}, /* stereo */
{ 0, 1, 2,255,255,255,255,255}, /* 3ch */
{ 0, 1, 2, 3,255,255,255,255}, /* 4ch */
{ 0, 1, 2, 3, 4,255,255,255}, /* 5ch */
{ 0, 1, 2, 3, 4, 5,255,255}, /* 5.1ch */
{ 0, 1, 2, 3, 4, 5, 6, 7}, /* 7ch */
{ 0, 1, 2, 3, 4, 5, 6, 7} /* 7.1ch */
{ 0, 1, 2, 3, 4, 5, 6, 7}, /* 7.1 front */
{ 0, 1, 2, 3, 4, 5, 6, 7}, /* reserved */
{ 0, 1, 2, 3, 4, 5, 6, 7}, /* reserved */
{ 0, 1, 2, 3, 4, 5, 6, 7}, /* reserved */
{ 0, 1, 2, 3, 4, 5, 6,255}, /* 6.1ch */
{ 0, 1, 2, 3, 4, 5, 6, 7}, /* 7.1 rear */
{ 0, 1, 2, 3, 4, 5, 6, 7}, /* reserved */
{ 0, 1, 2, 3, 4, 5, 6, 7} /* 7.1 top */
};
/* WAV file like mapping (from MPEG mapping). */
const UCHAR channelMappingTableWAV[8][8] =
const UCHAR channelMappingTableWAV[15][8] =
{
{ 0, 1, 2, 3, 4, 5, 6, 7}, /* fallback */
{ 0, 1,255,255,255,255,255,255}, /* mono / PS */
{ 0, 1,255,255,255,255,255,255}, /* stereo */
{ 2, 0, 1,255,255,255,255,255}, /* 3ch */
{ 2, 0, 1, 3,255,255,255,255}, /* 4ch */
{ 2, 0, 1, 3, 4,255,255,255}, /* 5ch */
{ 2, 0, 1, 4, 5, 3,255,255}, /* 5.1ch */
{ 0, 1, 2, 3, 4, 5, 6, 7}, /* 7ch */
{ 2, 0, 1, 6, 7, 4, 5, 3} /* 7.1ch */
{ 2, 6, 7, 0, 1, 4, 5, 3}, /* 7.1 front */
{ 0, 1, 2, 3, 4, 5, 6, 7}, /* reserved */
{ 0, 1, 2, 3, 4, 5, 6, 7}, /* reserved */
{ 0, 1, 2, 3, 4, 5, 6, 7}, /* reserved */
{ 2, 0, 1, 4, 5, 6, 3,255}, /* 6.1ch */
{ 2, 0, 1, 6, 7, 4, 5, 3}, /* 7.1 rear */
{ 0, 1, 2, 3, 4, 5, 6, 7}, /* reserved */
{ 2, 0, 1, 4, 5, 3, 6, 7} /* 7.1 top */
};
/* Lookup tables for elements in ER bitstream */
const MP4_ELEMENT_ID elementsTab[8][7] =
const MP4_ELEMENT_ID elementsTab[15][7] =
{
{ID_SCE, ID_EXT, ID_END, ID_NONE, ID_NONE,ID_NONE,ID_NONE }, /* 1 channel */
{ID_CPE, ID_EXT, ID_END, ID_NONE, ID_NONE,ID_NONE,ID_NONE } /* 2 channels */
,
{ID_SCE, ID_CPE, ID_EXT, ID_END, ID_NONE,ID_NONE,ID_NONE }, /* 3 channels */
{ID_SCE, ID_CPE, ID_SCE, ID_EXT, ID_END, ID_NONE,ID_NONE }, /* 4 channels */
{ID_SCE, ID_CPE, ID_CPE, ID_EXT, ID_END, ID_NONE,ID_NONE }, /* 5 channels */
{ID_SCE, ID_CPE, ID_CPE, ID_LFE, ID_EXT, ID_END, ID_NONE }, /* 6 channels */
{ID_SCE, ID_CPE, ID_CPE, ID_CPE, ID_LFE, ID_EXT, ID_END} /* 8 channels */
/* 1 */ { ID_SCE, ID_EXT, ID_END, ID_NONE, ID_NONE, ID_NONE, ID_NONE }, /* 1 channel */
/* 2 */ { ID_CPE, ID_EXT, ID_END, ID_NONE, ID_NONE, ID_NONE, ID_NONE } /* 2 channels */
/* 3 */ ,{ ID_SCE, ID_CPE, ID_EXT, ID_END, ID_NONE, ID_NONE, ID_NONE }, /* 3 channels */
/* 4 */ { ID_SCE, ID_CPE, ID_SCE, ID_EXT, ID_END, ID_NONE, ID_NONE }, /* 4 channels */
/* 5 */ { ID_SCE, ID_CPE, ID_CPE, ID_EXT, ID_END, ID_NONE, ID_NONE }, /* 5 channels */
/* 6 */ { ID_SCE, ID_CPE, ID_CPE, ID_LFE, ID_EXT, ID_END, ID_NONE } /* 6 channels */
/* 7 */ ,{ ID_SCE, ID_CPE, ID_CPE, ID_CPE, ID_LFE, ID_EXT, ID_END }, /* 8 channels */
/* 8 */ { ID_NONE, ID_NONE, ID_NONE, ID_NONE, ID_NONE, ID_NONE, ID_NONE }, /* reserved */
/* 9 */ { ID_NONE, ID_NONE, ID_NONE, ID_NONE, ID_NONE, ID_NONE, ID_NONE }, /* reserved */
/* 10 */ { ID_NONE, ID_NONE, ID_NONE, ID_NONE, ID_NONE, ID_NONE, ID_NONE }, /* reserved */
/* 11 */ { ID_SCE, ID_CPE, ID_CPE, ID_SCE, ID_LFE, ID_EXT, ID_END }, /* 7 channels */
/* 12 */ { ID_SCE, ID_CPE, ID_CPE, ID_CPE, ID_LFE, ID_EXT, ID_END }, /* 8 channels */
/* 13 */ { ID_NONE, ID_NONE, ID_NONE, ID_NONE, ID_NONE, ID_NONE, ID_NONE }, /* reserved */
/* 14 */ { ID_SCE, ID_CPE, ID_CPE, ID_LFE, ID_CPE, ID_EXT, ID_END } /* 8 channels */
};
/*! Random sign bit used for concealment
......
......@@ -177,11 +177,12 @@ extern const USHORT randomSign[AAC_NF_NO_RANDOM_VAL/16];
extern const FIXP_DBL pow2_div24minus1[47];
extern const int offsetTab[2][16];
/* Channel mapping indices for time domain I/O. First dimension is channel count-1. */
extern const UCHAR channelMappingTablePassthrough[8][8];
extern const UCHAR channelMappingTableWAV[8][8];
/* Channel mapping indices for time domain I/O.
The first dimension is the channel configuration index. */
extern const UCHAR channelMappingTablePassthrough[15][8];
extern const UCHAR channelMappingTableWAV[15][8];
/* Lookup tables for elements in ER bitstream */
extern const MP4_ELEMENT_ID elementsTab[8][7];
extern const MP4_ELEMENT_ID elementsTab[15][7];
#endif /* #ifndef AAC_ROM_H */
......@@ -130,7 +130,6 @@ void aacDecoder_drcInit (
/* init control fields */
self->enable = 0;
self->numThreads = 0;
self->digitalNorm = 0;
/* init params */
pParams = &self->params;
......@@ -139,12 +138,15 @@ void aacDecoder_drcInit (
pParams->usrCut = FL2FXCONST_DBL(0.0f);
pParams->boost = FL2FXCONST_DBL(0.0f);
pParams->usrBoost = FL2FXCONST_DBL(0.0f);
pParams->targetRefLevel = AACDEC_DRC_DEFAULT_REF_LEVEL;
pParams->targetRefLevel = -1;
pParams->expiryFrame = AACDEC_DRC_DFLT_EXPIRY_FRAMES;
pParams->applyDigitalNorm = 0;
pParams->applyHeavyCompression = 0;
/* initial program ref level = target ref level */
self->progRefLevel = pParams->targetRefLevel;
self->progRefLevelPresent = 0;
self->presMode = -1;
}
......@@ -222,11 +224,12 @@ AAC_DECODER_ERROR aacDecoder_drcSetParam (
return AAC_DEC_INVALID_HANDLE;
}
if (value < 0) {
self->digitalNorm = 0;
self->params.applyDigitalNorm = 0;
self->params.targetRefLevel = -1;
}
else {
/* ref_level must be between 0 and MAX_REFERENCE_LEVEL, inclusive */
self->digitalNorm = 1;
self->params.applyDigitalNorm = 1;
if (self->params.targetRefLevel != (SCHAR)value) {
self->params.targetRefLevel = (SCHAR)value;
self->progRefLevel = (SCHAR)value; /* Always set the program reference level equal to the
......@@ -234,6 +237,16 @@ AAC_DECODER_ERROR aacDecoder_drcSetParam (
}
}
break;
case APPLY_NORMALIZATION:
if (value < 0 || value > 1) {
return AAC_DEC_SET_PARAM_FAIL;
}
if (self == NULL) {
return AAC_DEC_INVALID_HANDLE;
}
/* Store new parameter value */
self->params.applyDigitalNorm = (UCHAR)value;
break;
case APPLY_HEAVY_COMPRESSION:
if (value < 0 || value > 1) {
return AAC_DEC_SET_PARAM_FAIL;
......@@ -278,7 +291,7 @@ AAC_DECODER_ERROR aacDecoder_drcSetParam (
self->enable = ( (self->params.boost > (FIXP_DBL)0)
|| (self->params.cut > (FIXP_DBL)0)
|| (self->params.applyHeavyCompression != 0)
|| (self->digitalNorm == 1) );
|| (self->params.targetRefLevel >= 0) );
return ErrorStatus;
......@@ -539,7 +552,7 @@ static int aacDecoder_drcReadCompression (
UINT payloadPosition )
{
int bitCnt = 0;
int dmxLevelsPresent, compressionPresent;
int dmxLevelsPresent, extensionPresent, compressionPresent;
int coarseGrainTcPresent, fineGrainTcPresent;
/* Move to the beginning of the DRC payload field */
......@@ -561,8 +574,9 @@ static int aacDecoder_drcReadCompression (
return 0;
}
FDKreadBits(bs, 2); /* dolby_surround_mode */
FDKreadBits(bs, 2); /* presentation_mode */
if (FDKreadBits(bs, 2) != 0) { /* reserved, set to 0 */
pDrcBs->presMode = FDKreadBits(bs, 2); /* presentation_mode */
FDKreadBits(bs, 1); /* stereo_downmix_mode */
if (FDKreadBits(bs, 1) != 0) { /* reserved, set to 0 */
return 0;
}
......@@ -571,9 +585,7 @@ static int aacDecoder_drcReadCompression (
return 0;
}
dmxLevelsPresent = FDKreadBits(bs, 1); /* downmixing_levels_MPEG4_status */
if (FDKreadBits(bs, 1) != 0) { /* reserved, set to 0 */
return 0;
}
extensionPresent = FDKreadBits(bs, 1); /* ancillary_data_extension_status; */
compressionPresent = FDKreadBits(bs, 1); /* audio_coding_mode_and_compression status */
coarseGrainTcPresent = FDKreadBits(bs, 1); /* coarse_grain_timecode_status */
fineGrainTcPresent = FDKreadBits(bs, 1); /* fine_grain_timecode_status */
......@@ -631,6 +643,19 @@ static int aacDecoder_drcReadCompression (
bitCnt += 16;
}
/* Read extension just to get the right amount of bits. */
if (extensionPresent) {
int extBits = 8;
FDKreadBits(bs, 1); /* reserved, set to 0 */
if (FDKreadBits(bs, 1)) extBits += 8; /* ext_downmixing_levels_status */
if (FDKreadBits(bs, 1)) extBits += 16; /* ext_downmixing_global_gains_status */
if (FDKreadBits(bs, 1)) extBits += 8; /* ext_downmixing_lfe_level_status */
FDKpushFor(bs, extBits - 4); /* skip the extension payload remainder. */
bitCnt += extBits;
}
return (bitCnt);
}
......@@ -780,9 +805,15 @@ static int aacDecoder_drcExtractAndMap (
*/
if (pThreadBs->progRefLevel >= 0) {
self->progRefLevel = pThreadBs->progRefLevel;
self->progRefLevelPresent = 1;
self->prlExpiryCount = 0; /* Got a new value -> Reset counter */
}
if (drcPayloadType == DVB_DRC_ANC_DATA) {
/* Announce the presentation mode of this valid thread. */
self->presMode = pThreadBs->presMode;
}
/* SCE, CPE and LFE */
for (ch = 0; ch < validChannels; ch++) {
int mapedChannel = channelMapping[ch];
......@@ -802,6 +833,7 @@ static int aacDecoder_drcExtractAndMap (
if ( (pParams->expiryFrame > 0)
&& (self->prlExpiryCount++ > pParams->expiryFrame) )
{ /* The program reference level is too old, so set it back to the target level. */
self->progRefLevelPresent = 0;
self->progRefLevel = pParams->targetRefLevel;
self->prlExpiryCount = 0;
}
......@@ -815,6 +847,7 @@ void aacDecoder_drcApply (
void *pSbrDec,
CAacDecoderChannelInfo *pAacDecoderChannelInfo,
CDrcChannelData *pDrcChData,
FIXP_DBL *extGain,
int ch, /* needed only for SBR */
int aacFrameSize,
int bSbrPresent )
......@@ -826,8 +859,8 @@ void aacDecoder_drcApply (
FIXP_DBL max_mantissa;
INT max_exponent;
FIXP_DBL norm_mantissa = FL2FXCONST_DBL(0.0f);
INT norm_exponent = 0;
FIXP_DBL norm_mantissa = FL2FXCONST_DBL(0.5f);
INT norm_exponent = 1;
FIXP_DBL fact_mantissa[MAX_DRC_BANDS];
INT fact_exponent[MAX_DRC_BANDS];
......@@ -849,6 +882,15 @@ void aacDecoder_drcApply (
if (!self->enable) {
sbrDecoder_drcDisable( (HANDLE_SBRDECODER)pSbrDec, ch );
if (extGain != NULL) {
INT gainScale = (INT)*extGain;
/* The gain scaling must be passed to the function in the buffer pointed on by extGain. */
if (gainScale >= 0 && gainScale <= DFRACT_BITS) {
*extGain = scaleValue(norm_mantissa, norm_exponent-gainScale);
} else {
FDK_ASSERT(0);
}
}
return;
}
......@@ -864,7 +906,7 @@ void aacDecoder_drcApply (
reduced DAC SNR (if signal is attenuated) or clipping (if signal is
boosted) */
if (self->digitalNorm == 1)
if (pParams->targetRefLevel >= 0)
{
/* 0.5^((targetRefLevel - progRefLevel)/24) */
norm_mantissa = fLdPow(
......@@ -874,7 +916,18 @@ void aacDecoder_drcApply (
3,
&norm_exponent );
}
else {
/* Always export the normalization gain (if possible). */
if (extGain != NULL) {
INT gainScale = (INT)*extGain;
/* The gain scaling must be passed to the function in the buffer pointed on by extGain. */
if (gainScale >= 0 && gainScale <= DFRACT_BITS) {
*extGain = scaleValue(norm_mantissa, norm_exponent-gainScale);
} else {
FDK_ASSERT(0);
}
}
if (self->params.applyDigitalNorm == 0) {
/* Reset normalization gain since this module must not apply it */
norm_mantissa = FL2FXCONST_DBL(0.5f);
norm_exponent = 1;
}
......@@ -1112,3 +1165,24 @@ int aacDecoder_drcEpilog (
return err;
}
/*
* Export relevant metadata info from bitstream payload.
*/
void aacDecoder_drcGetInfo (
HANDLE_AAC_DRC self,
SCHAR *pPresMode,
SCHAR *pProgRefLevel )
{
if (self != NULL) {
if (pPresMode != NULL) {
*pPresMode = self->presMode;
}
if (pProgRefLevel != NULL) {
if (self->progRefLevelPresent) {
*pProgRefLevel = self->progRefLevel;
} else {
*pProgRefLevel = -1;
}
}
}
}
......@@ -98,7 +98,6 @@ amm-info@iis.fraunhofer.de
#include "channel.h"
#include "FDK_bitstream.h"
#define AACDEC_DRC_DEFAULT_REF_LEVEL ( 108 ) /* -27 dB below full scale (typical for movies) */
#define AACDEC_DRC_DFLT_EXPIRY_FRAMES ( 50 ) /* Default DRC data expiry time in AAC frames */
/**
......@@ -111,6 +110,7 @@ typedef enum
TARGET_REF_LEVEL,
DRC_BS_DELAY,
DRC_DATA_EXPIRY_FRAME,
APPLY_NORMALIZATION,
APPLY_HEAVY_COMPRESSION
} AACDEC_DRC_PARAM;
......@@ -149,6 +149,8 @@ int aacDecoder_drcProlog (
* \param pSbrDec pointer to SBR decoder instance
* \param pAacDecoderChannelInfo AAC decoder channel instance to be processed
* \param pDrcDat DRC channel data
* \param extGain Pointer to a FIXP_DBL where a externally applyable gain will be stored into (independently on whether it will be apply internally or not).
* At function call the buffer must hold the scale (0 >= scale < DFRACT_BITS) to be applied on the gain value.
* \param ch channel index
* \param aacFrameSize AAC frame size
* \param bSbrPresent flag indicating that SBR is present, in which case DRC is handed over to the SBR instance pSbrDec
......@@ -158,6 +160,7 @@ void aacDecoder_drcApply (
void *pSbrDec,
CAacDecoderChannelInfo *pAacDecoderChannelInfo,
CDrcChannelData *pDrcDat,
FIXP_DBL *extGain,
int ch,
int aacFrameSize,
int bSbrPresent );
......@@ -170,5 +173,17 @@ int aacDecoder_drcEpilog (
UCHAR channelMapping[],
int validChannels );
/**
* \brief Get metadata information found in bitstream.
* \param self DRC module instance handle.
* \param pPresMode Pointer to field where the presentation mode will be written to.
* \param pProgRefLevel Pointer to field where the program reference level will be written to.
* \return Nothing.
*/
void aacDecoder_drcGetInfo (
HANDLE_AAC_DRC self,
SCHAR *pPresMode,
SCHAR *pProgRefLevel );
#endif /* AACDEC_DRC_H */
......@@ -124,6 +124,7 @@ typedef struct
{
UINT excludedChnsMask;
SCHAR progRefLevel;
SCHAR presMode; /* Presentation mode: 0 (not indicated), 1, 2, and 3 (reserved). */
SCHAR pceInstanceTag;
CDrcChannelData channelData;
......@@ -140,6 +141,7 @@ typedef struct
UINT expiryFrame;
SCHAR targetRefLevel;
UCHAR bsDelayEnable;
UCHAR applyDigitalNorm;
UCHAR applyHeavyCompression;
} CDrcParams;
......@@ -155,9 +157,11 @@ typedef struct
USHORT numPayloads; /* The number of DRC data payload elements found within frame */
USHORT numThreads; /* The number of DRC data threads extracted from the found payload elements */
SCHAR progRefLevel; /* Program reference level for all channels */
UCHAR progRefLevelPresent; /* Program reference level found in bitstream */
UINT prlExpiryCount; /* Counter that can be used to monitor the life time of the program reference level. */
SCHAR presMode; /* Presentation mode as defined in ETSI TS 101 154 */
UCHAR dvbAncDataAvailable; /* Flag that indicates whether DVB ancillary data is present or not */
UINT dvbAncDataPosition; /* Used to store the DVB ancillary data payload position in the bitstream (only one per frame) */
UINT drcPayloadPosition[MAX_DRC_THREADS]; /* Used to store the DRC payload positions in the bitstream */
......
......@@ -338,17 +338,22 @@ AAC_DECODER_ERROR CAacDecoder_AncDataParse (
\return Error code
*/
static AAC_DECODER_ERROR CDataStreamElement_Read (
HANDLE_AACDECODER self,
HANDLE_FDK_BITSTREAM bs,
CAncData *ancData,
HANDLE_AAC_DRC hDrcInfo,
HANDLE_TRANSPORTDEC pTp,
UCHAR *elementInstanceTag,
UINT alignmentAnchor )
{
HANDLE_TRANSPORTDEC pTp;
CAncData *ancData;
AAC_DECODER_ERROR error = AAC_DEC_OK;
UINT dataStart;
UINT dataStart, dseBits;
int dataByteAlignFlag, count;
FDK_ASSERT(self != NULL);
ancData = &self->ancData;
pTp = self->hInput;
int crcReg = transportDec_CrcStartReg(pTp, 0);
/* Element Instance Tag */
......@@ -361,6 +366,7 @@ static AAC_DECODER_ERROR CDataStreamElement_Read (
if (count == 255) {
count += FDKreadBits(bs,8); /* EscCount */
}
dseBits = count*8;
if (dataByteAlignFlag) {
FDKbyteAlign(bs, alignmentAnchor);
......@@ -372,20 +378,30 @@ static AAC_DECODER_ERROR CDataStreamElement_Read (
transportDec_CrcEndReg(pTp, crcReg);
{
INT readBits, dataBits = count<<3;
/* Move to the beginning of the data junk */
FDKpushBack(bs, dataStart-FDKgetValidBits(bs));
/* Read Anc data if available */
readBits = aacDecoder_drcMarkPayload( hDrcInfo, bs, DVB_DRC_ANC_DATA );
if (readBits != dataBits) {
/* Move to the end again. */
FDKpushBiDirectional(bs, FDKgetValidBits(bs)-dataStart+dataBits);
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));
/* Read DMX meta-data */
dmxErr = pcmDmx_Parse (
self->hPcmUtils,
bs,
dseBits,
0 /* not mpeg2 */ );
}
/* Move to the very end of the element. */
FDKpushBiDirectional(bs, FDKgetValidBits(bs)-dataStart+dseBits);
return error;
}
......@@ -701,6 +717,12 @@ void CStreamInfoInit(CStreamInfo *pStreamInfo)
pStreamInfo->numChannels = 0;
pStreamInfo->sampleRate = 0;
pStreamInfo->frameSize = 0;
pStreamInfo->outputDelay = 0;
/* DRC */
pStreamInfo->drcProgRefLev = -1; /* set program reference level to not indicated */
pStreamInfo->drcPresMode = -1; /* default: presentation mode not indicated */
}
/*!
......@@ -774,7 +796,7 @@ LINKSPEC_CPP void CAacDecoder_Close(HANDLE_AACDECODER self)
if (self == NULL)
return;
for (ch=0; ch<(6); ch++) {
for (ch=0; ch<(8); ch++) {
if (self->pAacDecoderStaticChannelInfo[ch] != NULL) {
if (self->pAacDecoderStaticChannelInfo[ch]->pOverlapBuffer != NULL) {
FreeOverlapBuffer (&self->pAacDecoderStaticChannelInfo[ch]->pOverlapBuffer);
......@@ -851,18 +873,19 @@ LINKSPEC_CPP AAC_DECODER_ERROR CAacDecoder_Init(HANDLE_AACDECODER self, const CS
/* valid number of channels -> copy program config element (PCE) from ASC */
FDKmemcpy(&self->pce, &asc->m_progrConfigElement, sizeof(CProgramConfig));
/* Built element table */
el = CProgramConfig_GetElementTable(&asc->m_progrConfigElement, self->elements, 7);
for (; el<7; el++) {
el = CProgramConfig_GetElementTable(&asc->m_progrConfigElement, self->elements, (8), &self->chMapIndex);
for (; el<(8); el++) {
self->elements[el] = ID_NONE;
}
} else {
return AAC_DEC_UNSUPPORTED_CHANNELCONFIG;
}
} else {
self->chMapIndex = 0;
if (transportDec_GetFormat(self->hInput) == TT_MP4_ADTS) {
/* set default max_channels for memory allocation because in implicit channel mapping mode
we don't know the actual number of channels until we processed at least one raw_data_block(). */
ascChannels = (6);
ascChannels = (8);
} else {
return AAC_DEC_UNSUPPORTED_CHANNELCONFIG;
}
......@@ -874,26 +897,34 @@ LINKSPEC_CPP AAC_DECODER_ERROR CAacDecoder_Init(HANDLE_AACDECODER self, const CS
case 1: case 2: case 3: case 4: case 5: case 6:
ascChannels = asc->m_channelConfiguration;
break;
case 7:
case 11:
ascChannels = 7;
break;
case 7: case 12: case 14:
ascChannels = 8;
break;
default:
return AAC_DEC_UNSUPPORTED_CHANNELCONFIG;
}
if (ascChannels > (8)) {
return AAC_DEC_UNSUPPORTED_CHANNELCONFIG;
}
/* Initialize constant mappings for channel config 1-7 */
if (asc->m_channelConfiguration > 0) {
int el;
FDKmemcpy(self->elements, elementsTab[asc->m_channelConfiguration-1], sizeof(MP4_ELEMENT_ID)*FDKmin(7,7));
for (el=7; el<7; el++) {
FDKmemcpy(self->elements, elementsTab[asc->m_channelConfiguration-1], sizeof(MP4_ELEMENT_ID)*FDKmin(7,(8)));
for (el=7; el<(8); el++) {
self->elements[el] = ID_NONE;
}
for (ch=0; ch<ascChannels; ch++) {
self->chMapping[ch] = ch;
}
for (; ch<(6); ch++) {
for (; ch<(8); ch++) {
self->chMapping[ch] = 255;
}
self->chMapIndex = asc->m_channelConfiguration;
}
#ifdef TP_PCE_ENABLE
else {
......@@ -909,9 +940,6 @@ LINKSPEC_CPP AAC_DECODER_ERROR CAacDecoder_Init(HANDLE_AACDECODER self, const CS
self->streamInfo.channelConfig = asc->m_channelConfiguration;
if (ascChannels > (6)) {
return AAC_DEC_UNSUPPORTED_CHANNELCONFIG;
}
if (self->streamInfo.aot != asc->m_aot) {
self->streamInfo.aot = asc->m_aot;
ascChanged = 1;
......@@ -1096,6 +1124,7 @@ LINKSPEC_CPP AAC_DECODER_ERROR CAacDecoder_DecodeFrame(
MP4_ELEMENT_ID type = ID_NONE; /* Current element type */
INT aacChannels=0; /* Channel counter for channels found in the bitstream */
int chOutMapIdx; /* Output channel mapping index (see comment below) */
INT auStartAnchor = (INT)FDKgetValidBits(bs); /* AU start bit buffer position for AU byte alignment */
......@@ -1119,12 +1148,12 @@ LINKSPEC_CPP AAC_DECODER_ERROR CAacDecoder_DecodeFrame(
if (self->streamInfo.channelConfig == 0) {
/* Init Channel/Element mapping table */
for (ch=0; ch<(6); ch++) {
for (ch=0; ch<(8); ch++) {
self->chMapping[ch] = 255;
}
if (!CProgramConfig_IsValid(pce)) {
int el;
for (el=0; el<7; el++) {
for (el=0; el<(8); el++) {
self->elements[el] = ID_NONE;
}
}
......@@ -1161,11 +1190,8 @@ LINKSPEC_CPP AAC_DECODER_ERROR CAacDecoder_DecodeFrame(
CConcealment_InitChannelData(&self->pAacDecoderStaticChannelInfo[ch]->concealmentInfo,
&self->concealCommonData,
self->streamInfo.aacSamplesPerFrame );
/* Clear concealment buffers to get rid of the complete history */
FDKmemclear(self->pAacDecoderStaticChannelInfo[ch]->concealmentInfo.spectralCoefficient, 1024 * sizeof(FIXP_CNCL));
FDKmemclear(self->pAacDecoderStaticChannelInfo[ch]->concealmentInfo.specScale, 8 * sizeof(SHORT));
/* Clear overlap-add buffers to avoid clicks. */
FDKmemclear(self->pAacDecoderStaticChannelInfo[ch]->IMdct.overlap.freq, OverlapBufferSize*sizeof(FIXP_DBL));
FDKmemclear(self->pAacDecoderStaticChannelInfo[ch]->pOverlapBuffer, OverlapBufferSize*sizeof(FIXP_DBL));
}
}
......@@ -1378,10 +1404,8 @@ LINKSPEC_CPP AAC_DECODER_ERROR CAacDecoder_DecodeFrame(
{
UCHAR element_instance_tag;
CDataStreamElement_Read( bs,
&self->ancData,
self->hDrcInfo,
self->hInput,
CDataStreamElement_Read( self,
bs,
&element_instance_tag,
auStartAnchor );
......@@ -1401,29 +1425,6 @@ LINKSPEC_CPP AAC_DECODER_ERROR CAacDecoder_DecodeFrame(
//self->frameOK = 0;
}
}
{
UCHAR *pDvbAncData = NULL;
AAC_DECODER_ERROR ancErr;
int ancIndex;
int dvbAncDataSize = 0;
/* Ask how many anc data elements are in buffer */
ancIndex = self->ancData.nrElements - 1;
/* Get the last one (if available) */
ancErr = CAacDecoder_AncDataGet( &self->ancData,
ancIndex,
&pDvbAncData,
&dvbAncDataSize );
if (ancErr == AAC_DEC_OK) {
pcmDmx_ReadDvbAncData (
self->hPcmUtils,
pDvbAncData,
dvbAncDataSize,
0 /* not mpeg2 */ );
}
}
break;
#ifdef TP_PCE_ENABLE
......@@ -1442,9 +1443,9 @@ LINKSPEC_CPP AAC_DECODER_ERROR CAacDecoder_DecodeFrame(
}
else if ( result > 1 ) {
/* Built element table */
int elIdx = CProgramConfig_GetElementTable(pce, self->elements, 7);
int elIdx = CProgramConfig_GetElementTable(pce, self->elements, (8), &self->chMapIndex);
/* Reset the remaining tabs */
for ( ; elIdx<7; elIdx++) {
for ( ; elIdx<(8); elIdx++) {
self->elements[elIdx] = ID_NONE;
}
/* Make new number of channel persistant */
......@@ -1510,10 +1511,19 @@ LINKSPEC_CPP AAC_DECODER_ERROR CAacDecoder_DecodeFrame(
break;
}
}
if (err == SBRDEC_OK) {
switch (err) {
case SBRDEC_PARSE_ERROR:
/* Can not go on parsing because we do not
know the length of the SBR extension data. */
FDKpushFor(bs, bitCnt);
bitCnt = 0;
break;
case SBRDEC_OK:
self->sbrEnabled = 1;
} else {
break;
default:
self->frameOK = 0;
break;
}
}
......@@ -1603,13 +1613,17 @@ LINKSPEC_CPP AAC_DECODER_ERROR CAacDecoder_DecodeFrame(
self->frameOK=0;
}
/* store or restore the number of channels */
/* store or restore the number of channels and the corresponding info */
if ( self->frameOK && !(flags &(AACDEC_CONCEAL|AACDEC_FLUSH)) ) {
self->concealChannels = aacChannels; /* store */
self->aacChannelsPrev = aacChannels; /* store */
FDKmemcpy(self->channelTypePrev, self->channelType, (8)*sizeof(AUDIO_CHANNEL_TYPE)); /* store */
FDKmemcpy(self->channelIndicesPrev, self->channelIndices, (8)*sizeof(UCHAR)); /* store */
self->sbrEnabledPrev = self->sbrEnabled;
} else {
if (self->aacChannels > 0) {
aacChannels = self->concealChannels; /* restore */
aacChannels = self->aacChannelsPrev; /* restore */
FDKmemcpy(self->channelType, self->channelTypePrev, (8)*sizeof(AUDIO_CHANNEL_TYPE)); /* restore */
FDKmemcpy(self->channelIndices, self->channelIndicesPrev, (8)*sizeof(UCHAR)); /* restore */
self->sbrEnabled = self->sbrEnabledPrev;
}
}
......@@ -1632,12 +1646,31 @@ LINKSPEC_CPP AAC_DECODER_ERROR CAacDecoder_DecodeFrame(
return ErrorStatus;
}
/* Setup the output channel mapping. The table below shows the four possibilities:
* # | chCfg | PCE | cChCfg | chOutMapIdx
* ---+-------+-----+--------+------------------
* 1 | > 0 | no | - | chCfg
* 2 | 0 | yes | > 0 | cChCfg
* 3 | 0 | yes | 0 | aacChannels || 0
* 4 | 0 | no | - | aacChannels || 0
* ---+-------+-----+--------+------------------
* Where chCfg is the channel configuration index from ASC and cChCfg is a corresponding chCfg
* derived from a given PCE. The variable aacChannels represents the number of channel found
* during bitstream decoding. Due to the structure of the mapping table it can only be used for
* mapping if its value is smaller than 7. Otherwise we use the fallback (0) which is a simple
* pass-through. The possibility #4 should appear only with MPEG-2 (ADTS) streams. This is
* mode is called "implicit channel mapping".
*/
chOutMapIdx = ((self->chMapIndex==0) && (aacChannels<7)) ? aacChannels : self->chMapIndex;
/*
Inverse transform
*/
{
int stride, offset, c;
/* Turn on/off DRC modules level normalization in digital domain depending on the limiter status. */
aacDecoder_drcSetParam( self->hDrcInfo, APPLY_NORMALIZATION, (self->limiterEnableCurr) ? 0 : 1 );
/* Extract DRC control data and map it to channels (without bitstream delay) */
aacDecoder_drcProlog (
self->hDrcInfo,
......@@ -1663,13 +1696,18 @@ LINKSPEC_CPP AAC_DECODER_ERROR CAacDecoder_DecodeFrame(
/* Setup offset and stride for time buffer traversal. */
if (interleaved) {
stride = aacChannels;
offset = self->channelOutputMapping[aacChannels-1][c];
offset = self->channelOutputMapping[chOutMapIdx][c];
} else {
stride = 1;
offset = self->channelOutputMapping[aacChannels-1][c] * self->streamInfo.aacSamplesPerFrame;
offset = self->channelOutputMapping[chOutMapIdx][c] * self->streamInfo.aacSamplesPerFrame;
}
if ( flags&AACDEC_FLUSH ) {
/* Clear pAacDecoderChannelInfo->pSpectralCoefficient because with AACDEC_FLUSH set it contains undefined data. */
FDKmemclear(pAacDecoderChannelInfo->pSpectralCoefficient, sizeof(FIXP_DBL)*self->streamInfo.aacSamplesPerFrame);
}
/*
Conceal defective spectral data
*/
......@@ -1688,12 +1726,15 @@ LINKSPEC_CPP AAC_DECODER_ERROR CAacDecoder_DecodeFrame(
/* Reset DRC control data for this channel */
aacDecoder_drcInitChannelData ( &self->pAacDecoderStaticChannelInfo[c]->drcData );
}
/* The DRC module demands to be called with the gain field holding the gain scale. */
self->extGain[0] = (FIXP_DBL)TDL_GAIN_SCALING;
/* DRC processing */
aacDecoder_drcApply (
self->hDrcInfo,
self->hSbrDecoder,
pAacDecoderChannelInfo,
&self->pAacDecoderStaticChannelInfo[c]->drcData,
self->extGain,
c,
self->streamInfo.aacSamplesPerFrame,
self->sbrEnabled
......@@ -1711,6 +1752,7 @@ LINKSPEC_CPP AAC_DECODER_ERROR CAacDecoder_DecodeFrame(
(self->frameOK && !(flags&AACDEC_CONCEAL)),
self->aacCommonData.workBufferCore1->mdctOutTemp
);
self->extGainDelay = self->streamInfo.aacSamplesPerFrame;
break;
case AACDEC_RENDER_ELDFB:
CBlock_FrequencyToTimeLowDelay(
......@@ -1720,6 +1762,7 @@ LINKSPEC_CPP AAC_DECODER_ERROR CAacDecoder_DecodeFrame(
self->streamInfo.aacSamplesPerFrame,
stride
);
self->extGainDelay = (self->streamInfo.aacSamplesPerFrame*2 - self->streamInfo.aacSamplesPerFrame/2 - 1)/2;
break;
default:
ErrorStatus = AAC_DEC_UNKNOWN;
......@@ -1743,11 +1786,20 @@ LINKSPEC_CPP AAC_DECODER_ERROR CAacDecoder_DecodeFrame(
);
}
/* Add additional concealment delay */
self->streamInfo.outputDelay += CConcealment_GetDelay(&self->concealCommonData) * self->streamInfo.aacSamplesPerFrame;
/* Map DRC data to StreamInfo structure */
aacDecoder_drcGetInfo (
self->hDrcInfo,
&self->streamInfo.drcPresMode,
&self->streamInfo.drcProgRefLev
);
/* Reorder channel type information tables. */
{
AUDIO_CHANNEL_TYPE types[(6)];
UCHAR idx[(6)];
AUDIO_CHANNEL_TYPE types[(8)];
UCHAR idx[(8)];
int c;
FDK_ASSERT(sizeof(self->channelType) == sizeof(types));
......@@ -1757,8 +1809,8 @@ LINKSPEC_CPP AAC_DECODER_ERROR CAacDecoder_DecodeFrame(
FDKmemcpy(idx, self->channelIndices, sizeof(idx));
for (c=0; c<aacChannels; c++) {
self->channelType[self->channelOutputMapping[aacChannels-1][c]] = types[c];
self->channelIndices[self->channelOutputMapping[aacChannels-1][c]] = idx[c];
self->channelType[self->channelOutputMapping[chOutMapIdx][c]] = types[c];
self->channelIndices[self->channelOutputMapping[chOutMapIdx][c]] = idx[c];
}
}
......
......@@ -111,6 +111,7 @@ amm-info@iis.fraunhofer.de
#include "aacdec_drc.h"
#include "pcmutils_lib.h"
#include "limiter.h"
/* Capabilities flags */
......@@ -176,27 +177,31 @@ struct AAC_DECODER_INSTANCE {
UINT flags; /*!< Flags for internal decoder use. DO NOT USE self::streaminfo::flags ! */
MP4_ELEMENT_ID elements[7]; /*!< Table where the element Id's are listed */
UCHAR elTags[7]; /*!< Table where the elements id Tags are listed */
UCHAR chMapping[(6)]; /*!< Table of MPEG canonical order to bitstream channel order mapping. */
MP4_ELEMENT_ID elements[(8)]; /*!< Table where the element Id's are listed */
UCHAR elTags[(8)]; /*!< Table where the elements id Tags are listed */
UCHAR chMapping[(8)]; /*!< Table of MPEG canonical order to bitstream channel order mapping. */
AUDIO_CHANNEL_TYPE channelType[(6)]; /*!< Audio channel type of each output audio channel (from 0 upto numChannels). */
UCHAR channelIndices[(6)]; /*!< Audio channel index for each output audio channel (from 0 upto numChannels). */
AUDIO_CHANNEL_TYPE channelType[(8)]; /*!< Audio channel type of each output audio channel (from 0 upto numChannels). */
UCHAR channelIndices[(8)]; /*!< Audio channel index for each output audio channel (from 0 upto numChannels). */
/* See ISO/IEC 13818-7:2005(E), 8.5.3.2 Explicit channel mapping using a program_config_element() */
const UCHAR (*channelOutputMapping)[8]; /*!< Table for MPEG canonical order to output channel order mapping. */
UCHAR chMapIndex; /*!< Index to access one line of the channelOutputMapping table. This is required
because not all 8 channel configurations have the same output mapping. */
CProgramConfig pce;
CStreamInfo streamInfo; /*!< pointer to StreamInfo data (read from the bitstream) */
CAacDecoderChannelInfo *pAacDecoderChannelInfo[(6)]; /*!< Temporal channel memory */
CAacDecoderStaticChannelInfo *pAacDecoderStaticChannelInfo[(6)]; /*!< Persistent channel memory */
CAacDecoderChannelInfo *pAacDecoderChannelInfo[(8)]; /*!< Temporal channel memory */
CAacDecoderStaticChannelInfo *pAacDecoderStaticChannelInfo[(8)]; /*!< Persistent channel memory */
CAacDecoderCommonData aacCommonData; /*!< Temporal shared data for all channels hooked into pAacDecoderChannelInfo */
CConcealParams concealCommonData;
INT concealChannels;
INT aacChannelsPrev; /*!< The amount of AAC core channels of the last successful decode call. */
AUDIO_CHANNEL_TYPE channelTypePrev[(8)]; /*!< Array holding the channelType values of the last successful decode call. */
UCHAR channelIndicesPrev[(8)]; /*!< Array holding the channelIndices values of the last successful decode call. */
HANDLE_SBRDECODER hSbrDecoder; /*!< SBR decoder handle. */
......@@ -214,6 +219,12 @@ struct AAC_DECODER_INSTANCE {
CAncData ancData; /*!< structure to handle ancillary data */
HANDLE_PCM_DOWNMIX hPcmUtils; /*!< privat data for the PCM utils. */
TDLimiterPtr hLimiter; /*!< Handle of time domain limiter. */
UCHAR limiterEnableUser; /*!< The limiter configuration requested by the library user */
UCHAR limiterEnableCurr; /*!< The current limiter configuration. */
FIXP_DBL extGain[1]; /*!< Gain that must be applied to the output signal. */
UINT extGainDelay; /*!< Delay that must be accounted for extGain. */
};
......
......@@ -110,7 +110,7 @@ amm-info@iis.fraunhofer.de
/* Decoder library info */
#define AACDECODER_LIB_VL0 2
#define AACDECODER_LIB_VL1 5
#define AACDECODER_LIB_VL2 5
#define AACDECODER_LIB_VL2 10
#define AACDECODER_LIB_TITLE "AAC Decoder Lib"
#define AACDECODER_LIB_BUILD_DATE __DATE__
#define AACDECODER_LIB_BUILD_TIME __TIME__
......@@ -397,12 +397,14 @@ aacDecoder_SetParam ( const HANDLE_AACDECODER self, /*!< Handle of the decode
CConcealParams *pConcealData = NULL;
HANDLE_AAC_DRC hDrcInfo = NULL;
HANDLE_PCM_DOWNMIX hPcmDmx = NULL;
TDLimiterPtr hPcmTdl = NULL;
/* check decoder handle */
if (self != NULL) {
pConcealData = &self->concealCommonData;
hDrcInfo = self->hDrcInfo;
hPcmDmx = self->hPcmUtils;
hPcmTdl = self->hLimiter;
} else {
errorStatus = AAC_DEC_INVALID_HANDLE;
}
......@@ -420,8 +422,8 @@ aacDecoder_SetParam ( const HANDLE_AACDECODER self, /*!< Handle of the decode
self->outputInterleaved = value;
break;
case AAC_PCM_OUTPUT_CHANNELS:
if (value < -1 || value > (6)) {
case AAC_PCM_MIN_OUTPUT_CHANNELS:
if (value < -1 || value > (8)) {
return AAC_DEC_SET_PARAM_FAIL;
}
{
......@@ -429,7 +431,30 @@ aacDecoder_SetParam ( const HANDLE_AACDECODER self, /*!< Handle of the decode
err = pcmDmx_SetParam (
hPcmDmx,
NUMBER_OF_OUTPUT_CHANNELS,
MIN_NUMBER_OF_OUTPUT_CHANNELS,
value );
switch (err) {
case PCMDMX_OK:
break;
case PCMDMX_INVALID_HANDLE:
return AAC_DEC_INVALID_HANDLE;
default:
return AAC_DEC_SET_PARAM_FAIL;
}
}
break;
case AAC_PCM_MAX_OUTPUT_CHANNELS:
if (value < -1 || value > (8)) {
return AAC_DEC_SET_PARAM_FAIL;
}
{
PCMDMX_ERROR err;
err = pcmDmx_SetParam (
hPcmDmx,
MAX_NUMBER_OF_OUTPUT_CHANNELS,
value );
switch (err) {
......@@ -449,7 +474,7 @@ aacDecoder_SetParam ( const HANDLE_AACDECODER self, /*!< Handle of the decode
err = pcmDmx_SetParam (
hPcmDmx,
DUAL_CHANNEL_DOWNMIX_MODE,
DMX_DUAL_CHANNEL_MODE,
value );
switch (err) {
......@@ -463,6 +488,47 @@ aacDecoder_SetParam ( const HANDLE_AACDECODER self, /*!< Handle of the decode
}
break;
case AAC_PCM_LIMITER_ENABLE:
if (value < -1 || value > 1) {
return AAC_DEC_SET_PARAM_FAIL;
}
if (self == NULL) {
return AAC_DEC_INVALID_HANDLE;
}
self->limiterEnableUser = value;
break;
case AAC_PCM_LIMITER_ATTACK_TIME:
if (value <= 0) { /* module function converts value to unsigned */
return AAC_DEC_SET_PARAM_FAIL;
}
switch (setLimiterAttack(hPcmTdl, value)) {
case TDLIMIT_OK:
break;
case TDLIMIT_INVALID_HANDLE:
return AAC_DEC_INVALID_HANDLE;
case TDLIMIT_INVALID_PARAMETER:
default:
return AAC_DEC_SET_PARAM_FAIL;
}
break;
case AAC_PCM_LIMITER_RELEAS_TIME:
if (value <= 0) { /* module function converts value to unsigned */
return AAC_DEC_SET_PARAM_FAIL;
}
switch (setLimiterRelease(hPcmTdl, value)) {
case TDLIMIT_OK:
break;
case TDLIMIT_INVALID_HANDLE:
return AAC_DEC_INVALID_HANDLE;
case TDLIMIT_INVALID_PARAMETER:
default:
return AAC_DEC_SET_PARAM_FAIL;
}
break;
case AAC_PCM_OUTPUT_CHANNEL_MAPPING:
switch (value) {
case 0:
......@@ -609,6 +675,14 @@ LINKSPEC_CPP HANDLE_AACDECODER aacDecoder_Open(TRANSPORT_TYPE transportFmt, UINT
goto bail;
}
aacDec->hLimiter = createLimiter(TDL_ATTACK_DEFAULT_MS, TDL_RELEASE_DEFAULT_MS, SAMPLE_MAX, (8), 96000);
if (NULL == aacDec->hLimiter) {
err = -1;
goto bail;
}
aacDec->limiterEnableUser = (UCHAR)-1;
aacDec->limiterEnableCurr = 0;
/* Assure that all modules have same delay */
......@@ -768,6 +842,7 @@ LINKSPEC_CPP AAC_DECODER_ERROR aacDecoder_DecodeFrame(
/* Signal bit stream interruption to other modules if required. */
if ( fTpInterruption || (flags & (AACDEC_INTR|AACDEC_CLRHIST)) )
{
sbrDecoder_SetParam(self->hSbrDecoder, SBR_CLEAR_HISTORY, (flags&AACDEC_CLRHIST));
aacDecoder_SignalInterruption(self);
if ( ! (flags & AACDEC_INTR) ) {
ErrorStatus = AAC_DEC_TRANSPORT_SYNC_ERROR;
......@@ -783,6 +858,19 @@ LINKSPEC_CPP AAC_DECODER_ERROR aacDecoder_DecodeFrame(
self->streamInfo.numBadBytes = 0;
self->streamInfo.numTotalBytes = 0;
}
/* Reset the output delay field. The modules will add their figures one after another. */
self->streamInfo.outputDelay = 0;
if (self->limiterEnableUser==(UCHAR)-1) {
/* Enbale limiter for all non-lowdelay AOT's. */
self->limiterEnableCurr = ( self->flags & (AC_LD|AC_ELD) ) ? 0 : 1;
}
else {
/* Use limiter configuration as requested. */
self->limiterEnableCurr = self->limiterEnableUser;
}
/* reset limiter gain on a per frame basis */
self->extGain[0] = FL2FXCONST_DBL(1.0f/(float)(1<<TDL_GAIN_SCALING));
ErrorStatus = CAacDecoder_DecodeFrame(self,
......@@ -825,11 +913,15 @@ LINKSPEC_CPP AAC_DECODER_ERROR aacDecoder_DecodeFrame(
if (self->sbrEnabled)
{
SBR_ERROR sbrError = SBRDEC_OK;
int chOutMapIdx = ((self->chMapIndex==0) && (self->streamInfo.numChannels<7)) ? self->streamInfo.numChannels : self->chMapIndex;
/* set params */
sbrDecoder_SetParam ( self->hSbrDecoder,
SBR_SYSTEM_BITSTREAM_DELAY,
self->sbrParams.bsDelay);
sbrDecoder_SetParam ( self->hSbrDecoder,
SBR_FLUSH_DATA,
(flags & AACDEC_FLUSH) );
if ( self->streamInfo.aot == AOT_ER_AAC_ELD ) {
/* Configure QMF */
......@@ -838,7 +930,16 @@ LINKSPEC_CPP AAC_DECODER_ERROR aacDecoder_DecodeFrame(
(self->flags & AC_LD_MPS) ? 1 : 0 );
}
{
PCMDMX_ERROR dmxErr;
INT maxOutCh = 0;
dmxErr = pcmDmx_GetParam(self->hPcmUtils, MAX_NUMBER_OF_OUTPUT_CHANNELS, &maxOutCh);
if ( (dmxErr == PCMDMX_OK) && (maxOutCh == 1) ) {
/* Disable PS processing if we have to create a mono output signal. */
self->psPossible = 0;
}
}
/* apply SBR processing */
......@@ -846,23 +947,29 @@ LINKSPEC_CPP AAC_DECODER_ERROR aacDecoder_DecodeFrame(
pTimeData,
&self->streamInfo.numChannels,
&self->streamInfo.sampleRate,
self->channelOutputMapping[self->streamInfo.numChannels-1],
self->channelOutputMapping[chOutMapIdx],
interleaved,
self->frameOK,
&self->psPossible);
if (sbrError == SBRDEC_OK) {
#define UPS_SCALE 2 /* Maximum upsampling factor is 4 (CELP+SBR) */
FIXP_DBL upsampleFactor = FL2FXCONST_DBL(1.0f/(1<<UPS_SCALE));
/* Update data in streaminfo structure. Assume that the SBR upsampling factor is either 1 or 2 */
self->flags |= AC_SBR_PRESENT;
if (self->streamInfo.aacSampleRate != self->streamInfo.sampleRate) {
if (self->streamInfo.frameSize == 768) {
self->streamInfo.frameSize = (self->streamInfo.aacSamplesPerFrame * 8) / 3;
upsampleFactor = FL2FXCONST_DBL(8.0f/(3<<UPS_SCALE));
} else {
self->streamInfo.frameSize = self->streamInfo.aacSamplesPerFrame << 1;
upsampleFactor = FL2FXCONST_DBL(2.0f/(1<<UPS_SCALE));
}
}
/* Apply upsampling factor to both the core frame length and the core delay */
self->streamInfo.frameSize = (INT)fMult((FIXP_DBL)self->streamInfo.aacSamplesPerFrame<<UPS_SCALE, upsampleFactor);
self->streamInfo.outputDelay = (UINT)(INT)fMult((FIXP_DBL)self->streamInfo.outputDelay<<UPS_SCALE, upsampleFactor);
self->streamInfo.outputDelay += sbrDecoder_GetDelay( self->hSbrDecoder );
if (self->psPossible) {
self->flags |= AC_PS_PRESENT;
......@@ -870,19 +977,20 @@ LINKSPEC_CPP AAC_DECODER_ERROR aacDecoder_DecodeFrame(
self->channelType[1] = ACT_FRONT;
self->channelIndices[0] = 0;
self->channelIndices[1] = 1;
} else {
self->flags &= ~AC_PS_PRESENT;
}
}
}
{
INT pcmLimiterScale = 0;
PCMDMX_ERROR dmxErr = PCMDMX_OK;
if ( flags & (AACDEC_INTR | AACDEC_CLRHIST) ) {
/* delete data from the past (e.g. mixdown coeficients) */
pcmDmx_Reset( self->hPcmUtils, PCMDMX_RESET_BS_DATA );
}
/* do PCM post processing */
pcmDmx_ApplyFrame (
dmxErr = pcmDmx_ApplyFrame (
self->hPcmUtils,
pTimeData,
self->streamInfo.frameSize,
......@@ -890,9 +998,39 @@ LINKSPEC_CPP AAC_DECODER_ERROR aacDecoder_DecodeFrame(
interleaved,
self->channelType,
self->channelIndices,
self->channelOutputMapping
self->channelOutputMapping,
(self->limiterEnableCurr) ? &pcmLimiterScale : NULL
);
if (dmxErr == PCMDMX_INVALID_MODE) {
/* Announce the framework that the current combination of channel configuration and downmix
* settings are not know to produce a predictable behavior and thus maybe produce strange output. */
ErrorStatus = AAC_DEC_DECODE_FRAME_ERROR;
}
if ( flags & AACDEC_CLRHIST ) {
/* Delete the delayed signal. */
resetLimiter(self->hLimiter);
}
if (self->limiterEnableCurr)
{
/* Set actual signal parameters */
setLimiterNChannels(self->hLimiter, self->streamInfo.numChannels);
setLimiterSampleRate(self->hLimiter, self->streamInfo.sampleRate);
applyLimiter(
self->hLimiter,
pTimeData,
self->extGain,
&pcmLimiterScale,
1,
self->extGainDelay,
self->streamInfo.frameSize
);
/* Announce the additional limiter output delay */
self->streamInfo.outputDelay += getLimiterDelay(self->hLimiter);
}
}
/* Signal interruption to take effect in next frame. */
......@@ -917,6 +1055,9 @@ LINKSPEC_CPP void aacDecoder_Close ( HANDLE_AACDECODER self )
return;
if (self->hLimiter != NULL) {
destroyLimiter(self->hLimiter);
}
if (self->hPcmUtils != NULL) {
pcmDmx_Close( &self->hPcmUtils );
......
......@@ -762,7 +762,6 @@ int
CConcealment_UpdateState( hConcealmentInfo,
frameOk );
if ( !frameOk )
{
/* Create data for signal rendering according to the selected concealment method and decoder operating mode. */
......@@ -775,11 +774,13 @@ int
{
default:
case ConcealMethodMute:
if (!frameOk) {
/* Mute spectral data in case of errors */
FDKmemclear(pAacDecoderChannelInfo->pSpectralCoefficient, samplesPerFrame * sizeof(FIXP_DBL));
/* Set last window shape */
pAacDecoderChannelInfo->icsInfo.WindowShape = hConcealmentInfo->windowShape;
appliedProcessing = 1;
}
break;
case ConcealMethodNoise:
......@@ -801,7 +802,7 @@ int
pSamplingRateInfo,
samplesPerFrame,
0, /* don't use tonal improvement */
0);
frameOk);
break;
}
......
......@@ -215,7 +215,7 @@ amm-info@iis.fraunhofer.de
#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 */
......
......@@ -96,7 +96,7 @@ amm-info@iis.fraunhofer.de
#if defined(__CC_ARM) || defined(__arm__) || defined(_M_ARM) /* cppp replaced: elif */
#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"
#endif /* #if defined all cores: bfin, arm, etc. */
......
......@@ -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
......
......@@ -146,12 +146,15 @@ typedef struct
UCHAR FrontElementIsCpe[PC_FSB_CHANNELS_MAX];
UCHAR FrontElementTagSelect[PC_FSB_CHANNELS_MAX];
UCHAR FrontElementHeightInfo[PC_FSB_CHANNELS_MAX];
UCHAR SideElementIsCpe[PC_FSB_CHANNELS_MAX];
UCHAR SideElementTagSelect[PC_FSB_CHANNELS_MAX];
UCHAR SideElementHeightInfo[PC_FSB_CHANNELS_MAX];
UCHAR BackElementIsCpe[PC_FSB_CHANNELS_MAX];
UCHAR BackElementTagSelect[PC_FSB_CHANNELS_MAX];
UCHAR BackElementHeightInfo[PC_FSB_CHANNELS_MAX];
UCHAR LfeElementTagSelect[PC_LFE_CHANNELS_MAX];
......@@ -324,16 +327,23 @@ int getSamplingRateIndex( UINT samplingRate )
*/
static inline int getNumberOfTotalChannels(int channelConfig)
{
if (channelConfig > 0 && channelConfig < 8)
return (channelConfig == 7)?8:channelConfig;
else
switch (channelConfig) {
case 1: case 2: case 3:
case 4: case 5: case 6:
return channelConfig;
case 7: case 12: case 14:
return 8;
case 11:
return 7;
default:
return 0;
}
}
static inline
int getNumberOfEffectiveChannels(const int channelConfig)
{
const int n[] = {0,1,2,3,4,5,5,7};
{ /* 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,0,0, 0, 6, 7, 0, 7, 0};
return n[channelConfig];
}
......
......@@ -151,6 +151,7 @@ typedef enum {
#define PC_ASSOCDATA_MAX 8
#define PC_CCEL_MAX 16 /* CC elements */
#define PC_COMMENTLENGTH 256
#define PC_NUM_HEIGHT_LAYER 3
/*!
......@@ -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
* give program config field.
* \param pPce A valid program config structure.
* \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,
MP4_ELEMENT_ID table[],
const INT elListSize );
const INT elListSize,
UCHAR *pChMapIdx );
/**
* \brief Initialize a given AudioSpecificConfig structure.
......
......@@ -90,6 +90,9 @@ amm-info@iis.fraunhofer.de
#include "tpdec_lib.h"
#include "tp_data.h"
#ifdef TP_PCE_ENABLE
#include "FDK_crc.h"
#endif
void CProgramConfig_Reset(CProgramConfig *pPce)
......@@ -111,13 +114,75 @@ int CProgramConfig_IsValid ( const CProgramConfig *pPce )
}
#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(
CProgramConfig *pPce,
HANDLE_FDK_BITSTREAM bs,
UINT alignmentAnchor
)
{
int i;
int i, err = 0;
int commentBytes;
pPce->NumEffectiveChannels = 0;
pPce->NumChannels = 0;
......@@ -190,8 +255,12 @@ void CProgramConfig_Read(
FDKbyteAlign(bs, alignmentAnchor);
pPce->CommentFieldBytes = (UCHAR) FDKreadBits(bs,8);
commentBytes = pPce->CommentFieldBytes;
for (i=0; i < pPce->CommentFieldBytes; i++)
/* Search for height info extension and read it if available */
err = CProgramConfig_ReadHeightExt( pPce, bs, &commentBytes, alignmentAnchor );
for (i=0; i < commentBytes; i++)
{
UCHAR text;
......@@ -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,
} else {
int el, numCh1 = 0, numCh2 = 0;
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;
numCh2 += pPce2->FrontElementIsCpe[el] ? 2 : 1;
}
......@@ -248,6 +321,10 @@ int CProgramConfig_Compare ( const CProgramConfig * const pPce1,
} else {
int el, numCh1 = 0, numCh2 = 0;
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;
numCh2 += pPce2->SideElementIsCpe[el] ? 2 : 1;
}
......@@ -261,6 +338,10 @@ int CProgramConfig_Compare ( const CProgramConfig * const pPce1,
} else {
int el, numCh1 = 0, numCh2 = 0;
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;
numCh2 += pPce2->BackElementIsCpe[el] ? 2 : 1;
}
......@@ -290,6 +371,44 @@ void CProgramConfig_GetDefault( CProgramConfig *pPce,
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 */
pPce->NumLfeChannelElements += 1;
pPce->NumChannels += 1;
......@@ -348,10 +467,11 @@ void CProgramConfig_GetDefault( CProgramConfig *pPce,
/**
* \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
* \return audio channel type.
*/
static
void getImplicitAudioChannelTypeAndIndex(
AUDIO_CHANNEL_TYPE *chType,
UCHAR *chIndex,
......@@ -364,9 +484,9 @@ void getImplicitAudioChannelTypeAndIndex(
*chIndex = index;
} else {
switch (channelConfig) {
case MODE_1_2_1:
case MODE_1_2_2:
case MODE_1_2_2_1:
case 4: /* SCE, CPE, SCE */
case 5: /* SCE, CPE, CPE */
case 6: /* SCE, CPE, CPE, LFE */
switch (index) {
case 3:
case 4:
......@@ -379,12 +499,12 @@ void getImplicitAudioChannelTypeAndIndex(
break;
}
break;
case MODE_1_2_2_2_1:
case 7: /* SCE,CPE,CPE,CPE,LFE */
switch (index) {
case 3:
case 4:
*chType = ACT_SIDE;
*chIndex = index - 3;
*chType = ACT_FRONT;
*chIndex = index;
break;
case 5:
case 6:
......@@ -397,6 +517,42 @@ void getImplicitAudioChannelTypeAndIndex(
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:
*chType = ACT_NONE;
break;
......@@ -467,7 +623,24 @@ int CProgramConfig_LookupElement(
else {
/* Accept the additional channel(s), only if the tag is in the lists */
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)
{
......@@ -476,87 +649,206 @@ int CProgramConfig_LookupElement(
case ID_SCE:
/* search in front channels */
for (i = 0; i < pPce->NumFrontChannelElements; i++) {
int heightLayer = pPce->FrontElementHeightInfo[i];
if (isCpe == pPce->FrontElementIsCpe[i] && pPce->FrontElementTagSelect[i] == tag) {
chMapping[cc] = channelIdx;
chType[cc] = ACT_FRONT;
chIndex[cc] = fc;
int h, elIdx = ec[heightLayer], chIdx = cc[heightLayer];
AUDIO_CHANNEL_TYPE aChType = (AUDIO_CHANNEL_TYPE)((heightLayer<<4) | ACT_FRONT);
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) {
chMapping[cc+1] = channelIdx+1;
chType[cc+1] = ACT_FRONT;
chIndex[cc+1] = fc+1;
chMapping[chIdx+1] = channelIdx+1;
chType[chIdx+1] = aChType;
chIndex[chIdx+1] = fc[heightLayer]+1;
}
*elMapping = ec;
*elMapping = elIdx;
return 1;
}
ec++;
ec[heightLayer] += 1;
if (pPce->FrontElementIsCpe[i]) {
cc+=2; fc+=2;
cc[heightLayer] += 2;
fc[heightLayer] += 2;
} else {
cc++; fc++;
cc[heightLayer] += 1;
fc[heightLayer] += 1;
}
}
/* search in side channels */
for (i = 0; i < pPce->NumSideChannelElements; i++) {
int heightLayer = pPce->SideElementHeightInfo[i];
if (isCpe == pPce->SideElementIsCpe[i] && pPce->SideElementTagSelect[i] == tag) {
chMapping[cc] = channelIdx;
chType[cc] = ACT_SIDE;
chIndex[cc] = sc;
int h, elIdx = ec[heightLayer], chIdx = cc[heightLayer];
AUDIO_CHANNEL_TYPE aChType = (AUDIO_CHANNEL_TYPE)((heightLayer<<4) | ACT_SIDE);
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) {
chMapping[cc+1] = channelIdx+1;
chType[cc+1] = ACT_SIDE;
chIndex[cc+1] = sc+1;
chMapping[chIdx+1] = channelIdx+1;
chType[chIdx+1] = aChType;
chIndex[chIdx+1] = sc[heightLayer]+1;
}
*elMapping = ec;
*elMapping = elIdx;
return 1;
}
ec++;
ec[heightLayer] += 1;
if (pPce->SideElementIsCpe[i]) {
cc+=2; sc+=2;
cc[heightLayer] += 2;
sc[heightLayer] += 2;
} else {
cc++; sc++;
cc[heightLayer] += 1;
sc[heightLayer] += 1;
}
}
/* search in back channels */
for (i = 0; i < pPce->NumBackChannelElements; i++) {
int heightLayer = pPce->BackElementHeightInfo[i];
if (isCpe == pPce->BackElementIsCpe[i] && pPce->BackElementTagSelect[i] == tag) {
chMapping[cc] = channelIdx;
chType[cc] = ACT_BACK;
chIndex[cc] = bc;
int h, elIdx = ec[heightLayer], chIdx = cc[heightLayer];
AUDIO_CHANNEL_TYPE aChType = (AUDIO_CHANNEL_TYPE)((heightLayer<<4) | ACT_BACK);
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) {
chMapping[cc+1] = channelIdx+1;
chType[cc+1] = ACT_BACK;
chIndex[cc+1] = bc+1;
chMapping[chIdx+1] = channelIdx+1;
chType[chIdx+1] = aChType;
chIndex[chIdx+1] = bc[heightLayer]+1;
}
*elMapping = ec;
*elMapping = elIdx;
return 1;
}
ec++;
ec[heightLayer] += 1;
if (pPce->BackElementIsCpe[i]) {
cc+=2; bc+=2;
cc[heightLayer] += 2;
bc[heightLayer] += 2;
} else {
cc++; bc++;
cc[heightLayer] += 1;
bc[heightLayer] += 1;
}
}
break;
case ID_LFE:
/* Initialize channel counter and element counter */
cc = pPce->NumEffectiveChannels;
ec = pPce->NumFrontChannelElements+ pPce->NumSideChannelElements + pPce->NumBackChannelElements;
{ /* Unfortunately we have to go through all normal height
layer elements to get the position of the LFE channels.
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 */
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 ) {
chMapping[cc] = channelIdx;
*elMapping = ec;
chType[cc] = ACT_LFE;
chIndex[cc] = lc;
chMapping[chIdx] = channelIdx;
*elMapping = elIdx;
chType[chIdx] = ACT_LFE;
chIndex[chIdx] = lc;
return 1;
}
ec++;
cc++;
lc++;
ec[0] += 1;
cc[0] += 1;
lc += 1;
}
break;
} break;
/* Non audio elements */
case ID_CCE:
......@@ -590,11 +882,17 @@ int CProgramConfig_LookupElement(
int CProgramConfig_GetElementTable(
const CProgramConfig *pPce,
MP4_ELEMENT_ID elList[],
const INT elListSize
const INT elListSize,
UCHAR *pChMapIdx
)
{
int i, el = 0;
FDK_ASSERT(elList != NULL);
FDK_ASSERT(pChMapIdx != NULL);
*pChMapIdx = 0;
if ( elListSize
< pPce->NumFrontChannelElements + pPce->NumSideChannelElements + pPce->NumBackChannelElements + pPce->NumLfeChannelElements
)
......@@ -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;
}
#endif
......@@ -728,6 +1067,8 @@ static INT ld_sbr_header( const CSAudioSpecificConfig *asc,
}
switch ( channelConfiguration ) {
case 14:
case 12:
case 7:
error |= cb->cbSbr(cb->cbSbrData, hBs, asc->m_samplingFrequency, asc->m_extensionSamplingFrequency, asc->m_samplesPerFrame, AOT_ER_AAC_ELD, ID_CPE, i++);
case 6:
......@@ -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++);
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:
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++);
......@@ -802,24 +1145,6 @@ TRANSPORTDEC_ERROR EldSpecificConfig_Parse(
}
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:
for(cnt=0; cnt<len; cnt++) {
FDKreadBits(hBs, 8 );
......
......@@ -2,7 +2,7 @@
/* library info */
#define TP_LIB_VL0 2
#define TP_LIB_VL1 3
#define TP_LIB_VL2 3
#define TP_LIB_VL2 4
#define TP_LIB_TITLE "MPEG Transport"
#define TP_LIB_BUILD_DATE __DATE__
#define TP_LIB_BUILD_TIME __TIME__
......@@ -146,12 +146,15 @@ typedef struct
UCHAR FrontElementIsCpe[PC_FSB_CHANNELS_MAX];
UCHAR FrontElementTagSelect[PC_FSB_CHANNELS_MAX];
UCHAR FrontElementHeightInfo[PC_FSB_CHANNELS_MAX];
UCHAR SideElementIsCpe[PC_FSB_CHANNELS_MAX];
UCHAR SideElementTagSelect[PC_FSB_CHANNELS_MAX];
UCHAR SideElementHeightInfo[PC_FSB_CHANNELS_MAX];
UCHAR BackElementIsCpe[PC_FSB_CHANNELS_MAX];
UCHAR BackElementTagSelect[PC_FSB_CHANNELS_MAX];
UCHAR BackElementHeightInfo[PC_FSB_CHANNELS_MAX];
UCHAR LfeElementTagSelect[PC_LFE_CHANNELS_MAX];
......@@ -324,16 +327,23 @@ int getSamplingRateIndex( UINT samplingRate )
*/
static inline int getNumberOfTotalChannels(int channelConfig)
{
if (channelConfig > 0 && channelConfig < 8)
return (channelConfig == 7)?8:channelConfig;
else
switch (channelConfig) {
case 1: case 2: case 3:
case 4: case 5: case 6:
return channelConfig;
case 7: case 12: case 14:
return 8;
case 11:
return 7;
default:
return 0;
}
}
static inline
int getNumberOfEffectiveChannels(const int channelConfig)
{
const int n[] = {0,1,2,3,4,5,5,7};
{ /* 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,0,0, 0, 6, 7, 0, 7, 0};
return n[channelConfig];
}
......
......@@ -2,7 +2,7 @@
/* library info */
#define TP_LIB_VL0 2
#define TP_LIB_VL1 3
#define TP_LIB_VL2 3
#define TP_LIB_VL2 4
#define TP_LIB_TITLE "MPEG Transport"
#define TP_LIB_BUILD_DATE __DATE__
#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,22 +95,8 @@ amm-info@iis.fraunhofer.de
#include "machine_type.h"
#include "common_fix.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: *
......@@ -118,46 +104,79 @@ amm-info@iis.fraunhofer.de
typedef enum
{
PCMDMX_OK = 0x0, /*!< No error happened. */
pcm_dmx_fatal_error_start,
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
party module. */
pcm_dmx_fatal_error_end,
PCMDMX_INVALID_HANDLE, /*!< The given instance handle is not valid. */
PCMDMX_INVALID_ARGUMENT, /*!< One of the parameters handed over is invalid. */
PCMDMX_INVALID_CH_CONFIG, /*!< The given channel configuration is not supported and
thus no processing was performed. */
PCMDMX_INVALID_CH_CONFIG, /*!< The given channel configuration is not supported and thus
no processing was performed. */
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_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;
/** 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: *
* ------------------------ */
typedef enum
{
DMX_BS_DATA_EXPIRY_FRAME, /*!< The number of frames without new metadata that have to
go by before the bitstream data expires. The value 0
disables expiry. */
DMX_BS_DATA_DELAY, /*!< The number of delay frames of the output samples
compared to the bitstream data. */
NUMBER_OF_OUTPUT_CHANNELS , /*!< The number of output channels (equals the number of
channels processed by the audio output setup). */
DUAL_CHANNEL_DOWNMIX_MODE /*!< Downmix mode for two channel audio data. */
DMX_BS_DATA_EXPIRY_FRAME, /*!< The number of frames without new metadata that have to go
by before the bitstream data expires. The value 0 disables
expiry. */
DMX_BS_DATA_DELAY, /*!< The number of delay frames of the output samples compared
to the bitstream data. */
MIN_NUMBER_OF_OUTPUT_CHANNELS, /*!< The minimum number of output channels. For all input
configurations that have less than the given channels the
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;
/* Parameter value types */
typedef enum
{
NEVER_DO_PS_DMX = -1, /*!< Never create a pseudo surround compatible downmix. */
AUTO_PS_DMX = 0, /*!< Create a pseudo surround compatible downmix only if
signalled in bitstreams meta data. (Default) */
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. */
MIXED_MODE = 0x3 /*!< Create a dual mono output signal by mixing the two
channels. */
} DUAL_CHANNEL_MODE;
......@@ -192,14 +211,40 @@ PCMDMX_ERROR pcmDmx_Open (
**/
PCMDMX_ERROR pcmDmx_SetParam (
HANDLE_PCM_DOWNMIX self,
PCMDMX_PARAM param,
UINT value
const PCMDMX_PARAM param,
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 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 the ancillary data transported in DSEs of DVB streams with MPEG-4 content
/** Read downmix meta-data from a given data buffer.
* @param [in] Handle of PCM downmix instance.
* @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.
* @returns Returns an error code.
**/
......@@ -211,7 +256,6 @@ PCMDMX_ERROR pcmDmx_ReadDvbAncData (
);
/** 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] Matrix mixdown index present flag extracted from PCE.
* @param [in] The 2 bit matrix mixdown index extracted from PCE.
......@@ -235,17 +279,25 @@ PCMDMX_ERROR pcmDmx_Reset (
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 [inout] Pointer to time buffer with decoded PCM samples.
* \param [in] Pointer where the amount of output samples is returned into.
* \param [inout] Pointer where the amount of output channels is returned into.
* \param [in] Flag which indicates if output time data are writtern interleaved or as subsequent blocks.
* \param [inout] Array were the corresponding channel type for each output audio channel is stored into.
* \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 [in] The I/O block size which is the number of samples per channel.
* \param [inout] Pointer to buffer that holds the number of input channels and where the
* amount of output channels is written to.
* \param [in] Flag which indicates if output time data is writtern interleaved or as
* subsequent blocks.
* \param [inout] Array were the corresponding channel type for each output audio channel is
* stored into.
* \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 (
......@@ -253,11 +305,11 @@ PCMDMX_ERROR pcmDmx_ApplyFrame (
INT_PCM *pPcmBuf,
UINT frameSize,
INT *nChannels,
int fInterleaved,
AUDIO_CHANNEL_TYPE channelType[],
UCHAR channelIndices[],
const UCHAR channelMapping[][8]
const UCHAR channelMapping[][8],
INT *pDmxOutScale
);
/** Close an instance of the PCM downmix module.
......
/* -----------------------------------------------------------------------------------------------------------
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
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_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. */
} SBRDEC_PARAM;
......@@ -308,7 +310,7 @@ SBR_ERROR sbrDecoder_Apply ( HANDLE_SBRDECODER self,
INT_PCM *timeData,
int *numChannels,
int *sampleRate,
const UCHAR channelMapping[(6)],
const UCHAR channelMapping[(8)],
const int interleaved,
const int coreDecodedOk,
UCHAR *psDecoded );
......@@ -329,6 +331,13 @@ SBR_ERROR sbrDecoder_Close ( HANDLE_SBRDECODER *self );
*/
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
}
......
......@@ -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_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_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_UPDATE 2
......
......@@ -107,19 +107,19 @@ amm-info@iis.fraunhofer.de
/*! SBR Decoder main structure */
C_ALLOC_MEM(Ram_SbrDecoder, struct SBR_DECODER_INSTANCE, 1)
/*! SBR Decoder element data <br>
Dimension: (4) */
C_ALLOC_MEM2(Ram_SbrDecElement, SBR_DECODER_ELEMENT, 1, (4))
Dimension: (8) */
C_ALLOC_MEM2(Ram_SbrDecElement, SBR_DECODER_ELEMENT, 1, (8))
/*! SBR Decoder individual channel data <br>
Dimension: (6) */
C_ALLOC_MEM2(Ram_SbrDecChannel, SBR_CHANNEL, 1, (6)+1)
Dimension: (8) */
C_ALLOC_MEM2(Ram_SbrDecChannel, SBR_CHANNEL, 1, (8)+1)
/*! Filter states for QMF-synthesis. <br>
Dimension: #(6) * (#QMF_FILTER_STATE_SYN_SIZE-#(64)) */
C_AALLOC_MEM2_L(Ram_sbr_QmfStatesSynthesis, FIXP_QSS, (640)-(64), (6)+1, SECT_DATA_L1)
Dimension: #(8) * (#QMF_FILTER_STATE_SYN_SIZE-#(64)) */
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.
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 */
......
......@@ -118,8 +118,8 @@ typedef struct
struct SBR_DECODER_INSTANCE
{
SBR_DECODER_ELEMENT *pSbrElement[(4)];
SBR_HEADER_DATA sbrHeader[(4)][(1)+1]; /* Sbr header for each individual channel of an element */
SBR_DECODER_ELEMENT *pSbrElement[(8)];
SBR_HEADER_DATA sbrHeader[(8)][(1)+1]; /* Sbr header for each individual channel of an element */
FIXP_DBL *workBuffer1;
FIXP_DBL *workBuffer2;
......
......@@ -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 )
typedef struct
......
......@@ -137,7 +137,7 @@ amm-info@iis.fraunhofer.de
/* Decoder library info */
#define SBRDECODER_LIB_VL0 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_BUILD_DATE __DATE__
#define SBRDECODER_LIB_BUILD_TIME __TIME__
......@@ -251,8 +251,10 @@ SBR_ERROR sbrDecoder_ResetElement (
if ( sampleRateIn == sampleRateOut ) {
synDownsampleFac = 2;
self->flags |= SBRDEC_DOWNSAMPLE;
} else {
synDownsampleFac = 1;
self->flags &= ~SBRDEC_DOWNSAMPLE;
}
self->synDownsampleFac = synDownsampleFac;
......@@ -428,7 +430,7 @@ SBR_ERROR sbrDecoder_InitElement (
int nSbrElementsStart = self->numSbrElements;
/* Check core codec AOT */
if (! sbrDecoder_isCoreCodecValid(coreCodec) || elementIndex >= (4)) {
if (! sbrDecoder_isCoreCodecValid(coreCodec) || elementIndex >= (8)) {
sbrError = SBRDEC_UNSUPPORTED_CONFIG;
goto bail;
}
......@@ -444,6 +446,7 @@ SBR_ERROR sbrDecoder_InitElement (
&& self->coreCodec == coreCodec
&& self->pSbrElement[elementIndex] != NULL
&& self->pSbrElement[elementIndex]->elementID == elementID
&& !(self->flags & SBRDEC_FORCE_RESET)
)
{
/* Nothing to do */
......@@ -550,8 +553,9 @@ bail:
if (nSbrElementsStart < self->numSbrElements) {
/* Free the memory allocated for this element */
sbrDecoder_DestroyElement( self, elementIndex );
} else if (self->pSbrElement[elementIndex] != NULL) {
/* Set error flag to trigger concealment */
} else if ( (self->pSbrElement[elementIndex] != NULL)
&& (elementIndex < (8)))
{ /* Set error flag to trigger concealment */
self->pSbrElement[elementIndex]->frameErrorFlag[self->pSbrElement[elementIndex]->useFrameSlot] = 1;
}
}
......@@ -615,7 +619,7 @@ INT sbrDecoder_Header (
SBR_ERROR sbrError = SBRDEC_OK;
int headerIndex;
if ( self == NULL || elementIndex > (4) )
if ( self == NULL || elementIndex > (8) )
{
return SBRDEC_UNSUPPORTED_CONFIG;
}
......@@ -728,6 +732,24 @@ SBR_ERROR sbrDecoder_SetParam (HANDLE_SBRDECODER self,
}
}
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:
{
int elementIndex;
......@@ -738,7 +760,8 @@ SBR_ERROR sbrDecoder_SetParam (HANDLE_SBRDECODER self,
}
/* 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;
int headerIndex = getHeaderSlot(self->pSbrElement[elementIndex]->useFrameSlot,
......@@ -750,7 +773,7 @@ SBR_ERROR sbrDecoder_SetParam (HANDLE_SBRDECODER self,
This switches off bitstream parsing until a new header arrives. */
hSbrHeader->syncState = UPSAMPLING;
hSbrHeader->status |= SBRDEC_HDR_STAT_UPDATE;
}
} }
}
break;
default:
......@@ -767,7 +790,7 @@ SBRDEC_DRC_CHANNEL * sbrDecoder_drcGetChannel( const HANDLE_SBRDECODER self, con
SBRDEC_DRC_CHANNEL *pSbrDrcChannelData = NULL;
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];
int c, elChannels;
......@@ -829,7 +852,7 @@ SBR_ERROR sbrDecoder_drcFeedChannel ( HANDLE_SBRDECODER self,
if (self == NULL) {
return SBRDEC_NOT_INITIALIZED;
}
if (ch > (6) || pNextFact_mag == NULL) {
if (ch > (8) || pNextFact_mag == NULL) {
return SBRDEC_SET_PARAM_FAIL;
}
......@@ -874,7 +897,7 @@ void sbrDecoder_drcDisable ( HANDLE_SBRDECODER self,
SBRDEC_DRC_CHANNEL *pSbrDrcChannelData = NULL;
if ( (self == NULL)
|| (ch > (6))
|| (ch > (8))
|| (self->numSbrElements == 0)
|| (self->numSbrChannels == 0) ) {
return;
......@@ -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) {
......@@ -1198,6 +1225,15 @@ sbrDecoder_DecodeElement (
int stereo = (hSbrElement->elementID == ID_CPE) ? 1 : 0;
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 */
hSbrHeader->frameErrorFlag = hSbrElement->frameErrorFlag[hSbrElement->useFrameSlot];
......@@ -1375,7 +1411,7 @@ SBR_ERROR sbrDecoder_Apply ( HANDLE_SBRDECODER self,
INT_PCM *timeData,
int *numChannels,
int *sampleRate,
const UCHAR channelMapping[(6)],
const UCHAR channelMapping[(8)],
const int interleaved,
const int coreDecodedOk,
UCHAR *psDecoded )
......@@ -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:
return errorStatus;
......@@ -1496,7 +1536,7 @@ SBR_ERROR sbrDecoder_Close ( HANDLE_SBRDECODER *pSelf )
FreeRam_SbrDecWorkBuffer2(&self->workBuffer2);
}
for (i = 0; i < (4); i++) {
for (i = 0; i < (8); i++) {
sbrDecoder_DestroyElement( self, i );
}
......@@ -1544,3 +1584,34 @@ INT sbrDecoder_GetLibInfo( LIB_INFO *info )
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
} 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). */
typedef enum {
MODE_INVALID = -1,
......@@ -263,17 +271,29 @@ typedef enum {
} 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 {
ACT_NONE,
ACT_FRONT,
ACT_SIDE,
ACT_BACK,
ACT_LFE,
ACT_FRONT_TOP,
ACT_SIDE_TOP,
ACT_BACK_TOP,
ACT_TOP /* Ts */
ACT_NONE = 0x00,
ACT_FRONT = 0x01, /*!< Front speaker position (at normal height) */
ACT_SIDE = 0x02, /*!< Side speaker position (at normal height) */
ACT_BACK = 0x03, /*!< Back speaker position (at normal height) */
ACT_LFE = 0x04, /*!< Low frequency effect speaker postion (front) */
ACT_TOP = 0x10, /*!< Top speaker area (for combination with speaker positions) */
ACT_FRONT_TOP = 0x11, /*!< Top front speaker = (ACT_FRONT|ACT_TOP) */
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;
typedef enum
......
......@@ -99,7 +99,7 @@ amm-info@iis.fraunhofer.de
/* library info */
#define SYS_LIB_VL0 1
#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_BUILD_DATE __DATE__
#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