diff options
author | Jean-Michel Trivi <jmtrivi@google.com> | 2013-08-27 16:28:09 -0700 |
---|---|---|
committer | Jean-Michel Trivi <jmtrivi@google.com> | 2013-08-27 16:28:09 -0700 |
commit | 5016eb7f6582fbb2d72d79be782325a12df08864 (patch) | |
tree | bc2325ebc6840a20d25f35a0c5a6a13454d2e402 /libMpegTPDec | |
parent | b9774f90651be61065ae40171fc321f6ced60e49 (diff) | |
download | fdk-aac-5016eb7f6582fbb2d72d79be782325a12df08864.tar.gz fdk-aac-5016eb7f6582fbb2d72d79be782325a12df08864.tar.bz2 fdk-aac-5016eb7f6582fbb2d72d79be782325a12df08864.zip |
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
Diffstat (limited to 'libMpegTPDec')
-rw-r--r-- | libMpegTPDec/include/tpdec_lib.h | 21 | ||||
-rw-r--r-- | libMpegTPDec/src/tpdec_adts.cpp | 4 | ||||
-rw-r--r-- | libMpegTPDec/src/tpdec_asc.cpp | 147 | ||||
-rw-r--r-- | libMpegTPDec/src/tpdec_latm.cpp | 20 | ||||
-rw-r--r-- | libMpegTPDec/src/tpdec_latm.h | 13 | ||||
-rw-r--r-- | libMpegTPDec/src/tpdec_lib.cpp | 444 | ||||
-rw-r--r-- | libMpegTPDec/src/version | 2 |
7 files changed, 476 insertions, 175 deletions
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) ; @@ -369,6 +368,82 @@ INT transportDec_GetBufferFullness( const HANDLE_TRANSPORTDEC hTp ) } /** + * \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. * \param hTp transport decoder handle. @@ -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__ |