ref: fdcecde1c7786b74426f32c4de4c9ab8b7667e5f
dir: /codec/decoder/core/src/decoder_core.cpp/
/*! * \copy * Copyright (c) 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. * * decoder_core.c: Wels decoder framework core implementation */ #include "decoder_core.h" #include "error_code.h" #include "memmgr_nal_unit.h" #include "au_parser.h" #include "decode_slice.h" #include "manage_dec_ref.h" #include "expand_pic.h" #include "decoder.h" #include "decode_mb_aux.h" #include "memory_align.h" #include "error_concealment.h" namespace WelsDec { static inline int32_t DecodeFrameConstruction (PWelsDecoderContext pCtx, uint8_t** ppDst, SBufferInfo* pDstInfo) { PDqLayer pCurDq = pCtx->pCurDqLayer; PPicture pPic = pCtx->pDec; const int32_t kiWidth = pCurDq->iMbWidth << 4; const int32_t kiHeight = pCurDq->iMbHeight << 4; const int32_t kiTotalNumMbInCurLayer = pCurDq->iMbWidth * pCurDq->iMbHeight; bool bFrameCompleteFlag = true; if (pPic->bNewSeqBegin) { memcpy (& (pCtx->sFrameCrop), & (pCurDq->sLayerInfo.sSliceInLayer.sSliceHeaderExt.sSliceHeader.pSps->sFrameCrop), sizeof (SPosOffset)); //confirmed_safe_unsafe_usage #ifdef LONG_TERM_REF pCtx->bParamSetsLostFlag = false; #else pCtx->bReferenceLostAtT0Flag = false; // need initialize it due new seq, 6/4/2010 #endif //LONG_TERM_REF if (pCtx->iTotalNumMbRec == kiTotalNumMbInCurLayer) { pCtx->bPrintFrameErrorTraceFlag = true; WelsLog (& (pCtx->sLogCtx), WELS_LOG_INFO, "DecodeFrameConstruction(): will output first frame of new sequence, %d x %d, crop_left:%d, crop_right:%d, crop_top:%d, crop_bottom:%d, ignored error packet:%d.", kiWidth, kiHeight, pCtx->sFrameCrop.iLeftOffset, pCtx->sFrameCrop.iRightOffset, pCtx->sFrameCrop.iTopOffset, pCtx->sFrameCrop.iBottomOffset, pCtx->iIgnoredErrorInfoPacketCount); pCtx->iIgnoredErrorInfoPacketCount = 0; } } const int32_t kiActualWidth = kiWidth - (pCtx->sFrameCrop.iLeftOffset + pCtx->sFrameCrop.iRightOffset) * 2; const int32_t kiActualHeight = kiHeight - (pCtx->sFrameCrop.iTopOffset + pCtx->sFrameCrop.iBottomOffset) * 2; if (pCtx->pParam->eEcActiveIdc == ERROR_CON_DISABLE) { if ((pCtx->sDecoderStatistics.uiWidth != (unsigned int) kiActualWidth) || (pCtx->sDecoderStatistics.uiHeight != (unsigned int) kiActualHeight)) { pCtx->sDecoderStatistics.uiResolutionChangeTimes++; pCtx->sDecoderStatistics.uiWidth = kiActualWidth; pCtx->sDecoderStatistics.uiHeight = kiActualHeight; } UpdateDecStatNoFreezingInfo (pCtx); } if (pCtx->pParam->bParseOnly) { //should exit for parse only to prevent access NULL pDstInfo PAccessUnit pCurAu = pCtx->pAccessUnitList; if (dsErrorFree == pCtx->iErrorCode) { //correct decoding, add to data buffer SParserBsInfo* pParser = pCtx->pParserBsInfo; SNalUnit* pCurNal = NULL; int32_t iTotalNalLen = 0; int32_t iNalLen = 0; int32_t iNum = 0; while (iNum < pParser->iNalNum) { iTotalNalLen += pParser->pNalLenInByte[iNum++]; } uint8_t* pDstBuf = pParser->pDstBuff + iTotalNalLen; int32_t iIdx = pCurAu->uiStartPos; int32_t iEndIdx = pCurAu->uiEndPos; uint8_t* pNalBs = NULL; pParser->uiOutBsTimeStamp = (pCurAu->pNalUnitsList [iIdx]) ? pCurAu->pNalUnitsList [iIdx]->uiTimeStamp : 0; //pParser->iNalNum = 0; pParser->iSpsWidthInPixel = (pCtx->pSps->iMbWidth << 4) - ((pCtx->pSps->sFrameCrop.iLeftOffset + pCtx->pSps->sFrameCrop.iRightOffset) << 1); pParser->iSpsHeightInPixel = (pCtx->pSps->iMbHeight << 4) - ((pCtx->pSps->sFrameCrop.iTopOffset + pCtx->pSps->sFrameCrop.iBottomOffset) << 1); if (pCurAu->pNalUnitsList [iIdx]->sNalHeaderExt.bIdrFlag) { //IDR if (pCtx->bFrameFinish) { //add required sps/pps if (pParser->iNalNum > pCtx->iMaxNalNum - 2) { //2 reserved for sps+pps WelsLog (& (pCtx->sLogCtx), WELS_LOG_INFO, "DecodeFrameConstruction(): current NAL num (%d) plus sps & pps exceeds permitted num (%d). Will expand", pParser->iNalNum, pCtx->iMaxNalNum); WELS_VERIFY_RETURN_IF (ERR_INFO_OUT_OF_MEMORY, ExpandBsLenBuffer (pCtx, pParser->iNalNum + 2)) } bool bSubSps = (NAL_UNIT_CODED_SLICE_EXT == pCurAu->pNalUnitsList [iIdx]->sNalHeaderExt.sNalUnitHeader.eNalUnitType); SSpsBsInfo* pSpsBs = NULL; SPpsBsInfo* pPpsBs = NULL; int32_t iSpsId = pCtx->pSps->iSpsId; int32_t iPpsId = pCtx->pPps->iPpsId; pCtx->bParamSetsLostFlag = false; //find required sps, pps and write into dst buff pSpsBs = bSubSps ? &pCtx->sSubsetSpsBsInfo [iSpsId] : &pCtx->sSpsBsInfo [iSpsId]; pPpsBs = &pCtx->sPpsBsInfo [iPpsId]; if (pDstBuf - pParser->pDstBuff + pSpsBs->uiSpsBsLen + pPpsBs->uiPpsBsLen >= MAX_ACCESS_UNIT_CAPACITY) { WelsLog (& (pCtx->sLogCtx), WELS_LOG_ERROR, "DecodeFrameConstruction(): sps pps size: (%d %d) too large. Failed to parse. \n", pSpsBs->uiSpsBsLen, pPpsBs->uiPpsBsLen); pCtx->iErrorCode |= dsOutOfMemory; pCtx->pParserBsInfo->iNalNum = 0; return ERR_INFO_OUT_OF_MEMORY; } memcpy (pDstBuf, pSpsBs->pSpsBsBuf, pSpsBs->uiSpsBsLen); pParser->pNalLenInByte [pParser->iNalNum ++] = pSpsBs->uiSpsBsLen; pDstBuf += pSpsBs->uiSpsBsLen; memcpy (pDstBuf, pPpsBs->pPpsBsBuf, pPpsBs->uiPpsBsLen); pParser->pNalLenInByte [pParser->iNalNum ++] = pPpsBs->uiPpsBsLen; pDstBuf += pPpsBs->uiPpsBsLen; pCtx->bFrameFinish = false; } } //then VCL data re-write if (pParser->iNalNum + iEndIdx - iIdx + 1 > pCtx->iMaxNalNum) { //calculate total NAL num WelsLog (& (pCtx->sLogCtx), WELS_LOG_INFO, "DecodeFrameConstruction(): current NAL num (%d) exceeds permitted num (%d). Will expand", pParser->iNalNum + iEndIdx - iIdx + 1, pCtx->iMaxNalNum); WELS_VERIFY_RETURN_IF (ERR_INFO_OUT_OF_MEMORY, ExpandBsLenBuffer (pCtx, pParser->iNalNum + iEndIdx - iIdx + 1)) } while (iIdx <= iEndIdx) { pCurNal = pCurAu->pNalUnitsList [iIdx ++]; iNalLen = pCurNal->sNalData.sVclNal.iNalLength; pNalBs = pCurNal->sNalData.sVclNal.pNalPos; pParser->pNalLenInByte [pParser->iNalNum ++] = iNalLen; if (pDstBuf - pParser->pDstBuff + iNalLen >= MAX_ACCESS_UNIT_CAPACITY) { WelsLog (& (pCtx->sLogCtx), WELS_LOG_ERROR, "DecodeFrameConstruction(): composed output size (%ld) exceeds (%d). Failed to parse. current data pos %d out of %d:, previously accumulated num: %d, total num: %d, previously accumulated len: %d, current len: %d, current buf pos: %p, header buf pos: %p \n", (long) (pDstBuf - pParser->pDstBuff + iNalLen), MAX_ACCESS_UNIT_CAPACITY, iIdx, iEndIdx, iNum, pParser->iNalNum, iTotalNalLen, iNalLen, pDstBuf, pParser->pDstBuff); pCtx->iErrorCode |= dsOutOfMemory; pCtx->pParserBsInfo->iNalNum = 0; return ERR_INFO_OUT_OF_MEMORY; } memcpy (pDstBuf, pNalBs, iNalLen); pDstBuf += iNalLen; } if (pCtx->iTotalNumMbRec == kiTotalNumMbInCurLayer) { //frame complete pCtx->iTotalNumMbRec = 0; pCtx->bFramePending = false; pCtx->bFrameFinish = true; //finish current frame and mark it } else if (pCtx->iTotalNumMbRec != 0) { //frame incomplete pCtx->bFramePending = true; pCtx->pDec->bIsComplete = false; pCtx->bFrameFinish = false; //current frame not finished pCtx->iErrorCode |= dsFramePending; return ERR_INFO_PARSEONLY_PENDING; //pCtx->pParserBsInfo->iNalNum = 0; } } else { //error pCtx->pParserBsInfo->uiOutBsTimeStamp = 0; pCtx->pParserBsInfo->iNalNum = 0; pCtx->pParserBsInfo->iSpsWidthInPixel = 0; pCtx->pParserBsInfo->iSpsHeightInPixel = 0; return ERR_INFO_PARSEONLY_ERROR; } return ERR_NONE; } if (pCtx->iTotalNumMbRec != kiTotalNumMbInCurLayer) { WelsLog (& (pCtx->sLogCtx), WELS_LOG_DEBUG, "DecodeFrameConstruction(): iTotalNumMbRec:%d, total_num_mb_sps:%d, cur_layer_mb_width:%d, cur_layer_mb_height:%d ", pCtx->iTotalNumMbRec, kiTotalNumMbInCurLayer, pCurDq->iMbWidth, pCurDq->iMbHeight); bFrameCompleteFlag = false; //return later after output buffer is done if (pCtx->bInstantDecFlag) //no-delay decoding, wait for new slice return ERR_INFO_MB_NUM_INADEQUATE; } else if (pCurDq->sLayerInfo.sNalHeaderExt.bIdrFlag && (pCtx->iErrorCode == dsErrorFree)) { //complete non-ECed IDR frame done pCtx->pDec->bIsComplete = true; pCtx->bFreezeOutput = false; } pCtx->iTotalNumMbRec = 0; //////output:::normal path pDstInfo->uiOutYuvTimeStamp = pPic->uiTimeStamp; ppDst[0] = pPic->pData[0]; ppDst[1] = pPic->pData[1]; ppDst[2] = pPic->pData[2]; pDstInfo->UsrData.sSystemBuffer.iFormat = videoFormatI420; pDstInfo->UsrData.sSystemBuffer.iWidth = kiActualWidth; pDstInfo->UsrData.sSystemBuffer.iHeight = kiActualHeight; pDstInfo->UsrData.sSystemBuffer.iStride[0] = pPic->iLinesize[0]; pDstInfo->UsrData.sSystemBuffer.iStride[1] = pPic->iLinesize[1]; ppDst[0] = ppDst[0] + pCtx->sFrameCrop.iTopOffset * 2 * pPic->iLinesize[0] + pCtx->sFrameCrop.iLeftOffset * 2; ppDst[1] = ppDst[1] + pCtx->sFrameCrop.iTopOffset * pPic->iLinesize[1] + pCtx->sFrameCrop.iLeftOffset; ppDst[2] = ppDst[2] + pCtx->sFrameCrop.iTopOffset * pPic->iLinesize[1] + pCtx->sFrameCrop.iLeftOffset; pDstInfo->iBufferStatus = 1; bool bOutResChange = (pCtx->iLastImgWidthInPixel != pDstInfo->UsrData.sSystemBuffer.iWidth) || (pCtx->iLastImgHeightInPixel != pDstInfo->UsrData.sSystemBuffer.iHeight); pCtx->iLastImgWidthInPixel = pDstInfo->UsrData.sSystemBuffer.iWidth; pCtx->iLastImgHeightInPixel = pDstInfo->UsrData.sSystemBuffer.iHeight; if (pCtx->pParam->eEcActiveIdc == ERROR_CON_DISABLE) //no buffer output if EC is disabled and frame incomplete pDstInfo->iBufferStatus = (int32_t) (bFrameCompleteFlag && pPic->bIsComplete); // When EC disable, ECed picture not output else if ((pCtx->pParam->eEcActiveIdc == ERROR_CON_SLICE_COPY_CROSS_IDR_FREEZE_RES_CHANGE || pCtx->pParam->eEcActiveIdc == ERROR_CON_SLICE_MV_COPY_CROSS_IDR_FREEZE_RES_CHANGE) && pCtx->iErrorCode && bOutResChange) pCtx->bFreezeOutput = true; if (pDstInfo->iBufferStatus == 0) { if (!bFrameCompleteFlag) pCtx->iErrorCode |= dsBitstreamError; return ERR_INFO_MB_NUM_INADEQUATE; } if (pCtx->bFreezeOutput) { pDstInfo->iBufferStatus = 0; if (pPic->bNewSeqBegin) { WelsLog (& (pCtx->sLogCtx), WELS_LOG_INFO, "DecodeFrameConstruction():New sequence detected, but freezed, correct MBs (%d) out of whole MBs (%d).", kiTotalNumMbInCurLayer - pCtx->iMbEcedNum, kiTotalNumMbInCurLayer); } } pCtx->iMbEcedNum = pPic->iMbEcedNum; pCtx->iMbNum = pPic->iMbNum; pCtx->iMbEcedPropNum = pPic->iMbEcedPropNum; if (pCtx->pParam->eEcActiveIdc != ERROR_CON_DISABLE) { if (pDstInfo->iBufferStatus && ((pCtx->sDecoderStatistics.uiWidth != (unsigned int) kiActualWidth) || (pCtx->sDecoderStatistics.uiHeight != (unsigned int) kiActualHeight))) { pCtx->sDecoderStatistics.uiResolutionChangeTimes++; pCtx->sDecoderStatistics.uiWidth = kiActualWidth; pCtx->sDecoderStatistics.uiHeight = kiActualHeight; } UpdateDecStat (pCtx, pDstInfo->iBufferStatus != 0); } return ERR_NONE; } inline bool CheckSliceNeedReconstruct (uint8_t uiLayerDqId, uint8_t uiTargetDqId) { return (uiLayerDqId == uiTargetDqId); // target layer } inline uint8_t GetTargetDqId (uint8_t uiTargetDqId, SDecodingParam* psParam) { uint8_t uiRequiredDqId = psParam ? psParam->uiTargetDqLayer : (uint8_t)255; return WELS_MIN (uiTargetDqId, uiRequiredDqId); } inline void HandleReferenceLostL0 (PWelsDecoderContext pCtx, PNalUnit pCurNal) { if (0 == pCurNal->sNalHeaderExt.uiTemporalId) { pCtx->bReferenceLostAtT0Flag = true; } pCtx->iErrorCode |= dsBitstreamError; } inline void HandleReferenceLost (PWelsDecoderContext pCtx, PNalUnit pCurNal) { if ((0 == pCurNal->sNalHeaderExt.uiTemporalId) || (1 == pCurNal->sNalHeaderExt.uiTemporalId)) { pCtx->bReferenceLostAtT0Flag = true; } pCtx->iErrorCode |= dsRefLost; } inline int32_t WelsDecodeConstructSlice (PWelsDecoderContext pCtx, PNalUnit pCurNal) { int32_t iRet = WelsTargetSliceConstruction (pCtx); if (iRet) { HandleReferenceLostL0 (pCtx, pCurNal); } return iRet; } int32_t ParsePredWeightedTable (PBitStringAux pBs, PSliceHeader pSh) { uint32_t uiCode; int32_t iList = 0; int32_t iCode; WELS_READ_VERIFY (BsGetUe (pBs, &uiCode)); WELS_CHECK_SE_BOTH_ERROR_NOLOG (uiCode, 0, 7, "luma_log2_weight_denom", GENERATE_ERROR_NO (ERR_LEVEL_SLICE_HEADER, ERR_INFO_INVALID_LUMA_LOG2_WEIGHT_DENOM)); pSh->sPredWeightTable.uiLumaLog2WeightDenom = uiCode; if (pSh->pSps->uiChromaArrayType != 0) { WELS_READ_VERIFY (BsGetUe (pBs, &uiCode)); WELS_CHECK_SE_BOTH_ERROR_NOLOG (uiCode, 0, 7, "chroma_log2_weight_denom", GENERATE_ERROR_NO (ERR_LEVEL_SLICE_HEADER, ERR_INFO_INVALID_CHROMA_LOG2_WEIGHT_DENOM)); pSh->sPredWeightTable.uiChromaLog2WeightDenom = uiCode; } do { for (int i = 0; i < pSh->uiRefCount[iList]; i++) { //luma WELS_READ_VERIFY (BsGetOneBit (pBs, &uiCode)); if (!!uiCode) { WELS_READ_VERIFY (BsGetSe (pBs, &iCode)); WELS_CHECK_SE_BOTH_ERROR_NOLOG (iCode, -128, 127, "luma_weight", GENERATE_ERROR_NO (ERR_LEVEL_SLICE_HEADER, ERR_INFO_INVALID_LUMA_WEIGHT)); pSh->sPredWeightTable.sPredList[iList].iLumaWeight[i] = iCode; WELS_READ_VERIFY (BsGetSe (pBs, &iCode)); WELS_CHECK_SE_BOTH_ERROR_NOLOG (iCode, -128, 127, "luma_offset", GENERATE_ERROR_NO (ERR_LEVEL_SLICE_HEADER, ERR_INFO_INVALID_LUMA_OFFSET)); pSh->sPredWeightTable.sPredList[iList].iLumaOffset[i] = iCode; } else { pSh->sPredWeightTable.sPredList[iList].iLumaWeight[i] = 1 << (pSh->sPredWeightTable.uiLumaLog2WeightDenom); pSh->sPredWeightTable.sPredList[iList].iLumaOffset[i] = 0; } //chroma if (pSh->pSps->uiChromaArrayType == 0) continue; WELS_READ_VERIFY (BsGetOneBit (pBs, &uiCode)); if (!!uiCode) { for (int j = 0; j < 2; j++) { WELS_READ_VERIFY (BsGetSe (pBs, &iCode)); WELS_CHECK_SE_BOTH_ERROR_NOLOG (iCode, -128, 127, "chroma_weight", GENERATE_ERROR_NO (ERR_LEVEL_SLICE_HEADER, ERR_INFO_INVALID_CHROMA_WEIGHT)); pSh->sPredWeightTable.sPredList[iList].iChromaWeight[i][j] = iCode; WELS_READ_VERIFY (BsGetSe (pBs, &iCode)); WELS_CHECK_SE_BOTH_ERROR_NOLOG (iCode, -128, 127, "chroma_offset", GENERATE_ERROR_NO (ERR_LEVEL_SLICE_HEADER, ERR_INFO_INVALID_CHROMA_OFFSET)); pSh->sPredWeightTable.sPredList[iList].iChromaOffset[i][j] = iCode; } } else { for (int j = 0; j < 2; j++) { pSh->sPredWeightTable.sPredList[iList].iChromaWeight[i][j] = 1 << (pSh->sPredWeightTable.uiChromaLog2WeightDenom); pSh->sPredWeightTable.sPredList[iList].iChromaOffset[i][j] = 0; } } } ++iList; } while (iList < LIST_1);//TODO: SUPPORT LIST_A return ERR_NONE; } /* * Predeclared function routines .. */ int32_t ParseRefPicListReordering (PBitStringAux pBs, PSliceHeader pSh) { int32_t iList = 0; const EWelsSliceType keSt = pSh->eSliceType; PRefPicListReorderSyn pRefPicListReordering = &pSh->pRefPicListReordering; PSps pSps = pSh->pSps; uint32_t uiCode; if (keSt == I_SLICE || keSt == SI_SLICE) return ERR_NONE; // Common syntaxs for P or B slices: list0, list1 followed if B slices used. do { WELS_READ_VERIFY (BsGetOneBit (pBs, &uiCode)); //ref_pic_list_modification_flag_l0 pRefPicListReordering->bRefPicListReorderingFlag[iList] = !!uiCode; if (pRefPicListReordering->bRefPicListReorderingFlag[iList]) { int32_t iIdx = 0; do { WELS_READ_VERIFY (BsGetUe (pBs, &uiCode)); //modification_of_pic_nums_idc const uint32_t kuiIdc = uiCode; //Fixed the referrence list reordering crash issue.(fault kIdc value > 3 case)--- if ((iIdx >= MAX_REF_PIC_COUNT) || (kuiIdc > 3)) { return GENERATE_ERROR_NO (ERR_LEVEL_SLICE_HEADER, ERR_INFO_INVALID_REF_REORDERING); } pRefPicListReordering->sReorderingSyn[iList][iIdx].uiReorderingOfPicNumsIdc = kuiIdc; if (kuiIdc == 3) break; if (iIdx >= pSh->uiRefCount[iList] || iIdx >= MAX_REF_PIC_COUNT) return GENERATE_ERROR_NO (ERR_LEVEL_SLICE_HEADER, ERR_INFO_INVALID_REF_REORDERING); if (kuiIdc == 0 || kuiIdc == 1) { // abs_diff_pic_num_minus1 should be in range 0 to MaxPicNum-1, MaxPicNum is derived as // 2^(4+log2_max_frame_num_minus4) WELS_READ_VERIFY (BsGetUe (pBs, &uiCode)); //abs_diff_pic_num_minus1 WELS_CHECK_SE_UPPER_ERROR_NOLOG (uiCode, (uint32_t) (1 << pSps->uiLog2MaxFrameNum), "abs_diff_pic_num_minus1", GENERATE_ERROR_NO (ERR_LEVEL_SLICE_HEADER, ERR_INFO_INVALID_REF_REORDERING)); pRefPicListReordering->sReorderingSyn[iList][iIdx].uiAbsDiffPicNumMinus1 = uiCode; // uiAbsDiffPicNumMinus1 } else if (kuiIdc == 2) { WELS_READ_VERIFY (BsGetUe (pBs, &uiCode)); //long_term_pic_num pRefPicListReordering->sReorderingSyn[iList][iIdx].uiLongTermPicNum = uiCode; } ++ iIdx; } while (true); } if (keSt != B_SLICE) break; ++ iList; } while (iList < LIST_A); return ERR_NONE; } int32_t ParseDecRefPicMarking (PWelsDecoderContext pCtx, PBitStringAux pBs, PSliceHeader pSh, PSps pSps, const bool kbIdrFlag) { PRefPicMarking const kpRefMarking = &pSh->sRefMarking; uint32_t uiCode; if (kbIdrFlag) { WELS_READ_VERIFY (BsGetOneBit (pBs, &uiCode)); //no_output_of_prior_pics_flag kpRefMarking->bNoOutputOfPriorPicsFlag = !!uiCode; WELS_READ_VERIFY (BsGetOneBit (pBs, &uiCode)); //long_term_reference_flag kpRefMarking->bLongTermRefFlag = !!uiCode; } else { WELS_READ_VERIFY (BsGetOneBit (pBs, &uiCode)); //adaptive_ref_pic_marking_mode_flag kpRefMarking->bAdaptiveRefPicMarkingModeFlag = !!uiCode; if (kpRefMarking->bAdaptiveRefPicMarkingModeFlag) { int32_t iIdx = 0; bool bAllowMmco5 = true, bMmco4Exist = false, bMmco5Exist = false, bMmco6Exist = false; do { WELS_READ_VERIFY (BsGetUe (pBs, &uiCode)); //memory_management_control_operation const uint32_t kuiMmco = uiCode; kpRefMarking->sMmcoRef[iIdx].uiMmcoType = kuiMmco; if (kuiMmco == MMCO_END) break; if (kuiMmco == MMCO_SHORT2UNUSED || kuiMmco == MMCO_SHORT2LONG) { bAllowMmco5 = false; WELS_READ_VERIFY (BsGetUe (pBs, &uiCode)); //difference_of_pic_nums_minus1 kpRefMarking->sMmcoRef[iIdx].iDiffOfPicNum = 1 + uiCode; kpRefMarking->sMmcoRef[iIdx].iShortFrameNum = (pSh->iFrameNum - kpRefMarking->sMmcoRef[iIdx].iDiffOfPicNum) & (( 1 << pSps->uiLog2MaxFrameNum) - 1); } else if (kuiMmco == MMCO_LONG2UNUSED) { bAllowMmco5 = false; WELS_READ_VERIFY (BsGetUe (pBs, &uiCode)); //long_term_pic_num kpRefMarking->sMmcoRef[iIdx].uiLongTermPicNum = uiCode; } if (kuiMmco == MMCO_SHORT2LONG || kuiMmco == MMCO_LONG) { if (kuiMmco == MMCO_LONG) { WELS_VERIFY_RETURN_IF (-1, bMmco6Exist); bMmco6Exist = true; } WELS_READ_VERIFY (BsGetUe (pBs, &uiCode)); //long_term_frame_idx kpRefMarking->sMmcoRef[iIdx].iLongTermFrameIdx = uiCode; } else if (kuiMmco == MMCO_SET_MAX_LONG) { WELS_VERIFY_RETURN_IF (-1, bMmco4Exist); bMmco4Exist = true; WELS_READ_VERIFY (BsGetUe (pBs, &uiCode)); //max_long_term_frame_idx_plus1 kpRefMarking->sMmcoRef[iIdx].iMaxLongTermFrameIdx = -1 + uiCode; } else if (kuiMmco == MMCO_RESET) { WELS_VERIFY_RETURN_IF (-1, (!bAllowMmco5 || bMmco5Exist)); bMmco5Exist = true; } ++ iIdx; } while (iIdx < MAX_MMCO_COUNT); } } return ERR_NONE; } bool FillDefaultSliceHeaderExt (PSliceHeaderExt pShExt, PNalUnitHeaderExt pNalExt) { if (pShExt == NULL || pNalExt == NULL) return false; if (pNalExt->iNoInterLayerPredFlag || pNalExt->uiQualityId > 0) pShExt->bBasePredWeightTableFlag = false; else pShExt->bBasePredWeightTableFlag = true; pShExt->uiRefLayerDqId = (uint8_t) - 1; pShExt->uiDisableInterLayerDeblockingFilterIdc = 0; pShExt->iInterLayerSliceAlphaC0Offset = 0; pShExt->iInterLayerSliceBetaOffset = 0; pShExt->bConstrainedIntraResamplingFlag = false; pShExt->uiRefLayerChromaPhaseXPlus1Flag = 0; pShExt->uiRefLayerChromaPhaseYPlus1 = 1; //memset(&pShExt->sScaledRefLayer, 0, sizeof(SPosOffset)); pShExt->iScaledRefLayerPicWidthInSampleLuma = pShExt->sSliceHeader.iMbWidth << 4; pShExt->iScaledRefLayerPicHeightInSampleLuma = pShExt->sSliceHeader.iMbHeight << 4; pShExt->bSliceSkipFlag = false; pShExt->bAdaptiveBaseModeFlag = false; pShExt->bDefaultBaseModeFlag = false; pShExt->bAdaptiveMotionPredFlag = false; pShExt->bDefaultMotionPredFlag = false; pShExt->bAdaptiveResidualPredFlag = false; pShExt->bDefaultResidualPredFlag = false; pShExt->bTCoeffLevelPredFlag = false; pShExt->uiScanIdxStart = 0; pShExt->uiScanIdxEnd = 15; return true; } int32_t InitBsBuffer (PWelsDecoderContext pCtx) { if (pCtx == NULL) return ERR_INFO_INVALID_PTR; CMemoryAlign* pMa = pCtx->pMemAlign; pCtx->iMaxBsBufferSizeInByte = MIN_ACCESS_UNIT_CAPACITY * MAX_BUFFERED_NUM; if ((pCtx->sRawData.pHead = static_cast<uint8_t*> (pMa->WelsMallocz (pCtx->iMaxBsBufferSizeInByte, "pCtx->sRawData.pHead"))) == NULL) { return ERR_INFO_OUT_OF_MEMORY; } pCtx->sRawData.pStartPos = pCtx->sRawData.pCurPos = pCtx->sRawData.pHead; pCtx->sRawData.pEnd = pCtx->sRawData.pHead + pCtx->iMaxBsBufferSizeInByte; if (pCtx->pParam->bParseOnly) { pCtx->pParserBsInfo = static_cast<SParserBsInfo*> (pMa->WelsMallocz (sizeof (SParserBsInfo), "pCtx->pParserBsInfo")); if (pCtx->pParserBsInfo == NULL) { return ERR_INFO_OUT_OF_MEMORY; } memset (pCtx->pParserBsInfo, 0, sizeof (SParserBsInfo)); pCtx->pParserBsInfo->pDstBuff = static_cast<uint8_t*> (pMa->WelsMallocz (MAX_ACCESS_UNIT_CAPACITY * sizeof (uint8_t), "pCtx->pParserBsInfo->pDstBuff")); if (pCtx->pParserBsInfo->pDstBuff == NULL) { return ERR_INFO_OUT_OF_MEMORY; } memset (pCtx->pParserBsInfo->pDstBuff, 0, MAX_ACCESS_UNIT_CAPACITY * sizeof (uint8_t)); if ((pCtx->sSavedData.pHead = static_cast<uint8_t*> (pMa->WelsMallocz (pCtx->iMaxBsBufferSizeInByte, "pCtx->sSavedData.pHead"))) == NULL) { return ERR_INFO_OUT_OF_MEMORY; } pCtx->sSavedData.pStartPos = pCtx->sSavedData.pCurPos = pCtx->sSavedData.pHead; pCtx->sSavedData.pEnd = pCtx->sSavedData.pHead + pCtx->iMaxBsBufferSizeInByte; pCtx->iMaxNalNum = MAX_NAL_UNITS_IN_LAYER + 2; //2 reserved for SPS+PPS pCtx->pParserBsInfo->pNalLenInByte = static_cast<int*> (pMa->WelsMallocz (pCtx->iMaxNalNum * sizeof (int), "pCtx->pParserBsInfo->pNalLenInByte")); if (pCtx->pParserBsInfo->pNalLenInByte == NULL) { return ERR_INFO_OUT_OF_MEMORY; } } return ERR_NONE; } int32_t ExpandBsBuffer (PWelsDecoderContext pCtx, const int kiSrcLen) { if (pCtx == NULL) return ERR_INFO_INVALID_PTR; int32_t iExpandStepShift = 1; int32_t iNewBuffLen = WELS_MAX ((kiSrcLen * MAX_BUFFERED_NUM), (pCtx->iMaxBsBufferSizeInByte << iExpandStepShift)); //allocate new bs buffer CMemoryAlign* pMa = pCtx->pMemAlign; //Realloc sRawData uint8_t* pNewBsBuff = static_cast<uint8_t*> (pMa->WelsMallocz (iNewBuffLen, "pCtx->sRawData.pHead")); if (pNewBsBuff == NULL) { WelsLog (& (pCtx->sLogCtx), WELS_LOG_ERROR, "ExpandBsBuffer() Failed for malloc pNewBsBuff (%d)", iNewBuffLen); pCtx->iErrorCode |= dsOutOfMemory; return ERR_INFO_OUT_OF_MEMORY; } //Calculate and set the bs start and end position for (uint32_t i = 0; i <= pCtx->pAccessUnitList->uiActualUnitsNum; i++) { PBitStringAux pSliceBitsRead = &pCtx->pAccessUnitList->pNalUnitsList[i]->sNalData.sVclNal.sSliceBitsRead; pSliceBitsRead->pStartBuf = pSliceBitsRead->pStartBuf - pCtx->sRawData.pHead + pNewBsBuff; pSliceBitsRead->pEndBuf = pSliceBitsRead->pEndBuf - pCtx->sRawData.pHead + pNewBsBuff; pSliceBitsRead->pCurBuf = pSliceBitsRead->pCurBuf - pCtx->sRawData.pHead + pNewBsBuff; } //Copy current buffer status to new buffer memcpy (pNewBsBuff, pCtx->sRawData.pHead, pCtx->iMaxBsBufferSizeInByte); pCtx->sRawData.pStartPos = pNewBsBuff + (pCtx->sRawData.pStartPos - pCtx->sRawData.pHead); pCtx->sRawData.pCurPos = pNewBsBuff + (pCtx->sRawData.pCurPos - pCtx->sRawData.pHead); pCtx->sRawData.pEnd = pNewBsBuff + iNewBuffLen; pMa->WelsFree (pCtx->sRawData.pHead, "pCtx->sRawData.pHead"); pCtx->sRawData.pHead = pNewBsBuff; if (pCtx->pParam->bParseOnly) { //Realloc sSavedData uint8_t* pNewSavedBsBuff = static_cast<uint8_t*> (pMa->WelsMallocz (iNewBuffLen, "pCtx->sSavedData.pHead")); if (pNewSavedBsBuff == NULL) { WelsLog (& (pCtx->sLogCtx), WELS_LOG_ERROR, "ExpandBsBuffer() Failed for malloc pNewSavedBsBuff (%d)", iNewBuffLen); pCtx->iErrorCode |= dsOutOfMemory; return ERR_INFO_OUT_OF_MEMORY; } //Copy current buffer status to new buffer memcpy (pNewSavedBsBuff, pCtx->sSavedData.pHead, pCtx->iMaxBsBufferSizeInByte); pCtx->sSavedData.pStartPos = pNewSavedBsBuff + (pCtx->sSavedData.pStartPos - pCtx->sSavedData.pHead); pCtx->sSavedData.pCurPos = pNewSavedBsBuff + (pCtx->sSavedData.pCurPos - pCtx->sSavedData.pHead); pCtx->sSavedData.pEnd = pNewSavedBsBuff + iNewBuffLen; pMa->WelsFree (pCtx->sSavedData.pHead, "pCtx->sSavedData.pHead"); pCtx->sSavedData.pHead = pNewSavedBsBuff; } pCtx->iMaxBsBufferSizeInByte = iNewBuffLen; return ERR_NONE; } int32_t ExpandBsLenBuffer (PWelsDecoderContext pCtx, const int kiCurrLen) { SParserBsInfo* pParser = pCtx->pParserBsInfo; if (!pParser->pNalLenInByte) return ERR_INFO_INVALID_ACCESS; int iNewLen = kiCurrLen; if (kiCurrLen >= MAX_MB_SIZE + 2) { //exceeds the max MB number of level 5.2 WelsLog (& (pCtx->sLogCtx), WELS_LOG_WARNING, "Current nal num (%d) exceededs %d.", kiCurrLen, MAX_MB_SIZE); pCtx->iErrorCode |= dsOutOfMemory; return ERR_INFO_OUT_OF_MEMORY; } else { iNewLen = kiCurrLen << 1; iNewLen = WELS_MIN (iNewLen, MAX_MB_SIZE + 2); } CMemoryAlign* pMa = pCtx->pMemAlign; int* pNewLenBuffer = static_cast<int*> (pMa->WelsMallocz (iNewLen * sizeof (int), "pCtx->pParserBsInfo->pNalLenInByte")); if (pNewLenBuffer == NULL) { pCtx->iErrorCode |= dsOutOfMemory; return ERR_INFO_OUT_OF_MEMORY; } //copy existing data from old length buffer to new memcpy (pNewLenBuffer, pParser->pNalLenInByte, pCtx->iMaxNalNum * sizeof (int)); pMa->WelsFree (pParser->pNalLenInByte, "pCtx->pParserBsInfo->pNalLenInByte"); pParser->pNalLenInByte = pNewLenBuffer; pCtx->iMaxNalNum = iNewLen; return ERR_NONE; } int32_t CheckBsBuffer (PWelsDecoderContext pCtx, const int32_t kiSrcLen) { if (kiSrcLen > MAX_ACCESS_UNIT_CAPACITY) { //exceeds max allowed data WelsLog (& (pCtx->sLogCtx), WELS_LOG_WARNING, "Max AU size exceeded. Allowed size = %d, current size = %d", MAX_ACCESS_UNIT_CAPACITY, kiSrcLen); pCtx->iErrorCode |= dsBitstreamError; return ERR_INFO_INVALID_ACCESS; } else if (kiSrcLen > pCtx->iMaxBsBufferSizeInByte / MAX_BUFFERED_NUM) { //may lead to buffer overwrite, prevent it by expanding buffer if (ExpandBsBuffer (pCtx, kiSrcLen)) { return ERR_INFO_OUT_OF_MEMORY; } } return ERR_NONE; } /* * WelsInitStaticMemory * Memory request for new introduced data * Especially for: * rbsp_au_buffer, cur_dq_layer_ptr and ref_dq_layer_ptr in MB info cache. * return: * 0 - success; otherwise returned error_no defined in error_no.h. */ int32_t WelsInitStaticMemory (PWelsDecoderContext pCtx) { if (pCtx == NULL) { return ERR_INFO_INVALID_PTR; } if (MemInitNalList (&pCtx->pAccessUnitList, MAX_NAL_UNIT_NUM_IN_AU, pCtx->pMemAlign) != 0) return ERR_INFO_OUT_OF_MEMORY; if (InitBsBuffer (pCtx) != 0) return ERR_INFO_OUT_OF_MEMORY; pCtx->uiTargetDqId = (uint8_t) - 1; pCtx->bEndOfStreamFlag = false; return ERR_NONE; } /* * WelsFreeStaticMemory * Free memory introduced in WelsInitStaticMemory at destruction of decoder. * */ void WelsFreeStaticMemory (PWelsDecoderContext pCtx) { if (pCtx == NULL) return; CMemoryAlign* pMa = pCtx->pMemAlign; MemFreeNalList (&pCtx->pAccessUnitList, pMa); if (pCtx->sRawData.pHead) { pMa->WelsFree (pCtx->sRawData.pHead, "pCtx->sRawData->pHead"); } pCtx->sRawData.pHead = NULL; pCtx->sRawData.pEnd = NULL; pCtx->sRawData.pStartPos = NULL; pCtx->sRawData.pCurPos = NULL; if (pCtx->pParam->bParseOnly) { if (pCtx->sSavedData.pHead) { pMa->WelsFree (pCtx->sSavedData.pHead, "pCtx->sSavedData->pHead"); } pCtx->sSavedData.pHead = NULL; pCtx->sSavedData.pEnd = NULL; pCtx->sSavedData.pStartPos = NULL; pCtx->sSavedData.pCurPos = NULL; if (pCtx->pParserBsInfo) { if (pCtx->pParserBsInfo->pNalLenInByte) { pMa->WelsFree (pCtx->pParserBsInfo->pNalLenInByte, "pCtx->pParserBsInfo->pNalLenInByte"); pCtx->pParserBsInfo->pNalLenInByte = NULL; pCtx->iMaxNalNum = 0; } if (pCtx->pParserBsInfo->pDstBuff) { pMa->WelsFree (pCtx->pParserBsInfo->pDstBuff, "pCtx->pParserBsInfo->pDstBuff"); pCtx->pParserBsInfo->pDstBuff = NULL; } pMa->WelsFree (pCtx->pParserBsInfo, "pCtx->pParserBsInfo"); pCtx->pParserBsInfo = NULL; } } if (NULL != pCtx->pParam) { pMa->WelsFree (pCtx->pParam, "pCtx->pParam"); pCtx->pParam = NULL; } } /* * DecodeNalHeaderExt * Trigger condition: NAL_UNIT_TYPE = NAL_UNIT_PREFIX or NAL_UNIT_CODED_SLICE_EXT * Parameter: * pNal: target NALUnit ptr * pSrc: NAL Unit bitstream */ void DecodeNalHeaderExt (PNalUnit pNal, uint8_t* pSrc) { PNalUnitHeaderExt pHeaderExt = &pNal->sNalHeaderExt; uint8_t uiCurByte = *pSrc; pHeaderExt->bIdrFlag = !! (uiCurByte & 0x40); pHeaderExt->uiPriorityId = uiCurByte & 0x3F; uiCurByte = * (++pSrc); pHeaderExt->iNoInterLayerPredFlag = uiCurByte >> 7; pHeaderExt->uiDependencyId = (uiCurByte & 0x70) >> 4; pHeaderExt->uiQualityId = uiCurByte & 0x0F; uiCurByte = * (++pSrc); pHeaderExt->uiTemporalId = uiCurByte >> 5; pHeaderExt->bUseRefBasePicFlag = !! (uiCurByte & 0x10); pHeaderExt->bDiscardableFlag = !! (uiCurByte & 0x08); pHeaderExt->bOutputFlag = !! (uiCurByte & 0x04); pHeaderExt->uiReservedThree2Bits = uiCurByte & 0x03; pHeaderExt->uiLayerDqId = (pHeaderExt->uiDependencyId << 4) | pHeaderExt->uiQualityId; } void UpdateDecoderStatisticsForActiveParaset (SDecoderStatistics* pDecoderStatistics, PSps pSps, PPps pPps) { pDecoderStatistics->iCurrentActiveSpsId = pSps->iSpsId; pDecoderStatistics->iCurrentActivePpsId = pPps->iPpsId; pDecoderStatistics->uiProfile = static_cast<unsigned int> (pSps->uiProfileIdc); pDecoderStatistics->uiLevel = pSps->uiLevelIdc; } #define SLICE_HEADER_IDR_PIC_ID_MAX 65535 #define SLICE_HEADER_REDUNDANT_PIC_CNT_MAX 127 #define SLICE_HEADER_ALPHAC0_BETA_OFFSET_MIN -12 #define SLICE_HEADER_ALPHAC0_BETA_OFFSET_MAX 12 #define SLICE_HEADER_INTER_LAYER_ALPHAC0_BETA_OFFSET_MIN -12 #define SLICE_HEADER_INTER_LAYER_ALPHAC0_BETA_OFFSET_MAX 12 #define MAX_NUM_REF_IDX_L0_ACTIVE_MINUS1 15 #define SLICE_HEADER_CABAC_INIT_IDC_MAX 2 /* * decode_slice_header_avc * Parse slice header of bitstream in avc for storing data structure */ int32_t ParseSliceHeaderSyntaxs (PWelsDecoderContext pCtx, PBitStringAux pBs, const bool kbExtensionFlag) { PNalUnit const kpCurNal = pCtx->pAccessUnitList->pNalUnitsList[pCtx->pAccessUnitList->uiAvailUnitsNum - 1]; PNalUnitHeaderExt pNalHeaderExt = NULL; PSliceHeader pSliceHead = NULL; PSliceHeaderExt pSliceHeadExt = NULL; PSubsetSps pSubsetSps = NULL; PSps pSps = NULL; PPps pPps = NULL; EWelsNalUnitType eNalType = static_cast<EWelsNalUnitType> (0); int32_t iPpsId = 0; int32_t iRet = ERR_NONE; uint8_t uiSliceType = 0; uint8_t uiQualityId = BASE_QUALITY_ID; bool bIdrFlag = false; bool bSgChangeCycleInvolved = false; // involved slice group change cycle ? uint32_t uiCode; int32_t iCode; SLogContext* pLogCtx = & (pCtx->sLogCtx); if (kpCurNal == NULL) { return ERR_INFO_OUT_OF_MEMORY; } pNalHeaderExt = &kpCurNal->sNalHeaderExt; pSliceHead = &kpCurNal->sNalData.sVclNal.sSliceHeaderExt.sSliceHeader; eNalType = pNalHeaderExt->sNalUnitHeader.eNalUnitType; pSliceHeadExt = &kpCurNal->sNalData.sVclNal.sSliceHeaderExt; if (pSliceHeadExt) { SRefBasePicMarking sBaseMarking; const bool kbStoreRefBaseFlag = pSliceHeadExt->bStoreRefBasePicFlag; memcpy (&sBaseMarking, &pSliceHeadExt->sRefBasePicMarking, sizeof (SRefBasePicMarking)); //confirmed_safe_unsafe_usage memset (pSliceHeadExt, 0, sizeof (SSliceHeaderExt)); pSliceHeadExt->bStoreRefBasePicFlag = kbStoreRefBaseFlag; memcpy (&pSliceHeadExt->sRefBasePicMarking, &sBaseMarking, sizeof (SRefBasePicMarking)); //confirmed_safe_unsafe_usage } kpCurNal->sNalData.sVclNal.bSliceHeaderExtFlag = kbExtensionFlag; // first_mb_in_slice WELS_READ_VERIFY (BsGetUe (pBs, &uiCode)); //first_mb_in_slice WELS_CHECK_SE_UPPER_ERROR (uiCode, 36863u, "first_mb_in_slice", GENERATE_ERROR_NO (ERR_LEVEL_SLICE_HEADER, ERR_INFO_INVALID_FIRST_MB_IN_SLICE)); pSliceHead->iFirstMbInSlice = uiCode; WELS_READ_VERIFY (BsGetUe (pBs, &uiCode)); //slice_type uiSliceType = uiCode; if (uiSliceType > 9) { WelsLog (pLogCtx, WELS_LOG_WARNING, "slice type too large (%d) at first_mb(%d)", uiSliceType, pSliceHead->iFirstMbInSlice); return GENERATE_ERROR_NO (ERR_LEVEL_SLICE_HEADER, ERR_INFO_INVALID_SLICE_TYPE); } if (uiSliceType > 4) uiSliceType -= 5; if (B_SLICE == uiSliceType) { WelsLog (pLogCtx, WELS_LOG_WARNING, "ParseSliceHeaderSyntaxs(): B slice not supported."); return GENERATE_ERROR_NO (ERR_LEVEL_SLICE_HEADER, ERR_INFO_UNSUPPORTED_BIPRED); } if ((NAL_UNIT_CODED_SLICE_IDR == eNalType) && (I_SLICE != uiSliceType)) { WelsLog (pLogCtx, WELS_LOG_WARNING, "Invalid slice type(%d) in IDR picture. ", uiSliceType); return GENERATE_ERROR_NO (ERR_LEVEL_SLICE_HEADER, ERR_INFO_INVALID_SLICE_TYPE); } if (kbExtensionFlag) { if (uiSliceType > 2) { WelsLog (pLogCtx, WELS_LOG_WARNING, "Invalid slice type(%d).", uiSliceType); return GENERATE_ERROR_NO (ERR_LEVEL_SLICE_HEADER, ERR_INFO_INVALID_SLICE_TYPE); } } pSliceHead->eSliceType = static_cast <EWelsSliceType> (uiSliceType); WELS_READ_VERIFY (BsGetUe (pBs, &uiCode)); //pic_parameter_set_id WELS_CHECK_SE_UPPER_ERROR (uiCode, (MAX_PPS_COUNT - 1), "iPpsId out of range", GENERATE_ERROR_NO (ERR_LEVEL_SLICE_HEADER, ERR_INFO_PPS_ID_OVERFLOW)); iPpsId = uiCode; //add check PPS available here if (pCtx->bPpsAvailFlags[iPpsId] == false) { pCtx->sDecoderStatistics.iPpsReportErrorNum++; if (pCtx->iPPSLastInvalidId != iPpsId) { WelsLog (pLogCtx, WELS_LOG_ERROR, "PPS id (%d) is invalid, previous id (%d) error ignored (%d)!", iPpsId, pCtx->iPPSLastInvalidId, pCtx->iPPSInvalidNum); pCtx->iPPSLastInvalidId = iPpsId; pCtx->iPPSInvalidNum = 0; } else { pCtx->iPPSInvalidNum++; } pCtx->iErrorCode |= dsNoParamSets; return GENERATE_ERROR_NO (ERR_LEVEL_SLICE_HEADER, ERR_INFO_INVALID_PPS_ID); } pCtx->iPPSLastInvalidId = -1; pPps = &pCtx->sPpsBuffer[iPpsId]; if (pPps->uiNumSliceGroups == 0) { WelsLog (pLogCtx, WELS_LOG_WARNING, "Invalid PPS referenced"); pCtx->iErrorCode |= dsNoParamSets; return GENERATE_ERROR_NO (ERR_LEVEL_SLICE_HEADER, ERR_INFO_NO_PARAM_SETS); } if (kbExtensionFlag) { pSubsetSps = &pCtx->sSubsetSpsBuffer[pPps->iSpsId]; pSps = &pSubsetSps->sSps; if (pCtx->bSubspsAvailFlags[pPps->iSpsId] == false) { pCtx->sDecoderStatistics.iSubSpsReportErrorNum++; if (pCtx->iSubSPSLastInvalidId != pPps->iSpsId) { WelsLog (pLogCtx, WELS_LOG_ERROR, "Sub SPS id (%d) is invalid, previous id (%d) error ignored (%d)!", pPps->iSpsId, pCtx->iSubSPSLastInvalidId, pCtx->iSubSPSInvalidNum); pCtx->iSubSPSLastInvalidId = pPps->iSpsId; pCtx->iSubSPSInvalidNum = 0; } else { pCtx->iSubSPSInvalidNum++; } pCtx->iErrorCode |= dsNoParamSets; return GENERATE_ERROR_NO (ERR_LEVEL_SLICE_HEADER, ERR_INFO_INVALID_SPS_ID); } pCtx->iSubSPSLastInvalidId = -1; } else { if (pCtx->bSpsAvailFlags[pPps->iSpsId] == false) { pCtx->sDecoderStatistics.iSpsReportErrorNum++; if (pCtx->iSPSLastInvalidId != pPps->iSpsId) { WelsLog (pLogCtx, WELS_LOG_ERROR, "SPS id (%d) is invalid, previous id (%d) error ignored (%d)!", pPps->iSpsId, pCtx->iSPSLastInvalidId, pCtx->iSPSInvalidNum); pCtx->iSPSLastInvalidId = pPps->iSpsId; pCtx->iSPSInvalidNum = 0; } else { pCtx->iSPSInvalidNum++; } pCtx->iErrorCode |= dsNoParamSets; return GENERATE_ERROR_NO (ERR_LEVEL_SLICE_HEADER, ERR_INFO_INVALID_SPS_ID); } pCtx->iSPSLastInvalidId = -1; pSps = &pCtx->sSpsBuffer[pPps->iSpsId]; } pSliceHead->iPpsId = iPpsId; pSliceHead->iSpsId = pPps->iSpsId; pSliceHead->pPps = pPps; pSliceHead->pSps = pSps; pSliceHeadExt->pSubsetSps = pSubsetSps; if (pSps->iNumRefFrames == 0) { if ((uiSliceType != I_SLICE) && (uiSliceType != SI_SLICE)) { WelsLog (pLogCtx, WELS_LOG_WARNING, "slice_type (%d) not supported for num_ref_frames = 0.", uiSliceType); return GENERATE_ERROR_NO (ERR_LEVEL_SLICE_HEADER, ERR_INFO_INVALID_SLICE_TYPE); } } bIdrFlag = (!kbExtensionFlag && eNalType == NAL_UNIT_CODED_SLICE_IDR) || (kbExtensionFlag && pNalHeaderExt->bIdrFlag); pSliceHead->bIdrFlag = bIdrFlag; if (pSps->uiLog2MaxFrameNum == 0) { WelsLog (pLogCtx, WELS_LOG_WARNING, "non existing SPS referenced"); return GENERATE_ERROR_NO (ERR_LEVEL_SLICE_HEADER, ERR_INFO_NO_PARAM_SETS); } // check first_mb_in_slice WELS_CHECK_SE_UPPER_ERROR ((uint32_t) (pSliceHead->iFirstMbInSlice), (pSps->uiTotalMbCount - 1), "first_mb_in_slice", GENERATE_ERROR_NO (ERR_LEVEL_SLICE_HEADER, ERR_INFO_INVALID_FIRST_MB_IN_SLICE)); WELS_READ_VERIFY (BsGetBits (pBs, pSps->uiLog2MaxFrameNum, &uiCode)); //frame_num pSliceHead->iFrameNum = uiCode; pSliceHead->bFieldPicFlag = false; pSliceHead->bBottomFiledFlag = false; if (!pSps->bFrameMbsOnlyFlag) { WelsLog (pLogCtx, WELS_LOG_WARNING, "ParseSliceHeaderSyntaxs(): frame_mbs_only_flag = %d not supported. ", pSps->bFrameMbsOnlyFlag); return GENERATE_ERROR_NO (ERR_LEVEL_SLICE_HEADER, ERR_INFO_UNSUPPORTED_MBAFF); } pSliceHead->iMbWidth = pSps->iMbWidth; pSliceHead->iMbHeight = pSps->iMbHeight / (1 + pSliceHead->bFieldPicFlag); if (bIdrFlag) { if (pSliceHead->iFrameNum != 0) { WelsLog (pLogCtx, WELS_LOG_WARNING, "ParseSliceHeaderSyntaxs(), invaild frame number: %d due to IDR frame introduced!", pSliceHead->iFrameNum); return GENERATE_ERROR_NO (ERR_LEVEL_SLICE_HEADER, ERR_INFO_INVALID_FRAME_NUM); } WELS_READ_VERIFY (BsGetUe (pBs, &uiCode)); //idr_pic_id // standard 7.4.3 idr_pic_id should be in range 0 to 65535, inclusive. WELS_CHECK_SE_UPPER_ERROR (uiCode, SLICE_HEADER_IDR_PIC_ID_MAX, "idr_pic_id", GENERATE_ERROR_NO (ERR_LEVEL_SLICE_HEADER, ERR_INFO_INVALID_IDR_PIC_ID)); pSliceHead->uiIdrPicId = uiCode; /* uiIdrPicId */ #ifdef LONG_TERM_REF pCtx->uiCurIdrPicId = pSliceHead->uiIdrPicId; #endif } pSliceHead->iDeltaPicOrderCntBottom = 0; pSliceHead->iDeltaPicOrderCnt[0] = pSliceHead->iDeltaPicOrderCnt[1] = 0; if (pSps->uiPocType == 0) { WELS_READ_VERIFY (BsGetBits (pBs, pSps->iLog2MaxPocLsb, &uiCode)); //pic_order_cnt_lsb pSliceHead->iPicOrderCntLsb = uiCode; if (pPps->bPicOrderPresentFlag && !pSliceHead->bFieldPicFlag) { WELS_READ_VERIFY (BsGetSe (pBs, &iCode)); //delta_pic_order_cnt_bottom pSliceHead->iDeltaPicOrderCntBottom = iCode; } } else if (pSps->uiPocType == 1 && !pSps->bDeltaPicOrderAlwaysZeroFlag) { WELS_READ_VERIFY (BsGetSe (pBs, &iCode)); //delta_pic_order_cnt[ 0 ] pSliceHead->iDeltaPicOrderCnt[0] = iCode; if (pPps->bPicOrderPresentFlag && !pSliceHead->bFieldPicFlag) { WELS_READ_VERIFY (BsGetSe (pBs, &iCode)); //delta_pic_order_cnt[ 1 ] pSliceHead->iDeltaPicOrderCnt[1] = iCode; } } pSliceHead->iRedundantPicCnt = 0; if (pPps->bRedundantPicCntPresentFlag) { WELS_READ_VERIFY (BsGetUe (pBs, &uiCode)); //redundant_pic_cnt // standard section 7.4.3, redundant_pic_cnt should be in range 0 to 127, inclusive. WELS_CHECK_SE_UPPER_ERROR (uiCode, SLICE_HEADER_REDUNDANT_PIC_CNT_MAX, "redundant_pic_cnt", GENERATE_ERROR_NO (ERR_LEVEL_SLICE_HEADER, ERR_INFO_INVALID_REDUNDANT_PIC_CNT)); pSliceHead->iRedundantPicCnt = uiCode; if (pSliceHead->iRedundantPicCnt > 0) { WelsLog (pLogCtx, WELS_LOG_WARNING, "Redundant picture not supported!"); return GENERATE_ERROR_NO (ERR_LEVEL_SLICE_HEADER, ERR_INFO_INVALID_REDUNDANT_PIC_CNT); } } //set defaults, might be overriden a few line later pSliceHead->uiRefCount[0] = pPps->uiNumRefIdxL0Active; pSliceHead->uiRefCount[1] = pPps->uiNumRefIdxL1Active; bool bReadNumRefFlag = (P_SLICE == uiSliceType); if (kbExtensionFlag) { bReadNumRefFlag &= (BASE_QUALITY_ID == pNalHeaderExt->uiQualityId); } if (bReadNumRefFlag) { WELS_READ_VERIFY (BsGetOneBit (pBs, &uiCode)); //num_ref_idx_active_override_flag pSliceHead->bNumRefIdxActiveOverrideFlag = !!uiCode; if (pSliceHead->bNumRefIdxActiveOverrideFlag) { WELS_READ_VERIFY (BsGetUe (pBs, &uiCode)); //num_ref_idx_l0_active_minus1 WELS_CHECK_SE_UPPER_ERROR (uiCode, MAX_NUM_REF_IDX_L0_ACTIVE_MINUS1, "num_ref_idx_l0_active_minus1", GENERATE_ERROR_NO (ERR_LEVEL_SLICE_HEADER, ERR_INFO_INVALID_NUM_REF_IDX_L0_ACTIVE_MINUS1)); pSliceHead->uiRefCount[0] = 1 + uiCode; } } if (pSliceHead->uiRefCount[0] > MAX_REF_PIC_COUNT || pSliceHead->uiRefCount[1] > MAX_REF_PIC_COUNT) { WelsLog (pLogCtx, WELS_LOG_WARNING, "reference overflow"); return GENERATE_ERROR_NO (ERR_LEVEL_SLICE_HEADER, ERR_INFO_REF_COUNT_OVERFLOW); } if (BASE_QUALITY_ID == uiQualityId) { iRet = ParseRefPicListReordering (pBs, pSliceHead); if (iRet != ERR_NONE) { WelsLog (pLogCtx, WELS_LOG_WARNING, "invalid ref pPic list reordering syntaxs!"); return iRet; } if (pPps->bWeightedPredFlag && (uiSliceType == P_SLICE)) { iRet = ParsePredWeightedTable (pBs, pSliceHead); if (iRet != ERR_NONE) { WelsLog (pLogCtx, WELS_LOG_WARNING, "invalid weighted prediction syntaxs!"); return iRet; } } if (kbExtensionFlag) { if (pNalHeaderExt->iNoInterLayerPredFlag || pNalHeaderExt->uiQualityId > 0) pSliceHeadExt->bBasePredWeightTableFlag = false; else pSliceHeadExt->bBasePredWeightTableFlag = true; } if (kpCurNal->sNalHeaderExt.sNalUnitHeader.uiNalRefIdc != 0) { iRet = ParseDecRefPicMarking (pCtx, pBs, pSliceHead, pSps, bIdrFlag); if (iRet != ERR_NONE) { return iRet; } if (kbExtensionFlag && !pSubsetSps->sSpsSvcExt.bSliceHeaderRestrictionFlag) { WELS_READ_VERIFY (BsGetOneBit (pBs, &uiCode)); //store_ref_base_pic_flag pSliceHeadExt->bStoreRefBasePicFlag = !!uiCode; if ((pNalHeaderExt->bUseRefBasePicFlag || pSliceHeadExt->bStoreRefBasePicFlag) && !bIdrFlag) { WelsLog (pLogCtx, WELS_LOG_WARNING, "ParseSliceHeaderSyntaxs(): bUseRefBasePicFlag or bStoreRefBasePicFlag = 1 not supported."); return GENERATE_ERROR_NO (ERR_LEVEL_SLICE_HEADER, ERR_INFO_UNSUPPORTED_ILP); } } } } if (pPps->bEntropyCodingModeFlag) { if (pSliceHead->eSliceType != I_SLICE && pSliceHead->eSliceType != SI_SLICE) { WELS_READ_VERIFY (BsGetUe (pBs, &uiCode)); WELS_CHECK_SE_UPPER_ERROR (uiCode, SLICE_HEADER_CABAC_INIT_IDC_MAX, "cabac_init_idc", ERR_INFO_INVALID_CABAC_INIT_IDC); pSliceHead->iCabacInitIdc = uiCode; } else pSliceHead->iCabacInitIdc = 0; } WELS_READ_VERIFY (BsGetSe (pBs, &iCode)); //slice_qp_delta pSliceHead->iSliceQpDelta = iCode; pSliceHead->iSliceQp = pPps->iPicInitQp + pSliceHead->iSliceQpDelta; if (pSliceHead->iSliceQp < 0 || pSliceHead->iSliceQp > 51) { WelsLog (pLogCtx, WELS_LOG_WARNING, "QP %d out of range", pSliceHead->iSliceQp); return GENERATE_ERROR_NO (ERR_LEVEL_SLICE_HEADER, ERR_INFO_INVALID_QP); } //FIXME qscale / qp ... stuff if (!kbExtensionFlag) { if (uiSliceType == SP_SLICE || uiSliceType == SI_SLICE) { WelsLog (pLogCtx, WELS_LOG_WARNING, "SP/SI not supported"); return GENERATE_ERROR_NO (ERR_LEVEL_SLICE_HEADER, ERR_INFO_UNSUPPORTED_SPSI); } } pSliceHead->uiDisableDeblockingFilterIdc = 0; pSliceHead->iSliceAlphaC0Offset = 0; pSliceHead->iSliceBetaOffset = 0; if (pPps->bDeblockingFilterControlPresentFlag) { WELS_READ_VERIFY (BsGetUe (pBs, &uiCode)); //disable_deblocking_filter_idc pSliceHead->uiDisableDeblockingFilterIdc = uiCode; //refer to JVT-X201wcm1.doc G.7.4.3.4--2010.4.20 if (pSliceHead->uiDisableDeblockingFilterIdc > 6) { WelsLog (pLogCtx, WELS_LOG_WARNING, "disable_deblock_filter_idc (%d) out of range [0, 6]", pSliceHead->uiDisableDeblockingFilterIdc); return GENERATE_ERROR_NO (ERR_LEVEL_SLICE_HEADER, ERR_INFO_INVALID_DBLOCKING_IDC); } if (pSliceHead->uiDisableDeblockingFilterIdc != 1) { WELS_READ_VERIFY (BsGetSe (pBs, &iCode)); //slice_alpha_c0_offset_div2 pSliceHead->iSliceAlphaC0Offset = iCode * 2; WELS_CHECK_SE_BOTH_ERROR (pSliceHead->iSliceAlphaC0Offset, SLICE_HEADER_ALPHAC0_BETA_OFFSET_MIN, SLICE_HEADER_ALPHAC0_BETA_OFFSET_MAX, "slice_alpha_c0_offset_div2 * 2", GENERATE_ERROR_NO (ERR_LEVEL_SLICE_HEADER, ERR_INFO_INVALID_SLICE_ALPHA_C0_OFFSET_DIV2)); WELS_READ_VERIFY (BsGetSe (pBs, &iCode)); //slice_beta_offset_div2 pSliceHead->iSliceBetaOffset = iCode * 2; WELS_CHECK_SE_BOTH_ERROR (pSliceHead->iSliceBetaOffset, SLICE_HEADER_ALPHAC0_BETA_OFFSET_MIN, SLICE_HEADER_ALPHAC0_BETA_OFFSET_MAX, "slice_beta_offset_div2 * 2", GENERATE_ERROR_NO (ERR_LEVEL_SLICE_HEADER, ERR_INFO_INVALID_SLICE_BETA_OFFSET_DIV2)); } } bSgChangeCycleInvolved = (pPps->uiNumSliceGroups > 1 && pPps->uiSliceGroupMapType >= 3 && pPps->uiSliceGroupMapType <= 5); if (kbExtensionFlag && bSgChangeCycleInvolved) bSgChangeCycleInvolved = (bSgChangeCycleInvolved && (uiQualityId == BASE_QUALITY_ID)); if (bSgChangeCycleInvolved) { if (pPps->uiSliceGroupChangeRate > 0) { const int32_t kiNumBits = (int32_t)WELS_CEIL (log (static_cast<double> (1 + pPps->uiPicSizeInMapUnits / pPps->uiSliceGroupChangeRate))); WELS_READ_VERIFY (BsGetBits (pBs, kiNumBits, &uiCode)); //lice_group_change_cycle pSliceHead->iSliceGroupChangeCycle = uiCode; } else pSliceHead->iSliceGroupChangeCycle = 0; } if (!kbExtensionFlag) { FillDefaultSliceHeaderExt (pSliceHeadExt, pNalHeaderExt); } else { /* Extra syntax elements newly introduced */ pSliceHeadExt->pSubsetSps = pSubsetSps; if (!pNalHeaderExt->iNoInterLayerPredFlag && BASE_QUALITY_ID == uiQualityId) { //the following should be deleted for CODE_CLEAN WELS_READ_VERIFY (BsGetUe (pBs, &uiCode)); //ref_layer_dq_id pSliceHeadExt->uiRefLayerDqId = uiCode; if (pSubsetSps->sSpsSvcExt.bInterLayerDeblockingFilterCtrlPresentFlag) { WELS_READ_VERIFY (BsGetUe (pBs, &uiCode)); //disable_inter_layer_deblocking_filter_idc pSliceHeadExt->uiDisableInterLayerDeblockingFilterIdc = uiCode; //refer to JVT-X201wcm1.doc G.7.4.3.4--2010.4.20 if (pSliceHeadExt->uiDisableInterLayerDeblockingFilterIdc > 6) { WelsLog (& (pCtx->sLogCtx), WELS_LOG_WARNING, "disable_inter_layer_deblock_filter_idc (%d) out of range [0, 6]", pSliceHeadExt->uiDisableInterLayerDeblockingFilterIdc); return GENERATE_ERROR_NO (ERR_LEVEL_SLICE_HEADER, ERR_INFO_INVALID_DBLOCKING_IDC); } if (pSliceHeadExt->uiDisableInterLayerDeblockingFilterIdc != 1) { WELS_READ_VERIFY (BsGetSe (pBs, &iCode)); //inter_layer_slice_alpha_c0_offset_div2 pSliceHeadExt->iInterLayerSliceAlphaC0Offset = iCode * 2; WELS_CHECK_SE_BOTH_ERROR (pSliceHeadExt->iInterLayerSliceAlphaC0Offset, SLICE_HEADER_INTER_LAYER_ALPHAC0_BETA_OFFSET_MIN, SLICE_HEADER_INTER_LAYER_ALPHAC0_BETA_OFFSET_MAX, "inter_layer_alpha_c0_offset_div2 * 2", GENERATE_ERROR_NO (ERR_LEVEL_SLICE_HEADER, ERR_INFO_INVALID_SLICE_ALPHA_C0_OFFSET_DIV2)); WELS_READ_VERIFY (BsGetSe (pBs, &iCode)); //inter_layer_slice_beta_offset_div2 pSliceHeadExt->iInterLayerSliceBetaOffset = iCode * 2; WELS_CHECK_SE_BOTH_ERROR (pSliceHeadExt->iInterLayerSliceBetaOffset, SLICE_HEADER_INTER_LAYER_ALPHAC0_BETA_OFFSET_MIN, SLICE_HEADER_INTER_LAYER_ALPHAC0_BETA_OFFSET_MAX, "inter_layer_slice_beta_offset_div2 * 2", GENERATE_ERROR_NO (ERR_LEVEL_SLICE_HEADER, ERR_INFO_INVALID_SLICE_BETA_OFFSET_DIV2)); } } pSliceHeadExt->uiRefLayerChromaPhaseXPlus1Flag = pSubsetSps->sSpsSvcExt.uiSeqRefLayerChromaPhaseXPlus1Flag; pSliceHeadExt->uiRefLayerChromaPhaseYPlus1 = pSubsetSps->sSpsSvcExt.uiSeqRefLayerChromaPhaseYPlus1; WELS_READ_VERIFY (BsGetOneBit (pBs, &uiCode)); //constrained_intra_resampling_flag pSliceHeadExt->bConstrainedIntraResamplingFlag = !!uiCode; { SPosOffset pos; pos.iLeftOffset = pSubsetSps->sSpsSvcExt.sSeqScaledRefLayer.iLeftOffset; pos.iTopOffset = pSubsetSps->sSpsSvcExt.sSeqScaledRefLayer.iTopOffset * (2 - pSps->bFrameMbsOnlyFlag); pos.iRightOffset = pSubsetSps->sSpsSvcExt.sSeqScaledRefLayer.iRightOffset; pos.iBottomOffset = pSubsetSps->sSpsSvcExt.sSeqScaledRefLayer.iBottomOffset * (2 - pSps->bFrameMbsOnlyFlag); //memcpy(&pSliceHeadExt->sScaledRefLayer, &pos, sizeof(SPosOffset));//confirmed_safe_unsafe_usage pSliceHeadExt->iScaledRefLayerPicWidthInSampleLuma = (pSliceHead->iMbWidth << 4) - (pos.iLeftOffset + pos.iRightOffset); pSliceHeadExt->iScaledRefLayerPicHeightInSampleLuma = (pSliceHead->iMbHeight << 4) - (pos.iTopOffset + pos.iBottomOffset) / (1 + pSliceHead->bFieldPicFlag); } } else if (uiQualityId > BASE_QUALITY_ID) { WelsLog (pLogCtx, WELS_LOG_WARNING, "MGS not supported."); return GENERATE_ERROR_NO (ERR_LEVEL_SLICE_HEADER, ERR_INFO_UNSUPPORTED_MGS); } else { pSliceHeadExt->uiRefLayerDqId = (uint8_t) - 1; } pSliceHeadExt->bSliceSkipFlag = false; pSliceHeadExt->bAdaptiveBaseModeFlag = false; pSliceHeadExt->bDefaultBaseModeFlag = false; pSliceHeadExt->bAdaptiveMotionPredFlag = false; pSliceHeadExt->bDefaultMotionPredFlag = false; pSliceHeadExt->bAdaptiveResidualPredFlag = false; pSliceHeadExt->bDefaultResidualPredFlag = false; if (pNalHeaderExt->iNoInterLayerPredFlag) pSliceHeadExt->bTCoeffLevelPredFlag = false; else pSliceHeadExt->bTCoeffLevelPredFlag = pSubsetSps->sSpsSvcExt.bSeqTCoeffLevelPredFlag; if (!pNalHeaderExt->iNoInterLayerPredFlag) { WELS_READ_VERIFY (BsGetOneBit (pBs, &uiCode)); //slice_skip_flag pSliceHeadExt->bSliceSkipFlag = !!uiCode; if (pSliceHeadExt->bSliceSkipFlag) { WelsLog (pLogCtx, WELS_LOG_WARNING, "bSliceSkipFlag == 1 not supported."); return GENERATE_ERROR_NO (ERR_LEVEL_SLICE_HEADER, ERR_INFO_UNSUPPORTED_SLICESKIP); } else { WELS_READ_VERIFY (BsGetOneBit (pBs, &uiCode)); //adaptive_base_mode_flag pSliceHeadExt->bAdaptiveBaseModeFlag = !!uiCode; if (!pSliceHeadExt->bAdaptiveBaseModeFlag) { WELS_READ_VERIFY (BsGetOneBit (pBs, &uiCode)); //default_base_mode_flag pSliceHeadExt->bDefaultBaseModeFlag = !!uiCode; } if (!pSliceHeadExt->bDefaultBaseModeFlag) { WELS_READ_VERIFY (BsGetOneBit (pBs, &uiCode)); //adaptive_motion_prediction_flag pSliceHeadExt->bAdaptiveMotionPredFlag = !!uiCode; if (!pSliceHeadExt->bAdaptiveMotionPredFlag) { WELS_READ_VERIFY (BsGetOneBit (pBs, &uiCode)); //default_motion_prediction_flag pSliceHeadExt->bDefaultMotionPredFlag = !!uiCode; } } WELS_READ_VERIFY (BsGetOneBit (pBs, &uiCode)); //adaptive_residual_prediction_flag pSliceHeadExt->bAdaptiveResidualPredFlag = !!uiCode; if (!pSliceHeadExt->bAdaptiveResidualPredFlag) { WELS_READ_VERIFY (BsGetOneBit (pBs, &uiCode)); //default_residual_prediction_flag pSliceHeadExt->bDefaultResidualPredFlag = !!uiCode; } } if (pSubsetSps->sSpsSvcExt.bAdaptiveTCoeffLevelPredFlag) { WELS_READ_VERIFY (BsGetOneBit (pBs, &uiCode)); //tcoeff_level_prediction_flag pSliceHeadExt->bTCoeffLevelPredFlag = !!uiCode; } } if (!pSubsetSps->sSpsSvcExt.bSliceHeaderRestrictionFlag) { WELS_READ_VERIFY (BsGetBits (pBs, 4, &uiCode)); //scan_idx_start pSliceHeadExt->uiScanIdxStart = uiCode; WELS_READ_VERIFY (BsGetBits (pBs, 4, &uiCode)); //scan_idx_end pSliceHeadExt->uiScanIdxEnd = uiCode; if (pSliceHeadExt->uiScanIdxStart != 0 || pSliceHeadExt->uiScanIdxEnd != 15) { WelsLog (pLogCtx, WELS_LOG_WARNING, "uiScanIdxStart (%d) != 0 and uiScanIdxEnd (%d) !=15 not supported here", pSliceHeadExt->uiScanIdxStart, pSliceHeadExt->uiScanIdxEnd); return GENERATE_ERROR_NO (ERR_LEVEL_SLICE_HEADER, ERR_INFO_UNSUPPORTED_MGS); } } else { pSliceHeadExt->uiScanIdxStart = 0; pSliceHeadExt->uiScanIdxEnd = 15; } } return ERR_NONE; } /* * Copy relative syntax elements of NALUnitHeaderExt, sRefPicBaseMarking and bStoreRefBasePicFlag in prefix nal unit. * pSrc: mark as decoded prefix NAL * ppDst: succeeded VCL NAL based AVC (I/P Slice) */ bool PrefetchNalHeaderExtSyntax (PWelsDecoderContext pCtx, PNalUnit const kppDst, PNalUnit const kpSrc) { PNalUnitHeaderExt pNalHdrExtD = NULL, pNalHdrExtS = NULL; PSliceHeaderExt pShExtD = NULL; PPrefixNalUnit pPrefixS = NULL; PSps pSps = NULL; int32_t iIdx = 0; if (kppDst == NULL || kpSrc == NULL) return false; pNalHdrExtD = &kppDst->sNalHeaderExt; pNalHdrExtS = &kpSrc->sNalHeaderExt; pShExtD = &kppDst->sNalData.sVclNal.sSliceHeaderExt; pPrefixS = &kpSrc->sNalData.sPrefixNal; pSps = &pCtx->sSpsBuffer[pCtx->sPpsBuffer[pShExtD->sSliceHeader.iPpsId].iSpsId]; pNalHdrExtD->uiDependencyId = pNalHdrExtS->uiDependencyId; pNalHdrExtD->uiQualityId = pNalHdrExtS->uiQualityId; pNalHdrExtD->uiTemporalId = pNalHdrExtS->uiTemporalId; pNalHdrExtD->uiPriorityId = pNalHdrExtS->uiPriorityId; pNalHdrExtD->bIdrFlag = pNalHdrExtS->bIdrFlag; pNalHdrExtD->iNoInterLayerPredFlag = pNalHdrExtS->iNoInterLayerPredFlag; pNalHdrExtD->bDiscardableFlag = pNalHdrExtS->bDiscardableFlag; pNalHdrExtD->bOutputFlag = pNalHdrExtS->bOutputFlag; pNalHdrExtD->bUseRefBasePicFlag = pNalHdrExtS->bUseRefBasePicFlag; pNalHdrExtD->uiLayerDqId = pNalHdrExtS->uiLayerDqId; pShExtD->bStoreRefBasePicFlag = pPrefixS->bStoreRefBasePicFlag; memcpy (&pShExtD->sRefBasePicMarking, &pPrefixS->sRefPicBaseMarking, sizeof (SRefBasePicMarking)); //confirmed_safe_unsafe_usage if (pShExtD->sRefBasePicMarking.bAdaptiveRefBasePicMarkingModeFlag) { PRefBasePicMarking pRefBasePicMarking = &pShExtD->sRefBasePicMarking; iIdx = 0; do { if (pRefBasePicMarking->mmco_base[iIdx].uiMmcoType == MMCO_END) break; if (pRefBasePicMarking->mmco_base[iIdx].uiMmcoType == MMCO_SHORT2UNUSED) pRefBasePicMarking->mmco_base[iIdx].iShortFrameNum = (pShExtD->sSliceHeader.iFrameNum - pRefBasePicMarking->mmco_base[iIdx].uiDiffOfPicNums) & ((1 << pSps->uiLog2MaxFrameNum) - 1); ++ iIdx; } while (iIdx < MAX_MMCO_COUNT); } return true; } int32_t UpdateAccessUnit (PWelsDecoderContext pCtx) { PAccessUnit pCurAu = pCtx->pAccessUnitList; int32_t iIdx = pCurAu->uiEndPos; // Conversed iterator pCtx->uiTargetDqId = pCurAu->pNalUnitsList[iIdx]->sNalHeaderExt.uiLayerDqId; pCurAu->uiActualUnitsNum = iIdx + 1; pCurAu->bCompletedAuFlag = true; // Added for mosaic avoidance, 11/19/2009 #ifdef LONG_TERM_REF if (pCtx->bParamSetsLostFlag || pCtx->bNewSeqBegin) #else if (pCtx->bReferenceLostAtT0Flag || pCtx->bNewSeqBegin) #endif { uint32_t uiActualIdx = 0; while (uiActualIdx < pCurAu->uiActualUnitsNum) { PNalUnit nal = pCurAu->pNalUnitsList[uiActualIdx]; if (nal->sNalHeaderExt.sNalUnitHeader.eNalUnitType == NAL_UNIT_CODED_SLICE_IDR || nal->sNalHeaderExt.bIdrFlag) { break; } ++ uiActualIdx; } if (uiActualIdx == pCurAu->uiActualUnitsNum) { // no found IDR nal within incoming AU, need exit to avoid mosaic issue, 11/19/2009 pCtx->sDecoderStatistics.uiIDRLostNum++; if (!pCtx->bParamSetsLostFlag) WelsLog (& (pCtx->sLogCtx), WELS_LOG_WARNING, "UpdateAccessUnit():::::Key frame lost.....CAN NOT find IDR from current AU."); pCtx->iErrorCode |= dsRefLost; if (pCtx->pParam->eEcActiveIdc == ERROR_CON_DISABLE) { #ifdef LONG_TERM_REF pCtx->iErrorCode |= dsNoParamSets; return dsNoParamSets; #else pCtx->iErrorCode |= dsRefLost; return ERR_INFO_REFERENCE_PIC_LOST; #endif } } } return ERR_NONE; } int32_t InitialDqLayersContext (PWelsDecoderContext pCtx, const int32_t kiMaxWidth, const int32_t kiMaxHeight) { int32_t i = 0; WELS_VERIFY_RETURN_IF (ERR_INFO_INVALID_PARAM, (NULL == pCtx || kiMaxWidth <= 0 || kiMaxHeight <= 0)) pCtx->sMb.iMbWidth = (kiMaxWidth + 15) >> 4; pCtx->sMb.iMbHeight = (kiMaxHeight + 15) >> 4; if (pCtx->bInitialDqLayersMem && kiMaxWidth <= pCtx->iPicWidthReq && kiMaxHeight <= pCtx->iPicHeightReq) // have same dimension memory, skipped return ERR_NONE; CMemoryAlign* pMa = pCtx->pMemAlign; UninitialDqLayersContext (pCtx); do { PDqLayer pDq = (PDqLayer)pMa->WelsMallocz (sizeof (SDqLayer), "PDqLayer"); if (pDq == NULL) return ERR_INFO_OUT_OF_MEMORY; pCtx->pDqLayersList[i] = pDq; //to keep consistence with in UninitialDqLayersContext() memset (pDq, 0, sizeof (SDqLayer)); pCtx->sMb.pMbType[i] = (int16_t*)pMa->WelsMallocz (pCtx->sMb.iMbWidth * pCtx->sMb.iMbHeight * sizeof (int16_t), "pCtx->sMb.pMbType[]"); pCtx->sMb.pMv[i][0] = (int16_t (*)[16][2])pMa->WelsMallocz (pCtx->sMb.iMbWidth * pCtx->sMb.iMbHeight * sizeof ( int16_t) * MV_A * MB_BLOCK4x4_NUM, "pCtx->sMb.pMv[][]"); pCtx->sMb.pRefIndex[i][0] = (int8_t (*)[MB_BLOCK4x4_NUM])pMa->WelsMallocz (pCtx->sMb.iMbWidth * pCtx->sMb.iMbHeight * sizeof ( int8_t) * MB_BLOCK4x4_NUM, "pCtx->sMb.pRefIndex[][]"); pCtx->sMb.pLumaQp[i] = (int8_t*)pMa->WelsMallocz (pCtx->sMb.iMbWidth * pCtx->sMb.iMbHeight * sizeof (int8_t), "pCtx->sMb.pLumaQp[]"); pCtx->sMb.pNoSubMbPartSizeLessThan8x8Flag[i] = (bool*)pMa->WelsMallocz (pCtx->sMb.iMbWidth * pCtx->sMb.iMbHeight * sizeof ( bool), "pCtx->sMb.pNoSubMbPartSizeLessThan8x8Flag[]"); pCtx->sMb.pTransformSize8x8Flag[i] = (bool*)pMa->WelsMallocz (pCtx->sMb.iMbWidth * pCtx->sMb.iMbHeight * sizeof (bool), "pCtx->sMb.pTransformSize8x8Flag[]"); pCtx->sMb.pChromaQp[i] = (int8_t (*)[2])pMa->WelsMallocz (pCtx->sMb.iMbWidth * pCtx->sMb.iMbHeight * sizeof ( int8_t) * 2, "pCtx->sMb.pChromaQp[]"); pCtx->sMb.pMvd[i][0] = (int16_t (*)[16][2])pMa->WelsMallocz (pCtx->sMb.iMbWidth * pCtx->sMb.iMbHeight * sizeof ( int16_t) * MV_A * MB_BLOCK4x4_NUM, "pCtx->sMb.pMvd[][]"); pCtx->sMb.pCbfDc[i] = (uint16_t*)pMa->WelsMallocz (pCtx->sMb.iMbWidth * pCtx->sMb.iMbHeight * sizeof (uint16_t), "pCtx->sMb.pCbfDc[]"); pCtx->sMb.pNzc[i] = (int8_t (*)[24])pMa->WelsMallocz (pCtx->sMb.iMbWidth * pCtx->sMb.iMbHeight * sizeof (int8_t) * 24, "pCtx->sMb.pNzc[]"); pCtx->sMb.pNzcRs[i] = (int8_t (*)[24])pMa->WelsMallocz (pCtx->sMb.iMbWidth * pCtx->sMb.iMbHeight * sizeof (int8_t) * 24, "pCtx->sMb.pNzcRs[]"); pCtx->sMb.pScaledTCoeff[i] = (int16_t (*)[MB_COEFF_LIST_SIZE])pMa->WelsMallocz (pCtx->sMb.iMbWidth * pCtx->sMb.iMbHeight * sizeof (int16_t) * MB_COEFF_LIST_SIZE, "pCtx->sMb.pScaledTCoeff[]"); pCtx->sMb.pIntraPredMode[i] = (int8_t (*)[8])pMa->WelsMallocz (pCtx->sMb.iMbWidth * pCtx->sMb.iMbHeight * sizeof ( int8_t) * 8, "pCtx->sMb.pIntraPredMode[]"); pCtx->sMb.pIntra4x4FinalMode[i] = (int8_t (*)[MB_BLOCK4x4_NUM])pMa->WelsMallocz (pCtx->sMb.iMbWidth * pCtx->sMb.iMbHeight * sizeof (int8_t) * MB_BLOCK4x4_NUM, "pCtx->sMb.pIntra4x4FinalMode[]"); pCtx->sMb.pIntraNxNAvailFlag[i] = (uint8_t (*))pMa->WelsMallocz (pCtx->sMb.iMbWidth * pCtx->sMb.iMbHeight * sizeof ( int8_t), "pCtx->sMb.pIntraNxNAvailFlag"); pCtx->sMb.pChromaPredMode[i] = (int8_t*)pMa->WelsMallocz (pCtx->sMb.iMbWidth * pCtx->sMb.iMbHeight * sizeof (int8_t), "pCtx->sMb.pChromaPredMode[]"); pCtx->sMb.pCbp[i] = (int8_t*)pMa->WelsMallocz (pCtx->sMb.iMbWidth * pCtx->sMb.iMbHeight * sizeof (int8_t), "pCtx->sMb.pCbp[]"); pCtx->sMb.pSubMbType[i] = (int8_t (*)[MB_PARTITION_SIZE])pMa->WelsMallocz (pCtx->sMb.iMbWidth * pCtx->sMb.iMbHeight * sizeof ( int8_t) * MB_PARTITION_SIZE, "pCtx->sMb.pSubMbType[]"); pCtx->sMb.pSliceIdc[i] = (int32_t*) pMa->WelsMallocz (pCtx->sMb.iMbWidth * pCtx->sMb.iMbHeight * sizeof (int32_t), "pCtx->sMb.pSliceIdc[]"); // using int32_t for slice_idc, 4/21/2010 pCtx->sMb.pResidualPredFlag[i] = (int8_t*) pMa->WelsMallocz (pCtx->sMb.iMbWidth * pCtx->sMb.iMbHeight * sizeof (int8_t), "pCtx->sMb.pResidualPredFlag[]"); pCtx->sMb.pInterPredictionDoneFlag[i] = (int8_t*) pMa->WelsMallocz (pCtx->sMb.iMbWidth * pCtx->sMb.iMbHeight * sizeof ( int8_t), "pCtx->sMb.pInterPredictionDoneFlag[]"); pCtx->sMb.pMbCorrectlyDecodedFlag[i] = (bool*) pMa->WelsMallocz (pCtx->sMb.iMbWidth * pCtx->sMb.iMbHeight * sizeof ( bool), "pCtx->sMb.pMbCorrectlyDecodedFlag[]"); pCtx->sMb.pMbRefConcealedFlag[i] = (bool*) pMa->WelsMallocz (pCtx->sMb.iMbWidth * pCtx->sMb.iMbHeight * sizeof (bool), "pCtx->pMbRefConcealedFlag[]"); // check memory block valid due above allocated.. WELS_VERIFY_RETURN_IF (ERR_INFO_OUT_OF_MEMORY, ((NULL == pCtx->sMb.pMbType[i]) || (NULL == pCtx->sMb.pMv[i][0]) || (NULL == pCtx->sMb.pRefIndex[i][0]) || (NULL == pCtx->sMb.pLumaQp[i]) || (NULL == pCtx->sMb.pNoSubMbPartSizeLessThan8x8Flag[i]) || (NULL == pCtx->sMb.pTransformSize8x8Flag[i]) || (NULL == pCtx->sMb.pChromaQp[i]) || (NULL == pCtx->sMb.pMvd[i][0]) || (NULL == pCtx->sMb.pCbfDc[i]) || (NULL == pCtx->sMb.pNzc[i]) || (NULL == pCtx->sMb.pNzcRs[i]) || (NULL == pCtx->sMb.pScaledTCoeff[i]) || (NULL == pCtx->sMb.pIntraPredMode[i]) || (NULL == pCtx->sMb.pIntra4x4FinalMode[i]) || (NULL == pCtx->sMb.pIntraNxNAvailFlag[i]) || (NULL == pCtx->sMb.pChromaPredMode[i]) || (NULL == pCtx->sMb.pCbp[i]) || (NULL == pCtx->sMb.pSubMbType[i]) || (NULL == pCtx->sMb.pSliceIdc[i]) || (NULL == pCtx->sMb.pResidualPredFlag[i]) || (NULL == pCtx->sMb.pInterPredictionDoneFlag[i]) || (NULL == pCtx->sMb.pMbRefConcealedFlag[i]) || (NULL == pCtx->sMb.pMbCorrectlyDecodedFlag[i]) ) ) memset (pCtx->sMb.pSliceIdc[i], 0xff, (pCtx->sMb.iMbWidth * pCtx->sMb.iMbHeight * sizeof (int32_t))); ++ i; } while (i < LAYER_NUM_EXCHANGEABLE); pCtx->bInitialDqLayersMem = true; pCtx->iPicWidthReq = kiMaxWidth; pCtx->iPicHeightReq = kiMaxHeight; return ERR_NONE; } void UninitialDqLayersContext (PWelsDecoderContext pCtx) { int32_t i = 0; CMemoryAlign* pMa = pCtx->pMemAlign; do { PDqLayer pDq = pCtx->pDqLayersList[i]; if (pDq == NULL) { ++ i; continue; } if (pCtx->sMb.pMbType[i]) { pMa->WelsFree (pCtx->sMb.pMbType[i], "pCtx->sMb.pMbType[]"); pCtx->sMb.pMbType[i] = NULL; } if (pCtx->sMb.pMv[i][0]) { pMa->WelsFree (pCtx->sMb.pMv[i][0], "pCtx->sMb.pMv[][]"); pCtx->sMb.pMv[i][0] = NULL; } if (pCtx->sMb.pRefIndex[i][0]) { pMa->WelsFree (pCtx->sMb.pRefIndex[i][0], "pCtx->sMb.pRefIndex[][]"); pCtx->sMb.pRefIndex[i][0] = NULL; } if (pCtx->sMb.pNoSubMbPartSizeLessThan8x8Flag[i]) { pMa->WelsFree (pCtx->sMb.pNoSubMbPartSizeLessThan8x8Flag[i], "pCtx->sMb.pNoSubMbPartSizeLessThan8x8Flag[]"); pCtx->sMb.pNoSubMbPartSizeLessThan8x8Flag[i] = NULL; } if (pCtx->sMb.pTransformSize8x8Flag[i]) { pMa->WelsFree (pCtx->sMb.pTransformSize8x8Flag[i], "pCtx->sMb.pTransformSize8x8Flag[]"); pCtx->sMb.pTransformSize8x8Flag[i] = NULL; } if (pCtx->sMb.pLumaQp[i]) { pMa->WelsFree (pCtx->sMb.pLumaQp[i], "pCtx->sMb.pLumaQp[]"); pCtx->sMb.pLumaQp[i] = NULL; } if (pCtx->sMb.pChromaQp[i]) { pMa->WelsFree (pCtx->sMb.pChromaQp[i], "pCtx->sMb.pChromaQp[]"); pCtx->sMb.pChromaQp[i] = NULL; } if (pCtx->sMb.pMvd[i][0]) { pMa->WelsFree (pCtx->sMb.pMvd[i][0], "pCtx->sMb.pMvd[][]"); pCtx->sMb.pMvd[i][0] = NULL; } if (pCtx->sMb.pCbfDc[i]) { pMa->WelsFree (pCtx->sMb.pCbfDc[i], "pCtx->sMb.pCbfDc[]"); pCtx->sMb.pCbfDc[i] = NULL; } if (pCtx->sMb.pNzc[i]) { pMa->WelsFree (pCtx->sMb.pNzc[i], "pCtx->sMb.pNzc[]"); pCtx->sMb.pNzc[i] = NULL; } if (pCtx->sMb.pNzcRs[i]) { pMa->WelsFree (pCtx->sMb.pNzcRs[i], "pCtx->sMb.pNzcRs[]"); pCtx->sMb.pNzcRs[i] = NULL; } if (pCtx->sMb.pScaledTCoeff[i]) { pMa->WelsFree (pCtx->sMb.pScaledTCoeff[i], "pCtx->sMb.pScaledTCoeff[]"); pCtx->sMb.pScaledTCoeff[i] = NULL; } if (pCtx->sMb.pIntraPredMode[i]) { pMa->WelsFree (pCtx->sMb.pIntraPredMode[i], "pCtx->sMb.pIntraPredMode[]"); pCtx->sMb.pIntraPredMode[i] = NULL; } if (pCtx->sMb.pIntra4x4FinalMode[i]) { pMa->WelsFree (pCtx->sMb.pIntra4x4FinalMode[i], "pCtx->sMb.pIntra4x4FinalMode[]"); pCtx->sMb.pIntra4x4FinalMode[i] = NULL; } if (pCtx->sMb.pIntraNxNAvailFlag[i]) { pMa->WelsFree (pCtx->sMb.pIntraNxNAvailFlag[i], "pCtx->sMb.pIntraNxNAvailFlag"); pCtx->sMb.pIntraNxNAvailFlag[i] = NULL; } if (pCtx->sMb.pChromaPredMode[i]) { pMa->WelsFree (pCtx->sMb.pChromaPredMode[i], "pCtx->sMb.pChromaPredMode[]"); pCtx->sMb.pChromaPredMode[i] = NULL; } if (pCtx->sMb.pCbp[i]) { pMa->WelsFree (pCtx->sMb.pCbp[i], "pCtx->sMb.pCbp[]"); pCtx->sMb.pCbp[i] = NULL; } // if (pCtx->sMb.pMotionPredFlag[i]) //{ // pMa->WelsFree( pCtx->sMb.pMotionPredFlag[i], "pCtx->sMb.pMotionPredFlag[]" ); // pCtx->sMb.pMotionPredFlag[i] = NULL; //} if (pCtx->sMb.pSubMbType[i]) { pMa->WelsFree (pCtx->sMb.pSubMbType[i], "pCtx->sMb.pSubMbType[]"); pCtx->sMb.pSubMbType[i] = NULL; } if (pCtx->sMb.pSliceIdc[i]) { pMa->WelsFree (pCtx->sMb.pSliceIdc[i], "pCtx->sMb.pSliceIdc[]"); pCtx->sMb.pSliceIdc[i] = NULL; } if (pCtx->sMb.pResidualPredFlag[i]) { pMa->WelsFree (pCtx->sMb.pResidualPredFlag[i], "pCtx->sMb.pResidualPredFlag[]"); pCtx->sMb.pResidualPredFlag[i] = NULL; } if (pCtx->sMb.pInterPredictionDoneFlag[i]) { pMa->WelsFree (pCtx->sMb.pInterPredictionDoneFlag[i], "pCtx->sMb.pInterPredictionDoneFlag[]"); pCtx->sMb.pInterPredictionDoneFlag[i] = NULL; } if (pCtx->sMb.pMbCorrectlyDecodedFlag[i]) { pMa->WelsFree (pCtx->sMb.pMbCorrectlyDecodedFlag[i], "pCtx->sMb.pMbCorrectlyDecodedFlag[]"); pCtx->sMb.pMbCorrectlyDecodedFlag[i] = NULL; } if (pCtx->sMb.pMbRefConcealedFlag[i]) { pMa->WelsFree (pCtx->sMb.pMbRefConcealedFlag[i], "pCtx->sMb.pMbRefConcealedFlag[]"); pCtx->sMb.pMbRefConcealedFlag[i] = NULL; } pMa->WelsFree (pDq, "pDq"); pDq = NULL; pCtx->pDqLayersList[i] = NULL; ++ i; } while (i < LAYER_NUM_EXCHANGEABLE); pCtx->iPicWidthReq = 0; pCtx->iPicHeightReq = 0; pCtx->bInitialDqLayersMem = false; } void ResetCurrentAccessUnit (PWelsDecoderContext pCtx) { PAccessUnit pCurAu = pCtx->pAccessUnitList; pCurAu->uiStartPos = 0; pCurAu->uiEndPos = 0; pCurAu->bCompletedAuFlag = false; if (pCurAu->uiActualUnitsNum > 0) { uint32_t iIdx = 0; const uint32_t kuiActualNum = pCurAu->uiActualUnitsNum; // a more simpler method to do nal units list management prefered here const uint32_t kuiAvailNum = pCurAu->uiAvailUnitsNum; const uint32_t kuiLeftNum = kuiAvailNum - kuiActualNum; // Swapping active nal unit nodes of succeeding AU with leading of list while (iIdx < kuiLeftNum) { PNalUnit t = pCurAu->pNalUnitsList[kuiActualNum + iIdx]; pCurAu->pNalUnitsList[kuiActualNum + iIdx] = pCurAu->pNalUnitsList[iIdx]; pCurAu->pNalUnitsList[iIdx] = t; ++ iIdx; } pCurAu->uiActualUnitsNum = pCurAu->uiAvailUnitsNum = kuiLeftNum; } } /*! * \brief Force reset current Acess Unit Nal list in case error parsing/decoding in current AU * \author * \history 11/16/2009 */ void ForceResetCurrentAccessUnit (PAccessUnit pAu) { uint32_t uiSucAuIdx = pAu->uiEndPos + 1; uint32_t uiCurAuIdx = 0; // swap the succeeding AU's nal units to the front while (uiSucAuIdx < pAu->uiAvailUnitsNum) { PNalUnit t = pAu->pNalUnitsList[uiSucAuIdx]; pAu->pNalUnitsList[uiSucAuIdx] = pAu->pNalUnitsList[uiCurAuIdx]; pAu->pNalUnitsList[uiCurAuIdx] = t; ++ uiSucAuIdx; ++ uiCurAuIdx; } // Update avail/actual units num accordingly for next AU parsing if (pAu->uiAvailUnitsNum > pAu->uiEndPos) pAu->uiAvailUnitsNum -= (pAu->uiEndPos + 1); else pAu->uiAvailUnitsNum = 0; pAu->uiActualUnitsNum = 0; pAu->uiStartPos = 0; pAu->uiEndPos = 0; pAu->bCompletedAuFlag = false; } //clear current corrupted NAL from pNalUnitsList void ForceClearCurrentNal (PAccessUnit pAu) { if (pAu->uiAvailUnitsNum > 0) -- pAu->uiAvailUnitsNum; } void ForceResetParaSetStatusAndAUList (PWelsDecoderContext pCtx) { pCtx->bSpsExistAheadFlag = false; pCtx->bSubspsExistAheadFlag = false; pCtx->bPpsExistAheadFlag = false; // Force clear the AU list pCtx->pAccessUnitList->uiAvailUnitsNum = 0; pCtx->pAccessUnitList->uiActualUnitsNum = 0; pCtx->pAccessUnitList->uiStartPos = 0; pCtx->pAccessUnitList->uiEndPos = 0; pCtx->pAccessUnitList->bCompletedAuFlag = false; } void CheckAvailNalUnitsListContinuity (PWelsDecoderContext pCtx, int32_t iStartIdx, int32_t iEndIdx) { PAccessUnit pCurAu = pCtx->pAccessUnitList; uint8_t uiLastNuDependencyId, uiLastNuLayerDqId; uint8_t uiCurNuDependencyId, uiCurNuQualityId, uiCurNuLayerDqId, uiCurNuRefLayerDqId; int32_t iCurNalUnitIdx = 0; //check the continuity of pNalUnitsList forwards (from pIdxNoInterLayerPred to end_postion) uiLastNuDependencyId = pCurAu->pNalUnitsList[iStartIdx]->sNalHeaderExt.uiDependencyId;//starting nal unit uiLastNuLayerDqId = pCurAu->pNalUnitsList[iStartIdx]->sNalHeaderExt.uiLayerDqId;//starting nal unit iCurNalUnitIdx = iStartIdx + 1;//current nal unit while (iCurNalUnitIdx <= iEndIdx) { uiCurNuDependencyId = pCurAu->pNalUnitsList[iCurNalUnitIdx]->sNalHeaderExt.uiDependencyId; uiCurNuQualityId = pCurAu->pNalUnitsList[iCurNalUnitIdx]->sNalHeaderExt.uiQualityId; uiCurNuLayerDqId = pCurAu->pNalUnitsList[iCurNalUnitIdx]->sNalHeaderExt.uiLayerDqId; uiCurNuRefLayerDqId = pCurAu->pNalUnitsList[iCurNalUnitIdx]->sNalData.sVclNal.sSliceHeaderExt.uiRefLayerDqId; if (uiCurNuDependencyId == uiLastNuDependencyId) { uiLastNuLayerDqId = uiCurNuLayerDqId; ++ iCurNalUnitIdx; } else { //uiCurNuDependencyId != uiLastNuDependencyId, new dependency arrive if (uiCurNuQualityId == 0) { uiLastNuDependencyId = uiCurNuDependencyId; if (uiCurNuRefLayerDqId == uiLastNuLayerDqId) { uiLastNuLayerDqId = uiCurNuLayerDqId; ++ iCurNalUnitIdx; } else { //cur_nu_layer_id != next_nu_ref_layer_dq_id, the chain is broken at this point break; } } else { //new dependency arrive, but no base quality layer, so we must stop in this point break; } } } -- iCurNalUnitIdx; pCurAu->uiEndPos = iCurNalUnitIdx; pCtx->uiTargetDqId = pCurAu->pNalUnitsList[iCurNalUnitIdx]->sNalHeaderExt.uiLayerDqId; } //main purpose: to support multi-slice and to include all slice which have the same uiDependencyId, uiQualityId and frame_num //for single slice, pIdxNoInterLayerPred SHOULD NOT be modified void RefineIdxNoInterLayerPred (PAccessUnit pCurAu, int32_t* pIdxNoInterLayerPred) { int32_t iLastNalDependId = pCurAu->pNalUnitsList[*pIdxNoInterLayerPred]->sNalHeaderExt.uiDependencyId; int32_t iLastNalQualityId = pCurAu->pNalUnitsList[*pIdxNoInterLayerPred]->sNalHeaderExt.uiQualityId; uint8_t uiLastNalTId = pCurAu->pNalUnitsList[*pIdxNoInterLayerPred]->sNalHeaderExt.uiTemporalId; int32_t iLastNalFrameNum = pCurAu->pNalUnitsList[*pIdxNoInterLayerPred]->sNalData.sVclNal.sSliceHeaderExt.sSliceHeader.iFrameNum; int32_t iLastNalPoc = pCurAu->pNalUnitsList[*pIdxNoInterLayerPred]->sNalData.sVclNal.sSliceHeaderExt.sSliceHeader.iPicOrderCntLsb; int32_t iLastNalFirstMb = pCurAu->pNalUnitsList[*pIdxNoInterLayerPred]->sNalData.sVclNal.sSliceHeaderExt.sSliceHeader.iFirstMbInSlice; int32_t iCurNalDependId, iCurNalQualityId, iCurNalTId, iCurNalFrameNum, iCurNalPoc, iCurNalFirstMb, iCurIdx, iFinalIdxNoInterLayerPred; bool bMultiSliceFind = false; iFinalIdxNoInterLayerPred = 0; iCurIdx = *pIdxNoInterLayerPred - 1; while (iCurIdx >= 0) { if (pCurAu->pNalUnitsList[iCurIdx]->sNalHeaderExt.iNoInterLayerPredFlag) { iCurNalDependId = pCurAu->pNalUnitsList[iCurIdx]->sNalHeaderExt.uiDependencyId; iCurNalQualityId = pCurAu->pNalUnitsList[iCurIdx]->sNalHeaderExt.uiQualityId; iCurNalTId = pCurAu->pNalUnitsList[iCurIdx]->sNalHeaderExt.uiTemporalId; iCurNalFrameNum = pCurAu->pNalUnitsList[iCurIdx]->sNalData.sVclNal.sSliceHeaderExt.sSliceHeader.iFrameNum; iCurNalPoc = pCurAu->pNalUnitsList[iCurIdx]->sNalData.sVclNal.sSliceHeaderExt.sSliceHeader.iPicOrderCntLsb; iCurNalFirstMb = pCurAu->pNalUnitsList[iCurIdx]->sNalData.sVclNal.sSliceHeaderExt.sSliceHeader.iFirstMbInSlice; if (iCurNalDependId == iLastNalDependId && iCurNalQualityId == iLastNalQualityId && iCurNalTId == uiLastNalTId && iCurNalFrameNum == iLastNalFrameNum && iCurNalPoc == iLastNalPoc && iCurNalFirstMb != iLastNalFirstMb) { bMultiSliceFind = true; iFinalIdxNoInterLayerPred = iCurIdx; --iCurIdx; continue; } else { break; } } --iCurIdx; } if (bMultiSliceFind && *pIdxNoInterLayerPred != iFinalIdxNoInterLayerPred) { *pIdxNoInterLayerPred = iFinalIdxNoInterLayerPred; } } bool CheckPocOfCurValidNalUnits (PAccessUnit pCurAu, int32_t pIdxNoInterLayerPred) { int32_t iEndIdx = pCurAu->uiEndPos; int32_t iCurAuPoc = pCurAu->pNalUnitsList[pIdxNoInterLayerPred]->sNalData.sVclNal.sSliceHeaderExt.sSliceHeader.iPicOrderCntLsb; int32_t iTmpPoc, i; for (i = pIdxNoInterLayerPred + 1; i < iEndIdx; i++) { iTmpPoc = pCurAu->pNalUnitsList[i]->sNalData.sVclNal.sSliceHeaderExt.sSliceHeader.iPicOrderCntLsb; if (iTmpPoc != iCurAuPoc) { return false; } } return true; } bool CheckIntegrityNalUnitsList (PWelsDecoderContext pCtx) { PAccessUnit pCurAu = pCtx->pAccessUnitList; const int32_t kiEndPos = pCurAu->uiEndPos; int32_t iIdxNoInterLayerPred = 0; if (!pCurAu->bCompletedAuFlag) return false; if (pCtx->bNewSeqBegin) { pCurAu->uiStartPos = 0; //step1: search the pNalUnit whose iNoInterLayerPredFlag equal to 1 backwards (from uiEndPos to 0) iIdxNoInterLayerPred = kiEndPos; while (iIdxNoInterLayerPred >= 0) { if (pCurAu->pNalUnitsList[iIdxNoInterLayerPred]->sNalHeaderExt.iNoInterLayerPredFlag) { break; } --iIdxNoInterLayerPred; } if (iIdxNoInterLayerPred < 0) { //can not find the Nal Unit whose no_inter_pred_falg equal to 1, MUST STOP decode return false; } //step2: support multi-slice, to include all base layer slice RefineIdxNoInterLayerPred (pCurAu, &iIdxNoInterLayerPred); pCurAu->uiStartPos = iIdxNoInterLayerPred; CheckAvailNalUnitsListContinuity (pCtx, iIdxNoInterLayerPred, kiEndPos); if (!CheckPocOfCurValidNalUnits (pCurAu, iIdxNoInterLayerPred)) { return false; } pCtx->iCurSeqIntervalTargetDependId = pCurAu->pNalUnitsList[pCurAu->uiEndPos]->sNalHeaderExt.uiDependencyId; pCtx->iCurSeqIntervalMaxPicWidth = pCurAu->pNalUnitsList[pCurAu->uiEndPos]->sNalData.sVclNal.sSliceHeaderExt.sSliceHeader.iMbWidth << 4; pCtx->iCurSeqIntervalMaxPicHeight = pCurAu->pNalUnitsList[pCurAu->uiEndPos]->sNalData.sVclNal.sSliceHeaderExt.sSliceHeader.iMbHeight << 4; } else { //P_SLICE //step 1: search uiDependencyId equal to pCtx->cur_seq_interval_target_dependency_id bool bGetDependId = false; int32_t iIdxDependId = 0; iIdxDependId = kiEndPos; while (iIdxDependId >= 0) { if (pCtx->iCurSeqIntervalTargetDependId == pCurAu->pNalUnitsList[iIdxDependId]->sNalHeaderExt.uiDependencyId) { bGetDependId = true; break; } else { --iIdxDependId; } } //step 2: switch according to whether or not find the index of pNalUnit whose uiDependencyId equal to iCurSeqIntervalTargetDependId if (bGetDependId) { //get the index of pNalUnit whose uiDependencyId equal to iCurSeqIntervalTargetDependId bool bGetNoInterPredFront = false; //step 2a: search iNoInterLayerPredFlag [0....iIdxDependId] iIdxNoInterLayerPred = iIdxDependId; while (iIdxNoInterLayerPred >= 0) { if (pCurAu->pNalUnitsList[iIdxNoInterLayerPred]->sNalHeaderExt.iNoInterLayerPredFlag) { bGetNoInterPredFront = true; break; } --iIdxNoInterLayerPred; } //step 2b: switch, whether or not find the NAL unit whose no_inter_pred_flag equal to 1 among [0....iIdxDependId] if (bGetNoInterPredFront) { //YES RefineIdxNoInterLayerPred (pCurAu, &iIdxNoInterLayerPred); pCurAu->uiStartPos = iIdxNoInterLayerPred; CheckAvailNalUnitsListContinuity (pCtx, iIdxNoInterLayerPred, iIdxDependId); if (!CheckPocOfCurValidNalUnits (pCurAu, iIdxNoInterLayerPred)) { return false; } } else { //NO, should find the NAL unit whose no_inter_pred_flag equal to 1 among [iIdxDependId....uiEndPos] iIdxNoInterLayerPred = iIdxDependId; while (iIdxNoInterLayerPred <= kiEndPos) { if (pCurAu->pNalUnitsList[iIdxNoInterLayerPred]->sNalHeaderExt.iNoInterLayerPredFlag) { break; } ++iIdxNoInterLayerPred; } if (iIdxNoInterLayerPred > kiEndPos) { return false; //cann't find the index of pNalUnit whose no_inter_pred_flag = 1 } RefineIdxNoInterLayerPred (pCurAu, &iIdxNoInterLayerPred); pCurAu->uiStartPos = iIdxNoInterLayerPred; CheckAvailNalUnitsListContinuity (pCtx, iIdxNoInterLayerPred, kiEndPos); if (!CheckPocOfCurValidNalUnits (pCurAu, iIdxNoInterLayerPred)) { return false; } } } else { //without the index of pNalUnit, should process this AU as common case iIdxNoInterLayerPred = kiEndPos; while (iIdxNoInterLayerPred >= 0) { if (pCurAu->pNalUnitsList[iIdxNoInterLayerPred]->sNalHeaderExt.iNoInterLayerPredFlag) { break; } --iIdxNoInterLayerPred; } if (iIdxNoInterLayerPred < 0) { return false; //cann't find the index of pNalUnit whose iNoInterLayerPredFlag = 1 } RefineIdxNoInterLayerPred (pCurAu, &iIdxNoInterLayerPred); pCurAu->uiStartPos = iIdxNoInterLayerPred; CheckAvailNalUnitsListContinuity (pCtx, iIdxNoInterLayerPred, kiEndPos); if (!CheckPocOfCurValidNalUnits (pCurAu, iIdxNoInterLayerPred)) { return false; } } } return true; } void CheckOnlyOneLayerInAu (PWelsDecoderContext pCtx) { PAccessUnit pCurAu = pCtx->pAccessUnitList; int32_t iEndIdx = pCurAu->uiEndPos; int32_t iCurIdx = pCurAu->uiStartPos; uint8_t uiDId = pCurAu->pNalUnitsList[iCurIdx]->sNalHeaderExt.uiDependencyId; uint8_t uiQId = pCurAu->pNalUnitsList[iCurIdx]->sNalHeaderExt.uiQualityId; uint8_t uiTId = pCurAu->pNalUnitsList[iCurIdx]->sNalHeaderExt.uiTemporalId; uint8_t uiCurDId, uiCurQId, uiCurTId; pCtx->bOnlyOneLayerInCurAuFlag = true; if (iEndIdx == iCurIdx) { //only one NAL in pNalUnitsList return; } ++iCurIdx; while (iCurIdx <= iEndIdx) { uiCurDId = pCurAu->pNalUnitsList[iCurIdx]->sNalHeaderExt.uiDependencyId; uiCurQId = pCurAu->pNalUnitsList[iCurIdx]->sNalHeaderExt.uiQualityId; uiCurTId = pCurAu->pNalUnitsList[iCurIdx]->sNalHeaderExt.uiTemporalId; if (uiDId != uiCurDId || uiQId != uiCurQId || uiTId != uiCurTId) { pCtx->bOnlyOneLayerInCurAuFlag = false; return; } ++iCurIdx; } } int32_t WelsDecodeAccessUnitStart (PWelsDecoderContext pCtx) { // Roll back NAL units not being belong to current access unit list for proceeded access unit int32_t iRet = UpdateAccessUnit (pCtx); if (iRet != ERR_NONE) return iRet; pCtx->pAccessUnitList->uiStartPos = 0; if (!pCtx->bAvcBasedFlag && !CheckIntegrityNalUnitsList (pCtx)) { pCtx->iErrorCode |= dsBitstreamError; return dsBitstreamError; } //check current AU has only one layer or not //If YES, can use deblocking based on AVC if (!pCtx->bAvcBasedFlag) { CheckOnlyOneLayerInAu (pCtx); } return ERR_NONE; } void WelsDecodeAccessUnitEnd (PWelsDecoderContext pCtx) { //save previous header info PAccessUnit pCurAu = pCtx->pAccessUnitList; PNalUnit pCurNal = pCurAu->pNalUnitsList[pCurAu->uiEndPos]; memcpy (&pCtx->sLastNalHdrExt, &pCurNal->sNalHeaderExt, sizeof (SNalUnitHeaderExt)); memcpy (&pCtx->sLastSliceHeader, &pCurNal->sNalData.sVclNal.sSliceHeaderExt.sSliceHeader, sizeof (SSliceHeader)); // uninitialize context of current access unit and rbsp buffer clean ResetCurrentAccessUnit (pCtx); } /* CheckNewSeqBeginAndUpdateActiveLayerSps * return: * true - the AU to be construct is the start of new sequence; false - not */ static bool CheckNewSeqBeginAndUpdateActiveLayerSps (PWelsDecoderContext pCtx) { bool bNewSeq = false; PAccessUnit pCurAu = pCtx->pAccessUnitList; PSps pTmpLayerSps[MAX_LAYER_NUM]; for (int i = 0; i < MAX_LAYER_NUM; i++) { pTmpLayerSps[i] = NULL; } // track the layer sps for the current au for (unsigned int i = pCurAu->uiStartPos; i <= pCurAu->uiEndPos; i++) { uint32_t uiDid = pCurAu->pNalUnitsList[i]->sNalHeaderExt.uiDependencyId; pTmpLayerSps[uiDid] = pCurAu->pNalUnitsList[i]->sNalData.sVclNal.sSliceHeaderExt.sSliceHeader.pSps; if ((pCurAu->pNalUnitsList[i]->sNalHeaderExt.sNalUnitHeader.eNalUnitType == NAL_UNIT_CODED_SLICE_IDR) || (pCurAu->pNalUnitsList[i]->sNalHeaderExt.bIdrFlag)) bNewSeq = true; } int iMaxActiveLayer = 0, iMaxCurrentLayer = 0; for (int i = MAX_LAYER_NUM - 1; i >= 0; i--) { if (pCtx->pActiveLayerSps[i] != NULL) { iMaxActiveLayer = i; break; } } for (int i = MAX_LAYER_NUM - 1; i >= 0; i--) { if (pTmpLayerSps[i] != NULL) { iMaxCurrentLayer = i; break; } } if ((iMaxCurrentLayer != iMaxActiveLayer) || (pTmpLayerSps[iMaxCurrentLayer] != pCtx->pActiveLayerSps[iMaxActiveLayer])) { bNewSeq = true; } // fill active sps if the current sps is not null while active layer is null if (!bNewSeq) { for (int i = 0; i < MAX_LAYER_NUM; i++) { if (pCtx->pActiveLayerSps[i] == NULL && pTmpLayerSps[i] != NULL) { pCtx->pActiveLayerSps[i] = pTmpLayerSps[i]; } } } else { // UpdateActiveLayerSps if new sequence start memcpy (&pCtx->pActiveLayerSps[0], &pTmpLayerSps[0], MAX_LAYER_NUM * sizeof (PSps)); } return bNewSeq; } static void WriteBackActiveParameters (PWelsDecoderContext pCtx) { if (pCtx->iOverwriteFlags & OVERWRITE_PPS) { memcpy (&pCtx->sPpsBuffer[pCtx->sPpsBuffer[MAX_PPS_COUNT].iPpsId], &pCtx->sPpsBuffer[MAX_PPS_COUNT], sizeof (SPps)); } if (pCtx->iOverwriteFlags & OVERWRITE_SPS) { memcpy (&pCtx->sSpsBuffer[pCtx->sSpsBuffer[MAX_SPS_COUNT].iSpsId], &pCtx->sSpsBuffer[MAX_SPS_COUNT], sizeof (SSps)); pCtx->bNewSeqBegin = true; } if (pCtx->iOverwriteFlags & OVERWRITE_SUBSETSPS) { memcpy (&pCtx->sSubsetSpsBuffer[pCtx->sSubsetSpsBuffer[MAX_SPS_COUNT].sSps.iSpsId], &pCtx->sSubsetSpsBuffer[MAX_SPS_COUNT], sizeof (SSubsetSps)); pCtx->bNewSeqBegin = true; } pCtx->iOverwriteFlags = OVERWRITE_NONE; } /* * DecodeFinishUpdate * decoder finish decoding, update active parameter sets and new seq status * */ void DecodeFinishUpdate (PWelsDecoderContext pCtx) { pCtx->bNewSeqBegin = false; WriteBackActiveParameters (pCtx); pCtx->bNewSeqBegin = pCtx->bNewSeqBegin || pCtx->bNextNewSeqBegin; pCtx->bNextNewSeqBegin = false; // reset it if (pCtx->bNewSeqBegin) ResetActiveSPSForEachLayer (pCtx); } /* * ConstructAccessUnit * construct an access unit for given input bitstream, maybe partial NAL Unit, one or more Units are involved to * joint a collective access unit. * parameter\ * buf: bitstream data buffer * bit_len: size in bit length of data * buf_len: size in byte length of data * coded_au: mark an Access Unit decoding finished * return: * 0 - success; otherwise returned error_no defined in error_no.h */ int32_t ConstructAccessUnit (PWelsDecoderContext pCtx, uint8_t** ppDst, SBufferInfo* pDstInfo) { int32_t iErr; PAccessUnit pCurAu = pCtx->pAccessUnitList; pCtx->bAuReadyFlag = false; pCtx->bLastHasMmco5 = false; bool bTmpNewSeqBegin = CheckNewSeqBeginAndUpdateActiveLayerSps (pCtx); pCtx->bNewSeqBegin = pCtx->bNewSeqBegin || bTmpNewSeqBegin; iErr = WelsDecodeAccessUnitStart (pCtx); GetVclNalTemporalId (pCtx); if (ERR_NONE != iErr) { ForceResetCurrentAccessUnit (pCtx->pAccessUnitList); if (!pCtx->pParam->bParseOnly) pDstInfo->iBufferStatus = 0; pCtx->bNewSeqBegin = pCtx->bNewSeqBegin || pCtx->bNextNewSeqBegin; pCtx->bNextNewSeqBegin = false; // reset it if (pCtx->bNewSeqBegin) ResetActiveSPSForEachLayer (pCtx); return iErr; } pCtx->pSps = pCurAu->pNalUnitsList[pCurAu->uiStartPos]->sNalData.sVclNal.sSliceHeaderExt.sSliceHeader.pSps; pCtx->pPps = pCurAu->pNalUnitsList[pCurAu->uiStartPos]->sNalData.sVclNal.sSliceHeaderExt.sSliceHeader.pPps; //try to allocate or relocate DPB memory only when new sequence is coming. if (pCtx->bNewSeqBegin) { WelsResetRefPic (pCtx); //clear ref pPic when IDR NAL iErr = SyncPictureResolutionExt (pCtx, pCtx->pSps->iMbWidth, pCtx->pSps->iMbHeight); if (ERR_NONE != iErr) { WelsLog (& (pCtx->sLogCtx), WELS_LOG_WARNING, "sync picture resolution ext failed, the error is %d", iErr); return iErr; } } iErr = DecodeCurrentAccessUnit (pCtx, ppDst, pDstInfo); WelsDecodeAccessUnitEnd (pCtx); if (ERR_NONE != iErr) { WelsLog (& (pCtx->sLogCtx), WELS_LOG_DEBUG, "returned error from decoding:[0x%x]", iErr); return iErr; } return ERR_NONE; } static inline void InitDqLayerInfo (PDqLayer pDqLayer, PLayerInfo pLayerInfo, PNalUnit pNalUnit, PPicture pPicDec) { PNalUnitHeaderExt pNalHdrExt = &pNalUnit->sNalHeaderExt; PSliceHeaderExt pShExt = &pNalUnit->sNalData.sVclNal.sSliceHeaderExt; PSliceHeader pSh = &pShExt->sSliceHeader; const uint8_t kuiQualityId = pNalHdrExt->uiQualityId; memcpy (&pDqLayer->sLayerInfo, pLayerInfo, sizeof (SLayerInfo)); //confirmed_safe_unsafe_usage pDqLayer->pDec = pPicDec; pDqLayer->iMbWidth = pSh->iMbWidth; // MB width of this picture pDqLayer->iMbHeight = pSh->iMbHeight;// MB height of this picture pDqLayer->iSliceIdcBackup = (pSh->iFirstMbInSlice << 7) | (pNalHdrExt->uiDependencyId << 4) | (pNalHdrExt->uiQualityId); /* Common syntax elements across all slices of a DQLayer */ pDqLayer->uiPpsId = pLayerInfo->pPps->iPpsId; pDqLayer->uiDisableInterLayerDeblockingFilterIdc = pShExt->uiDisableInterLayerDeblockingFilterIdc; pDqLayer->iInterLayerSliceAlphaC0Offset = pShExt->iInterLayerSliceAlphaC0Offset; pDqLayer->iInterLayerSliceBetaOffset = pShExt->iInterLayerSliceBetaOffset; pDqLayer->iSliceGroupChangeCycle = pSh->iSliceGroupChangeCycle; pDqLayer->bStoreRefBasePicFlag = pShExt->bStoreRefBasePicFlag; pDqLayer->bTCoeffLevelPredFlag = pShExt->bTCoeffLevelPredFlag; pDqLayer->bConstrainedIntraResamplingFlag = pShExt->bConstrainedIntraResamplingFlag; pDqLayer->uiRefLayerDqId = pShExt->uiRefLayerDqId; pDqLayer->uiRefLayerChromaPhaseXPlus1Flag = pShExt->uiRefLayerChromaPhaseXPlus1Flag; pDqLayer->uiRefLayerChromaPhaseYPlus1 = pShExt->uiRefLayerChromaPhaseYPlus1; //memcpy(&pDqLayer->sScaledRefLayer, &pShExt->sScaledRefLayer, sizeof(SPosOffset));//confirmed_safe_unsafe_usage if (kuiQualityId == BASE_QUALITY_ID) { pDqLayer->pRefPicListReordering = &pSh->pRefPicListReordering; pDqLayer->pRefPicMarking = &pSh->sRefMarking; if (pSh->pPps->bWeightedPredFlag) { pDqLayer->bUseWeightPredictionFlag = true; pDqLayer->pPredWeightTable = &pSh->sPredWeightTable; } else pDqLayer->bUseWeightPredictionFlag = false; pDqLayer->pRefPicBaseMarking = &pShExt->sRefBasePicMarking; } pDqLayer->uiLayerDqId = pNalHdrExt->uiLayerDqId; // dq_id of current layer pDqLayer->bUseRefBasePicFlag = pNalHdrExt->bUseRefBasePicFlag; } void WelsDqLayerDecodeStart (PWelsDecoderContext pCtx, PNalUnit pCurNal, PSps pSps, PPps pPps) { PSliceHeader pSh = &pCurNal->sNalData.sVclNal.sSliceHeaderExt.sSliceHeader; pCtx->eSliceType = pSh->eSliceType; pCtx->pSliceHeader = pSh; pCtx->iFrameNum = pSh->iFrameNum; UpdateDecoderStatisticsForActiveParaset (& (pCtx->sDecoderStatistics), pSps, pPps); } int32_t InitRefPicList (PWelsDecoderContext pCtx, const uint8_t kuiNRi, int32_t iPoc) { int32_t iRet = ERR_NONE; iRet = WelsInitRefList (pCtx, iPoc); if ((pCtx->eSliceType != I_SLICE && pCtx->eSliceType != SI_SLICE)) { iRet = WelsReorderRefList (pCtx); } return iRet; } void InitCurDqLayerData (PWelsDecoderContext pCtx, PDqLayer pCurDq) { if (NULL != pCtx && NULL != pCurDq) { pCurDq->pMbType = pCtx->sMb.pMbType[0]; pCurDq->pSliceIdc = pCtx->sMb.pSliceIdc[0]; pCurDq->pMv[0] = pCtx->sMb.pMv[0][0]; pCurDq->pRefIndex[0] = pCtx->sMb.pRefIndex[0][0]; pCurDq->pNoSubMbPartSizeLessThan8x8Flag = pCtx->sMb.pNoSubMbPartSizeLessThan8x8Flag[0]; pCurDq->pTransformSize8x8Flag = pCtx->sMb.pTransformSize8x8Flag[0]; pCurDq->pLumaQp = pCtx->sMb.pLumaQp[0]; pCurDq->pChromaQp = pCtx->sMb.pChromaQp[0]; pCurDq->pMvd[0] = pCtx->sMb.pMvd[0][0]; pCurDq->pCbfDc = pCtx->sMb.pCbfDc[0]; pCurDq->pNzc = pCtx->sMb.pNzc[0]; pCurDq->pNzcRs = pCtx->sMb.pNzcRs[0]; pCurDq->pScaledTCoeff = pCtx->sMb.pScaledTCoeff[0]; pCurDq->pIntraPredMode = pCtx->sMb.pIntraPredMode[0]; pCurDq->pIntra4x4FinalMode = pCtx->sMb.pIntra4x4FinalMode[0]; pCurDq->pIntraNxNAvailFlag = pCtx->sMb.pIntraNxNAvailFlag[0]; pCurDq->pChromaPredMode = pCtx->sMb.pChromaPredMode[0]; pCurDq->pCbp = pCtx->sMb.pCbp[0]; pCurDq->pSubMbType = pCtx->sMb.pSubMbType[0]; pCurDq->pInterPredictionDoneFlag = pCtx->sMb.pInterPredictionDoneFlag[0]; pCurDq->pResidualPredFlag = pCtx->sMb.pResidualPredFlag[0]; pCurDq->pMbCorrectlyDecodedFlag = pCtx->sMb.pMbCorrectlyDecodedFlag[0]; pCurDq->pMbRefConcealedFlag = pCtx->sMb.pMbRefConcealedFlag[0]; } } /* * DecodeCurrentAccessUnit * Decode current access unit when current AU is completed. */ int32_t DecodeCurrentAccessUnit (PWelsDecoderContext pCtx, uint8_t** ppDst, SBufferInfo* pDstInfo) { int32_t iRefCount[LIST_A]; PNalUnit pNalCur = NULL; PAccessUnit pCurAu = pCtx->pAccessUnitList; int32_t iIdx = pCurAu->uiStartPos; int32_t iEndIdx = pCurAu->uiEndPos; int32_t iPpsId = 0; int32_t iRet = ERR_NONE; bool bAllRefComplete = true; // Assume default all ref picutres are complete const uint8_t kuiTargetLayerDqId = GetTargetDqId (pCtx->uiTargetDqId, pCtx->pParam); const uint8_t kuiDependencyIdMax = (kuiTargetLayerDqId & 0x7F) >> 4; int16_t iLastIdD = -1, iLastIdQ = -1; int16_t iCurrIdD = 0, iCurrIdQ = 0; uint8_t uiNalRefIdc = 0; bool bFreshSliceAvailable = true; // Another fresh slice comingup for given dq layer, for multiple slices in case of header parts of slices sometimes loss over error-prone channels, 8/14/2008 //update pCurDqLayer at the starting of AU decoding if (pCtx->bInitialDqLayersMem) { pCtx->pCurDqLayer = pCtx->pDqLayersList[0]; } InitCurDqLayerData (pCtx, pCtx->pCurDqLayer); pNalCur = pCurAu->pNalUnitsList[iIdx]; while (iIdx <= iEndIdx) { PDqLayer dq_cur = pCtx->pCurDqLayer; SLayerInfo pLayerInfo; PSliceHeaderExt pShExt = NULL; PSliceHeader pSh = NULL; if (pCtx->pDec == NULL) { pCtx->pDec = PrefetchPic (pCtx->pPicBuff[0]); if (pCtx->iTotalNumMbRec != 0) pCtx->iTotalNumMbRec = 0; if (NULL == pCtx->pDec) { WelsLog (& (pCtx->sLogCtx), WELS_LOG_ERROR, "DecodeCurrentAccessUnit()::::::PrefetchPic ERROR, pSps->iNumRefFrames:%d.", pCtx->pSps->iNumRefFrames); // The error code here need to be separated from the dsOutOfMemory pCtx->iErrorCode |= dsOutOfMemory; return ERR_INFO_REF_COUNT_OVERFLOW; } pCtx->pDec->bNewSeqBegin = pCtx->bNewSeqBegin; //set flag for start decoding } else if (pCtx->iTotalNumMbRec == 0) { //pDec != NULL, already start pCtx->pDec->bNewSeqBegin = pCtx->bNewSeqBegin; //set flag for start decoding } pCtx->pDec->uiTimeStamp = pNalCur->uiTimeStamp; if (pCtx->iTotalNumMbRec == 0) { //Picture start to decode for (int32_t i = 0; i < LAYER_NUM_EXCHANGEABLE; ++ i) memset (pCtx->sMb.pSliceIdc[i], 0xff, (pCtx->sMb.iMbWidth * pCtx->sMb.iMbHeight * sizeof (int32_t))); memset (pCtx->pCurDqLayer->pMbCorrectlyDecodedFlag, 0, pCtx->pSps->iMbWidth * pCtx->pSps->iMbHeight * sizeof (bool)); memset (pCtx->pCurDqLayer->pMbRefConcealedFlag, 0, pCtx->pSps->iMbWidth * pCtx->pSps->iMbHeight * sizeof (bool)); pCtx->pDec->iMbNum = pCtx->pSps->iMbWidth * pCtx->pSps->iMbHeight; pCtx->pDec->iMbEcedNum = 0; pCtx->pDec->iMbEcedPropNum = 0; } pCtx->bRPLRError = false; GetI4LumaIChromaAddrTable (pCtx->iDecBlockOffsetArray, pCtx->pDec->iLinesize[0], pCtx->pDec->iLinesize[1]); if (pNalCur->sNalHeaderExt.uiLayerDqId > kuiTargetLayerDqId) { // confirmed pNalCur will never be NULL break; // Per formance it need not to decode the remaining bits any more due to given uiLayerDqId required, 9/2/2009 } memset (&pLayerInfo, 0, sizeof (SLayerInfo)); /* * Loop decoding for slices (even FMO and/ multiple slices) within a dq layer */ while (iIdx <= iEndIdx) { bool bReconstructSlice; iCurrIdQ = pNalCur->sNalHeaderExt.uiQualityId; iCurrIdD = pNalCur->sNalHeaderExt.uiDependencyId; pSh = &pNalCur->sNalData.sVclNal.sSliceHeaderExt.sSliceHeader; pShExt = &pNalCur->sNalData.sVclNal.sSliceHeaderExt; pCtx->bRPLRError = false; bReconstructSlice = CheckSliceNeedReconstruct (pNalCur->sNalHeaderExt.uiLayerDqId, kuiTargetLayerDqId); memcpy (&pLayerInfo.sNalHeaderExt, &pNalCur->sNalHeaderExt, sizeof (SNalUnitHeaderExt)); //confirmed_safe_unsafe_usage pCtx->pDec->iFrameNum = pSh->iFrameNum; pCtx->pDec->iFramePoc = pSh->iPicOrderCntLsb; // still can not obtain correct, because current do not support POCtype 2 pCtx->pDec->bIdrFlag = pNalCur->sNalHeaderExt.bIdrFlag; memcpy (&pLayerInfo.sSliceInLayer.sSliceHeaderExt, pShExt, sizeof (SSliceHeaderExt)); //confirmed_safe_unsafe_usage pLayerInfo.sSliceInLayer.bSliceHeaderExtFlag = pNalCur->sNalData.sVclNal.bSliceHeaderExtFlag; pLayerInfo.sSliceInLayer.eSliceType = pSh->eSliceType; pLayerInfo.sSliceInLayer.iLastMbQp = pSh->iSliceQp; dq_cur->pBitStringAux = &pNalCur->sNalData.sVclNal.sSliceBitsRead; uiNalRefIdc = pNalCur->sNalHeaderExt.sNalUnitHeader.uiNalRefIdc; iPpsId = pSh->iPpsId; pLayerInfo.pPps = pSh->pPps; pLayerInfo.pSps = pSh->pSps; pLayerInfo.pSubsetSps = pShExt->pSubsetSps; pCtx->pFmo = &pCtx->sFmoList[iPpsId]; iRet = FmoParamUpdate (pCtx->pFmo, pLayerInfo.pSps, pLayerInfo.pPps, &pCtx->iActiveFmoNum, pCtx->pMemAlign); if (ERR_NONE != iRet) { if (iRet == ERR_INFO_OUT_OF_MEMORY) { pCtx->iErrorCode |= dsOutOfMemory; WelsLog (& (pCtx->sLogCtx), WELS_LOG_ERROR, "DecodeCurrentAccessUnit(), Fmo param alloc failed"); } else { pCtx->iErrorCode |= dsBitstreamError; WelsLog (& (pCtx->sLogCtx), WELS_LOG_WARNING, "DecodeCurrentAccessUnit(), FmoParamUpdate failed, eSliceType: %d.", pSh->eSliceType); } return GENERATE_ERROR_NO (ERR_LEVEL_SLICE_HEADER, ERR_INFO_FMO_INIT_FAIL); } bFreshSliceAvailable = (iCurrIdD != iLastIdD || iCurrIdQ != iLastIdQ); // do not need condition of (first_mb == 0) due multiple slices might be disorder WelsDqLayerDecodeStart (pCtx, pNalCur, pLayerInfo.pSps, pLayerInfo.pPps); if (iCurrIdQ == BASE_QUALITY_ID) { ST64 (iRefCount, LD64 (pLayerInfo.sSliceInLayer.sSliceHeaderExt.sSliceHeader.uiRefCount)); } if ((iLastIdD < 0) || //case 1: first layer (iLastIdD == iCurrIdD)) { //case 2: same uiDId InitDqLayerInfo (dq_cur, &pLayerInfo, pNalCur, pCtx->pDec); if (!dq_cur->sLayerInfo.pSps->bGapsInFrameNumValueAllowedFlag) { const bool kbIdrFlag = dq_cur->sLayerInfo.sNalHeaderExt.bIdrFlag || (dq_cur->sLayerInfo.sNalHeaderExt.sNalUnitHeader.eNalUnitType == NAL_UNIT_CODED_SLICE_IDR); // Subclause 8.2.5.2 Decoding process for gaps in frame_num if (!kbIdrFlag && pSh->iFrameNum != pCtx->iPrevFrameNum && pSh->iFrameNum != ((pCtx->iPrevFrameNum + 1) & ((1 << dq_cur->sLayerInfo.pSps->uiLog2MaxFrameNum) - 1))) { WelsLog (& (pCtx->sLogCtx), WELS_LOG_WARNING, "referencing pictures lost due frame gaps exist, prev_frame_num: %d, curr_frame_num: %d", pCtx->iPrevFrameNum, pSh->iFrameNum); bAllRefComplete = false; pCtx->iErrorCode |= dsRefLost; if (pCtx->pParam->eEcActiveIdc == ERROR_CON_DISABLE) { #ifdef LONG_TERM_REF pCtx->bParamSetsLostFlag = true; #else pCtx->bReferenceLostAtT0Flag = true; #endif return GENERATE_ERROR_NO (ERR_LEVEL_SLICE_HEADER, ERR_INFO_REFERENCE_PIC_LOST); } } } if (iCurrIdD == kuiDependencyIdMax && iCurrIdQ == BASE_QUALITY_ID) { iRet = InitRefPicList (pCtx, uiNalRefIdc, pSh->iPicOrderCntLsb); if (iRet) { pCtx->bRPLRError = true; bAllRefComplete = false; // RPLR error, set ref pictures complete flag false HandleReferenceLost (pCtx, pNalCur); WelsLog (& (pCtx->sLogCtx), WELS_LOG_DEBUG, "reference picture introduced by this frame is lost during transmission! uiTId: %d", pNalCur->sNalHeaderExt.uiTemporalId); if (pCtx->pParam->eEcActiveIdc == ERROR_CON_DISABLE) { if (pCtx->iTotalNumMbRec == 0) pCtx->pDec = NULL; return iRet; } } } iRet = WelsDecodeSlice (pCtx, bFreshSliceAvailable, pNalCur); //Output good store_base reconstruction when enhancement quality layer occurred error for MGS key picture case if (iRet != ERR_NONE) { WelsLog (& (pCtx->sLogCtx), WELS_LOG_WARNING, "DecodeCurrentAccessUnit() failed (%d) in frame: %d uiDId: %d uiQId: %d", iRet, pSh->iFrameNum, iCurrIdD, iCurrIdQ); bAllRefComplete = false; HandleReferenceLostL0 (pCtx, pNalCur); if (pCtx->pParam->eEcActiveIdc == ERROR_CON_DISABLE) { if (pCtx->iTotalNumMbRec == 0) pCtx->pDec = NULL; return iRet; } } if (bReconstructSlice) { if ((iRet = WelsDecodeConstructSlice (pCtx, pNalCur)) != ERR_NONE) { pCtx->pDec->bIsComplete = false; // reconstruction error, directly set the flag false return iRet; } } if (bAllRefComplete && pCtx->eSliceType != I_SLICE) { if (pCtx->sRefPic.uiRefCount[LIST_0] > 0) { bAllRefComplete &= CheckRefPicturesComplete (pCtx); } else { bAllRefComplete = false; } } } #if defined (_DEBUG) && !defined (CODEC_FOR_TESTBED) fprintf (stderr, "cur_frame : %d\tiCurrIdD : %d\n ", dq_cur->sLayerInfo.sSliceInLayer.sSliceHeaderExt.sSliceHeader.iFrameNum, iCurrIdD); #endif//#if !CODEC_FOR_TESTBED iLastIdD = iCurrIdD; iLastIdQ = iCurrIdQ; //pNalUnitsList overflow. ++ iIdx; if (iIdx <= iEndIdx) { pNalCur = pCurAu->pNalUnitsList[iIdx]; } else { pNalCur = NULL; } if (pNalCur == NULL || iLastIdD != pNalCur->sNalHeaderExt.uiDependencyId || iLastIdQ != pNalCur->sNalHeaderExt.uiQualityId) break; } // Set the current dec picture complete flag. The flag will be reset when current picture need do ErrorCon. pCtx->pDec->bIsComplete = bAllRefComplete; if (!pCtx->pDec->bIsComplete) { // Ref pictures ECed, result in ECed pCtx->iErrorCode |= dsDataErrorConcealed; } // A dq layer decoded here #if defined (_DEBUG) && !defined (CODEC_FOR_TESTBED) #undef fprintf fprintf (stderr, "POC: #%d, FRAME: #%d, D: %d, Q: %d, T: %d, P: %d, %d\n", pSh->iPicOrderCntLsb, pSh->iFrameNum, iCurrIdD, iCurrIdQ, dq_cur->sLayerInfo.sNalHeaderExt.uiTemporalId, dq_cur->sLayerInfo.sNalHeaderExt.uiPriorityId, dq_cur->sLayerInfo.sSliceInLayer.sSliceHeaderExt.sSliceHeader.iSliceQp); #endif//#if !CODEC_FOR_TESTBED if (dq_cur->uiLayerDqId == kuiTargetLayerDqId) { if (!pCtx->bInstantDecFlag) { if (!pCtx->pParam->bParseOnly) { //Do error concealment here if ((NeedErrorCon (pCtx)) && (pCtx->pParam->eEcActiveIdc != ERROR_CON_DISABLE)) { ImplementErrorCon (pCtx); pCtx->iTotalNumMbRec = pCtx->pSps->iMbWidth * pCtx->pSps->iMbHeight; pCtx->pDec->iSpsId = pCtx->pSps->iSpsId; pCtx->pDec->iPpsId = pCtx->pPps->iPpsId; } } } iRet = DecodeFrameConstruction (pCtx, ppDst, pDstInfo); if (iRet) return iRet; pCtx->pPreviousDecodedPictureInDpb = pCtx->pDec; //store latest decoded picture for EC if (uiNalRefIdc > 0) { iRet = WelsMarkAsRef (pCtx); if (iRet != ERR_NONE) { if (iRet == ERR_INFO_DUPLICATE_FRAME_NUM) pCtx->iErrorCode |= dsBitstreamError; if (pCtx->pParam->eEcActiveIdc == ERROR_CON_DISABLE) { pCtx->pDec = NULL; return iRet; } } if (!pCtx->pParam->bParseOnly) ExpandReferencingPicture (pCtx->pDec->pData, pCtx->pDec->iWidthInPixel, pCtx->pDec->iHeightInPixel, pCtx->pDec->iLinesize, pCtx->sExpandPicFunc.pfExpandLumaPicture, pCtx->sExpandPicFunc.pfExpandChromaPicture); } pCtx->pDec = NULL; //after frame decoding, always set to NULL } // need update frame_num due current frame is well decoded if (pCurAu->pNalUnitsList[pCurAu->uiStartPos]->sNalHeaderExt.sNalUnitHeader.uiNalRefIdc > 0) pCtx->iPrevFrameNum = pSh->iFrameNum; if (pCtx->bLastHasMmco5) pCtx->iPrevFrameNum = 0; } return ERR_NONE; } bool CheckAndFinishLastPic (PWelsDecoderContext pCtx, uint8_t** ppDst, SBufferInfo* pDstInfo) { PAccessUnit pAu = pCtx->pAccessUnitList; bool bAuBoundaryFlag = false; if (IS_VCL_NAL (pCtx->sCurNalHead.eNalUnitType, 1)) { //VCL data, AU list should have data PNalUnit pCurNal = pAu->pNalUnitsList[pAu->uiEndPos]; bAuBoundaryFlag = (pCtx->iTotalNumMbRec != 0) && (CheckAccessUnitBoundaryExt (&pCtx->sLastNalHdrExt, &pCurNal->sNalHeaderExt, &pCtx->sLastSliceHeader, &pCurNal->sNalData.sVclNal.sSliceHeaderExt.sSliceHeader)); } else { //non VCL if (pCtx->sCurNalHead.eNalUnitType == NAL_UNIT_AU_DELIMITER) { bAuBoundaryFlag = true; } else if (pCtx->sCurNalHead.eNalUnitType == NAL_UNIT_SEI) { bAuBoundaryFlag = true; } else if (pCtx->sCurNalHead.eNalUnitType == NAL_UNIT_SPS) { bAuBoundaryFlag = !! (pCtx->iOverwriteFlags & OVERWRITE_SPS); } else if (pCtx->sCurNalHead.eNalUnitType == NAL_UNIT_SUBSET_SPS) { bAuBoundaryFlag = !! (pCtx->iOverwriteFlags & OVERWRITE_SUBSETSPS); } else if (pCtx->sCurNalHead.eNalUnitType == NAL_UNIT_PPS) { bAuBoundaryFlag = !! (pCtx->iOverwriteFlags & OVERWRITE_PPS); } if (bAuBoundaryFlag && pCtx->pAccessUnitList->uiAvailUnitsNum != 0) { //Construct remaining data first ConstructAccessUnit (pCtx, ppDst, pDstInfo); } } //Do Error Concealment here if (bAuBoundaryFlag && (pCtx->iTotalNumMbRec != 0) && NeedErrorCon (pCtx)) { //AU ready but frame not completely reconed if (pCtx->pParam->eEcActiveIdc != ERROR_CON_DISABLE) { ImplementErrorCon (pCtx); pCtx->iTotalNumMbRec = pCtx->pSps->iMbWidth * pCtx->pSps->iMbHeight; pCtx->pDec->iSpsId = pCtx->pSps->iSpsId; pCtx->pDec->iPpsId = pCtx->pPps->iPpsId; DecodeFrameConstruction (pCtx, ppDst, pDstInfo); pCtx->pPreviousDecodedPictureInDpb = pCtx->pDec; //save ECed pic for future use if (pCtx->sLastNalHdrExt.sNalUnitHeader.uiNalRefIdc > 0) { MarkECFrameAsRef (pCtx); } } else if (pCtx->pParam->bParseOnly) { //clear parse only internal data status pCtx->pParserBsInfo->iNalNum = 0; pCtx->bFrameFinish = true; //clear frame pending status here! } else { if (DecodeFrameConstruction (pCtx, ppDst, pDstInfo)) { if ((pCtx->sLastNalHdrExt.sNalUnitHeader.uiNalRefIdc > 0) && (pCtx->sLastNalHdrExt.uiTemporalId == 0)) pCtx->iErrorCode |= dsNoParamSets; else pCtx->iErrorCode |= dsBitstreamError; pCtx->pDec = NULL; return false; } } pCtx->pDec = NULL; if (pAu->pNalUnitsList[pAu->uiStartPos]->sNalHeaderExt.sNalUnitHeader.uiNalRefIdc > 0) pCtx->iPrevFrameNum = pCtx->sLastSliceHeader.iFrameNum; //save frame_num if (pCtx->bLastHasMmco5) pCtx->iPrevFrameNum = 0; } return ERR_NONE; } bool CheckRefPicturesComplete (PWelsDecoderContext pCtx) { // Multi Reference, RefIdx may differ bool bAllRefComplete = true; int32_t iRealMbIdx = pCtx->pCurDqLayer->sLayerInfo.sSliceInLayer.sSliceHeaderExt.sSliceHeader.iFirstMbInSlice; for (int32_t iMbIdx = 0; bAllRefComplete && iMbIdx < pCtx->pCurDqLayer->sLayerInfo.sSliceInLayer.iTotalMbInCurSlice; iMbIdx++) { switch (pCtx->pCurDqLayer->pMbType[iRealMbIdx]) { case MB_TYPE_SKIP: case MB_TYPE_16x16: bAllRefComplete &= pCtx->sRefPic.pRefList[ LIST_0 ][ pCtx->pCurDqLayer->pRefIndex[0][iRealMbIdx][0] ]->bIsComplete; break; case MB_TYPE_16x8: bAllRefComplete &= pCtx->sRefPic.pRefList[ LIST_0 ][ pCtx->pCurDqLayer->pRefIndex[0][iRealMbIdx][0] ]->bIsComplete; bAllRefComplete &= pCtx->sRefPic.pRefList[ LIST_0 ][ pCtx->pCurDqLayer->pRefIndex[0][iRealMbIdx][8] ]->bIsComplete; break; case MB_TYPE_8x16: bAllRefComplete &= pCtx->sRefPic.pRefList[ LIST_0 ][ pCtx->pCurDqLayer->pRefIndex[0][iRealMbIdx][0] ]->bIsComplete; bAllRefComplete &= pCtx->sRefPic.pRefList[ LIST_0 ][ pCtx->pCurDqLayer->pRefIndex[0][iRealMbIdx][2] ]->bIsComplete; break; case MB_TYPE_8x8: case MB_TYPE_8x8_REF0: bAllRefComplete &= pCtx->sRefPic.pRefList[ LIST_0 ][ pCtx->pCurDqLayer->pRefIndex[0][iRealMbIdx][0] ]->bIsComplete; bAllRefComplete &= pCtx->sRefPic.pRefList[ LIST_0 ][ pCtx->pCurDqLayer->pRefIndex[0][iRealMbIdx][2] ]->bIsComplete; bAllRefComplete &= pCtx->sRefPic.pRefList[ LIST_0 ][ pCtx->pCurDqLayer->pRefIndex[0][iRealMbIdx][8] ]->bIsComplete; bAllRefComplete &= pCtx->sRefPic.pRefList[ LIST_0 ][ pCtx->pCurDqLayer->pRefIndex[0][iRealMbIdx][10] ]->bIsComplete; break; default: break; } iRealMbIdx = (pCtx->pPps->uiNumSliceGroups > 1) ? FmoNextMb (pCtx->pFmo, iRealMbIdx) : (pCtx->pCurDqLayer->sLayerInfo.sSliceInLayer.sSliceHeaderExt.sSliceHeader.iFirstMbInSlice + iMbIdx); if (iRealMbIdx == -1) //caused by abnormal return of FmoNextMb() return false; } return bAllRefComplete; } } // namespace WelsDec