/* * fill data fields in default for decoder context */ void WelsDecoderDefaults (PWelsDecoderContext pCtx) { int32_t iCpuCores = 1; memset (pCtx, 0, sizeof (SWelsDecoderContext)); // fill zero first pCtx->pArgDec = NULL; pCtx->iOutputColorFormat = videoFormatI420; // yuv in default pCtx->bHaveGotMemory = false; // not ever request memory blocks for decoder context related pCtx->uiCpuFlag = 0; pCtx->bAuReadyFlag = 0; // au data is not ready pCtx->uiCpuFlag = WelsCPUFeatureDetect (&iCpuCores); pCtx->iImgWidthInPixel = 0; pCtx->iImgHeightInPixel = 0; // alloc picture data when picture size is available pCtx->iFrameNum = -1; pCtx->iPrevFrameNum = -1; pCtx->iErrorCode = ERR_NONE; pCtx->pDec = NULL; WelsResetRefPic (pCtx); pCtx->iActiveFmoNum = 0; pCtx->pPicBuff[LIST_0] = NULL; pCtx->pPicBuff[LIST_1] = NULL; pCtx->bAvcBasedFlag = true; pCtx->iErrorConMethod = ERROR_CON_DISABLE; }
/* * free memory blocks in avc */ void WelsFreeMem (PWelsDecoderContext pCtx) { int32_t iListIdx = 0; /* TODO: free memory blocks introduced in avc */ ResetFmoList (pCtx); WelsResetRefPic (pCtx); // for sPicBuff for (iListIdx = LIST_0; iListIdx < LIST_A; ++ iListIdx) { PPicBuff* pPicBuff = &pCtx->pPicBuff[iListIdx]; if (NULL != pPicBuff && NULL != *pPicBuff) { DestroyPicBuff (pPicBuff); } } // added for safe memory pCtx->iImgWidthInPixel = 0; pCtx->iImgHeightInPixel = 0; pCtx->iLastImgWidthInPixel = 0; pCtx->iLastImgHeightInPixel = 0; pCtx->bFreezeOutput = true; pCtx->bHaveGotMemory = false; WelsFree (pCtx->pCabacDecEngine, "pCtx->pCabacDecEngine"); }
/* * free memory dynamically allocated during decoder */ void WelsFreeDynamicMemory (PWelsDecoderContext pCtx) { int32_t iListIdx = 0; CMemoryAlign* pMa = pCtx->pMemAlign; //free dq layer memory UninitialDqLayersContext (pCtx); //free FMO memory ResetFmoList (pCtx); //free ref-pic list & picture memory WelsResetRefPic (pCtx); for (iListIdx = LIST_0; iListIdx < LIST_A; ++ iListIdx) { PPicBuff* pPicBuff = &pCtx->pPicBuff[iListIdx]; if (NULL != pPicBuff && NULL != *pPicBuff) { DestroyPicBuff (pPicBuff, pMa); } } // added for safe memory pCtx->iImgWidthInPixel = 0; pCtx->iImgHeightInPixel = 0; pCtx->iLastImgWidthInPixel = 0; pCtx->iLastImgHeightInPixel = 0; pCtx->bFreezeOutput = true; pCtx->bHaveGotMemory = false; //free CABAC memory pMa->WelsFree (pCtx->pCabacDecEngine, "pCtx->pCabacDecEngine"); }
/* * fill data fields in default for decoder context */ void WelsDecoderDefaults (PWelsDecoderContext pCtx, SLogContext* pLogCtx) { int32_t iCpuCores = 1; pCtx->sLogCtx = *pLogCtx; pCtx->pArgDec = NULL; pCtx->eOutputColorFormat = videoFormatI420; // yuv in default pCtx->bHaveGotMemory = false; // not ever request memory blocks for decoder context related pCtx->uiCpuFlag = 0; pCtx->bAuReadyFlag = 0; // au data is not ready pCtx->bCabacInited = false; pCtx->uiCpuFlag = WelsCPUFeatureDetect (&iCpuCores); pCtx->iImgWidthInPixel = 0; pCtx->iImgHeightInPixel = 0; // alloc picture data when picture size is available pCtx->iLastImgWidthInPixel = 0; pCtx->iLastImgHeightInPixel = 0; pCtx->bFreezeOutput = true; pCtx->iFrameNum = -1; pCtx->iPrevFrameNum = -1; pCtx->iErrorCode = ERR_NONE; pCtx->pDec = NULL; WelsResetRefPic (pCtx); pCtx->iActiveFmoNum = 0; pCtx->pPicBuff[LIST_0] = NULL; pCtx->pPicBuff[LIST_1] = NULL; pCtx->bAvcBasedFlag = true; pCtx->eErrorConMethod = ERROR_CON_SLICE_MV_COPY_CROSS_IDR_FREEZE_RES_CHANGE; pCtx->pPreviousDecodedPictureInDpb = NULL; pCtx->sDecoderStatistics.iAvgLumaQp = -1; pCtx->bSpsLatePps = false; pCtx->bUseScalingList = false; pCtx->iSpsErrorIgnored = 0; pCtx->iSubSpsErrorIgnored = 0; pCtx->iPpsErrorIgnored = 0; pCtx->iPPSInvalidNum = 0; pCtx->iPPSLastInvalidId = -1; pCtx->iSPSInvalidNum = 0; pCtx->iSPSLastInvalidId = -1; pCtx->iSubSPSInvalidNum = 0; pCtx->iSubSPSLastInvalidId = -1; }
/* * request memory blocks for decoder avc part */ int32_t WelsRequestMem (PWelsDecoderContext pCtx, const int32_t kiMbWidth, const int32_t kiMbHeight) { const int32_t kiPicWidth = kiMbWidth << 4; const int32_t kiPicHeight = kiMbHeight << 4; int32_t iErr = ERR_NONE; int32_t iListIdx = 0; //, mb_blocks = 0; int32_t iPicQueueSize = 0; // adaptive size of picture queue, = (pSps->iNumRefFrames x 2) bool bNeedChangePicQueue = true; WELS_VERIFY_RETURN_IF (ERR_INFO_INVALID_PARAM, (NULL == pCtx || kiPicWidth <= 0 || kiPicHeight <= 0)) // Fixed the issue about different gop size over last, 5/17/2010 // get picture queue size currently iPicQueueSize = GetTargetRefListSize (pCtx); // adaptive size of picture queue, = (pSps->iNumRefFrames x 2) pCtx->iPicQueueNumber = iPicQueueSize; if (pCtx->pPicBuff[LIST_0] != NULL && pCtx->pPicBuff[LIST_0]->iCapacity == iPicQueueSize) // comparing current picture queue size requested and previous allocation picture queue bNeedChangePicQueue = false; // HD based pic buffer need consider memory size consumed when switch from 720p to other lower size WELS_VERIFY_RETURN_IF (ERR_NONE, pCtx->bHaveGotMemory && (kiPicWidth == pCtx->iImgWidthInPixel && kiPicHeight == pCtx->iImgHeightInPixel) && (!bNeedChangePicQueue)) // have same scaled buffer // sync update pRefList WelsResetRefPic (pCtx); // added to sync update ref list due to pictures are free // for Recycled_Pic_Queue for (iListIdx = LIST_0; iListIdx < LIST_A; ++ iListIdx) { PPicBuff* ppPic = &pCtx->pPicBuff[iListIdx]; if (NULL != ppPic && NULL != *ppPic) { DestroyPicBuff (ppPic); } } pCtx->pPreviousDecodedPictureInDpb = NULL; // currently only active for LIST_0 due to have no B frames iErr = CreatePicBuff (pCtx, &pCtx->pPicBuff[LIST_0], iPicQueueSize, kiPicWidth, kiPicHeight); if (iErr != ERR_NONE) return iErr; pCtx->iImgWidthInPixel = kiPicWidth; // target width of image to be reconstruted while decoding pCtx->iImgHeightInPixel = kiPicHeight; // target height of image to be reconstruted while decoding pCtx->bHaveGotMemory = true; // global memory for decoder context related is requested pCtx->pDec = NULL; // need prefetch a new pic due to spatial size changed return ERR_NONE; }
/* * fill data fields in default for decoder context */ void_t WelsDecoderDefaults (PWelsDecoderContext pCtx) { int32_t iCpuCores = 1; memset (pCtx, 0, sizeof (SWelsDecoderContext)); // fill zero first pCtx->pArgDec = NULL; pCtx->iOutputColorFormat = videoFormatI420; // yuv in default pCtx->bHaveGotMemory = false; // not ever request memory blocks for decoder context related pCtx->uiCpuFlag = 0; pCtx->bAuReadyFlag = 0; // au data is not ready g_uiCacheLineSize = 16; #if defined(X86_ASM) pCtx->uiCpuFlag = WelsCPUFeatureDetect (&iCpuCores); #ifdef HAVE_CACHE_LINE_ALIGN if (pCtx->uiCpuFlag & WELS_CPU_CACHELINE_64) { g_uiCacheLineSize = 64; } else if (pCtx->uiCpuFlag & WELS_CPU_CACHELINE_32) { g_uiCacheLineSize = 32; } #endif//HAVE_CACHE_LINE_ALIGN #endif//X86_ASM pCtx->iImgWidthInPixel = 0; pCtx->iImgHeightInPixel = 0; // alloc picture data when picture size is available pCtx->iFrameNum = -1; pCtx->iPrevFrameNum = -1; pCtx->iErrorCode = ERR_NONE; pCtx->pDec = NULL; WelsResetRefPic (pCtx); pCtx->iActiveFmoNum = 0; pCtx->pPicBuff[LIST_0] = NULL; pCtx->pPicBuff[LIST_1] = NULL; pCtx->bAvcBasedFlag = true; }
static int32_t MMCOProcess (PWelsDecoderContext pCtx, uint32_t uiMmcoType, int32_t iShortFrameNum, uint32_t uiLongTermPicNum , int32_t iLongTermFrameIdx, int32_t iMaxLongTermFrameIdx) { PRefPic pRefPic = &pCtx->sRefPic; PPicture pPic = NULL; int32_t i = 0; int32_t iRet = ERR_NONE; switch (uiMmcoType) { case MMCO_SHORT2UNUSED: pPic = WelsDelShortFromListSetUnref (pRefPic, iShortFrameNum); if (pPic == NULL) { WelsLog (& (pCtx->sLogCtx), WELS_LOG_WARNING, "MMCO_SHORT2UNUSED: delete a empty entry from short term list"); } break; case MMCO_LONG2UNUSED: pPic = WelsDelLongFromListSetUnref (pRefPic, uiLongTermPicNum); if (pPic == NULL) { WelsLog (& (pCtx->sLogCtx), WELS_LOG_WARNING, "MMCO_LONG2UNUSED: delete a empty entry from long term list"); } break; case MMCO_SHORT2LONG: if (iLongTermFrameIdx > pRefPic->iMaxLongTermFrameIdx) { return ERR_INFO_INVALID_MMCO_LONG_TERM_IDX_EXCEED_MAX; } pPic = WelsDelShortFromList (pRefPic, iShortFrameNum); if (pPic == NULL) { WelsLog (& (pCtx->sLogCtx), WELS_LOG_WARNING, "MMCO_LONG2LONG: delete a empty entry from short term list"); break; } WelsDelLongFromListSetUnref (pRefPic, iLongTermFrameIdx); #ifdef LONG_TERM_REF pCtx->bCurAuContainLtrMarkSeFlag = true; pCtx->iFrameNumOfAuMarkedLtr = iShortFrameNum; WelsLog (& (pCtx->sLogCtx), WELS_LOG_INFO, "ex_mark_avc():::MMCO_SHORT2LONG:::LTR marking....iFrameNum: %d", pCtx->iFrameNumOfAuMarkedLtr); #endif MarkAsLongTerm (pRefPic, iShortFrameNum, iLongTermFrameIdx); break; case MMCO_SET_MAX_LONG: pRefPic->iMaxLongTermFrameIdx = iMaxLongTermFrameIdx; for (i = 0 ; i < pRefPic->uiLongRefCount[LIST_0]; i++) { if (pRefPic->pLongRefList[LIST_0][i]->iLongTermFrameIdx > pRefPic->iMaxLongTermFrameIdx) { WelsDelLongFromListSetUnref (pRefPic, pRefPic->pLongRefList[LIST_0][i]->iLongTermFrameIdx); } } break; case MMCO_RESET: WelsResetRefPic (pCtx); pCtx->bLastHasMmco5 = true; break; case MMCO_LONG: if (iLongTermFrameIdx > pRefPic->iMaxLongTermFrameIdx) { return ERR_INFO_INVALID_MMCO_LONG_TERM_IDX_EXCEED_MAX; } WelsDelLongFromListSetUnref (pRefPic, iLongTermFrameIdx); if (pRefPic->uiLongRefCount[LIST_0] + pRefPic->uiShortRefCount[LIST_0] >= WELS_MAX (1, pCtx->pSps->iNumRefFrames)) { return ERR_INFO_INVALID_MMCO_REF_NUM_OVERFLOW; } #ifdef LONG_TERM_REF pCtx->bCurAuContainLtrMarkSeFlag = true; pCtx->iFrameNumOfAuMarkedLtr = pCtx->iFrameNum; WelsLog (& (pCtx->sLogCtx), WELS_LOG_INFO, "ex_mark_avc():::MMCO_LONG:::LTR marking....iFrameNum: %d", pCtx->iFrameNum); #endif iRet = AddLongTermToList (pRefPic, pCtx->pDec, iLongTermFrameIdx); break; default : break; } return iRet; }
static int32_t MMCOProcess( PWelsDecoderContext pCtx,uint32_t uiMmcoType,bool_t bRefBasePic, int32_t iShortFrameNum,uint32_t uiLongTermPicNum ,int32_t iLongTermFrameIdx,int32_t iMaxLongTermFrameIdx ) { PRefPic pRefPic = &pCtx->sRefPic; PPicture pPic = NULL; int32_t i = 0; int32_t iRet = ERR_NONE; switch (uiMmcoType) { case MMCO_SHORT2UNUSED: pPic = WelsDelShortFromListSetUnref(pRefPic,iShortFrameNum,(ERemoveFlag) bRefBasePic); break; case MMCO_LONG2UNUSED: pPic = WelsDelLongFromListSetUnref(pRefPic,uiLongTermPicNum,(ERemoveFlag) bRefBasePic); break; case MMCO_SHORT2LONG: if(iLongTermFrameIdx > pRefPic->iMaxLongTermFrameIdx){ return ERR_INFO_INVALID_MMCO_LONG_TERM_IDX_EXCEED_MAX; } pPic = WelsDelShortFromList(pRefPic,iShortFrameNum,REMOVE_TARGET); WelsDelLongFromListSetUnref(pRefPic,iLongTermFrameIdx,REMOVE_TARGET); WelsDelShortFromList(pRefPic,iShortFrameNum,REMOVE_BASE); WelsDelLongFromListSetUnref(pRefPic,iLongTermFrameIdx,REMOVE_BASE); #ifdef LONG_TERM_REF pCtx->bCurAuContainLtrMarkSeFlag = true; pCtx->iFrameNumOfAuMarkedLtr = iShortFrameNum; WelsLog( pCtx, WELS_LOG_INFO, "ex_mark_avc():::MMCO_SHORT2LONG:::LTR marking....iFrameNum: %d\n", pCtx->iFrameNumOfAuMarkedLtr ); #endif MarkAsLongTerm(pRefPic,iShortFrameNum,iLongTermFrameIdx); break; case MMCO_SET_MAX_LONG: pRefPic->iMaxLongTermFrameIdx = iMaxLongTermFrameIdx; for (i = 0 ;i <pRefPic->uiLongRefCount[LIST_0];i++) { if (pRefPic->pLongRefList[LIST_0][i]->iLongTermFrameIdx > pRefPic->iMaxLongTermFrameIdx) { WelsDelLongFromListSetUnref(pRefPic,pRefPic->pLongRefList[LIST_0][i]->iLongTermFrameIdx,REMOVE_BASE_FIRST); } } break; case MMCO_RESET: WelsResetRefPic(pCtx); pCtx->bLastHasMmco5 = true; break; case MMCO_LONG: if(iLongTermFrameIdx > pRefPic->iMaxLongTermFrameIdx){ return ERR_INFO_INVALID_MMCO_LONG_TERM_IDX_EXCEED_MAX; } #ifdef LONG_TERM_REF pCtx->bCurAuContainLtrMarkSeFlag = true; pCtx->iFrameNumOfAuMarkedLtr = pCtx->iFrameNum; WelsLog( pCtx, WELS_LOG_INFO, "ex_mark_avc():::MMCO_LONG:::LTR marking....iFrameNum: %d\n", pCtx->iFrameNum ); #endif WelsDelLongFromListSetUnref(pRefPic,iLongTermFrameIdx,REMOVE_TARGET); WelsDelLongFromListSetUnref(pRefPic,iLongTermFrameIdx,REMOVE_BASE); iRet = AddLongTermToList(pRefPic,pCtx->pDec,iLongTermFrameIdx); break; default : break; } return iRet; }
/* * request memory blocks for decoder avc part */ int32_t WelsRequestMem (PWelsDecoderContext pCtx, const int32_t kiMbWidth, const int32_t kiMbHeight, bool& bReallocFlag) { const int32_t kiPicWidth = kiMbWidth << 4; const int32_t kiPicHeight = kiMbHeight << 4; int32_t iErr = ERR_NONE; int32_t iListIdx = 0; //, mb_blocks = 0; int32_t iPicQueueSize = 0; // adaptive size of picture queue, = (pSps->iNumRefFrames x 2) bReallocFlag = false; bool bNeedChangePicQueue = true; CMemoryAlign* pMa = pCtx->pMemAlign; WELS_VERIFY_RETURN_IF (ERR_INFO_INVALID_PARAM, (NULL == pCtx || kiPicWidth <= 0 || kiPicHeight <= 0)) // Fixed the issue about different gop size over last, 5/17/2010 // get picture queue size currently iPicQueueSize = GetTargetRefListSize (pCtx); // adaptive size of picture queue, = (pSps->iNumRefFrames x 2) pCtx->iPicQueueNumber = iPicQueueSize; if (pCtx->pPicBuff[LIST_0] != NULL && pCtx->pPicBuff[LIST_0]->iCapacity == iPicQueueSize) // comparing current picture queue size requested and previous allocation picture queue bNeedChangePicQueue = false; // HD based pic buffer need consider memory size consumed when switch from 720p to other lower size WELS_VERIFY_RETURN_IF (ERR_NONE, pCtx->bHaveGotMemory && (kiPicWidth == pCtx->iImgWidthInPixel && kiPicHeight == pCtx->iImgHeightInPixel) && (!bNeedChangePicQueue)) // have same scaled buffer // sync update pRefList WelsResetRefPic (pCtx); // added to sync update ref list due to pictures are free if (pCtx->bHaveGotMemory && (kiPicWidth == pCtx->iImgWidthInPixel && kiPicHeight == pCtx->iImgHeightInPixel) && pCtx->pPicBuff[LIST_0] != NULL && pCtx->pPicBuff[LIST_0]->iCapacity != iPicQueueSize) { // currently only active for LIST_0 due to have no B frames WelsLog (& (pCtx->sLogCtx), WELS_LOG_INFO, "WelsRequestMem(): memory re-alloc for no resolution change (size = %d * %d), ref list size change from %d to %d", kiPicWidth, kiPicHeight, pCtx->pPicBuff[LIST_0]->iCapacity, iPicQueueSize); if (pCtx->pPicBuff[LIST_0]->iCapacity < iPicQueueSize) { iErr = IncreasePicBuff (pCtx, &pCtx->pPicBuff[LIST_0], pCtx->pPicBuff[LIST_0]->iCapacity, kiPicWidth, kiPicHeight, iPicQueueSize); } else { iErr = DecreasePicBuff (pCtx, &pCtx->pPicBuff[LIST_0], pCtx->pPicBuff[LIST_0]->iCapacity, kiPicWidth, kiPicHeight, iPicQueueSize); } } else { if (pCtx->bHaveGotMemory) WelsLog (& (pCtx->sLogCtx), WELS_LOG_INFO, "WelsRequestMem(): memory re-alloc for resolution change, size change from %d * %d to %d * %d, ref list size change from %d to %d", pCtx->iImgWidthInPixel, pCtx->iImgHeightInPixel, kiPicWidth, kiPicHeight, pCtx->pPicBuff[LIST_0]->iCapacity, iPicQueueSize); else WelsLog (& (pCtx->sLogCtx), WELS_LOG_INFO, "WelsRequestMem(): memory alloc size = %d * %d, ref list size = %d", kiPicWidth, kiPicHeight, iPicQueueSize); // for Recycled_Pic_Queue for (iListIdx = LIST_0; iListIdx < LIST_A; ++ iListIdx) { PPicBuff* ppPic = &pCtx->pPicBuff[iListIdx]; if (NULL != ppPic && NULL != *ppPic) { DestroyPicBuff (ppPic, pMa); } } pCtx->pPreviousDecodedPictureInDpb = NULL; // currently only active for LIST_0 due to have no B frames iErr = CreatePicBuff (pCtx, &pCtx->pPicBuff[LIST_0], iPicQueueSize, kiPicWidth, kiPicHeight); } if (iErr != ERR_NONE) return iErr; pCtx->iImgWidthInPixel = kiPicWidth; // target width of image to be reconstruted while decoding pCtx->iImgHeightInPixel = kiPicHeight; // target height of image to be reconstruted while decoding pCtx->bHaveGotMemory = true; // global memory for decoder context related is requested pCtx->pDec = NULL; // need prefetch a new pic due to spatial size changed if (pCtx->pCabacDecEngine == NULL) pCtx->pCabacDecEngine = (SWelsCabacDecEngine*) pMa->WelsMallocz (sizeof (SWelsCabacDecEngine), "pCtx->pCabacDecEngine"); WELS_VERIFY_RETURN_IF (ERR_INFO_OUT_OF_MEMORY, (NULL == pCtx->pCabacDecEngine)) bReallocFlag = true; // memory re-allocation successfully finished return ERR_NONE; }