diff options
Diffstat (limited to 'libMpegTPDec/src/tpdec_latm.cpp')
-rw-r--r-- | libMpegTPDec/src/tpdec_latm.cpp | 364 |
1 files changed, 364 insertions, 0 deletions
diff --git a/libMpegTPDec/src/tpdec_latm.cpp b/libMpegTPDec/src/tpdec_latm.cpp new file mode 100644 index 0000000..28daebc --- /dev/null +++ b/libMpegTPDec/src/tpdec_latm.cpp @@ -0,0 +1,364 @@ +/***************************** MPEG-4 AAC Decoder ************************** + + (C) Copyright Fraunhofer IIS (2004) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + $Id$ + Author(s): Daniel Homm + Description: + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + +******************************************************************************/ + +#include "tpdec_latm.h" + + +#include "FDK_bitstream.h" + + +#define TPDEC_TRACKINDEX(p,l) (2*(p) + (l)) + +static +UINT CLatmDemux_GetValue(HANDLE_FDK_BITSTREAM bs) +{ + UCHAR bytesForValue = 0, tmp = 0; + int value = 0; + + bytesForValue = (UCHAR) FDKreadBits(bs,2); + + for (UINT i=0; i<=bytesForValue; i++) { + value <<= 8; + tmp = (UCHAR) FDKreadBits(bs,8); + value += tmp; + } + + return value; +} + + +static +TRANSPORTDEC_ERROR CLatmDemux_ReadAudioMuxElement( + HANDLE_FDK_BITSTREAM bs, + CLatmDemux *pLatmDemux, + int m_muxConfigPresent, + CSTpCallBacks *pTpDecCallbacks, + CSAudioSpecificConfig *pAsc + ) +{ + TRANSPORTDEC_ERROR ErrorStatus = TRANSPORTDEC_OK; + + if (m_muxConfigPresent) { + pLatmDemux->m_useSameStreamMux = FDKreadBits(bs,1); + + if (!pLatmDemux->m_useSameStreamMux) { + if ((ErrorStatus = CLatmDemux_ReadStreamMuxConfig(bs, pLatmDemux, pTpDecCallbacks, pAsc))) { + return (ErrorStatus); + } + } + } + + if (pLatmDemux->m_AudioMuxVersionA == 0) { + /* Do only once per call, because parsing and decoding is done in-line. */ + if ((ErrorStatus = CLatmDemux_ReadPayloadLengthInfo(bs,pLatmDemux))) { + return (ErrorStatus); + } + } else { + /* audioMuxVersionA > 0 is reserved for future extensions */ + ErrorStatus = TRANSPORTDEC_UNSUPPORTED_FORMAT; + } + + return (ErrorStatus); +} + +TRANSPORTDEC_ERROR CLatmDemux_Read( + HANDLE_FDK_BITSTREAM bs, + CLatmDemux *pLatmDemux, + TRANSPORT_TYPE tt, + CSTpCallBacks *pTpDecCallbacks, + CSAudioSpecificConfig *pAsc, + const INT ignoreBufferFullness + ) +{ + UINT cntBits; + UINT cmpBufferFullness; + UINT audioMuxLengthBytesLast = 0; + TRANSPORTDEC_ERROR ErrorStatus = TRANSPORTDEC_OK; + + cntBits = FDKgetValidBits(bs); + + if ((INT)cntBits < MIN_LATM_HEADERLENGTH) { + return TRANSPORTDEC_NOT_ENOUGH_BITS; + } + + if ((ErrorStatus = CLatmDemux_ReadAudioMuxElement(bs, pLatmDemux, (tt != TT_MP4_LATM_MCP0), pTpDecCallbacks, pAsc))) + return (ErrorStatus); + + if (!ignoreBufferFullness) + { + cmpBufferFullness = 24+audioMuxLengthBytesLast*8 + + pLatmDemux->m_linfo[0][0].m_bufferFullness* pAsc[TPDEC_TRACKINDEX(0,0)].m_channelConfiguration*32; + + /* evaluate buffer fullness */ + + if (pLatmDemux->m_linfo[0][0].m_bufferFullness != 0xFF) + { + if (!pLatmDemux->BufferFullnessAchieved) + { + if (cntBits < cmpBufferFullness) + { + /* condition for start of decoding is not fulfilled */ + + /* the current frame will not be decoded */ + return TRANSPORTDEC_NOT_ENOUGH_BITS; + } + else + { + pLatmDemux->BufferFullnessAchieved = 1; + } + } + } + } + + return (ErrorStatus); +} + + +TRANSPORTDEC_ERROR CLatmDemux_ReadStreamMuxConfig( + HANDLE_FDK_BITSTREAM bs, + CLatmDemux *pLatmDemux, + CSTpCallBacks *pTpDecCallbacks, + CSAudioSpecificConfig *pAsc + ) +{ + LATM_LAYER_INFO *p_linfo = NULL; + TRANSPORTDEC_ERROR ErrorStatus = TRANSPORTDEC_OK; + + pLatmDemux->m_AudioMuxVersion = FDKreadBits(bs,1); + + if (pLatmDemux->m_AudioMuxVersion == 0) { + pLatmDemux->m_AudioMuxVersionA = 0; + } else { + pLatmDemux->m_AudioMuxVersionA = FDKreadBits(bs,1); + } + + if (pLatmDemux->m_AudioMuxVersionA == 0) { + if (pLatmDemux->m_AudioMuxVersion == 1) { + pLatmDemux->m_taraBufferFullness = CLatmDemux_GetValue(bs); + } + pLatmDemux->m_allStreamsSameTimeFraming = FDKreadBits(bs,1); + pLatmDemux->m_noSubFrames = FDKreadBits(bs,6) + 1; + pLatmDemux->m_numProgram = FDKreadBits(bs,4) + 1; + + if (pLatmDemux->m_numProgram > 1) { + return TRANSPORTDEC_UNSUPPORTED_FORMAT; + } + + int idCnt = 0; + for (UINT prog = 0; prog < pLatmDemux->m_numProgram; prog++) { + pLatmDemux->m_numLayer = FDKreadBits(bs,3) + 1; + if (pLatmDemux->m_numLayer > 2) { + return TRANSPORTDEC_UNSUPPORTED_FORMAT; + } + + for (UINT lay = 0; lay < pLatmDemux->m_numLayer; lay++) { + p_linfo = &pLatmDemux->m_linfo[prog][lay]; + + p_linfo->m_streamID = idCnt++; + p_linfo->m_frameLengthInBits = 0; + + if( (prog == 0) && (lay == 0) ) { + pLatmDemux->m_useSameConfig = 0; + } else { + pLatmDemux->m_useSameConfig = FDKreadBits(bs,1); + } + + if (pLatmDemux->m_useSameConfig) { + if (lay > 1) { + FDKmemcpy(&pAsc[TPDEC_TRACKINDEX(prog,lay)], &pAsc[TPDEC_TRACKINDEX(prog,lay-1)], sizeof(CSAudioSpecificConfig)); + } else { + return TRANSPORTDEC_PARSE_ERROR; + } + } else { + if (pLatmDemux->m_AudioMuxVersion == 1) + { + FDK_BITSTREAM tmpBs; + UINT ascStartPos, ascLen=0; + + ascLen = CLatmDemux_GetValue(bs); + ascStartPos = FDKgetValidBits(bs); + tmpBs = *bs; + FDKsyncCache(&tmpBs); + tmpBs.hBitBuf.ValidBits = ascLen; + + /* Read ASC */ + if ((ErrorStatus = AudioSpecificConfig_Parse(&pAsc[TPDEC_TRACKINDEX(prog,lay)], &tmpBs, 1, pTpDecCallbacks))) { + return (ErrorStatus); + } + + /* The field p_linfo->m_ascLen could be wrong, so check if */ + if ( 0 > (INT)FDKgetValidBits(&tmpBs)) { + return TRANSPORTDEC_PARSE_ERROR; + } + FDKpushFor(bs, ascLen); /* position bitstream after ASC */ + } + else { + /* Read ASC */ + if ((ErrorStatus = AudioSpecificConfig_Parse(&pAsc[TPDEC_TRACKINDEX(prog,lay)], bs, 0, pTpDecCallbacks))) { + return (ErrorStatus); + } + } + { + int cbError; + + cbError = pTpDecCallbacks->cbUpdateConfig(pTpDecCallbacks->cbUpdateConfigData, &pAsc[TPDEC_TRACKINDEX(prog,lay)]); + if (cbError != 0) { + return TRANSPORTDEC_UNKOWN_ERROR; + } + } + } + + p_linfo->m_frameLengthType = FDKreadBits(bs,3); + switch( p_linfo->m_frameLengthType ) { + case 0: + p_linfo->m_bufferFullness = FDKreadBits(bs,8); + + if (!pLatmDemux->m_allStreamsSameTimeFraming) { + if ((lay > 0) && (pAsc[TPDEC_TRACKINDEX(prog,lay)].m_aot == AOT_AAC_SCAL || pAsc[TPDEC_TRACKINDEX(prog,lay)].m_aot == AOT_ER_AAC_SCAL)) { + return TRANSPORTDEC_UNSUPPORTED_FORMAT; + } + } + break; + case 1: + /* frameLength = FDKreadBits(bs,9); */ + case 3: + case 4: + case 5: + /* CELP */ + case 6: + case 7: + /* HVXC */ + default: + return TRANSPORTDEC_PARSE_ERROR; //_LATM_INVALIDFRAMELENGTHTYPE; + + } /* switch framelengthtype*/ + + } /* layer loop */ + } /* prog loop */ + + pLatmDemux->m_otherDataPresent = FDKreadBits(bs,1); + pLatmDemux->m_otherDataLength = 0; + + if (pLatmDemux->m_otherDataPresent) { + int otherDataLenEsc = 0; + do { + pLatmDemux->m_otherDataLength <<= 8; // *= 256 + otherDataLenEsc = FDKreadBits(bs,1); + pLatmDemux->m_otherDataLength += FDKreadBits(bs,8); + } while (otherDataLenEsc); + } + + pLatmDemux->m_crcCheckPresent = FDKreadBits(bs,1); + pLatmDemux->m_crcCheckSum = 0; + + if (pLatmDemux->m_crcCheckPresent) { + pLatmDemux->m_crcCheckSum = FDKreadBits(bs,8); + } + + } + else { + /* audioMuxVersionA > 0 is reserved for future extensions */ + ErrorStatus = TRANSPORTDEC_UNSUPPORTED_FORMAT; + } + return (ErrorStatus); +} + +TRANSPORTDEC_ERROR CLatmDemux_ReadPayloadLengthInfo(HANDLE_FDK_BITSTREAM bs, CLatmDemux *pLatmDemux) +{ + TRANSPORTDEC_ERROR ErrorStatus = TRANSPORTDEC_OK; + int totalPayloadBits = 0; + + if( pLatmDemux->m_allStreamsSameTimeFraming == 1 ) { + for (UINT prog=0; prog<pLatmDemux->m_numProgram; prog++ ) { + for (UINT lay=0; lay<pLatmDemux->m_numLayer; lay++ ) { + LATM_LAYER_INFO *p_linfo = &pLatmDemux->m_linfo[prog][lay]; + + switch (p_linfo->m_frameLengthType ) { + case 0: + p_linfo->m_frameLengthInBits = CLatmDemux_ReadAuChunkLengthInfo(bs); + totalPayloadBits += p_linfo->m_frameLengthInBits; + break; + case 3: + case 5: + case 7: + default: + return TRANSPORTDEC_PARSE_ERROR; //AAC_DEC_LATM_INVALIDFRAMELENGTHTYPE; + } + } + } + } + else { + ErrorStatus = TRANSPORTDEC_PARSE_ERROR; //AAC_DEC_LATM_TIMEFRAMING; + } + if ((INT)FDKgetValidBits(bs) < totalPayloadBits) { + return TRANSPORTDEC_NOT_ENOUGH_BITS; + } + if (pLatmDemux->m_audioMuxLengthBytes > 0 && totalPayloadBits > pLatmDemux->m_audioMuxLengthBytes*8) { + return TRANSPORTDEC_PARSE_ERROR; + } + return (ErrorStatus); +} + +int CLatmDemux_ReadAuChunkLengthInfo(HANDLE_FDK_BITSTREAM bs) +{ + UCHAR endFlag; + int len = 0; + + do { + UCHAR tmp = (UCHAR) FDKreadBits(bs,8); + endFlag = (tmp < 255); + + len += tmp; + + } while( endFlag == 0 ); + + len <<= 3; /* convert from bytes to bits */ + + return len; +} + +int CLatmDemux_GetFrameLengthInBits(CLatmDemux *pLatmDemux) +{ + return pLatmDemux->m_linfo[0][0].m_frameLengthInBits; +} + +int CLatmDemux_GetOtherDataPresentFlag(CLatmDemux *pLatmDemux) +{ + return pLatmDemux->m_otherDataPresent ? 1 : 0; +} + +int CLatmDemux_GetOtherDataLength(CLatmDemux *pLatmDemux) +{ + return pLatmDemux->m_otherDataLength; +} + +UINT CLatmDemux_GetNrOfSubFrames(CLatmDemux *pLatmDemux) +{ + return pLatmDemux->m_noSubFrames; +} + |