From 5016eb7f6582fbb2d72d79be782325a12df08864 Mon Sep 17 00:00:00 2001 From: Jean-Michel Trivi Date: Tue, 27 Aug 2013 16:28:09 -0700 Subject: Decoder stability, sanity checks improvements * AAC-Decoder - Improved PCE handling for saver (re-)configuration and metadata processing. Modified file(s): libAACdec/src/aacdecoder.cpp libAACdec/src/aacdecoder_lib.cpp - Transport layer changes (config found) -> to be evaluated. Modified file(s): libMpegTPDec/include/tpdec_lib.h libMpegTPDec/src/tpdec_latm.h libMpegTPDec/src/version libMpegTPDec/src/tpdec_asc.cpp libMpegTPDec/src/tpdec_lib.cpp libMpegTPDec/src/tpdec_adts.cpp libMpegTPDec/src/tpdec_latm.cpp libSYS/include/FDK_audio.h libSYS/src/genericStds.cpp - Enable concealment state machine to skip states if the corresponding parameter is set to zero. Modified file(s): libAACdec/src/conceal.cpp - Add some more sanity checks to avoid segmentation faults especially when setting dynamic API params. Modified file(s): libAACdec/src/aacdecoder_lib.cpp - Fix to do a fail-safe initialization of IMDCT for all channels even with corrupt streams. Modified file(s): libAACdec/src/aacdecoder.cpp - HCR decoder fix (remove warnings). Modified file(s): libAACdec/src/block.cpp - Fix border calculation in SBR decoder's LPP transposer patch determination. Modified file(s): libSBRdec/src/env_dec.cpp libSBRdec/src/sbrdecoder.cpp libSBRdec/src/lpp_tran.cpp Bug 9428126 Change-Id: Ib415b702b88a7ec8e9a55789d79cafb39296d26b --- libAACdec/src/aacdecoder.cpp | 144 ++++++++----- libAACdec/src/aacdecoder_lib.cpp | 26 ++- libAACdec/src/block.cpp | 14 +- libAACdec/src/conceal.cpp | 102 ++++++--- libMpegTPDec/include/tpdec_lib.h | 21 ++ libMpegTPDec/src/tpdec_adts.cpp | 4 +- libMpegTPDec/src/tpdec_asc.cpp | 147 ++++++++++++- libMpegTPDec/src/tpdec_latm.cpp | 20 +- libMpegTPDec/src/tpdec_latm.h | 13 +- libMpegTPDec/src/tpdec_lib.cpp | 444 +++++++++++++++++++++++++-------------- libMpegTPDec/src/version | 2 +- libSBRdec/src/env_dec.cpp | 4 +- libSBRdec/src/lpp_tran.cpp | 18 +- libSBRdec/src/sbrdecoder.cpp | 10 +- libSYS/include/FDK_audio.h | 6 + libSYS/src/genericStds.cpp | 2 +- 16 files changed, 683 insertions(+), 294 deletions(-) diff --git a/libAACdec/src/aacdecoder.cpp b/libAACdec/src/aacdecoder.cpp index 3d00d34..3a2a561 100644 --- a/libAACdec/src/aacdecoder.cpp +++ b/libAACdec/src/aacdecoder.cpp @@ -373,7 +373,7 @@ static AAC_DECODER_ERROR CDataStreamElement_Read ( { INT readBits, dataBits = count<<3; - + /* Move to the beginning of the data junk */ FDKpushBack(bs, dataStart-FDKgetValidBits(bs)); @@ -394,23 +394,26 @@ static AAC_DECODER_ERROR CDataStreamElement_Read ( \brief Read Program Config Element \bs Bitstream Handle - \count Pointer to program config element. + \pTp Transport decoder handle for CRC handling + \pce Pointer to PCE buffer + \channelConfig Current channel configuration + \alignAnchor Anchor for byte alignment - \return Error code + \return PCE status (-1: fail, 0: no new PCE, 1: PCE updated, 2: PCE updated need re-config). */ -static AAC_DECODER_ERROR CProgramConfigElement_Read ( +static int CProgramConfigElement_Read ( HANDLE_FDK_BITSTREAM bs, HANDLE_TRANSPORTDEC pTp, CProgramConfig *pce, - UINT channelConfig, - UINT alignAnchor ) + const UINT channelConfig, + const UINT alignAnchor ) { - AAC_DECODER_ERROR error = AAC_DEC_OK; + int pceStatus = 0; int crcReg; /* read PCE to temporal buffer first */ C_ALLOC_SCRATCH_START(tmpPce, CProgramConfig, 1); - + CProgramConfig_Init(tmpPce); CProgramConfig_Reset(tmpPce); @@ -421,22 +424,43 @@ static AAC_DECODER_ERROR CProgramConfigElement_Read ( transportDec_CrcEndReg(pTp, crcReg); if ( CProgramConfig_IsValid(tmpPce) - && ( (channelConfig == 6 && (tmpPce->NumChannels == 6)) - || (channelConfig == 5 && (tmpPce->NumChannels == 5)) - || (channelConfig == 0 && (tmpPce->NumChannels == pce->NumChannels)) ) - && (tmpPce->NumFrontChannelElements == 2) - && (tmpPce->NumSideChannelElements == 0) - && (tmpPce->NumBackChannelElements == 1) && (tmpPce->Profile == 1) ) - { /* Copy the complete PCE including metadata. */ - FDKmemcpy(pce, tmpPce, sizeof(CProgramConfig)); + { + if ( !pce->isValid && (channelConfig > 0) ) { + /* Create a standard channel config PCE to compare with */ + CProgramConfig_GetDefault( pce, channelConfig ); + } + + if (pce->isValid) { + /* Compare the new and the old PCE (tags ignored) */ + switch ( CProgramConfig_Compare( pce, tmpPce ) ) + { + case 1: /* Channel configuration not changed. Just new metadata. */ + FDKmemcpy(pce, tmpPce, sizeof(CProgramConfig)); /* Store the complete PCE */ + pceStatus = 1; /* New PCE but no change of config */ + break; + case 2: /* The number of channels are identical but not the config */ + if (channelConfig == 0) { + FDKmemcpy(pce, tmpPce, sizeof(CProgramConfig)); /* Store the complete PCE */ + pceStatus = 2; /* Decoder needs re-configuration */ + } + break; + case -1: /* The channel configuration is completely different */ + pceStatus = -1; /* Not supported! */ + break; + case 0: /* Nothing to do because PCE matches the old one exactly. */ + default: + /* pceStatus = 0; */ + break; + } + } } C_ALLOC_SCRATCH_END(tmpPce, CProgramConfig, 1); - return error; + return pceStatus; } -#endif +#endif /* TP_PCE_ENABLE */ /*! \brief Parse Extension Payload @@ -591,7 +615,7 @@ AAC_DECODER_ERROR CAacDecoder_ExtPayloadParse (HANDLE_AACDECODER self, { /* ... created to circumvent the missing length in ER-Syntax. */ int bitCnt, len = FDKreadBits(hBs, 4); *count -= 4; - + if (len == 15) { int add_len = FDKreadBits(hBs, 8); *count -= 8; @@ -609,9 +633,7 @@ AAC_DECODER_ERROR CAacDecoder_ExtPayloadParse (HANDLE_AACDECODER self, /* Check NOTE 2: The extension_payload() included here must not have extension_type == EXT_DATA_LENGTH. */ error = AAC_DEC_PARSE_ERROR; - goto bail; - } - else { + } else { /* rewind and call myself again. */ FDKpushBack(hBs, 4); @@ -622,7 +644,7 @@ AAC_DECODER_ERROR CAacDecoder_ExtPayloadParse (HANDLE_AACDECODER self, &bitCnt, previous_element, elIndex, - 1 ); /* Treat same as fill element */ + 0 ); *count -= len - bitCnt; } @@ -754,8 +776,12 @@ LINKSPEC_CPP void CAacDecoder_Close(HANDLE_AACDECODER self) for (ch=0; ch<(6); ch++) { if (self->pAacDecoderStaticChannelInfo[ch] != NULL) { - FreeOverlapBuffer (&self->pAacDecoderStaticChannelInfo[ch]->pOverlapBuffer); - FreeAacDecoderStaticChannelInfo (&self->pAacDecoderStaticChannelInfo[ch]); + if (self->pAacDecoderStaticChannelInfo[ch]->pOverlapBuffer != NULL) { + FreeOverlapBuffer (&self->pAacDecoderStaticChannelInfo[ch]->pOverlapBuffer); + } + if (self->pAacDecoderStaticChannelInfo[ch] != NULL) { + FreeAacDecoderStaticChannelInfo (&self->pAacDecoderStaticChannelInfo[ch]); + } } if (self->pAacDecoderChannelInfo[ch] != NULL) { FreeAacDecoderChannelInfo (&self->pAacDecoderChannelInfo[ch]); @@ -768,8 +794,12 @@ LINKSPEC_CPP void CAacDecoder_Close(HANDLE_AACDECODER self) FreeDrcInfo(&self->hDrcInfo); } - FreeWorkBufferCore1 (&self->aacCommonData.workBufferCore1); - FreeWorkBufferCore2 (&self->aacCommonData.workBufferCore2); + if (self->aacCommonData.workBufferCore1 != NULL) { + FreeWorkBufferCore1 (&self->aacCommonData.workBufferCore1); + } + if (self->aacCommonData.workBufferCore2 != NULL) { + FreeWorkBufferCore2 (&self->aacCommonData.workBufferCore2); + } FreeAacDecoder ( &self); } @@ -994,12 +1024,14 @@ LINKSPEC_CPP AAC_DECODER_ERROR CAacDecoder_Init(HANDLE_AACDECODER self, const CS CPns_InitPns(&self->pAacDecoderChannelInfo[ch]->data.aac.PnsData, &self->aacCommonData.pnsInterChannelData, &self->aacCommonData.pnsCurrentSeed, self->aacCommonData.pnsRandomSeed); } + if (ascChannels > self->aacChannels) + { + /* Make allocated channel count persistent in decoder context. */ + self->aacChannels = ascChannels; + } HcrInitRom(&self->aacCommonData.overlay.aac.erHcrInfo); setHcrType(&self->aacCommonData.overlay.aac.erHcrInfo, ID_SCE); - - /* Make allocated channel count persistent in decoder context. */ - self->aacChannels = ascChannels; } /* Make amount of signalled channels persistent in decoder context. */ @@ -1009,8 +1041,10 @@ LINKSPEC_CPP AAC_DECODER_ERROR CAacDecoder_Init(HANDLE_AACDECODER self, const CS /* Update structures */ if (ascChanged) { - /* Things to be done for each channel, which do not involved allocating memory. */ - for (ch = 0; ch < ascChannels; ch++) { + /* Things to be done for each channel, which do not involve allocating memory. + Doing these things only on the channels needed for the current configuration + (ascChannels) could lead to memory access violation later (error concealment). */ + for (ch = 0; ch < self->aacChannels; ch++) { switch (self->streamInfo.aot) { case AOT_ER_AAC_ELD: case AOT_ER_AAC_LD: @@ -1241,10 +1275,10 @@ LINKSPEC_CPP AAC_DECODER_ERROR CAacDecoder_DecodeFrame( else { self->frameOK = 0; } - /* Create SBR element for SBR for upsampling. */ - if ( (type == ID_LFE) - && ( (self->flags & AC_SBR_PRESENT) - || (self->sbrEnabled == 1) ) ) + /* Create SBR element for SBR for upsampling for LFE elements, + and if SBR was explicitly signaled, because the first frame(s) + may not contain SBR payload (broken encoder, bit errors). */ + if ( (self->flags & AC_SBR_PRESENT) || (self->sbrEnabled == 1) ) { SBR_ERROR sbrError; @@ -1254,7 +1288,7 @@ LINKSPEC_CPP AAC_DECODER_ERROR CAacDecoder_DecodeFrame( self->streamInfo.extSamplingRate, self->streamInfo.aacSamplesPerFrame, self->streamInfo.aot, - ID_LFE, + type, previous_element_index ); if (sbrError != SBRDEC_OK) { @@ -1394,26 +1428,34 @@ LINKSPEC_CPP AAC_DECODER_ERROR CAacDecoder_DecodeFrame( #ifdef TP_PCE_ENABLE case ID_PCE: - - if ( CProgramConfigElement_Read( bs, + { + int result = CProgramConfigElement_Read( + bs, self->hInput, pce, self->streamInfo.channelConfig, - auStartAnchor ) ) - { /* Built element table */ - int elIdx = CProgramConfig_GetElementTable(pce, self->elements, 7); - /* Reset the remaining tabs */ - for ( ; elIdx<7; elIdx++) { - self->elements[elIdx] = ID_NONE; - } - /* Make new number of channel persistant */ - self->ascChannels = pce->NumChannels; - /* If PCE is not first element conceal this frame to avoid inconsistencies */ - if ( element_count != 0 ) { + auStartAnchor ); + if ( result < 0 ) { + /* Something went wrong */ + ErrorStatus = AAC_DEC_PARSE_ERROR; self->frameOK = 0; } + else if ( result > 1 ) { + /* Built element table */ + int elIdx = CProgramConfig_GetElementTable(pce, self->elements, 7); + /* Reset the remaining tabs */ + for ( ; elIdx<7; elIdx++) { + self->elements[elIdx] = ID_NONE; + } + /* Make new number of channel persistant */ + self->ascChannels = pce->NumChannels; + /* If PCE is not first element conceal this frame to avoid inconsistencies */ + if ( element_count != 0 ) { + self->frameOK = 0; + } + } + pceRead = (result>=0) ? 1 : 0; } - pceRead = 1; break; #endif /* TP_PCE_ENABLE */ diff --git a/libAACdec/src/aacdecoder_lib.cpp b/libAACdec/src/aacdecoder_lib.cpp index 247fcef..9a70f24 100644 --- a/libAACdec/src/aacdecoder_lib.cpp +++ b/libAACdec/src/aacdecoder_lib.cpp @@ -110,7 +110,7 @@ amm-info@iis.fraunhofer.de /* Decoder library info */ #define AACDECODER_LIB_VL0 2 #define AACDECODER_LIB_VL1 5 -#define AACDECODER_LIB_VL2 3 +#define AACDECODER_LIB_VL2 4 #define AACDECODER_LIB_TITLE "AAC Decoder Lib" #define AACDECODER_LIB_BUILD_DATE __DATE__ #define AACDECODER_LIB_BUILD_TIME __TIME__ @@ -261,7 +261,7 @@ setConcealMethod ( const HANDLE_AACDECODER self, /*!< Handle of the decoder i HANDLE_SBRDECODER hSbrDec = NULL; HANDLE_AAC_DRC hDrcInfo = NULL; HANDLE_PCM_DOWNMIX hPcmDmx = NULL; - CConcealmentMethod backupMethod; + CConcealmentMethod backupMethod = ConcealMethodNone; int backupDelay = 0; int bsDelay = 0; @@ -396,11 +396,15 @@ aacDecoder_SetParam ( const HANDLE_AACDECODER self, /*!< Handle of the decode AAC_DECODER_ERROR errorStatus = AAC_DEC_OK; CConcealParams *pConcealData = NULL; HANDLE_AAC_DRC hDrcInfo = NULL; + HANDLE_PCM_DOWNMIX hPcmDmx = NULL; /* check decoder handle */ if (self != NULL) { pConcealData = &self->concealCommonData; hDrcInfo = self->hDrcInfo; + hPcmDmx = self->hPcmUtils; + } else { + errorStatus = AAC_DEC_INVALID_HANDLE; } /* configure the subsystems */ @@ -417,11 +421,14 @@ aacDecoder_SetParam ( const HANDLE_AACDECODER self, /*!< Handle of the decode break; case AAC_PCM_OUTPUT_CHANNELS: + if (value < -1 || value > (6)) { + return AAC_DEC_SET_PARAM_FAIL; + } { PCMDMX_ERROR err; err = pcmDmx_SetParam ( - self->hPcmUtils, + hPcmDmx, NUMBER_OF_OUTPUT_CHANNELS, value ); @@ -441,7 +448,7 @@ aacDecoder_SetParam ( const HANDLE_AACDECODER self, /*!< Handle of the decode PCMDMX_ERROR err; err = pcmDmx_SetParam ( - self->hPcmUtils, + hPcmDmx, DUAL_CHANNEL_DOWNMIX_MODE, value ); @@ -459,10 +466,14 @@ aacDecoder_SetParam ( const HANDLE_AACDECODER self, /*!< Handle of the decode case AAC_PCM_OUTPUT_CHANNEL_MAPPING: switch (value) { case 0: - self->channelOutputMapping = channelMappingTablePassthrough; + if (self != NULL) { + self->channelOutputMapping = channelMappingTablePassthrough; + } break; case 1: - self->channelOutputMapping = channelMappingTableWAV; + if (self != NULL) { + self->channelOutputMapping = channelMappingTableWAV; + } break; default: errorStatus = AAC_DEC_SET_PARAM_FAIL; @@ -472,6 +483,9 @@ aacDecoder_SetParam ( const HANDLE_AACDECODER self, /*!< Handle of the decode case AAC_QMF_LOWPOWER: + if (value < -1 || value > 1) { + return AAC_DEC_SET_PARAM_FAIL; + } if (self == NULL) { return AAC_DEC_INVALID_HANDLE; } diff --git a/libAACdec/src/block.cpp b/libAACdec/src/block.cpp index 0424edb..9d703cc 100644 --- a/libAACdec/src/block.cpp +++ b/libAACdec/src/block.cpp @@ -589,7 +589,6 @@ AAC_DECODER_ERROR CBlock_ReadSpectralData(HANDLE_FDK_BITSTREAM bs, { H_HCR_INFO hHcr = &pAacDecoderChannelInfo->pComData->overlay.aac.erHcrInfo; int hcrStatus = 0; - int hcrConcealWholeFrame = 0; /* advanced Huffman decoding starts here (HCR decoding :) */ if ( pAacDecoderChannelInfo->pDynData->specificTo.aac.lenOfReorderedSpectralData != 0 ) { @@ -598,24 +597,19 @@ AAC_DECODER_ERROR CBlock_ReadSpectralData(HANDLE_FDK_BITSTREAM bs, hcrStatus = HcrInit(hHcr, pAacDecoderChannelInfo, pSamplingRateInfo, bs); if (hcrStatus != 0) { -#if HCR_ERROR_CONCEALMENT - hcrConcealWholeFrame = 1; - return AAC_DEC_DECODE_FRAME_ERROR; /* concealment is muting in the first step, therefore return now */ - // hcr decoding is not skipped because of returning above -#else return AAC_DEC_DECODE_FRAME_ERROR; -#endif } /* HCR decoding short */ hcrStatus = HcrDecoder(hHcr, pAacDecoderChannelInfo, pSamplingRateInfo, bs); - + if (hcrStatus != 0) { #if HCR_ERROR_CONCEALMENT - HcrMuteErroneousLines(hHcr); + HcrMuteErroneousLines(hHcr); #else - return AAC_DEC_DECODE_FRAME_ERROR; + return AAC_DEC_DECODE_FRAME_ERROR; #endif /* HCR_ERROR_CONCEALMENT */ + } FDKpushFor (bs, pAacDecoderChannelInfo->pDynData->specificTo.aac.lenOfReorderedSpectralData); } diff --git a/libAACdec/src/conceal.cpp b/libAACdec/src/conceal.cpp index 733b959..c26051c 100644 --- a/libAACdec/src/conceal.cpp +++ b/libAACdec/src/conceal.cpp @@ -441,7 +441,7 @@ AAC_DECODER_ERROR /* set confort noise level which will be inserted while in state 'muting' */ if (comfNoiseLevel != AACDEC_CONCEAL_PARAM_NOT_SPECIFIED) { - if ( (comfNoiseLevel < 0) + if ( (comfNoiseLevel < -1) || (comfNoiseLevel > 127) ) { return AAC_DEC_SET_PARAM_FAIL; } @@ -1527,8 +1527,13 @@ static void { case ConcealState_Ok: if (!frameOk) { - /* change to state SINGLE-FRAME-LOSS */ - pConcealmentInfo->concealState = ConcealState_Single; + if (pConcealCommonData->numFadeOutFrames > 0) { + /* change to state SINGLE-FRAME-LOSS */ + pConcealmentInfo->concealState = ConcealState_Single; + } else { + /* change to state MUTE */ + pConcealmentInfo->concealState = ConcealState_Mute; + } pConcealmentInfo->cntFadeFrames = 0; pConcealmentInfo->cntValidFrames = 0; } @@ -1561,11 +1566,16 @@ static void case ConcealState_FadeOut: pConcealmentInfo->cntFadeFrames += 1; /* used to address the fade-out factors */ if (pConcealmentInfo->cntValidFrames > pConcealCommonData->numMuteReleaseFrames) { - /* change to state FADE-IN */ - pConcealmentInfo->concealState = ConcealState_FadeIn; - pConcealmentInfo->cntFadeFrames = findEquiFadeFrame( pConcealCommonData, - pConcealmentInfo->cntFadeFrames-1, - 0 /* FadeOut -> FadeIn */); + if (pConcealCommonData->numFadeInFrames > 0) { + /* change to state FADE-IN */ + pConcealmentInfo->concealState = ConcealState_FadeIn; + pConcealmentInfo->cntFadeFrames = findEquiFadeFrame( pConcealCommonData, + pConcealmentInfo->cntFadeFrames-1, + 0 /* FadeOut -> FadeIn */); + } else { + /* change to state OK */ + pConcealmentInfo->concealState = ConcealState_Ok; + } } else { if (pConcealmentInfo->cntFadeFrames >= pConcealCommonData->numFadeOutFrames) { /* change to state MUTE */ @@ -1576,9 +1586,14 @@ static void case ConcealState_Mute: if (pConcealmentInfo->cntValidFrames > pConcealCommonData->numMuteReleaseFrames) { - /* change to state FADE-IN */ - pConcealmentInfo->concealState = ConcealState_FadeIn; - pConcealmentInfo->cntFadeFrames = pConcealCommonData->numFadeInFrames - 1; + if (pConcealCommonData->numFadeInFrames > 0) { + /* change to state FADE-IN */ + pConcealmentInfo->concealState = ConcealState_FadeIn; + pConcealmentInfo->cntFadeFrames = pConcealCommonData->numFadeInFrames - 1; + } else { + /* change to state OK */ + pConcealmentInfo->concealState = ConcealState_Ok; + } } break; @@ -1590,11 +1605,16 @@ static void pConcealmentInfo->concealState = ConcealState_Ok; } } else { - /* change to state FADE-OUT */ - pConcealmentInfo->concealState = ConcealState_FadeOut; - pConcealmentInfo->cntFadeFrames = findEquiFadeFrame( pConcealCommonData, - pConcealmentInfo->cntFadeFrames+1, - 1 /* FadeIn -> FadeOut */); + if (pConcealCommonData->numFadeOutFrames > 0) { + /* change to state FADE-OUT */ + pConcealmentInfo->concealState = ConcealState_FadeOut; + pConcealmentInfo->cntFadeFrames = findEquiFadeFrame( pConcealCommonData, + pConcealmentInfo->cntFadeFrames+1, + 1 /* FadeIn -> FadeOut */); + } else { + /* change to state MUTE */ + pConcealmentInfo->concealState = ConcealState_Mute; + } } break; @@ -1625,8 +1645,13 @@ static void case ConcealState_Ok: if (!(pConcealmentInfo->prevFrameOk[1] || (pConcealmentInfo->prevFrameOk[0] && !pConcealmentInfo->prevFrameOk[1] && frameOk))) { - /* Fade out only if the energy interpolation algorithm can not be applied! */ - pConcealmentInfo->concealState = ConcealState_FadeOut; + if (pConcealCommonData->numFadeOutFrames > 0) { + /* Fade out only if the energy interpolation algorithm can not be applied! */ + pConcealmentInfo->concealState = ConcealState_FadeOut; + } else { + /* change to state MUTE */ + pConcealmentInfo->concealState = ConcealState_Mute; + } pConcealmentInfo->cntFadeFrames = 0; pConcealmentInfo->cntValidFrames = 0; } @@ -1640,11 +1665,16 @@ static void pConcealmentInfo->cntFadeFrames += 1; if (pConcealmentInfo->cntValidFrames > pConcealCommonData->numMuteReleaseFrames) { - /* change to state FADE-IN */ - pConcealmentInfo->concealState = ConcealState_FadeIn; - pConcealmentInfo->cntFadeFrames = findEquiFadeFrame( pConcealCommonData, - pConcealmentInfo->cntFadeFrames-1, - 0 /* FadeOut -> FadeIn */); + if (pConcealCommonData->numFadeInFrames > 0) { + /* change to state FADE-IN */ + pConcealmentInfo->concealState = ConcealState_FadeIn; + pConcealmentInfo->cntFadeFrames = findEquiFadeFrame( pConcealCommonData, + pConcealmentInfo->cntFadeFrames-1, + 0 /* FadeOut -> FadeIn */); + } else { + /* change to state OK */ + pConcealmentInfo->concealState = ConcealState_Ok; + } } else { if (pConcealmentInfo->cntFadeFrames >= pConcealCommonData->numFadeOutFrames) { /* change to state MUTE */ @@ -1655,9 +1685,14 @@ static void case ConcealState_Mute: if (pConcealmentInfo->cntValidFrames > pConcealCommonData->numMuteReleaseFrames) { - /* change to state FADE-IN */ - pConcealmentInfo->concealState = ConcealState_FadeIn; - pConcealmentInfo->cntFadeFrames = pConcealCommonData->numFadeInFrames - 1; + if (pConcealCommonData->numFadeInFrames > 0) { + /* change to state FADE-IN */ + pConcealmentInfo->concealState = ConcealState_FadeIn; + pConcealmentInfo->cntFadeFrames = pConcealCommonData->numFadeInFrames - 1; + } else { + /* change to state OK */ + pConcealmentInfo->concealState = ConcealState_Ok; + } } break; @@ -1670,11 +1705,16 @@ static void pConcealmentInfo->concealState = ConcealState_Ok; } } else { - /* change to state FADE-OUT */ - pConcealmentInfo->concealState = ConcealState_FadeOut; - pConcealmentInfo->cntFadeFrames = findEquiFadeFrame( pConcealCommonData, - pConcealmentInfo->cntFadeFrames+1, - 1 /* FadeIn -> FadeOut */); + if (pConcealCommonData->numFadeOutFrames > 0) { + /* change to state FADE-OUT */ + pConcealmentInfo->concealState = ConcealState_FadeOut; + pConcealmentInfo->cntFadeFrames = findEquiFadeFrame( pConcealCommonData, + pConcealmentInfo->cntFadeFrames+1, + 1 /* FadeIn -> FadeOut */); + } else { + /* change to state MUTE */ + pConcealmentInfo->concealState = ConcealState_Mute; + } } break; } /* End switch(pConcealmentInfo->concealState) */ diff --git a/libMpegTPDec/include/tpdec_lib.h b/libMpegTPDec/include/tpdec_lib.h index 5cec91d..fb4c41d 100644 --- a/libMpegTPDec/include/tpdec_lib.h +++ b/libMpegTPDec/include/tpdec_lib.h @@ -186,6 +186,27 @@ int CProgramConfig_IsValid ( const CProgramConfig *pPce ); void CProgramConfig_Read ( CProgramConfig *pPce, HANDLE_FDK_BITSTREAM bs, UINT alignAnchor ); + +/*! + \brief Compare two Program Config Elements. + \param pPce1 Pointer to first Program Config Element structure. + \param pPce2 Pointer to second Program Config Element structure. + \return -1 if PCEs are completely different, + 0 if PCEs are completely equal, + 1 if PCEs are different but have the same channel config, + 2 if PCEs have different channel config but same number of channels. +*/ +int CProgramConfig_Compare ( const CProgramConfig * const pPce1, + const CProgramConfig * const pPce2 ); + +/*! + \brief Get a Program Config Element that matches the predefined MPEG-4 channel configurations 1-14. + \param pPce Program Config Element structure. + \param channelConfig MPEG-4 channel configuration. + \return void +*/ +void CProgramConfig_GetDefault ( CProgramConfig *pPce, + const UINT channelConfig ); #endif /* TP_PCE_ENABLE */ /** diff --git a/libMpegTPDec/src/tpdec_adts.cpp b/libMpegTPDec/src/tpdec_adts.cpp index b5c67c2..c455681 100644 --- a/libMpegTPDec/src/tpdec_adts.cpp +++ b/libMpegTPDec/src/tpdec_adts.cpp @@ -374,12 +374,12 @@ int adtsRead_GetRawDataBlockLength( length = -1; /* raw data block length is unknown */ } else { if (blockNum < 0 || blockNum > 3) { - return TRANSPORTDEC_INVALID_PARAMETER; + length = -1; } length = (pAdts->rawDataBlockDist[blockNum] << 3) - 16; } } - if (blockNum == 0) { + if (blockNum == 0 && length > 0) { length -= pAdts->bs.num_pce_bits; } return length; diff --git a/libMpegTPDec/src/tpdec_asc.cpp b/libMpegTPDec/src/tpdec_asc.cpp index e6278d6..59ad58b 100644 --- a/libMpegTPDec/src/tpdec_asc.cpp +++ b/libMpegTPDec/src/tpdec_asc.cpp @@ -205,6 +205,145 @@ void CProgramConfig_Read( pPce->isValid = 1; } + +/* + * Compare two program configurations. + * Returns the result of the comparison: + * -1 - completely different + * 0 - completely equal + * 1 - different but same channel configuration + * 2 - different channel configuration but same number of channels + */ +int CProgramConfig_Compare ( const CProgramConfig * const pPce1, + const CProgramConfig * const pPce2 ) +{ + int result = 0; /* Innocent until proven false. */ + + if (FDKmemcmp(pPce1, pPce2, sizeof(CProgramConfig)) != 0) + { /* Configurations are not completely different. + So look into details and analyse the channel configurations: */ + result = -1; + + if (pPce1->NumChannels == pPce2->NumChannels) + { /* Now the logic changes. We first assume to have the same channel configuration + and then prove if this assumption is true. */ + result = 1; + + /* Front channels */ + if (pPce1->NumFrontChannelElements != pPce2->NumFrontChannelElements) { + result = 2; /* different number of front channel elements */ + } else { + int el, numCh1 = 0, numCh2 = 0; + for (el = 0; el < pPce1->NumFrontChannelElements; el += 1) { + numCh1 += pPce1->FrontElementIsCpe[el] ? 2 : 1; + numCh2 += pPce2->FrontElementIsCpe[el] ? 2 : 1; + } + if (numCh1 != numCh2) { + result = 2; /* different number of front channels */ + } + } + /* Side channels */ + if (pPce1->NumSideChannelElements != pPce2->NumSideChannelElements) { + result = 2; /* different number of side channel elements */ + } else { + int el, numCh1 = 0, numCh2 = 0; + for (el = 0; el < pPce1->NumSideChannelElements; el += 1) { + numCh1 += pPce1->SideElementIsCpe[el] ? 2 : 1; + numCh2 += pPce2->SideElementIsCpe[el] ? 2 : 1; + } + if (numCh1 != numCh2) { + result = 2; /* different number of side channels */ + } + } + /* Back channels */ + if (pPce1->NumBackChannelElements != pPce2->NumBackChannelElements) { + result = 2; /* different number of back channel elements */ + } else { + int el, numCh1 = 0, numCh2 = 0; + for (el = 0; el < pPce1->NumBackChannelElements; el += 1) { + numCh1 += pPce1->BackElementIsCpe[el] ? 2 : 1; + numCh2 += pPce2->BackElementIsCpe[el] ? 2 : 1; + } + if (numCh1 != numCh2) { + result = 2; /* different number of back channels */ + } + } + /* LFE channels */ + if (pPce1->NumLfeChannelElements != pPce2->NumLfeChannelElements) { + result = 2; /* different number of lfe channels */ + } + /* LFEs are always SCEs so we don't need to count the channels. */ + } + } + + return result; +} + +void CProgramConfig_GetDefault( CProgramConfig *pPce, + const UINT channelConfig ) +{ + FDK_ASSERT(pPce != NULL); + + /* Init PCE */ + CProgramConfig_Init(pPce); + pPce->Profile = 1; /* Set AAC LC because it is the only supported object type. */ + + switch (channelConfig) { + /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ + case 6: /* 3/0/2.1ch */ + pPce->NumLfeChannelElements += 1; + pPce->NumChannels += 1; + case 5: /* 3/0/2.0ch */ + case 4: /* 3/0/1.0ch */ + pPce->NumBackChannelElements += 1; + pPce->BackElementIsCpe[0] = (channelConfig>4) ? 1 : 0; + pPce->NumChannels += (channelConfig>4) ? 2 : 1; + pPce->NumEffectiveChannels += (channelConfig>4) ? 2 : 1; + case 3: /* 3/0/0.0ch */ + pPce->NumFrontChannelElements += 1; + pPce->FrontElementIsCpe[1] = 1; + pPce->NumChannels += 2; + pPce->NumEffectiveChannels += 2; + case 1: /* 1/0/0.0ch */ + pPce->NumFrontChannelElements += 1; + pPce->FrontElementIsCpe[0] = 0; + pPce->NumChannels += 1; + pPce->NumEffectiveChannels += 1; + pPce->isValid = 1; + break; + /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ + case 2: /* 2/0/0.ch */ + pPce->NumFrontChannelElements = 1; + pPce->FrontElementIsCpe[0] = 1; + pPce->NumChannels += 2; + pPce->NumEffectiveChannels += 2; + pPce->isValid = 1; + break; + /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ + default: + pPce->isValid = 0; /* To be explicit! */ + break; + } + + if (pPce->isValid) { + /* Create valid element instance tags */ + int el, elTagSce = 0, elTagCpe = 0; + + for (el = 0; el < pPce->NumFrontChannelElements; el += 1) { + pPce->FrontElementTagSelect[el] = (pPce->FrontElementIsCpe) ? elTagCpe++ : elTagSce++; + } + for (el = 0; el < pPce->NumSideChannelElements; el += 1) { + pPce->SideElementTagSelect[el] = (pPce->SideElementIsCpe) ? elTagCpe++ : elTagSce++; + } + for (el = 0; el < pPce->NumBackChannelElements; el += 1) { + pPce->BackElementTagSelect[el] = (pPce->BackElementIsCpe) ? elTagCpe++ : elTagSce++; + } + elTagSce = 0; + for (el = 0; el < pPce->NumLfeChannelElements; el += 1) { + pPce->LfeElementTagSelect[el] = elTagSce++; + } + } +} #endif /* TP_PCE_ENABLE */ /** @@ -589,18 +728,18 @@ static INT ld_sbr_header( const CSAudioSpecificConfig *asc, } switch ( channelConfiguration ) { + 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: case 5: error |= cb->cbSbr(cb->cbSbrData, hBs, asc->m_samplingFrequency, asc->m_extensionSamplingFrequency, asc->m_samplesPerFrame, AOT_ER_AAC_ELD, ID_CPE, i++); case 3: error |= cb->cbSbr(cb->cbSbrData, hBs, asc->m_samplingFrequency, asc->m_extensionSamplingFrequency, asc->m_samplesPerFrame, AOT_ER_AAC_ELD, ID_CPE, i++); break; - case 7: - error |= cb->cbSbr(cb->cbSbrData, hBs, asc->m_samplingFrequency, asc->m_extensionSamplingFrequency, asc->m_samplesPerFrame, AOT_ER_AAC_ELD, ID_SCE, i++); - case 6: - 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++); break; } diff --git a/libMpegTPDec/src/tpdec_latm.cpp b/libMpegTPDec/src/tpdec_latm.cpp index 7595c5e..5710d77 100644 --- a/libMpegTPDec/src/tpdec_latm.cpp +++ b/libMpegTPDec/src/tpdec_latm.cpp @@ -120,7 +120,8 @@ TRANSPORTDEC_ERROR CLatmDemux_ReadAudioMuxElement( CLatmDemux *pLatmDemux, int m_muxConfigPresent, CSTpCallBacks *pTpDecCallbacks, - CSAudioSpecificConfig *pAsc + CSAudioSpecificConfig *pAsc, + int *pfConfigFound ) { TRANSPORTDEC_ERROR ErrorStatus = TRANSPORTDEC_OK; @@ -129,12 +130,17 @@ TRANSPORTDEC_ERROR CLatmDemux_ReadAudioMuxElement( pLatmDemux->m_useSameStreamMux = FDKreadBits(bs,1); if (!pLatmDemux->m_useSameStreamMux) { - if ((ErrorStatus = CLatmDemux_ReadStreamMuxConfig(bs, pLatmDemux, pTpDecCallbacks, pAsc))) { + if ((ErrorStatus = CLatmDemux_ReadStreamMuxConfig(bs, pLatmDemux, pTpDecCallbacks, pAsc, pfConfigFound))) { return (ErrorStatus); } } } + /* If there was no configuration read, its not possible to parse PayloadLengthInfo below. */ + if (! *pfConfigFound) { + return TRANSPORTDEC_SYNC_ERROR; + } + if (pLatmDemux->m_AudioMuxVersionA == 0) { /* Do only once per call, because parsing and decoding is done in-line. */ if ((ErrorStatus = CLatmDemux_ReadPayloadLengthInfo(bs,pLatmDemux))) { @@ -154,6 +160,7 @@ TRANSPORTDEC_ERROR CLatmDemux_Read( TRANSPORT_TYPE tt, CSTpCallBacks *pTpDecCallbacks, CSAudioSpecificConfig *pAsc, + int *pfConfigFound, const INT ignoreBufferFullness ) { @@ -168,7 +175,7 @@ TRANSPORTDEC_ERROR CLatmDemux_Read( return TRANSPORTDEC_NOT_ENOUGH_BITS; } - if ((ErrorStatus = CLatmDemux_ReadAudioMuxElement(bs, pLatmDemux, (tt != TT_MP4_LATM_MCP0), pTpDecCallbacks, pAsc))) + if ((ErrorStatus = CLatmDemux_ReadAudioMuxElement(bs, pLatmDemux, (tt != TT_MP4_LATM_MCP0), pTpDecCallbacks, pAsc, pfConfigFound))) return (ErrorStatus); if (!ignoreBufferFullness) @@ -205,7 +212,8 @@ TRANSPORTDEC_ERROR CLatmDemux_ReadStreamMuxConfig( HANDLE_FDK_BITSTREAM bs, CLatmDemux *pLatmDemux, CSTpCallBacks *pTpDecCallbacks, - CSAudioSpecificConfig *pAsc + CSAudioSpecificConfig *pAsc, + int * pfConfigFound ) { LATM_LAYER_INFO *p_linfo = NULL; @@ -272,6 +280,7 @@ TRANSPORTDEC_ERROR CLatmDemux_ReadStreamMuxConfig( if ((ErrorStatus = AudioSpecificConfig_Parse(&pAsc[TPDEC_TRACKINDEX(prog,lay)], &tmpBs, 1, pTpDecCallbacks))) { return (ErrorStatus); } + *pfConfigFound = 1; /* The field p_linfo->m_ascLen could be wrong, so check if */ if ( 0 > (INT)FDKgetValidBits(&tmpBs)) { @@ -292,6 +301,7 @@ TRANSPORTDEC_ERROR CLatmDemux_ReadStreamMuxConfig( if (cbError != 0) { return TRANSPORTDEC_UNKOWN_ERROR; } + *pfConfigFound = 1; } } @@ -377,7 +387,7 @@ TRANSPORTDEC_ERROR CLatmDemux_ReadPayloadLengthInfo(HANDLE_FDK_BITSTREAM bs, CLa else { ErrorStatus = TRANSPORTDEC_PARSE_ERROR; //AAC_DEC_LATM_TIMEFRAMING; } - if (pLatmDemux->m_audioMuxLengthBytes > 0 && totalPayloadBits > pLatmDemux->m_audioMuxLengthBytes*8) { + if (pLatmDemux->m_audioMuxLengthBytes > (UINT)0 && totalPayloadBits > (int)pLatmDemux->m_audioMuxLengthBytes*8) { return TRANSPORTDEC_PARSE_ERROR; } return (ErrorStatus); diff --git a/libMpegTPDec/src/tpdec_latm.h b/libMpegTPDec/src/tpdec_latm.h index e8dd37a..6dc13e8 100644 --- a/libMpegTPDec/src/tpdec_latm.h +++ b/libMpegTPDec/src/tpdec_latm.h @@ -144,14 +144,25 @@ TRANSPORTDEC_ERROR CLatmDemux_Read( TRANSPORT_TYPE tt, CSTpCallBacks *pTpDecCallbacks, CSAudioSpecificConfig *pAsc, + int *pfConfigFound, const INT ignoreBufferFullness ); +/** + * \brief Read StreamMuxConfig + * \param bs bit stream handle as data source + * \param pLatmDemux pointer to CLatmDemux struct of current LATM context + * \param pTpDecCallbacks Call back structure for configuration callbacks + * \param pAsc pointer to a ASC for configuration storage + * \param pfConfigFound pointer to a flag which is set to 1 if a configuration was found and processed successfully + * \return error code + */ TRANSPORTDEC_ERROR CLatmDemux_ReadStreamMuxConfig( HANDLE_FDK_BITSTREAM bs, CLatmDemux *pLatmDemux, CSTpCallBacks *pTpDecCallbacks, - CSAudioSpecificConfig *pAsc + CSAudioSpecificConfig *pAsc, + int * pfConfigFound ); TRANSPORTDEC_ERROR CLatmDemux_ReadPayloadLengthInfo(HANDLE_FDK_BITSTREAM bs, CLatmDemux *pLatmDemux); diff --git a/libMpegTPDec/src/tpdec_lib.cpp b/libMpegTPDec/src/tpdec_lib.cpp index 8de20eb..1f9f29b 100644 --- a/libMpegTPDec/src/tpdec_lib.cpp +++ b/libMpegTPDec/src/tpdec_lib.cpp @@ -197,8 +197,7 @@ HANDLE_TRANSPORTDEC transportDec_Open( const TRANSPORT_TYPE transportFmt, const if (hInput != NULL) { /* Create bitstream */ - if ( (transportFmt == TT_MP4_RAW) - || (transportFmt == TT_DRM) ){ + if ( TT_IS_PACKET(transportFmt) ) { hInput->bsBuffer = NULL; } else { hInput->bsBuffer = GetRam_TransportDecoderBuffer(0); @@ -222,7 +221,9 @@ TRANSPORTDEC_ERROR transportDec_OutOfBandConfig(HANDLE_TRANSPORTDEC hTp, UCHAR * FDK_BITSTREAM bs; HANDLE_FDK_BITSTREAM hBs = &bs; - FDKinitBitStream(hBs, conf, 0x80000000, length<<3, BS_READER); + FDKinitBitStream(hBs, conf, 0x10000000, length<<3, BS_READER); + + int fConfigFound = 0; /* config transport decoder */ switch (hTp->transportFmt) { @@ -234,27 +235,27 @@ TRANSPORTDEC_ERROR transportDec_OutOfBandConfig(HANDLE_TRANSPORTDEC hTp, UCHAR * return TRANSPORTDEC_INVALID_PARAMETER; } CLatmDemux *pLatmDemux = &hTp->parser.latm; - err = CLatmDemux_ReadStreamMuxConfig(hBs, pLatmDemux, &hTp->callbacks, hTp->asc); + err = CLatmDemux_ReadStreamMuxConfig(hBs, pLatmDemux, &hTp->callbacks, hTp->asc, &fConfigFound); if (err != TRANSPORTDEC_OK) { return err; } } break; default: - case TT_MP4_RAW: + fConfigFound = 1; err = AudioSpecificConfig_Parse(&hTp->asc[layer], hBs, 1, &hTp->callbacks); - break; - } - if (err == TRANSPORTDEC_OK) { - int errC; + if (err == TRANSPORTDEC_OK) { + int errC; - errC = hTp->callbacks.cbUpdateConfig(hTp->callbacks.cbUpdateConfigData, &hTp->asc[layer]); - if (errC != 0) { - err = TRANSPORTDEC_PARSE_ERROR; - } + errC = hTp->callbacks.cbUpdateConfig(hTp->callbacks.cbUpdateConfigData, &hTp->asc[layer]); + if (errC != 0) { + err = TRANSPORTDEC_PARSE_ERROR; + } + } + break; } - if (err == TRANSPORTDEC_OK) { + if (err == TRANSPORTDEC_OK && fConfigFound) { hTp->flags |= TPDEC_CONFIG_FOUND; } @@ -313,18 +314,16 @@ TRANSPORTDEC_ERROR transportDec_FillData( /* set bitbuffer shortcut */ hBs = &hTp->bitStream[layer]; - switch (hTp->transportFmt) { - case TT_MP4_RAW: - case TT_DRM: + if ( TT_IS_PACKET(hTp->transportFmt) ) { + if (hTp->numberOfRawDataBlocks == 0) { /* For packet based transport, pass input buffer to bitbuffer without copying the data. Unfortunately we do not know the actual buffer size. And the FDK bit buffer implementation needs a number 2^x. So we assume the maximum of 48 channels with 6144 bits per channel and round it up to the next power of 2 => 65536 bytes */ FDKinitBitStream(hBs, pBuffer, 0x10000, (*pBytesValid)<<3, BS_READER); *pBytesValid = 0; - break; - - default: + } + } else { /* ... else feed bitbuffer with new stream data (append). */ if (hTp->numberOfRawDataBlocks <= 0) { FDKfeedBuffer (hBs, pBuffer, bufferSize, pBytesValid) ; @@ -368,6 +367,82 @@ INT transportDec_GetBufferFullness( const HANDLE_TRANSPORTDEC hTp ) return bufferFullness; } +/** + * \brief adjust bit stream position and the end of an access unit. + * \param hTp transport decoder handle. + * \return error code. + */ +static +TRANSPORTDEC_ERROR transportDec_AdjustEndOfAccessUnit(HANDLE_TRANSPORTDEC hTp) +{ + HANDLE_FDK_BITSTREAM hBs = &hTp->bitStream[0]; + TRANSPORTDEC_ERROR err = TRANSPORTDEC_OK; + + switch (hTp->transportFmt) { + case TT_MP4_LOAS: + case TT_MP4_LATM_MCP0: + case TT_MP4_LATM_MCP1: + if ( hTp->numberOfRawDataBlocks == 0 ) + { + /* Do byte align at the end of AudioMuxElement. */ + FDKbyteAlign(hBs, hTp->globalFramePos); + + /* Check global frame length */ + if (hTp->transportFmt == TT_MP4_LOAS && hTp->parser.latm.m_audioMuxLengthBytes > 0) + { + int loasOffset; + + loasOffset = (hTp->parser.latm.m_audioMuxLengthBytes*8 + FDKgetValidBits(hBs)) - hTp->globalFramePos; + if (loasOffset != 0) { + FDKpushBiDirectional(hBs, loasOffset); + /* For ELD and other payloads there is an unknown amount of padding, so ignore unread bits, but + throw an error only if too many bits where read. */ + if (loasOffset < 0) { + err = TRANSPORTDEC_PARSE_ERROR; + } + } + } + } + break; + + case TT_MP4_ADTS: + if (hTp->parser.adts.bs.protection_absent == 0) + { + int offset; + + /* Calculate offset to end of AU */ + offset = hTp->parser.adts.rawDataBlockDist[hTp->parser.adts.bs.num_raw_blocks-hTp->numberOfRawDataBlocks]<<3; + /* CAUTION: The PCE (if available) is declared to be a part of the header! */ + offset -= hTp->accessUnitAnchor[0] - FDKgetValidBits(hBs) + 16 + hTp->parser.adts.bs.num_pce_bits; + FDKpushBiDirectional(hBs, offset); + } + if (hTp->parser.adts.bs.num_raw_blocks > 0 && hTp->parser.adts.bs.protection_absent == 0) { + /* Note this CRC read currently happens twice because of transportDec_CrcCheck() */ + hTp->parser.adts.crcReadValue = FDKreadBits(hBs, 16); + } + if ( hTp->numberOfRawDataBlocks == 0 ) + { + /* Check global frame length */ + if (hTp->parser.adts.bs.protection_absent == 0) + { + int offset; + + offset = (hTp->parser.adts.bs.frame_length*8 - ADTS_SYNCLENGTH + FDKgetValidBits(hBs)) - hTp->globalFramePos; + if (offset != 0) { + FDKpushBiDirectional(hBs, offset); + } + } + } + break; + + default: + break; + } + + return err; +} + + /** * \brief Determine additional buffer fullness contraint due to burst data reception. * The parameter TPDEC_PARAM_BURSTPERIOD must have been set as a precondition. @@ -432,51 +507,152 @@ TRANSPORTDEC_ERROR additionalHoldOffNeeded( } } -/** - * \brief adjust bit stream position and the end of an access unit. - * \param hTp transport decoder handle. - * \return error code. - */ -static -TRANSPORTDEC_ERROR transportDec_AdjustEndOfAccessUnit(HANDLE_TRANSPORTDEC hTp) +static TRANSPORTDEC_ERROR transportDec_readHeader( + HANDLE_TRANSPORTDEC hTp, + HANDLE_FDK_BITSTREAM hBs, + int syncLength, + int ignoreBufferFullness, + int *pRawDataBlockLength, + int *pfTraverseMoreFrames, + int *pSyncLayerFrameBits, + int *pfConfigFound, + int *pHeaderBits + ) { - HANDLE_FDK_BITSTREAM hBs = &hTp->bitStream[0]; TRANSPORTDEC_ERROR err = TRANSPORTDEC_OK; + int rawDataBlockLength = *pRawDataBlockLength; + int fTraverseMoreFrames = (pfTraverseMoreFrames != NULL) ? *pfTraverseMoreFrames : 0; + int syncLayerFrameBits = (pSyncLayerFrameBits != NULL) ? *pSyncLayerFrameBits : 0; + int fConfigFound = (pfConfigFound != NULL) ? *pfConfigFound : 0; + int startPos; + + startPos = FDKgetValidBits(hBs); switch (hTp->transportFmt) { - case TT_MP4_LOAS: - case TT_MP4_LATM_MCP0: - case TT_MP4_LATM_MCP1: - if ( hTp->numberOfRawDataBlocks == 0 ) + case TT_MP4_ADTS: + if (hTp->numberOfRawDataBlocks <= 0) { - /* Check global frame length */ - if (hTp->transportFmt == TT_MP4_LOAS && hTp->parser.latm.m_audioMuxLengthBytes > 0) - { - int loasOffset; + int errC; - loasOffset = (hTp->parser.latm.m_audioMuxLengthBytes*8 + FDKgetValidBits(hBs)) - hTp->globalFramePos; - if (loasOffset != 0) { - FDKpushBiDirectional(hBs, loasOffset); - /* For ELD and other payloads there is an unknown amount of padding, so ignore unread bits, but - throw an error only if too many bits where read. */ - if (loasOffset < 0) { - err = TRANSPORTDEC_PARSE_ERROR; + hTp->globalFramePos = FDKgetValidBits(hBs); + + /* Parse ADTS header */ + err = adtsRead_DecodeHeader( &hTp->parser.adts, &hTp->asc[0], hBs, ignoreBufferFullness ); + if (err != TRANSPORTDEC_OK) { + if (err != TRANSPORTDEC_NOT_ENOUGH_BITS) { + err = TRANSPORTDEC_SYNC_ERROR; + } + } else { + errC = hTp->callbacks.cbUpdateConfig(hTp->callbacks.cbUpdateConfigData, &hTp->asc[0]); + if (errC != 0) { + if (errC == TRANSPORTDEC_NEED_TO_RESTART) { + err = TRANSPORTDEC_NEED_TO_RESTART; + goto bail; + } else { + err = TRANSPORTDEC_SYNC_ERROR; } + } else { + fConfigFound = 1; + hTp->numberOfRawDataBlocks = hTp->parser.adts.bs.num_raw_blocks+1; } } + } + else { + /* Reset CRC because the next bits are the beginning of a raw_data_block() */ + FDKcrcReset(&hTp->parser.adts.crcInfo); + hTp->parser.adts.bs.num_pce_bits = 0; + } + if (err == TRANSPORTDEC_OK) { + hTp->numberOfRawDataBlocks--; + rawDataBlockLength = adtsRead_GetRawDataBlockLength(&hTp->parser.adts, (hTp->parser.adts.bs.num_raw_blocks-hTp->numberOfRawDataBlocks)); + if (rawDataBlockLength <= 0) { + /* No further frame traversal possible. */ + fTraverseMoreFrames = 0; + } + syncLayerFrameBits = (hTp->parser.adts.bs.frame_length<<3) - (startPos - FDKgetValidBits(hBs)) - syncLength; + if (syncLayerFrameBits <= 0) { + err = TRANSPORTDEC_SYNC_ERROR; + } + } else { + hTp->numberOfRawDataBlocks = 0; + } + break; + case TT_MP4_LOAS: + if (hTp->numberOfRawDataBlocks <= 0) + { + syncLayerFrameBits = FDKreadBits(hBs, 13); + hTp->parser.latm.m_audioMuxLengthBytes = syncLayerFrameBits; + syncLayerFrameBits <<= 3; + } + case TT_MP4_LATM_MCP1: + case TT_MP4_LATM_MCP0: + if (hTp->numberOfRawDataBlocks <= 0) + { + hTp->globalFramePos = FDKgetValidBits(hBs); - /* Do global LOAS/LATM audioMuxElement byte alignment */ - FDKbyteAlign(hBs, hTp->globalFramePos); + err = CLatmDemux_Read( + hBs, + &hTp->parser.latm, + hTp->transportFmt, + &hTp->callbacks, + hTp->asc, + &fConfigFound, + ignoreBufferFullness); + + if (err != TRANSPORTDEC_OK) { + if (err != TRANSPORTDEC_NOT_ENOUGH_BITS) { + err = TRANSPORTDEC_SYNC_ERROR; + } + } else { + hTp->numberOfRawDataBlocks = CLatmDemux_GetNrOfSubFrames(&hTp->parser.latm); + if (hTp->transportFmt == TT_MP4_LOAS) { + syncLayerFrameBits -= startPos - FDKgetValidBits(hBs) - (13); + } + } + } else { + err = CLatmDemux_ReadPayloadLengthInfo(hBs, &hTp->parser.latm); + if (err != TRANSPORTDEC_OK) { + err = TRANSPORTDEC_SYNC_ERROR; + } + } + if (err == TRANSPORTDEC_OK) { + rawDataBlockLength = CLatmDemux_GetFrameLengthInBits(&hTp->parser.latm); + hTp->numberOfRawDataBlocks--; + } else { + hTp->numberOfRawDataBlocks = 0; } break; default: + { + syncLayerFrameBits = 0; + } break; } +bail: + + *pRawDataBlockLength = rawDataBlockLength; + + if (pHeaderBits != NULL) { + *pHeaderBits += startPos - (INT)FDKgetValidBits(hBs); + } + if (pfConfigFound != NULL) { + *pfConfigFound = fConfigFound; + } + + if (pfTraverseMoreFrames != NULL) { + *pfTraverseMoreFrames = fTraverseMoreFrames; + } + if (pSyncLayerFrameBits != NULL) { + *pSyncLayerFrameBits = syncLayerFrameBits; + } + if (pfConfigFound != NULL) { + *pfConfigFound = fConfigFound; + } + return err; } - /* How many bits to advance for synchronization search. */ #define TPDEC_SYNCSKIP 8 @@ -493,9 +669,9 @@ TRANSPORTDEC_ERROR synchronization( INT rawDataBlockLength = 0, rawDataBlockLengthPrevious; INT totalBits; INT headerBits = 0, headerBitsFirstFrame = 0, headerBitsPrevious; - INT numFramesTraversed = 0, fTraverseMoreFrames, fConfigFound = 0, startPos, startPosFirstFrame = -1; + INT numFramesTraversed = 0, fTraverseMoreFrames, fConfigFound = (hTp->flags & TPDEC_CONFIG_FOUND), startPosFirstFrame = -1; INT numRawDataBlocksFirstFrame = 0, numRawDataBlocksPrevious, globalFramePosFirstFrame = 0, rawDataBlockLengthFirstFrame = 0; - INT ignoreBufferFullness = hTp->flags & (TPDEC_IGNORE_BUFFERFULLNESS|TPDEC_SYNCOK); + INT ignoreBufferFullness = hTp->flags & (TPDEC_LOST_FRAMES_PENDING|TPDEC_IGNORE_BUFFERFULLNESS|TPDEC_SYNCOK); /* Synch parameters */ INT syncLength; /* Length of sync word in bits */ @@ -506,10 +682,7 @@ TRANSPORTDEC_ERROR synchronization( totalBits = (INT)FDKgetValidBits(hBs); if (totalBits <= 0) { - /* Return sync error, because this happens only in case of severly damaged bit streams. - Returning TRANSPORTDEC_NOT_ENOUGH_BITS here is very dangerous. */ - /* numberOfRawDataBlocks must be always reset in case of sync errors. */ - hTp->numberOfRawDataBlocks = 0; + err = TRANSPORTDEC_NOT_ENOUGH_BITS; goto bail; } @@ -579,100 +752,22 @@ TRANSPORTDEC_ERROR synchronization( numRawDataBlocksPrevious = hTp->numberOfRawDataBlocks; /* Parse transport header (raw data block granularity) */ - startPos = FDKgetValidBits(hBs); if (err == TRANSPORTDEC_OK ) { - switch (hTp->transportFmt) { - case TT_MP4_ADTS: - if (hTp->numberOfRawDataBlocks <= 0) - { - int errC; - - /* Parse ADTS header */ - err = adtsRead_DecodeHeader( &hTp->parser.adts, &hTp->asc[0], hBs, ignoreBufferFullness ); - if (err != TRANSPORTDEC_OK) { - if (err != TRANSPORTDEC_NOT_ENOUGH_BITS) { - err = TRANSPORTDEC_SYNC_ERROR; - } - } else { - errC = hTp->callbacks.cbUpdateConfig(hTp->callbacks.cbUpdateConfigData, &hTp->asc[0]); - if (errC != 0) { - err = TRANSPORTDEC_SYNC_ERROR; - } else { - hTp->numberOfRawDataBlocks = hTp->parser.adts.bs.num_raw_blocks+1; - /* CAUTION: The PCE (if available) is declared to be a part of the header! */ - hTp->globalFramePos = FDKgetValidBits(hBs) + hTp->parser.adts.bs.num_pce_bits; - } - } - } - else { - /* Reset CRC because the next bits are the beginning of a raw_data_block() */ - FDKcrcReset(&hTp->parser.adts.crcInfo); - hTp->globalFramePos = FDKgetValidBits(hBs); - } - if (err == TRANSPORTDEC_OK) { - hTp->numberOfRawDataBlocks--; - rawDataBlockLength = adtsRead_GetRawDataBlockLength(&hTp->parser.adts, (hTp->parser.adts.bs.num_raw_blocks-hTp->numberOfRawDataBlocks)); - syncLayerFrameBits = (hTp->parser.adts.bs.frame_length<<3) - (startPos - FDKgetValidBits(hBs)) - syncLength; - if (syncLayerFrameBits <= 0) { - err = TRANSPORTDEC_SYNC_ERROR; - } - } else { - hTp->numberOfRawDataBlocks = 0; - } - break; - case TT_MP4_LOAS: - if (hTp->numberOfRawDataBlocks <= 0) - { - syncLayerFrameBits = FDKreadBits(hBs, 13); - hTp->parser.latm.m_audioMuxLengthBytes = syncLayerFrameBits; - syncLayerFrameBits <<= 3; - } - case TT_MP4_LATM_MCP1: - case TT_MP4_LATM_MCP0: - if (hTp->numberOfRawDataBlocks <= 0) - { - hTp->globalFramePos = FDKgetValidBits(hBs); - - err = CLatmDemux_Read( - hBs, - &hTp->parser.latm, - hTp->transportFmt, - &hTp->callbacks, - hTp->asc, - ignoreBufferFullness); - - if (err != TRANSPORTDEC_OK) { - if (err != TRANSPORTDEC_NOT_ENOUGH_BITS) { - err = TRANSPORTDEC_SYNC_ERROR; - } - } else { - hTp->numberOfRawDataBlocks = CLatmDemux_GetNrOfSubFrames(&hTp->parser.latm); - syncLayerFrameBits -= startPos - FDKgetValidBits(hBs) - (13); - } - } else { - err = CLatmDemux_ReadPayloadLengthInfo(hBs, &hTp->parser.latm); - if (err != TRANSPORTDEC_OK) { - err = TRANSPORTDEC_SYNC_ERROR; - } - } - if (err == TRANSPORTDEC_OK) { - rawDataBlockLength = CLatmDemux_GetFrameLengthInBits(&hTp->parser.latm); - hTp->numberOfRawDataBlocks--; - } else { - hTp->numberOfRawDataBlocks = 0; - } - break; - default: - { - syncLayerFrameBits = 0; - } - break; - } + err = transportDec_readHeader( + hTp, + hBs, + syncLength, + ignoreBufferFullness, + &rawDataBlockLength, + &fTraverseMoreFrames, + &syncLayerFrameBits, + &fConfigFound, + &headerBits + ); } - headerBits += startPos - (INT)FDKgetValidBits(hBs); bitsAvail -= headerBits; checkLengthBits = syncLayerFrameBits; @@ -702,12 +797,12 @@ TRANSPORTDEC_ERROR synchronization( /* Enforce re-sync of transport headers. */ hTp->numberOfRawDataBlocks = 0; - /* Ensure that the bit amount lands and a multiple of TPDEC_SYNCSKIP */ + /* Ensure that the bit amount lands at a multiple of TPDEC_SYNCSKIP */ bits = (bitsAvail + headerBits) % TPDEC_SYNCSKIP; /* Rewind - TPDEC_SYNCSKIP, in order to look for a synch one bit ahead next time. */ FDKpushBiDirectional(hBs, -(headerBits - TPDEC_SYNCSKIP) + bits); bitsAvail += headerBits - TPDEC_SYNCSKIP - bits; - headerBits = 0; + headerBits = 0; } /* Frame traversal */ @@ -731,7 +826,15 @@ TRANSPORTDEC_ERROR synchronization( } /* Break when config was found or it is not possible anymore to find a config */ - if (startPosFirstFrame != -1 && (fConfigFound || err != TRANSPORTDEC_OK)) { + if (startPosFirstFrame != -1 && (fConfigFound || err != TRANSPORTDEC_OK)) + { + /* In case of ECD and sync error, do not rewind anywhere. */ + if (err == TRANSPORTDEC_SYNC_ERROR) + { + startPosFirstFrame = -1; + fConfigFound = 0; + numFramesTraversed = 0; + } break; } } @@ -759,7 +862,7 @@ TRANSPORTDEC_ERROR synchronization( } /* Additional burst data mode buffer fullness check. */ - if ( !(hTp->flags & (TPDEC_IGNORE_BUFFERFULLNESS|TPDEC_SYNCOK)) && err == TRANSPORTDEC_OK) { + if ( !(hTp->flags & (TPDEC_LOST_FRAMES_PENDING|TPDEC_IGNORE_BUFFERFULLNESS|TPDEC_SYNCOK)) && err == TRANSPORTDEC_OK) { err = additionalHoldOffNeeded(hTp, transportDec_GetBufferFullness(hTp), FDKgetValidBits(hBs) - syncLayerFrameBits); if (err == TRANSPORTDEC_NOT_ENOUGH_BITS) { hTp->holdOffFrames++; @@ -789,10 +892,22 @@ TRANSPORTDEC_ERROR synchronization( bail: hTp->auLength[0] = rawDataBlockLength; + /* Detect pointless TRANSPORTDEC_NOT_ENOUGH_BITS error case, were the bit buffer is already full, + or no new burst packet fits. Recover by advancing the bit buffer. */ + if ( (TRANSPORTDEC_NOT_ENOUGH_BITS == err) && (FDKgetValidBits(hBs) >= ((TRANSPORTDEC_INBUF_SIZE*8 - ((hTp->avgBitRate*hTp->burstPeriod)/1000)) - 7)) ) + { + FDKpushFor(hBs, TPDEC_SYNCSKIP); + err = TRANSPORTDEC_SYNC_ERROR; + } + if (err == TRANSPORTDEC_OK) { hTp->flags |= TPDEC_SYNCOK; } + if (fConfigFound) { + hTp->flags |= TPDEC_CONFIG_FOUND; + } + if (pHeaderBits != NULL) { *pHeaderBits = headerBits; } @@ -925,6 +1040,10 @@ TRANSPORTDEC_ERROR transportDec_ReadAccessUnit( const HANDLE_TRANSPORTDEC hTp, c hBs = &hTp->bitStream[layer]; + if ((INT)FDKgetValidBits(hBs) <= 0) { + err = TRANSPORTDEC_NOT_ENOUGH_BITS; + } + switch (hTp->transportFmt) { case TT_MP4_ADIF: @@ -964,20 +1083,26 @@ TRANSPORTDEC_ERROR transportDec_ReadAccessUnit( const HANDLE_TRANSPORTDEC hTp, c break; case TT_MP4_RAW: - if ((INT)FDKgetValidBits(hBs) <= 0 && layer == 0) { - err = TRANSPORTDEC_NOT_ENOUGH_BITS; - } /* One Access Unit was filled into buffer. So get the length out of the buffer. */ hTp->auLength[layer] = FDKgetValidBits(hBs); hTp->flags |= TPDEC_SYNCOK; break; + case TT_MP4_LATM_MCP0: + case TT_MP4_LATM_MCP1: + { + int fConfigFound = hTp->flags & TPDEC_CONFIG_FOUND; + err = transportDec_readHeader(hTp, hBs, 0, 1, &hTp->auLength[layer], NULL, NULL, &fConfigFound, NULL); + if (fConfigFound) { + hTp->flags |= TPDEC_CONFIG_FOUND; + } + } + break; + case TT_RSVD50: case TT_MP4_ADTS: case TT_MP4_LOAS: - case TT_MP4_LATM_MCP0: - case TT_MP4_LATM_MCP1: err = transportDec_readStream(hTp, layer); break; @@ -1026,13 +1151,10 @@ TRANSPORTDEC_ERROR transportDec_EndAccessUnit(HANDLE_TRANSPORTDEC hTp) { TRANSPORTDEC_ERROR err = TRANSPORTDEC_OK; + err = transportDec_AdjustEndOfAccessUnit(hTp); switch (hTp->transportFmt) { - case TT_MP4_LOAS: - case TT_MP4_LATM_MCP0: - case TT_MP4_LATM_MCP1: - break; default: break; } @@ -1082,8 +1204,11 @@ TRANSPORTDEC_ERROR transportDec_SetParam ( const HANDLE_TRANSPORTDEC hTp, FDKresetBitbuffer(&hTp->bitStream[i]); hTp->auLength[i] = 0; hTp->accessUnitAnchor[i] = 0; - } + } hTp->flags &= ~(TPDEC_SYNCOK|TPDEC_LOST_FRAMES_PENDING); + if (hTp->transportFmt != TT_MP4_ADIF) { + hTp->flags &= ~TPDEC_CONFIG_FOUND; + } hTp->remainder = 0; hTp->avgBitRate = 0; hTp->missingAccessUnits = 0; @@ -1117,7 +1242,7 @@ void transportDec_Close(HANDLE_TRANSPORTDEC *phTp) if (phTp != NULL) { if (*phTp != NULL) { - if ((*phTp)->transportFmt != TT_MP4_RAW && (*phTp)->transportFmt != TT_DRM) { + if ( ! TT_IS_PACKET((*phTp)->transportFmt) ) { FreeRam_TransportDecoderBuffer(&(*phTp)->bsBuffer); } if (*phTp != NULL) { @@ -1188,13 +1313,8 @@ TRANSPORTDEC_ERROR transportDec_CrcCheck(HANDLE_TRANSPORTDEC pTp) if ( (pTp->parser.adts.bs.num_raw_blocks > 0) && (pTp->parser.adts.bs.protection_absent == 0) ) { HANDLE_FDK_BITSTREAM hBs = &pTp->bitStream[0]; - int bitDiff; - /* Calculate possible offset to CRC value. */ - bitDiff = pTp->parser.adts.rawDataBlockDist[pTp->parser.adts.bs.num_raw_blocks-pTp->numberOfRawDataBlocks]<<3; - bitDiff -= pTp->globalFramePos - FDKgetValidBits(hBs) + 16; - FDKpushBiDirectional(hBs, bitDiff); - pTp->parser.adts.crcReadValue = FDKreadBits(hBs, 16); + transportDec_AdjustEndOfAccessUnit(pTp); } return adtsRead_CrcCheck(&pTp->parser.adts); default: diff --git a/libMpegTPDec/src/version b/libMpegTPDec/src/version index d998903..91c4c67 100644 --- a/libMpegTPDec/src/version +++ b/libMpegTPDec/src/version @@ -2,7 +2,7 @@ /* library info */ #define TP_LIB_VL0 2 #define TP_LIB_VL1 3 -#define TP_LIB_VL2 1 +#define TP_LIB_VL2 2 #define TP_LIB_TITLE "MPEG Transport" #define TP_LIB_BUILD_DATE __DATE__ #define TP_LIB_BUILD_TIME __TIME__ diff --git a/libSBRdec/src/env_dec.cpp b/libSBRdec/src/env_dec.cpp index 5aa5ba7..24b2d3b 100644 --- a/libSBRdec/src/env_dec.cpp +++ b/libSBRdec/src/env_dec.cpp @@ -624,8 +624,8 @@ timeCompensateFirstEnvelope (HANDLE_SBR_HEADER_DATA hHeaderData, /*!< Static con deltaExp = FDK_getNumOctavesDiv8(newLen, refLen); - /* Shift by -3 to rescale ld-table, 1-ampRes to enable coarser steps */ - shift = (FRACT_BITS - 1 - ENV_EXP_FRACT + 1 - h_sbr_data->ampResolutionCurrentFrame - 3); + /* Shift by -3 to rescale ld-table, ampRes-1 to enable coarser steps */ + shift = (FRACT_BITS - 1 - ENV_EXP_FRACT - 1 + h_sbr_data->ampResolutionCurrentFrame - 3); deltaExp = deltaExp >> shift; pFrameInfo->borders[0] = estimatedStartPos; pFrameInfo->bordersNoise[0] = estimatedStartPos; diff --git a/libSBRdec/src/lpp_tran.cpp b/libSBRdec/src/lpp_tran.cpp index 2e59205..117e739 100644 --- a/libSBRdec/src/lpp_tran.cpp +++ b/libSBRdec/src/lpp_tran.cpp @@ -875,22 +875,8 @@ resetLppTransposer (HANDLE_SBR_LPP_TRANS hLppTrans, /*!< Handle of lpp transpos /* * Initialize the patching parameter */ - desiredBorder = 21; - if (fs < 92017) { - desiredBorder = 23; - } - if (fs < 75132) { - desiredBorder = 32; - } - if (fs < 55426) { - desiredBorder = 43; - } - if (fs < 46009) { - desiredBorder = 46; - } - if (fs < 35777) { - desiredBorder = 64; - } + /* ISO/IEC 14496-3 (Figure 4.48): goalSb = round( 2.048e6 / fs ) */ + desiredBorder = (((2048000*2) / fs) + 1) >> 1; desiredBorder = findClosestEntry(desiredBorder, v_k_master, numMaster, 1); /* Adapt region to master-table */ diff --git a/libSBRdec/src/sbrdecoder.cpp b/libSBRdec/src/sbrdecoder.cpp index ecddec3..26b2ea2 100644 --- a/libSBRdec/src/sbrdecoder.cpp +++ b/libSBRdec/src/sbrdecoder.cpp @@ -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 2 +#define SBRDECODER_LIB_VL2 3 #define SBRDECODER_LIB_TITLE "SBR Decoder" #define SBRDECODER_LIB_BUILD_DATE __DATE__ #define SBRDECODER_LIB_BUILD_TIME __TIME__ @@ -552,7 +552,7 @@ bail: sbrDecoder_DestroyElement( self, elementIndex ); } else if (self->pSbrElement[elementIndex] != NULL) { /* Set error flag to trigger concealment */ - self->pSbrElement[elementIndex]->frameErrorFlag[self->pSbrElement[elementIndex]->useFrameSlot] = 1;; + self->pSbrElement[elementIndex]->frameErrorFlag[self->pSbrElement[elementIndex]->useFrameSlot] = 1; } } @@ -731,6 +731,12 @@ SBR_ERROR sbrDecoder_SetParam (HANDLE_SBRDECODER self, case SBR_BS_INTERRUPTION: { int elementIndex; + + if (self == NULL) { + errorStatus = SBRDEC_NOT_INITIALIZED; + break; + } + /* Loop over SBR elements */ for (elementIndex = 0; elementIndex < self->numSbrElements; elementIndex++) { diff --git a/libSYS/include/FDK_audio.h b/libSYS/include/FDK_audio.h index b31dadc..e38a326 100644 --- a/libSYS/include/FDK_audio.h +++ b/libSYS/include/FDK_audio.h @@ -144,6 +144,12 @@ typedef enum } TRANSPORT_TYPE; +#define TT_IS_PACKET(x) \ + ( ((x) == TT_MP4_RAW) \ + || ((x) == TT_DRM) \ + || ((x) == TT_MP4_LATM_MCP0) \ + || ((x) == TT_MP4_LATM_MCP1) ) + /** * Audio Object Type definitions. */ diff --git a/libSYS/src/genericStds.cpp b/libSYS/src/genericStds.cpp index 07dd3e3..92887d1 100644 --- a/libSYS/src/genericStds.cpp +++ b/libSYS/src/genericStds.cpp @@ -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 1 +#define SYS_LIB_VL2 2 #define SYS_LIB_TITLE "System Integration Library" #define SYS_LIB_BUILD_DATE __DATE__ #define SYS_LIB_BUILD_TIME __TIME__ -- cgit v1.2.3