Skip to content

Instantly share code, notes, and snippets.

@Megawats777
Created April 15, 2020 20:46
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Megawats777/9d4fc3757739c475936b5e3c6c3d12d8 to your computer and use it in GitHub Desktop.
Save Megawats777/9d4fc3757739c475936b5e3c6c3d12d8 to your computer and use it in GitHub Desktop.
DecodeCurrentAccessUnit-02
/*
* DecodeCurrentAccessUnit
* Decode current access unit when current AU is completed.
*/
int32_t DecodeCurrentAccessUnit (PWelsDecoderContext pCtx, uint8_t** ppDst, SBufferInfo* pDstInfo) {
PNalUnit pNalCur = pCtx->pNalCur = NULL;
PAccessUnit pCurAu = pCtx->pAccessUnitList;
int32_t iIdx = pCurAu->uiStartPos;
int32_t iEndIdx = pCurAu->uiEndPos;
//get current thread ctx
PWelsDecoderThreadCTX pThreadCtx = NULL;
if (pCtx->pThreadCtx != NULL) {
pThreadCtx = (PWelsDecoderThreadCTX)pCtx->pThreadCtx;
}
//get last thread ctx
PWelsDecoderThreadCTX pLastThreadCtx = NULL;
if (pCtx->pLastThreadCtx != NULL) {
pLastThreadCtx = (PWelsDecoderThreadCTX) (pCtx->pLastThreadCtx);
if (pLastThreadCtx->pDec == NULL) {
pLastThreadCtx->pDec = PrefetchLastPicForThread (pCtx->pPicBuff,
pLastThreadCtx->iPicBuffIdx);
}
}
int32_t iThreadCount = GetThreadCount (pCtx);
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;
pCtx->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 == NULL) {
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 (pLastThreadCtx != NULL) {
pSh = &pNalCur->sNalData.sVclNal.sSliceHeaderExt.sSliceHeader;
if (pSh->iFirstMbInSlice == 0) {
if (pLastThreadCtx->pCtx->pDec != NULL && pLastThreadCtx->pCtx->pDec->bIsUngroupedMultiSlice) {
WAIT_EVENT (&pLastThreadCtx->sSliceDecodeFinish, WELS_DEC_THREAD_WAIT_INFINITE);
}
pCtx->pDec = NULL;
pCtx->iTotalNumMbRec = 0;
} else if (pLastThreadCtx->pCtx->pDec != NULL) {
if (pSh->iFrameNum == pLastThreadCtx->pCtx->pDec->iFrameNum
&& pSh->iPicOrderCntLsb == pLastThreadCtx->pCtx->pDec->iFramePoc) {
WAIT_EVENT (&pLastThreadCtx->sSliceDecodeFinish, WELS_DEC_THREAD_WAIT_INFINITE);
pCtx->pDec = pLastThreadCtx->pCtx->pDec;
pCtx->pDec->bIsUngroupedMultiSlice = true;
pCtx->sRefPic = pLastThreadCtx->pCtx->sRefPic;
pCtx->iTotalNumMbRec = pLastThreadCtx->pCtx->iTotalNumMbRec;
}
}
}
bool isNewFrame = true;
if (iThreadCount > 1) {
isNewFrame = pCtx->pDec == NULL;
}
if (pCtx->pDec == NULL) {
if (pLastThreadCtx != NULL) {
pLastThreadCtx->pDec->bUsedAsRef = pLastThreadCtx->pCtx->uiNalRefIdc > 0;
if (pLastThreadCtx->pDec->bUsedAsRef) {
for (int32_t listIdx = LIST_0; listIdx < LIST_A; ++listIdx) {
uint32_t i = 0;
while (i < MAX_DPB_COUNT && pLastThreadCtx->pCtx->sRefPic.pRefList[listIdx][i]) {
pLastThreadCtx->pDec->pRefPic[listIdx][i] = pLastThreadCtx->pCtx->sRefPic.pRefList[listIdx][i];
++i;
}
}
pLastThreadCtx->pCtx->sTmpRefPic = pLastThreadCtx->pCtx->sRefPic;
WelsMarkAsRef (pLastThreadCtx->pCtx, pLastThreadCtx->pDec);
pCtx->sRefPic = pLastThreadCtx->pCtx->sTmpRefPic;
} else {
pCtx->sRefPic = pLastThreadCtx->pCtx->sRefPic;
}
}
pCtx->pDec = PrefetchPic (pCtx->pPicBuff);
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;
}
if (pThreadCtx != NULL) {
pCtx->pDec->bIsUngroupedMultiSlice = false;
pThreadCtx->pDec = pCtx->pDec;
if (iThreadCount > 1) ++pCtx->pDec->iRefCount;
uint32_t uiMbHeight = (pCtx->pDec->iHeightInPixel + 15) >> 4;
for (uint32_t i = 0; i < uiMbHeight; ++i) {
RESET_EVENT (&pCtx->pDec->pReadyEvent[i]);
}
}
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;
pCtx->pDec->uiDecodingTimeStamp = pCtx->uiDecodingTimeStamp;
if (pThreadCtx != NULL) {
pThreadCtx->iPicBuffIdx = pCtx->pDec->iPicBuffIdx;
pCtx->pCurDqLayer->pMbCorrectlyDecodedFlag = pCtx->pDec->pMbCorrectlyDecodedFlag;
}
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));
memset (pCtx->pDec->pRefPic[LIST_0], 0, sizeof (PPicture) * MAX_DPB_COUNT);
memset (pCtx->pDec->pRefPic[LIST_1], 0, sizeof (PPicture) * MAX_DPB_COUNT);
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;
pCtx->pDec->eSliceType = pSh->eSliceType;
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;
pCtx->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 ((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
int32_t iPrevFrameNum = pCtx->pLastDecPicInfo->iPrevFrameNum;
if (pLastThreadCtx != NULL) {
if (pCtx->bNewSeqBegin) {
iPrevFrameNum = 0;
} else if (pLastThreadCtx->pDec != NULL) {
iPrevFrameNum = pLastThreadCtx->pDec->iFrameNum;
} else {
iPrevFrameNum = pCtx->bNewSeqBegin ? 0 : pLastThreadCtx->pCtx->iFrameNum;
}
}
if (!kbIdrFlag &&
pSh->iFrameNum != iPrevFrameNum &&
pSh->iFrameNum != ((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",
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 && isNewFrame) {
iRet = InitRefPicList (pCtx, 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;
}
}
}
//calculate Colocated mv scaling factor for temporal direct prediction
if (pSh->eSliceType == B_SLICE && !pSh->iDirectSpatialMvPredFlag)
ComputeColocatedTemporalScaling (pCtx);
if (iThreadCount > 1) {
memset (&pCtx->lastReadyHeightOffset[0][0], -1, LIST_A * MAX_REF_PIC_COUNT * sizeof (int16_t));
SET_EVENT (&pThreadCtx->sSliceDecodeStart);
iRet = WelsDecodeAndConstructSlice (pCtx);
} else {
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 (iThreadCount <= 1 && 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 (iThreadCount <= 1) {
if (pCtx->sRefPic.uiRefCount[LIST_0] > 0) {
bAllRefComplete &= CheckRefPicturesComplete (pCtx);
} else {
bAllRefComplete = false;
}
}
}
}
#if defined (_DEBUG) && !defined (CODEC_FOR_TESTBED)
WelsLog (& (pCtx->sLogCtx), WELS_LOG_DEBUG, "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
WelsLog (& (pCtx->sLogCtx), WELS_LOG_DEBUG, "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;
}
}
}
if (iThreadCount >= 1) {
int32_t id = pThreadCtx->sThreadInfo.uiThrNum;
for (int32_t i = 0; i < iThreadCount; ++i) {
if (i == id || pThreadCtx[i - id].pCtx->uiDecodingTimeStamp == 0) continue;
if (pThreadCtx[i - id].pCtx->uiDecodingTimeStamp < pCtx->uiDecodingTimeStamp) {
WAIT_EVENT (&pThreadCtx[i - id].sSliceDecodeFinish, WELS_DEC_THREAD_WAIT_INFINITE);
}
}
pCtx->pLastDecPicInfo->uiDecodingTimeStamp = pCtx->uiDecodingTimeStamp;
}
iRet = DecodeFrameConstruction (pCtx, ppDst, pDstInfo);
if (iRet) {
if (iThreadCount > 1) {
SET_EVENT (&pThreadCtx->sSliceDecodeFinish);
}
return iRet;
}
pCtx->pLastDecPicInfo->pPreviousDecodedPictureInDpb = pCtx->pDec; //store latest decoded picture for EC
pCtx->bUsedAsRef = pCtx->uiNalRefIdc > 0;
if (iThreadCount <= 1) {
if (pCtx->bUsedAsRef) {
for (int32_t listIdx = LIST_0; listIdx < LIST_A; ++listIdx) {
uint32_t i = 0;
while (i < MAX_DPB_COUNT && pCtx->sRefPic.pRefList[listIdx][i]) {
pCtx->pDec->pRefPic[listIdx][i] = pCtx->sRefPic.pRefList[listIdx][i];
++i;
}
}
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);
}
} else if (iThreadCount > 1) {
SET_EVENT (&pThreadCtx->sImageReady);
}
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->pLastDecPicInfo->iPrevFrameNum = pSh->iFrameNum;
if (pCtx->pLastDecPicInfo->bLastHasMmco5)
pCtx->pLastDecPicInfo->iPrevFrameNum = 0;
if (iThreadCount > 1) {
int32_t id = pThreadCtx->sThreadInfo.uiThrNum;
for (int32_t i = 0; i < iThreadCount; ++i) {
if (pThreadCtx[i - id].pCtx != NULL) {
unsigned long long uiTimeStamp = pThreadCtx[i - id].pCtx->uiTimeStamp;
if (uiTimeStamp > 0 && pThreadCtx[i - id].pCtx->sSpsPpsCtx.iSeqId > pCtx->sSpsPpsCtx.iSeqId) {
CopySpsPps (pThreadCtx[i - id].pCtx, pCtx);
if (pCtx->pPicBuff != pThreadCtx[i - id].pCtx->pPicBuff) {
pCtx->pPicBuff = pThreadCtx[i - id].pCtx->pPicBuff;
}
InitialDqLayersContext (pCtx, pCtx->pSps->iMbWidth << 4, pCtx->pSps->iMbHeight << 4);
break;
}
}
}
}
if (iThreadCount > 1) {
SET_EVENT (&pThreadCtx->sSliceDecodeFinish);
}
}
return ERR_NONE;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment