ref: 3331ff656676a43e5fd97327c569734399d5fa40
dir: /codec/decoder/core/src/au_parser.cpp/
/*! * \copy * Copyright (c) 2009-2013, Cisco Systems * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * * * \file au_parser.c * * \brief Interfaces introduced in Access Unit level based parser * * \date 03/10/2009 Created * ************************************************************************************* */ #include <string.h> #include "codec_def.h" #include "ls_defines.h" #include "macros.h" #include "au_parser.h" #include "decoder.h" #include "error_code.h" #include "dec_frame.h" #include "dec_golomb.h" #include "bit_stream.h" #include "utils.h" #include "codec_app_def.h" #include "memmgr_nal_unit.h" #include "decoder_core.h" #include "wels_common_basis.h" #include "decoder_core.h" #include "manage_dec_ref.h" #include "mem_align.h" namespace WelsDec { /*! ************************************************************************************* * \brief Start Code Prefix (0x 00 00 00 01) detection * * \param pBuf bitstream payload buffer * \param pOffset offset between NAL rbsp and original bitsteam that * start code prefix is seperated from. * \param iBufSize count size of buffer * * \return RBSP buffer of start code prefix exclusive * * \note N/A ************************************************************************************* */ uint8_t* DetectStartCodePrefix( const uint8_t *kpBuf, int32_t *pOffset, int32_t iBufSize ) { uint8_t *pBits = (uint8_t *)kpBuf; do { int32_t iIdx = 0; while( (iIdx<iBufSize) && (!(*pBits)) ){ ++ pBits; ++ iIdx; } if( iIdx >= iBufSize ) break; ++ iIdx; ++ pBits; if( (iIdx>=3) && ((*(pBits-1)) == 0x1) ){ *pOffset = ((uint32_t)pBits) - ((uint32_t)kpBuf); return pBits; } iBufSize -= iIdx; } while (1); return NULL; } /*! ************************************************************************************* * \brief to parse nal unit * * \param pCtx decoder context * \param pNalUnitHeader parsed result of NAL Unit Header to output * \param pSrcRbsp bitstream buffer to input * \param iSrcRbspLen length size of bitstream buffer payload * \param pSrcNal * \param iSrcNalLen * \param pConsumedBytes consumed bytes during parsing * * \return decoded bytes payload, might be (pSrcRbsp+1) if no escapes * * \note N/A ************************************************************************************* */ uint8_t* ParseNalHeader( PWelsDecoderContext pCtx, SNalUnitHeader *pNalUnitHeader, uint8_t *pSrcRbsp, int32_t iSrcRbspLen, uint8_t *pSrcNal, int32_t iSrcNalLen, int32_t* pConsumedBytes ) { PNalUnit pCurNal = NULL; uint8_t* pNal = pSrcRbsp; int32_t iNalSize = iSrcRbspLen; PBitStringAux pBs = NULL; bool_t bExtensionFlag = false; int32_t iErr = ERR_NONE; int32_t iBitSize = 0; pNalUnitHeader->eNalUnitType = NAL_UNIT_UNSPEC_0;//SHOULD init it. because pCtx->sCurNalHead is common variable. //remove the consecutive ZERO at the end of current NAL in the reverse order.--2011.6.1 { int32_t iIndex = iSrcRbspLen - 1; uint8_t uiBsZero = 0; while ( iIndex >= 0 ) { uiBsZero = pSrcRbsp[iIndex]; if ( 0 == uiBsZero ) { --iNalSize; --iIndex; } else { break; } } } pNalUnitHeader->uiForbiddenZeroBit = (uint8_t)(pNal[0] >> 7); // uiForbiddenZeroBit if ( pNalUnitHeader->uiForbiddenZeroBit )//2010.4.14 { return NULL; //uiForbiddenZeroBit should always equal to 0 } pNalUnitHeader->uiNalRefIdc = (uint8_t)(pNal[0] >> 5); // uiNalRefIdc pNalUnitHeader->eNalUnitType = (ENalUnitType)(pNal[0] & 0x1f); // eNalUnitType ++pNal; --iNalSize; ++(*pConsumedBytes); #ifdef DEBUG_PARSE_INFO WelsLog(pCtx, WELS_LOG_INFO, "nal type: %d \n", pNalUnitHeader->eNalUnitType); #endif if ( !(IS_SEI_NAL(pNalUnitHeader->eNalUnitType) || IS_SPS_NAL(pNalUnitHeader->eNalUnitType) || pCtx->bSpsExistAheadFlag) ) { WelsLog( pCtx, WELS_LOG_WARNING, "parse_nal(), no exist Sequence Parameter Sets ahead of sequence when try to decode NAL(type:%d).\n", pNalUnitHeader->eNalUnitType); pCtx->iErrorCode = dsNoParamSets; return NULL; } if ( !(IS_SEI_NAL(pNalUnitHeader->eNalUnitType) || IS_PARAM_SETS_NALS(pNalUnitHeader->eNalUnitType) || pCtx->bPpsExistAheadFlag) ) { WelsLog( pCtx, WELS_LOG_WARNING, "parse_nal(), no exist Picture Parameter Sets ahead of sequence when try to decode NAL(type:%d).\n", pNalUnitHeader->eNalUnitType); pCtx->iErrorCode = dsNoParamSets; return NULL; } if ( (IS_VCL_NAL_AVC_BASE(pNalUnitHeader->eNalUnitType) && !(pCtx->bSpsExistAheadFlag || pCtx->bPpsExistAheadFlag)) || (IS_NEW_INTRODUCED_NAL(pNalUnitHeader->eNalUnitType) && !(pCtx->bSpsExistAheadFlag || pCtx->bSubspsExistAheadFlag || pCtx->bPpsExistAheadFlag) ) ) { WelsLog( pCtx, WELS_LOG_WARNING, "ParseNalHeader(), no exist Parameter Sets ahead of sequence when try to decode slice(type:%d).\n", pNalUnitHeader->eNalUnitType); pCtx->iErrorCode |= dsNoParamSets; return NULL; } switch(pNalUnitHeader->eNalUnitType){ case NAL_UNIT_SEI: if ( pCtx->pAccessUnitList->uiAvailUnitsNum > 0 ) { pCtx->pAccessUnitList->uiEndPos = pCtx->pAccessUnitList->uiAvailUnitsNum - 1; pCtx->bAuReadyFlag = true; } break; case NAL_UNIT_SPS: if ( pCtx->pAccessUnitList->uiAvailUnitsNum > 0 ) { pCtx->pAccessUnitList->uiEndPos = pCtx->pAccessUnitList->uiAvailUnitsNum - 1; pCtx->bAuReadyFlag = true; } break; case NAL_UNIT_PREFIX: pCurNal = &pCtx->sPrefixNal; if ( iNalSize < NAL_UNIT_HEADER_EXT_SIZE ) { return NULL; } DecodeNalHeaderExt( pCurNal, pNal ); pNal += NAL_UNIT_HEADER_EXT_SIZE; iNalSize -= NAL_UNIT_HEADER_EXT_SIZE; *pConsumedBytes += NAL_UNIT_HEADER_EXT_SIZE; pCurNal->sNalHeaderExt.sNalUnitHeader.uiForbiddenZeroBit = pNalUnitHeader->uiForbiddenZeroBit; pCurNal->sNalHeaderExt.sNalUnitHeader.uiNalRefIdc = pNalUnitHeader->uiNalRefIdc; pCurNal->sNalHeaderExt.sNalUnitHeader.eNalUnitType = pNalUnitHeader->eNalUnitType; pBs = &pCtx->sBs; iBitSize = (iNalSize<<3) - BsGetTrailingBits( pNal + iNalSize - 1 ); // convert into bit InitBits( pBs, pNal, iBitSize); ParsePrefixNalUnit( pCtx, pBs ); break; case NAL_UNIT_CODED_SLICE_EXT: bExtensionFlag = true; case NAL_UNIT_CODED_SLICE: case NAL_UNIT_CODED_SLICE_IDR: { PAccessUnit pCurAu = NULL; uint32_t uiAvailNalNum; pCurNal = MemGetNextNal( &pCtx->pAccessUnitList ); if( NULL == pCurNal ) { WelsLog( pCtx, WELS_LOG_WARNING, "MemGetNextNal() fail due out of memory.\n"); pCtx->iErrorCode |= dsOutOfMemory; return NULL; } pCurNal->sNalHeaderExt.sNalUnitHeader.uiForbiddenZeroBit = pNalUnitHeader->uiForbiddenZeroBit; pCurNal->sNalHeaderExt.sNalUnitHeader.uiNalRefIdc = pNalUnitHeader->uiNalRefIdc; pCurNal->sNalHeaderExt.sNalUnitHeader.eNalUnitType = pNalUnitHeader->eNalUnitType; pCurAu = pCtx->pAccessUnitList; uiAvailNalNum = pCurAu->uiAvailUnitsNum; if( pNalUnitHeader->eNalUnitType == NAL_UNIT_CODED_SLICE_EXT ) { if ( iNalSize < NAL_UNIT_HEADER_EXT_SIZE ) { return NULL; } DecodeNalHeaderExt( pCurNal, pNal ); if( pCurNal->sNalHeaderExt.uiQualityId != 0 || pCurNal->sNalHeaderExt.bUseRefBasePicFlag ) { if( pCurNal->sNalHeaderExt.uiQualityId != 0 ) WelsLog(pCtx, WELS_LOG_WARNING, "ParseNalHeader():uiQualityId (%d) != 0, MGS not supported!\n", pCurNal->sNalHeaderExt.uiQualityId); if( pCurNal->sNalHeaderExt.bUseRefBasePicFlag != 0 ) WelsLog(pCtx, WELS_LOG_WARNING, "ParseNalHeader():bUseRefBasePicFlag (%d) != 0, MGS not supported!\n", pCurNal->sNalHeaderExt.bUseRefBasePicFlag); pCtx->iErrorCode |= dsInvalidArgument; ForceClearCurrentNal( pCurAu ); if ( uiAvailNalNum > 1 ) { pCurAu->uiEndPos = uiAvailNalNum - 2; pCtx->bAuReadyFlag = true; } return NULL; } pNal += NAL_UNIT_HEADER_EXT_SIZE; iNalSize -= NAL_UNIT_HEADER_EXT_SIZE; *pConsumedBytes += NAL_UNIT_HEADER_EXT_SIZE; } else { if ( NAL_UNIT_PREFIX == pCtx->sPrefixNal.sNalHeaderExt.sNalUnitHeader.eNalUnitType ) { PrefetchNalHeaderExtSyntax( pCtx, pCurNal, &pCtx->sPrefixNal ); } pCurNal->sNalHeaderExt.bIdrFlag = ( NAL_UNIT_CODED_SLICE_IDR == pNalUnitHeader->eNalUnitType ) ? true : false; //SHOULD update this flag for AVC if no prefix NAL pCurNal->sNalHeaderExt.iNoInterLayerPredFlag = 1; } pBs = &pCurAu->pNalUnitsList[uiAvailNalNum-1]->sNalData.sVclNal.sSliceBitsRead; iBitSize = (iNalSize<<3) - BsGetTrailingBits( pNal+ iNalSize - 1 ); // convert into bit InitBits( pBs, pNal, iBitSize); iErr = ParseSliceHeaderSyntaxs( pCtx, pBs, bExtensionFlag ); if ( iErr != ERR_NONE ) { //if current NAL occur error when parsing, should clean it from pNalUnitsList //otherwise, when Next good NAL decoding, this corrupt NAL is considered as normal NAL and lead to decoder crash ForceClearCurrentNal( pCurAu ); if ( uiAvailNalNum > 1 ) { pCurAu->uiEndPos = uiAvailNalNum - 2; pCtx->bAuReadyFlag = true; } #ifdef MOSAIC_AVOID_BASED_ON_SPS_PPS_ID if ( dsNoParamSets & pCtx->iErrorCode ) { if ( uiAvailNalNum <= 1 ) //no any data to decode and SPS/PPS ID mismatch, SHOULD request IDR { #ifdef LONG_TERM_REF pCtx->bParamSetsLostFlag = true; #else pCtx->bReferenceLostAtT0Flag = true; #endif ResetParameterSetsState( pCtx ); } return NULL; } else { return NULL; } #else return NULL; #endif //MOSAIC_AVOID_BASED_ON_SPS_PPS_ID } if ( (uiAvailNalNum > 1) && CheckAccessUnitBoundary( pCurAu->pNalUnitsList[uiAvailNalNum-1], pCurAu->pNalUnitsList[uiAvailNalNum-2], pCurAu->pNalUnitsList[uiAvailNalNum-1]->sNalData.sVclNal.sSliceHeaderExt.sSliceHeader.pSps) ) { pCurAu->uiEndPos = uiAvailNalNum - 2; pCtx->bAuReadyFlag = true; } } break; default: break; } return pNal; } bool_t CheckAccessUnitBoundaryExt( PNalUnitHeaderExt pLastNalHdrExt, PNalUnitHeaderExt pCurNalHeaderExt, PSliceHeader pLastSliceHeader, PSliceHeader pCurSliceHeader ) { const PSps kpSps = pCurSliceHeader->pSps; //Sub-clause 7.1.4.1.1 temporal_id if (pLastNalHdrExt->uiTemporalId != pCurNalHeaderExt->uiTemporalId) { return TRUE; } // Subclause 7.4.1.2.5 if ( pLastSliceHeader->iRedundantPicCnt < pCurSliceHeader->iRedundantPicCnt ) return FALSE; else if ( pLastSliceHeader->iRedundantPicCnt > pCurSliceHeader->iRedundantPicCnt ) return TRUE; // Subclause G7.4.1.2.4 if ( pLastNalHdrExt->uiDependencyId < pCurNalHeaderExt->uiDependencyId ) return FALSE; else if ( pLastNalHdrExt->uiDependencyId > pCurNalHeaderExt->uiDependencyId ) return TRUE; if ( pLastNalHdrExt->uiQualityId < pCurNalHeaderExt->uiQualityId ) return FALSE; else if ( pLastNalHdrExt->uiQualityId > pCurNalHeaderExt->uiQualityId ) return TRUE; // Subclause 7.4.1.2.4 if ( pLastSliceHeader->iFrameNum != pCurSliceHeader->iFrameNum ) return TRUE; if ( pLastSliceHeader->iPpsId != pCurSliceHeader->iPpsId ) return TRUE; if ( pLastSliceHeader->bFieldPicFlag != pCurSliceHeader->bFieldPicFlag ) return TRUE; if ( pLastSliceHeader->bBottomFiledFlag != pCurSliceHeader->bBottomFiledFlag ) return TRUE; if ( (pLastNalHdrExt->sNalUnitHeader.uiNalRefIdc != NRI_PRI_LOWEST) != (pCurNalHeaderExt->sNalUnitHeader.uiNalRefIdc != NRI_PRI_LOWEST) ) return TRUE; if ( pLastNalHdrExt->bIdrFlag != pCurNalHeaderExt->bIdrFlag ) return TRUE; if ( pCurNalHeaderExt->bIdrFlag ){ if ( pLastSliceHeader->uiIdrPicId != pCurSliceHeader->uiIdrPicId ) return TRUE; } if ( kpSps->uiPocType == 0 ){ if ( pLastSliceHeader->iPicOrderCntLsb != pCurSliceHeader->iPicOrderCntLsb ) return TRUE; if ( pLastSliceHeader->iDeltaPicOrderCntBottom != pCurSliceHeader->iDeltaPicOrderCntBottom ) return TRUE; } else if ( kpSps->uiPocType == 1 ){ if ( pLastSliceHeader->iDeltaPicOrderCnt[0] != pCurSliceHeader->iDeltaPicOrderCnt[0] ) return TRUE; if ( pLastSliceHeader->iDeltaPicOrderCnt[1] != pCurSliceHeader->iDeltaPicOrderCnt[1] ) return TRUE; } return FALSE; } bool_t CheckAccessUnitBoundary( const PNalUnit kpCurNal, const PNalUnit kpLastNal, const PSps kpSps ) { const PNalUnitHeaderExt kpLastNalHeaderExt = &kpLastNal->sNalHeaderExt; const PNalUnitHeaderExt kpCurNalHeaderExt = &kpCurNal->sNalHeaderExt; const SSliceHeader *kpLastSliceHeader = &kpLastNal->sNalData.sVclNal.sSliceHeaderExt.sSliceHeader; const SSliceHeader *kpCurSliceHeader = &kpCurNal->sNalData.sVclNal.sSliceHeaderExt.sSliceHeader; //Sub-clause 7.1.4.1.1 temporal_id if (kpLastNalHeaderExt->uiTemporalId != kpCurNalHeaderExt->uiTemporalId) { return TRUE; } // Subclause 7.4.1.2.5 if ( kpLastSliceHeader->iRedundantPicCnt < kpCurSliceHeader->iRedundantPicCnt ) return FALSE; else if ( kpLastSliceHeader->iRedundantPicCnt > kpCurSliceHeader->iRedundantPicCnt ) return TRUE; // Subclause G7.4.1.2.4 if ( kpLastNalHeaderExt->uiDependencyId < kpCurNalHeaderExt->uiDependencyId ) return FALSE; else if ( kpLastNalHeaderExt->uiDependencyId > kpCurNalHeaderExt->uiDependencyId ) return TRUE; if ( kpLastNalHeaderExt->uiQualityId < kpCurNalHeaderExt->uiQualityId ) return FALSE; else if ( kpLastNalHeaderExt->uiQualityId > kpCurNalHeaderExt->uiQualityId ) return TRUE; // Subclause 7.4.1.2.4 if ( kpLastSliceHeader->iFrameNum != kpCurSliceHeader->iFrameNum ) return TRUE; if ( kpLastSliceHeader->iPpsId != kpCurSliceHeader->iPpsId ) return TRUE; if ( kpLastSliceHeader->bFieldPicFlag != kpCurSliceHeader->bFieldPicFlag ) return TRUE; if ( kpLastSliceHeader->bBottomFiledFlag != kpCurSliceHeader->bBottomFiledFlag ) return TRUE; if ( (kpLastNalHeaderExt->sNalUnitHeader.uiNalRefIdc != NRI_PRI_LOWEST) != (kpCurNalHeaderExt->sNalUnitHeader.uiNalRefIdc != NRI_PRI_LOWEST) ) return TRUE; if ( kpLastNalHeaderExt->bIdrFlag != kpCurNalHeaderExt->bIdrFlag ) return TRUE; if ( kpCurNalHeaderExt->bIdrFlag ){ if ( kpLastSliceHeader->uiIdrPicId != kpCurSliceHeader->uiIdrPicId ) return TRUE; } if ( kpSps->uiPocType == 0 ){ if ( kpLastSliceHeader->iPicOrderCntLsb != kpCurSliceHeader->iPicOrderCntLsb ) return TRUE; if ( kpLastSliceHeader->iDeltaPicOrderCntBottom != kpCurSliceHeader->iDeltaPicOrderCntBottom ) return TRUE; } else if ( kpSps->uiPocType == 1 ){ if ( kpLastSliceHeader->iDeltaPicOrderCnt[0] != kpCurSliceHeader->iDeltaPicOrderCnt[0] ) return TRUE; if ( kpLastSliceHeader->iDeltaPicOrderCnt[1] != kpCurSliceHeader->iDeltaPicOrderCnt[1] ) return TRUE; } return FALSE; } /*! ************************************************************************************* * \brief to parse NON VCL NAL Units * * \param pCtx decoder context * \param rbsp rbsp buffer of NAL Unit * \param src_len length of rbsp buffer * * \return 0 - successed * 1 - failed * ************************************************************************************* */ int32_t ParseNonVclNal( PWelsDecoderContext pCtx, uint8_t *pRbsp, const int32_t kiSrcLen ) { PBitStringAux pBs = NULL; ENalUnitType eNalType = NAL_UNIT_UNSPEC_0; // make initial value as unspecified int32_t iPicWidth = 0; int32_t iPicHeight = 0; int32_t iBitSize = 0; int32_t iErr = ERR_NONE; pBs = &pCtx->sBs; // SBitStringAux instance for non VCL NALs decoding iBitSize = (kiSrcLen<<3) - BsGetTrailingBits( pRbsp + kiSrcLen - 1 ); // convert into bit eNalType = pCtx->sCurNalHead.eNalUnitType; switch( eNalType ) { case NAL_UNIT_SPS: case NAL_UNIT_SUBSET_SPS: if ( iBitSize > 0 ) InitBits( pBs, pRbsp, iBitSize ); #ifdef DEBUG_PARSE_INFO WelsLog(pCtx, WELS_LOG_INFO, "parsing nal: %d \n", eNalType); #endif iErr = ParseSps( pCtx, pBs, &iPicWidth, &iPicHeight ); if ( ERR_NONE != iErr ) // modified for pSps/pSubsetSps invalid, 12/1/2009 { pCtx->iErrorCode |= dsNoParamSets; return iErr; } if ( ERR_NONE == iErr ) UpdateMaxPictureResolution( pCtx, iPicWidth, iPicHeight ); break; case NAL_UNIT_PPS: if ( iBitSize > 0 ) InitBits( pBs, pRbsp, iBitSize ); #ifdef DEBUG_PARSE_INFO WelsLog(pCtx, WELS_LOG_INFO, "parsing nal: %d \n", eNalType); #endif iErr = ParsePps( pCtx, &pCtx->sPpsBuffer[0], pBs ); if ( ERR_NONE != iErr ) // modified for pps invalid, 12/1/2009 { pCtx->iErrorCode |= dsNoParamSets; return iErr; } pCtx->bPpsExistAheadFlag = true; break; case NAL_UNIT_SEI: break; case NAL_UNIT_PREFIX: break; case NAL_UNIT_CODED_SLICE_DPA: case NAL_UNIT_CODED_SLICE_DPB: case NAL_UNIT_CODED_SLICE_DPC: break; default: break; } return iErr; } void_t ParseRefBasePicMarking ( PBitStringAux pBs, PRefBasePicMarking pRefBasePicMarking ) { const bool_t kbAdaptiveMarkingModeFlag = !!BsGetOneBit( pBs ); pRefBasePicMarking->bAdaptiveRefBasePicMarkingModeFlag = kbAdaptiveMarkingModeFlag; if ( kbAdaptiveMarkingModeFlag ){ int32_t iIdx = 0; do { const uint32_t kuiMmco = BsGetUe( pBs ); pRefBasePicMarking->mmco_base[iIdx].uiMmcoType = kuiMmco; if (kuiMmco == MMCO_END) break; if (kuiMmco == MMCO_SHORT2UNUSED){ pRefBasePicMarking->mmco_base[iIdx].uiDiffOfPicNums = 1 + BsGetUe( pBs ); pRefBasePicMarking->mmco_base[iIdx].iShortFrameNum = 0; } else if (kuiMmco == MMCO_LONG2UNUSED){ pRefBasePicMarking->mmco_base[iIdx].uiLongTermPicNum = BsGetUe( pBs ); } ++ iIdx; } while(iIdx < MAX_MMCO_COUNT); } } void_t ParsePrefixNalUnit ( PWelsDecoderContext pCtx, PBitStringAux pBs ) { PNalUnit pCurNal = &pCtx->sPrefixNal; if ( pCurNal->sNalHeaderExt.sNalUnitHeader.uiNalRefIdc != 0 ){ PNalUnitHeaderExt head_ext = &pCurNal->sNalHeaderExt; PPrefixNalUnit sPrefixNal = &pCurNal->sNalData.sPrefixNal; sPrefixNal->bStoreRefBasePicFlag = !!BsGetOneBit( pBs ); if ( (head_ext->bUseRefBasePicFlag || sPrefixNal->bStoreRefBasePicFlag) && !head_ext->bIdrFlag ) { ParseRefBasePicMarking ( pBs, &sPrefixNal->sRefPicBaseMarking ); } sPrefixNal->bPrefixNalUnitAdditionalExtFlag = !!BsGetOneBit( pBs ); if ( sPrefixNal->bPrefixNalUnitAdditionalExtFlag ){ sPrefixNal->bPrefixNalUnitExtFlag = !!BsGetOneBit( pBs ); } } } int32_t DecodeSpsSvcExt( PWelsDecoderContext pCtx, PSubsetSps pSpsExt, PBitStringAux pBs ) { PSpsSvcExt pExt = NULL; uint8_t uiChromaArrayType = 1; pExt = &pSpsExt->sSpsSvcExt; pExt->bInterLayerDeblockingFilterCtrlPresentFlag = !!BsGetOneBit( pBs ); pExt->uiExtendedSpatialScalability = BsGetBits( pBs, 2 ); if ( pExt->uiExtendedSpatialScalability > 2 ) { WelsLog(pCtx, WELS_LOG_WARNING, "DecodeSpsSvcExt():extended_spatial_scalability (%d) != 0, ESS not supported!\n", pExt->uiExtendedSpatialScalability); return GENERATE_ERROR_NO(ERR_LEVEL_PARAM_SETS, ERR_INFO_INVALID_ESS); } pExt->uiChromaPhaseXPlus1Flag = 0; // FIXME: Incoherent with JVT X201 standard (= 1), but conformance to JSVM (= 0) implementation. pExt->uiChromaPhaseYPlus1 = 1; uiChromaArrayType = pSpsExt->sSps.uiChromaArrayType; pExt->uiChromaPhaseXPlus1Flag = BsGetOneBit( pBs ); pExt->uiChromaPhaseYPlus1 = BsGetBits( pBs, 2 ); pExt->uiSeqRefLayerChromaPhaseXPlus1Flag = pExt->uiChromaPhaseXPlus1Flag; pExt->uiSeqRefLayerChromaPhaseYPlus1 = pExt->uiChromaPhaseYPlus1; memset(&pExt->sSeqScaledRefLayer, 0, sizeof(SPosOffset)); if ( pExt->uiExtendedSpatialScalability == 1 ){ SPosOffset* const kpPos = &pExt->sSeqScaledRefLayer; pExt->uiSeqRefLayerChromaPhaseXPlus1Flag = BsGetOneBit( pBs ); pExt->uiSeqRefLayerChromaPhaseYPlus1 = BsGetBits( pBs, 2 ); kpPos->iLeftOffset = BsGetSe( pBs ); kpPos->iTopOffset = BsGetSe( pBs ); kpPos->iRightOffset = BsGetSe( pBs ); kpPos->iBottomOffset= BsGetSe( pBs ); } pExt->bSeqTCoeffLevelPredFlag = !!BsGetOneBit( pBs ); pExt->bAdaptiveTCoeffLevelPredFlag = false; if ( pExt->bSeqTCoeffLevelPredFlag ) pExt->bAdaptiveTCoeffLevelPredFlag = !!BsGetOneBit( pBs ); pExt->bSliceHeaderRestrictionFlag = !!BsGetOneBit( pBs ); return 0; } /*! ************************************************************************************* * \brief to parse Sequence Parameter Set (SPS) * * \param pCtx Decoder context * \param pBsAux bitstream reader auxiliary * \param pPicWidth picture width current Sps represented * \param pPicHeight picture height current Sps represented * * \return 0 - successed * 1 - failed * * \note Call it in case eNalUnitType is SPS. ************************************************************************************* */ int32_t ParseSps( PWelsDecoderContext pCtx, PBitStringAux pBsAux, int32_t *pPicWidth, int32_t *pPicHeight ) { PBitStringAux pBs = pBsAux; PSps pSps = NULL; PSubsetSps pSubsetSps = NULL; SNalUnitHeader *pNalHead= &pCtx->sCurNalHead; ProfileIdc uiProfileIdc; uint8_t uiLevelIdc; int32_t iSpsId; bool_t bConstraintSetFlags[6] = { false }; const bool_t kbUseSubsetFlag = IS_SUBSET_SPS_NAL(pNalHead->eNalUnitType); if ( kbUseSubsetFlag ) // SubsetSps { pCtx->bSubspsExistAheadFlag = true; } else // Sps { pCtx->bSpsExistAheadFlag = true; // added for EC, 10/28/2009 // for safe memset( &pCtx->bSpsAvailFlags[0], 0, sizeof(pCtx->bSpsAvailFlags) ); memset( &pCtx->bSubspsAvailFlags[0], 0, sizeof(pCtx->bSubspsAvailFlags) ); memset( &pCtx->bPpsAvailFlags[0], 0, sizeof(pCtx->bPpsAvailFlags) ); #ifdef MOSAIC_AVOID_BASED_ON_SPS_PPS_ID pCtx->iSpsTotalNum = 0; pCtx->iSubspsTotalNum = 0; pCtx->iPpsTotalNum = 0; #endif //MOSAIC_AVOID_BASED_ON_SPS_PPS_ID } uiProfileIdc = BsGetBits( pBs, 8 ); bConstraintSetFlags[0] = !!BsGetOneBit( pBs ); // constraint_set0_flag bConstraintSetFlags[1] = !!BsGetOneBit( pBs ); // constraint_set1_flag bConstraintSetFlags[2] = !!BsGetOneBit( pBs ); // constraint_set2_flag bConstraintSetFlags[3] = !!BsGetOneBit( pBs ); // constraint_set3_flag bConstraintSetFlags[4] = !!BsGetOneBit( pBs ); // constraint_set4_flag bConstraintSetFlags[5] = !!BsGetOneBit( pBs ); // constraint_set5_flag BsGetBits( pBs, 2 ); // reserved_zero_2bits, equal to 0 uiLevelIdc = BsGetBits( pBs, 8 ); // level_idc iSpsId = BsGetUe( pBs ); // seq_parameter_set_id if ( iSpsId >= MAX_SPS_COUNT || iSpsId < 0 ) // Modified to check invalid negative iSpsId, 12/1/2009 { WelsLog( pCtx, WELS_LOG_WARNING, " iSpsId is out of range! \n"); return GENERATE_ERROR_NO(ERR_LEVEL_PARAM_SETS, ERR_INFO_SPS_ID_OVERFLOW); } if ( kbUseSubsetFlag ) { #ifdef MOSAIC_AVOID_BASED_ON_SPS_PPS_ID pSubsetSps = &pCtx->sSubsetSpsBuffer[pCtx->iSubspsTotalNum]; pCtx->bSubspsAvailFlags[pCtx->iSubspsTotalNum] = true; pSubsetSps->sSps.iSpsId = iSpsId; pSps = &pSubsetSps->sSps; ++pCtx->iSubspsTotalNum; #else pSubsetSps = &pCtx->sSubsetSpsBuffer[iSpsId]; pSps = &pSubsetSps->sSps; pCtx->bSubspsAvailFlags[iSpsId] = true; // added for EC, 10/28/2009 #endif //MOSAIC_AVOID_BASED_ON_SPS_PPS_ID } else { #ifdef MOSAIC_AVOID_BASED_ON_SPS_PPS_ID pSps = &pCtx->sSpsBuffer[pCtx->iSpsTotalNum]; pCtx->bSpsAvailFlags[pCtx->iSpsTotalNum] = true; pSps->iSpsId = iSpsId; ++pCtx->iSpsTotalNum; #else pSps = &pCtx->sSpsBuffer[iSpsId]; pCtx->bSpsAvailFlags[iSpsId] = true; // added for EC, 10/28/2009 #endif //MOSAIC_AVOID_BASED_ON_SPS_PPS_ID } // syntax elements in default pSps->uiChromaFormatIdc = 1; pSps->uiBitDepthLuma = pSps->uiBitDepthChroma = 8; pSps->uiProfileIdc = uiProfileIdc; pSps->uiLevelIdc = uiLevelIdc; pSps->iSpsId = iSpsId; if ( PRO_SCALABLE_BASELINE == uiProfileIdc || PRO_SCALABLE_HIGH == uiProfileIdc || PRO_HIGH == uiProfileIdc || PRO_HIGH10 == uiProfileIdc || PRO_HIGH422 == uiProfileIdc || PRO_HIGH444 == uiProfileIdc || PRO_CAVLC444 == uiProfileIdc || 44 == uiProfileIdc ){ pSps->uiChromaFormatIdc = BsGetUe( pBs ); if( pSps->uiChromaFormatIdc != 1 ) { WelsLog( pCtx, WELS_LOG_WARNING, "ParseSps(): chroma_format_idc (%d) = 1 supported.\n", pSps->uiChromaFormatIdc); return GENERATE_ERROR_NO(ERR_LEVEL_PARAM_SETS, ERR_INFO_UNSUPPORTED_NON_BASELINE); } pSps->uiChromaArrayType = pSps->uiChromaFormatIdc; pSps->uiBitDepthLuma = 8 + BsGetUe( pBs ); if( pSps->uiBitDepthLuma != 8 ) { WelsLog( pCtx, WELS_LOG_WARNING, "ParseSps(): bit_depth_luma (%d) Only 8 bit supported.\n", pSps->uiBitDepthLuma); return GENERATE_ERROR_NO(ERR_LEVEL_PARAM_SETS, ERR_INFO_UNSUPPORTED_NON_BASELINE); } pSps->uiBitDepthChroma = 8 + BsGetUe( pBs ); if( pSps->uiBitDepthChroma != 8 ) { WelsLog( pCtx, WELS_LOG_WARNING, "ParseSps(): bit_depth_chroma (%d). Only 8 bit supported.\n", pSps->uiBitDepthChroma); return GENERATE_ERROR_NO(ERR_LEVEL_PARAM_SETS, ERR_INFO_UNSUPPORTED_NON_BASELINE); } pSps->bQpPrimeYZeroTransfBypassFlag = !!BsGetOneBit( pBs ); pSps->bSeqScalingMatrixPresentFlag = !!BsGetOneBit( pBs ); if ( pSps->bSeqScalingMatrixPresentFlag ){ // For high profile, it is not used in current application. FIXME WelsLog( pCtx, WELS_LOG_WARNING, "ParseSps(): seq_scaling_matrix_present_flag (%d). Feature not supported.\n", pSps->bSeqScalingMatrixPresentFlag); return GENERATE_ERROR_NO(ERR_LEVEL_PARAM_SETS, ERR_INFO_UNSUPPORTED_NON_BASELINE); } } pSps->uiLog2MaxFrameNum = 4 + BsGetUe( pBs ); // log2_max_frame_num_minus4 pSps->uiPocType = BsGetUe( pBs ); // pic_order_cnt_type if ( 0 == pSps->uiPocType ) { pSps->iLog2MaxPocLsb = 4 + BsGetUe( pBs ); // log2_max_pic_order_cnt_lsb_minus4 } else if ( 1 == pSps->uiPocType ) { int32_t i; pSps->bDeltaPicOrderAlwaysZeroFlag = !!BsGetOneBit( pBs ); // bDeltaPicOrderAlwaysZeroFlag pSps->iOffsetForNonRefPic = BsGetSe( pBs ); // iOffsetForNonRefPic pSps->iOffsetForTopToBottomField = BsGetSe( pBs ); // iOffsetForTopToBottomField pSps->iNumRefFramesInPocCycle = BsGetUe( pBs ); // num_ref_frames_in_pic_order_cnt_cycle for( i = 0; i < pSps->iNumRefFramesInPocCycle; i++ ) pSps->iOffsetForRefFrame[ i ] = BsGetSe( pBs ); // iOffsetForRefFrame[ i ] } if ( pSps->uiPocType > 2 ) { WelsLog( pCtx, WELS_LOG_WARNING, " illegal pic_order_cnt_type: %d ! \n", pSps->uiPocType ); return GENERATE_ERROR_NO(ERR_LEVEL_PARAM_SETS, ERR_INFO_INVALID_POC_TYPE); } pSps->iNumRefFrames = BsGetUe( pBs ); // max_num_ref_frames pSps->bGapsInFrameNumValueAllowedFlag = !!BsGetOneBit( pBs ); // bGapsInFrameNumValueAllowedFlag pSps->iMbWidth = 1 + BsGetUe( pBs ); // pic_width_in_mbs_minus1 pSps->iMbHeight = 1 + BsGetUe( pBs ); // pic_height_in_map_units_minus1 pSps->uiTotalMbCount = pSps->iMbWidth * pSps->iMbHeight; pSps->bFrameMbsOnlyFlag = !!BsGetOneBit( pBs ); // frame_mbs_only_flag if ( !pSps->bFrameMbsOnlyFlag ) { WelsLog( pCtx, WELS_LOG_WARNING, "ParseSps(): frame_mbs_only_flag (%d) not supported.\n", pSps->bFrameMbsOnlyFlag); return GENERATE_ERROR_NO(ERR_LEVEL_PARAM_SETS, ERR_INFO_UNSUPPORTED_MBAFF); } pSps->bDirect8x8InferenceFlag = !!BsGetOneBit( pBs ); // direct_8x8_inference_flag pSps->bFrameCroppingFlag = !!BsGetOneBit( pBs ); // frame_cropping_flag if ( pSps->bFrameCroppingFlag ) { pSps->sFrameCrop.iLeftOffset = BsGetUe( pBs ); // frame_crop_left_offset pSps->sFrameCrop.iRightOffset = BsGetUe( pBs ); // frame_crop_right_offset pSps->sFrameCrop.iTopOffset = BsGetUe( pBs ); // frame_crop_top_offset pSps->sFrameCrop.iBottomOffset = BsGetUe( pBs ); // frame_crop_bottom_offset } else { pSps->sFrameCrop.iLeftOffset = 0; // frame_crop_left_offset pSps->sFrameCrop.iRightOffset = 0; // frame_crop_right_offset pSps->sFrameCrop.iTopOffset = 0; // frame_crop_top_offset pSps->sFrameCrop.iBottomOffset = 0; // frame_crop_bottom_offset } pSps->bVuiParamPresentFlag = !!BsGetOneBit( pBs ); // vui_parameters_present_flag // Check if SPS SVC extension applicated if ( kbUseSubsetFlag && ( PRO_SCALABLE_BASELINE == uiProfileIdc || PRO_SCALABLE_HIGH == uiProfileIdc ) ) { if ( DecodeSpsSvcExt( pCtx, pSubsetSps, pBs ) != ERR_NONE ){ return -1; } pSubsetSps->bSvcVuiParamPresentFlag = !!BsGetOneBit( pBs ); if ( pSubsetSps->bSvcVuiParamPresentFlag ){ } } if ( PRO_SCALABLE_BASELINE == uiProfileIdc || PRO_SCALABLE_HIGH == uiProfileIdc ) pCtx->bAvcBasedFlag = false; else pCtx->bAvcBasedFlag = true; // added for avc base pBs *pPicWidth = pSps->iMbWidth << 4; *pPicHeight = pSps->iMbHeight << 4; return 0; } /*! ************************************************************************************* * \brief to parse Picture Parameter Set (PPS) * * \param pCtx Decoder context * \param pPpsList pps list * \param pBsAux bitstream reader auxiliary * * \return 0 - successed * 1 - failed * * \note Call it in case eNalUnitType is PPS. ************************************************************************************* */ int32_t ParsePps( PWelsDecoderContext pCtx, PPps pPpsList, PBitStringAux pBsAux ) { PPps pPps = NULL; uint32_t uiPpsId = 0; uint32_t iTmp; uiPpsId = BsGetUe(pBsAux); if ( uiPpsId >= MAX_PPS_COUNT ) { return ERR_INFO_PPS_ID_OVERFLOW; } #ifdef MOSAIC_AVOID_BASED_ON_SPS_PPS_ID pPps = &pPpsList[pCtx->iPpsTotalNum]; #else pPps = &pPpsList[uiPpsId]; #endif //MOSAIC_AVOID_BASED_ON_SPS_PPS_ID pPps->iPpsId = uiPpsId; pPps->iSpsId = BsGetUe(pBsAux); if (pPps->iSpsId >= MAX_SPS_COUNT) { return ERR_INFO_SPS_ID_OVERFLOW; } pPps->bEntropyCodingModeFlag = !!BsGetOneBit(pBsAux); pPps->bPicOrderPresentFlag = !!BsGetOneBit(pBsAux); pPps->uiNumSliceGroups = 1 + BsGetUe(pBsAux); if (pPps->uiNumSliceGroups > MAX_SLICEGROUP_IDS) { return ERR_INFO_INVALID_SLICEGROUP; } if (pPps->uiNumSliceGroups > 1) { pPps->uiSliceGroupMapType = BsGetUe(pBsAux); if( pPps->uiSliceGroupMapType > 1) { WelsLog( pCtx, WELS_LOG_WARNING, "ParsePps(): slice_group_map_type (%d): support only 0,1.\n", pPps->uiSliceGroupMapType); return GENERATE_ERROR_NO(ERR_LEVEL_PARAM_SETS, ERR_INFO_UNSUPPORTED_FMOTYPE); } switch(pPps->uiSliceGroupMapType) { case 0: for (iTmp = 0; iTmp < pPps->uiNumSliceGroups; iTmp++) { pPps->uiRunLength[iTmp] = 1 + BsGetUe(pBsAux); } break; default: break; } } pPps->uiNumRefIdxL0Active = 1 + BsGetUe(pBsAux); pPps->uiNumRefIdxL1Active = 1 + BsGetUe(pBsAux); if (pPps->uiNumRefIdxL0Active > MAX_REF_PIC_COUNT || pPps->uiNumRefIdxL1Active > MAX_REF_PIC_COUNT) { return ERR_INFO_REF_COUNT_OVERFLOW; } pPps->bWeightedPredFlag = !!BsGetOneBit(pBsAux); pPps->uiWeightedBipredIdc = BsGetBits(pBsAux, 2); if( pPps->bWeightedPredFlag || pPps->uiWeightedBipredIdc != 0 ) { WelsLog( pCtx, WELS_LOG_WARNING, "ParsePps(): weighted_pred_flag (%d) weighted_bipred_idc (%d) neither supported.\n", pPps->bWeightedPredFlag, pPps->uiWeightedBipredIdc); return GENERATE_ERROR_NO(ERR_LEVEL_PARAM_SETS, ERR_INFO_UNSUPPORTED_WP); } pPps->iPicInitQp = 26 + BsGetSe(pBsAux); pPps->iPicInitQs = 26 + BsGetSe(pBsAux); pPps->iChromaQpIndexOffset = BsGetSe(pBsAux); pPps->bDeblockingFilterControlPresentFlag = !!BsGetOneBit(pBsAux); pPps->bConstainedIntraPredFlag = !!BsGetOneBit(pBsAux); pPps->bRedundantPicCntPresentFlag = !!BsGetOneBit(pBsAux); #ifdef MOSAIC_AVOID_BASED_ON_SPS_PPS_ID pCtx->bPpsAvailFlags[pCtx->iPpsTotalNum] = true; ++pCtx->iPpsTotalNum; #else pCtx->bPpsAvailFlags[uiPpsId] = true; // added for EC, 10/28/2009 #endif //MOSAIC_AVOID_BASED_ON_SPS_PPS_ID return ERR_NONE; } /*! ************************************************************************************* * \brief to parse SEI message payload * * \param pSei sei message to be parsed output * \param pBsAux bitstream reader auxiliary * * \return 0 - successed * 1 - failed * * \note Call it in case eNalUnitType is NAL_UNIT_SEI. ************************************************************************************* */ int32_t ParseSei( void_t *pSei, PBitStringAux pBsAux ) // reserved Sei_Msg type { return ERR_NONE; } /*! ************************************************************************************* * \brief reset fmo list due to got Sps now * * \param pCtx decoder context * * \return count number of fmo context units are reset ************************************************************************************* */ int32_t ResetFmoList( PWelsDecoderContext pCtx ) { int32_t iCountNum = 0; if ( NULL != pCtx ) { // Fixed memory leak due to PPS_ID might not be continuous sometimes, 1/5/2010 UninitFmoList( &pCtx->sFmoList[0], MAX_PPS_COUNT, pCtx->iActiveFmoNum ); iCountNum = pCtx->iActiveFmoNum; pCtx->iActiveFmoNum = 0; } return iCountNum; } } // namespace WelsDec