ref: 7676c5b65bcc7f3deb60f90a85928a2775e7feba
dir: /codec/decoder/core/src/manage_dec_ref.cpp/
/*!
* \copy
* Copyright (c) 2008-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.
*
*
* manage_ref_pic.cpp
*
* Abstract
* Implementation for managing reference picture
*
* History
* 07/21/2008 Created
*
*****************************************************************************/
#include "manage_dec_ref.h"
#include "error_code.h"
namespace WelsDec {
static PPicture WelsDelShortFromList (PRefPic pRefPic, int32_t iFrameNum);
static PPicture WelsDelLongFromList (PRefPic pRefPic, uint32_t uiLongTermFrameIdx);
static PPicture WelsDelShortFromListSetUnref (PRefPic pRefPic, int32_t iFrameNum);
static PPicture WelsDelLongFromListSetUnref (PRefPic pRefPic, uint32_t uiLongTermFrameIdx);
static int32_t MMCO (PWelsDecoderContext pCtx, PRefPicMarking pRefPicMarking);
static int32_t MMCOProcess (PWelsDecoderContext pCtx, uint32_t uiMmcoType,
int32_t iShortFrameNum, uint32_t uiLongTermPicNum, int32_t iLongTermFrameIdx, int32_t iMaxLongTermFrameIdx);
static int32_t SlidingWindow (PWelsDecoderContext pCtx);
static int32_t AddShortTermToList (PRefPic pRefPic, PPicture pPic);
static int32_t AddLongTermToList (PRefPic pRefPic, PPicture pPic, int32_t iLongTermFrameIdx);
static int32_t MarkAsLongTerm (PRefPic pRefPic, int32_t iFrameNum, int32_t iLongTermFrameIdx);
#ifdef LONG_TERM_REF
int32_t GetLTRFrameIndex (PRefPic pRefPic, int32_t iAncLTRFrameNum);
#endif
static int32_t RemainOneBufferInDpbForEC (PWelsDecoderContext pCtx);
static void SetUnRef (PPicture pRef) {
if (NULL != pRef) {
pRef->bUsedAsRef = false;
pRef->bIsLongRef = false;
pRef->iFrameNum = -1;
pRef->iFramePoc = 0;
pRef->iLongTermFrameIdx = -1;
pRef->uiQualityId = -1;
pRef->uiTemporalId = -1;
pRef->uiSpatialId = -1;
pRef->iSpsId = -1;
}
}
//reset pRefList when
// 1.sps arrived that is new sequence starting
// 2.IDR NAL i.e. 1st layer in IDR AU
void WelsResetRefPic (PWelsDecoderContext pCtx) {
int32_t i = 0;
PRefPic pRefPic = &pCtx->sRefPic;
pCtx->sRefPic.uiLongRefCount[LIST_0] = pCtx->sRefPic.uiShortRefCount[LIST_0] = 0;
pRefPic->uiRefCount[LIST_0] = 0;
for (i = 0; i < MAX_SHORT_REF_COUNT; i++) {
if (pRefPic->pShortRefList[LIST_0][i] != NULL) {
SetUnRef (pRefPic->pShortRefList[LIST_0][i]);
pRefPic->pShortRefList[LIST_0][i] = NULL;
}
}
pRefPic->uiShortRefCount[LIST_0] = 0;
for (i = 0; i < MAX_LONG_REF_COUNT; i++) {
if (pRefPic->pLongRefList[LIST_0][i] != NULL) {
SetUnRef (pRefPic->pLongRefList[LIST_0][i]);
pRefPic->pLongRefList[LIST_0][i] = NULL;
}
}
pRefPic->uiLongRefCount[LIST_0] = 0;
}
/**
* fills the pRefPic.pRefList.
*/
int32_t WelsInitRefList (PWelsDecoderContext pCtx, int32_t iPoc) {
int32_t i, iCount = 0;
if ((pCtx->sRefPic.uiShortRefCount[LIST_0] + pCtx->sRefPic.uiLongRefCount[LIST_0] <= 0) && (pCtx->eSliceType != I_SLICE
&& pCtx->eSliceType != SI_SLICE)) {
if (pCtx->iErrorConMethod != ERROR_CON_DISABLE) { //IDR lost!, recover it for future decoding with data all set to 0
PPicture pRef = PrefetchPic (pCtx->pPicBuff[0]);
if (pRef != NULL) {
memset (pRef->pData[0], 0, pRef->iLinesize[0] * pRef->iHeightInPixel);
memset (pRef->pData[1], 0, pRef->iLinesize[1] * pRef->iHeightInPixel / 2);
memset (pRef->pData[2], 0, pRef->iLinesize[2] * pRef->iHeightInPixel / 2);
pRef->iFrameNum = 0;
pRef->iFramePoc = 0;
pRef->uiTemporalId = pRef->uiQualityId = 0;
AddShortTermToList (&pCtx->sRefPic, pRef);
} else {
WelsLog (pCtx, WELS_LOG_ERROR, "WelsInitRefList()::PrefetchPic for EC errors.\n");
pCtx->iErrorCode |= dsOutOfMemory;
return ERR_INFO_REF_COUNT_OVERFLOW;
}
}
}
PPicture* ppShoreRefList = pCtx->sRefPic.pShortRefList[LIST_0];
PPicture* ppLongRefList = pCtx->sRefPic.pLongRefList[LIST_0];
memset (pCtx->sRefPic.pRefList[LIST_0], 0, MAX_REF_PIC_COUNT * sizeof (PPicture));
//short
for (i = 0; i < pCtx->sRefPic.uiShortRefCount[LIST_0]; ++i) {
pCtx->sRefPic.pRefList[LIST_0][iCount++ ] = ppShoreRefList[i];
}
//long
for (i = 0; i < pCtx->sRefPic.uiLongRefCount[LIST_0] ; ++i) {
pCtx->sRefPic.pRefList[LIST_0][iCount++ ] = ppLongRefList[i];
}
pCtx->sRefPic.uiRefCount[LIST_0] = iCount;
return ERR_NONE;
}
int32_t WelsReorderRefList (PWelsDecoderContext pCtx) {
PRefPicListReorderSyn pRefPicListReorderSyn = pCtx->pCurDqLayer->pRefPicListReordering;
PNalUnitHeaderExt pNalHeaderExt = &pCtx->pCurDqLayer->sLayerInfo.sNalHeaderExt;
PSliceHeader pSliceHeader = &pCtx->pCurDqLayer->sLayerInfo.sSliceInLayer.sSliceHeaderExt.sSliceHeader;
PPicture pPic = NULL;
PPicture* ppRefList = pCtx->sRefPic.pRefList[LIST_0];
int32_t iRefCount = pCtx->sRefPic.uiRefCount[LIST_0];
int32_t iPredFrameNum = pSliceHeader->iFrameNum;
int32_t iMaxPicNum = 1 << pSliceHeader->pSps->uiLog2MaxFrameNum;
int32_t iAbsDiffPicNum = -1;
int32_t iReorderingIndex = 0;
int32_t i = 0;
if (pCtx->eSliceType == I_SLICE || pCtx->eSliceType == SI_SLICE) {
return ERR_NONE;
}
if (iRefCount <= 0) {
pCtx->iErrorCode = dsNoParamSets; //No any reference for decoding, SHOULD request IDR
return ERR_INFO_REFERENCE_PIC_LOST;
}
if (pRefPicListReorderSyn->bRefPicListReorderingFlag[LIST_0]) {
while (pRefPicListReorderSyn->sReorderingSyn[LIST_0][iReorderingIndex].uiReorderingOfPicNumsIdc != 3) {
uint16_t uiReorderingOfPicNumsIdc =
pRefPicListReorderSyn->sReorderingSyn[LIST_0][iReorderingIndex].uiReorderingOfPicNumsIdc;
if (uiReorderingOfPicNumsIdc < 2) {
iAbsDiffPicNum = pRefPicListReorderSyn->sReorderingSyn[LIST_0][iReorderingIndex].uiAbsDiffPicNumMinus1 + 1;
if (uiReorderingOfPicNumsIdc == 0) {
iPredFrameNum -= iAbsDiffPicNum;
} else {
iPredFrameNum += iAbsDiffPicNum;
}
iPredFrameNum &= iMaxPicNum - 1;
for (i = iRefCount - 1; i >= iReorderingIndex; i--) {
if (ppRefList[i]->iFrameNum == iPredFrameNum && !ppRefList[i]->bIsLongRef) {
if ((pNalHeaderExt->uiQualityId == ppRefList[i]->uiQualityId)
&& (pSliceHeader->iSpsId != ppRefList[i]->iSpsId)) { //check;
WelsLog (pCtx, WELS_LOG_WARNING, "WelsReorderRefList()::::BASE LAYER::::iSpsId:%d, ref_sps_id:%d\n",
pSliceHeader->iSpsId, ppRefList[i]->iSpsId);
pCtx->iErrorCode = dsNoParamSets; //cross-IDR reference frame selection, SHOULD request IDR.--
return ERR_INFO_REFERENCE_PIC_LOST;
} else {
break;
}
}
}
} else if (uiReorderingOfPicNumsIdc == 2) {
for (i = iRefCount - 1; i >= iReorderingIndex; i--) {
if (ppRefList[i]->bIsLongRef
&& ppRefList[i]->iLongTermFrameIdx ==
pRefPicListReorderSyn->sReorderingSyn[LIST_0][iReorderingIndex].uiLongTermPicNum) {
if ((pNalHeaderExt->uiQualityId == ppRefList[i]->uiQualityId)
&& (pSliceHeader->iSpsId != ppRefList[i]->iSpsId)) { //check;
WelsLog (pCtx, WELS_LOG_WARNING, "WelsReorderRefList()::::BASE LAYER::::iSpsId:%d, ref_sps_id:%d\n",
pSliceHeader->iSpsId, ppRefList[i]->iSpsId);
pCtx->iErrorCode = dsNoParamSets; //cross-IDR reference frame selection, SHOULD request IDR.--
return ERR_INFO_REFERENCE_PIC_LOST;
} else {
break;
}
}
}
}
if (i < iReorderingIndex) {
return ERR_INFO_REFERENCE_PIC_LOST;
}
pPic = ppRefList[i];
memmove (&ppRefList[1 + iReorderingIndex], &ppRefList[iReorderingIndex],
(i - iReorderingIndex)*sizeof (PPicture)); //confirmed_safe_unsafe_usage
ppRefList[iReorderingIndex] = pPic;
iReorderingIndex++;
}
}
return ERR_NONE;
}
int32_t WelsMarkAsRef (PWelsDecoderContext pCtx) {
PRefPic pRefPic = &pCtx->sRefPic;
PRefPicMarking pRefPicMarking = pCtx->pCurDqLayer->pRefPicMarking;
PAccessUnit pCurAU = pCtx->pAccessUnitList;
bool bIsIDRAU = false;
uint32_t j;
int32_t iRet = ERR_NONE;
pCtx->pDec->uiQualityId = pCtx->pCurDqLayer->sLayerInfo.sNalHeaderExt.uiQualityId;
pCtx->pDec->uiTemporalId = pCtx->pCurDqLayer->sLayerInfo.sNalHeaderExt.uiTemporalId;
for (j = pCurAU->uiStartPos; j <= pCurAU->uiEndPos; j++) {
if (pCurAU->pNalUnitsList[j]->sNalHeaderExt.sNalUnitHeader.eNalUnitType == NAL_UNIT_CODED_SLICE_IDR
|| pCurAU->pNalUnitsList[j]->sNalHeaderExt.bIdrFlag) {
bIsIDRAU = true;
break;
}
}
if (bIsIDRAU) {
if (pRefPicMarking->bLongTermRefFlag) {
pCtx->sRefPic.iMaxLongTermFrameIdx = 0;
AddLongTermToList (pRefPic, pCtx->pDec, 0);
} else {
pCtx->sRefPic.iMaxLongTermFrameIdx = -1;
}
} else {
if (pRefPicMarking->bAdaptiveRefPicMarkingModeFlag) {
iRet = MMCO (pCtx, pRefPicMarking);
if (iRet != ERR_NONE) {
if (pCtx->iErrorConMethod != ERROR_CON_DISABLE) {
iRet = RemainOneBufferInDpbForEC (pCtx);
} else {
return iRet;
}
}
if (pCtx->bLastHasMmco5) {
pCtx->pDec->iFrameNum = 0;
pCtx->pDec->iFramePoc = 0;
}
} else {
iRet = SlidingWindow (pCtx);
if (iRet != ERR_NONE) {
if (pCtx->iErrorConMethod != ERROR_CON_DISABLE) {
iRet = RemainOneBufferInDpbForEC (pCtx);
} else {
return iRet;
}
}
}
}
if (!pCtx->pDec->bIsLongRef) {
if (pRefPic->uiLongRefCount[LIST_0] + pRefPic->uiShortRefCount[LIST_0] >= WELS_MAX (1, pCtx->pSps->iNumRefFrames)) {
if (pCtx->iErrorConMethod != ERROR_CON_DISABLE) {
iRet = RemainOneBufferInDpbForEC (pCtx);
} else {
return ERR_INFO_INVALID_MMCO_REF_NUM_OVERFLOW;
}
}
AddShortTermToList (pRefPic, pCtx->pDec);
}
return iRet;
}
static int32_t MMCO (PWelsDecoderContext pCtx, PRefPicMarking pRefPicMarking) {
PSps pSps = pCtx->pCurDqLayer->sLayerInfo.pSps;
int32_t i = 0;
int32_t iRet = ERR_NONE;
for (i = 0; pRefPicMarking->sMmcoRef[i].uiMmcoType != MMCO_END; i++) {
uint32_t uiMmcoType = pRefPicMarking->sMmcoRef[i].uiMmcoType;
int32_t iShortFrameNum = (pCtx->iFrameNum - pRefPicMarking->sMmcoRef[i].iDiffOfPicNum) & ((
1 << pSps->uiLog2MaxFrameNum) - 1);
uint32_t uiLongTermPicNum = pRefPicMarking->sMmcoRef[i].uiLongTermPicNum;
int32_t iLongTermFrameIdx = pRefPicMarking->sMmcoRef[i].iLongTermFrameIdx;
int32_t iMaxLongTermFrameIdx = pRefPicMarking->sMmcoRef[i].iMaxLongTermFrameIdx;
if (uiMmcoType > MMCO_LONG) {
return ERR_INFO_INVALID_MMCO_OPCODE_BASE;
}
iRet = MMCOProcess (pCtx, uiMmcoType, iShortFrameNum, uiLongTermPicNum, iLongTermFrameIdx, iMaxLongTermFrameIdx);
if (iRet != ERR_NONE) {
return iRet;
}
}
return ERR_NONE;
}
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, WELS_LOG_WARNING, "MMCO_SHORT2UNUSED: delete a empty entry from short term list\n");
}
break;
case MMCO_LONG2UNUSED:
pPic = WelsDelLongFromListSetUnref (pRefPic, uiLongTermPicNum);
if (pPic == NULL) {
WelsLog (pCtx, WELS_LOG_WARNING, "MMCO_LONG2UNUSED: delete a empty entry from long term list\n");
}
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, WELS_LOG_WARNING, "MMCO_LONG2LONG: delete a empty entry from short term list\n");
break;
}
WelsDelLongFromListSetUnref (pRefPic, iLongTermFrameIdx);
#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);
}
}
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, WELS_LOG_INFO, "ex_mark_avc():::MMCO_LONG:::LTR marking....iFrameNum: %d\n", pCtx->iFrameNum);
#endif
iRet = AddLongTermToList (pRefPic, pCtx->pDec, iLongTermFrameIdx);
break;
default :
break;
}
return iRet;
}
static int32_t SlidingWindow (PWelsDecoderContext pCtx) {
PRefPic pRefPic = &pCtx->sRefPic;
PPicture pPic = NULL;
int32_t i = 0;
if (pCtx->sRefPic.uiShortRefCount[LIST_0] + pCtx->sRefPic.uiLongRefCount[LIST_0] >= pCtx->pSps->iNumRefFrames) {
for (i = pRefPic->uiShortRefCount[LIST_0] - 1; i >= 0; i--) {
pPic = WelsDelShortFromList (pRefPic, pRefPic->pShortRefList[LIST_0][i]->iFrameNum);
if (pPic) {
SetUnRef (pPic);
break;
} else {
return ERR_INFO_INVALID_MMCO_REF_NUM_OVERFLOW;
}
}
}
return ERR_NONE;
}
static PPicture WelsDelShortFromList (PRefPic pRefPic, int32_t iFrameNum) {
int32_t i = 0;
int32_t iMoveSize = 0;
PPicture pPic = NULL;
for (i = 0; i < pRefPic->uiShortRefCount[LIST_0]; i++) {
if (pRefPic->pShortRefList[LIST_0][i]->iFrameNum == iFrameNum) {
iMoveSize = pRefPic->uiShortRefCount[LIST_0] - i - 1;
pRefPic->pShortRefList[LIST_0][i]->bUsedAsRef = false;
pPic = pRefPic->pShortRefList[LIST_0][i];
pRefPic->pShortRefList[LIST_0][i] = NULL;
if (iMoveSize > 0) {
memmove (&pRefPic->pShortRefList[LIST_0][i], &pRefPic->pShortRefList[LIST_0][i + 1],
iMoveSize * sizeof (PPicture)); //confirmed_safe_unsafe_usage
}
pRefPic->uiShortRefCount[LIST_0]--;
pRefPic->pShortRefList[LIST_0][pRefPic->uiShortRefCount[LIST_0]] = NULL;
break;
}
}
return pPic;
}
static PPicture WelsDelShortFromListSetUnref (PRefPic pRefPic, int32_t iFrameNum) {
PPicture pPic = WelsDelShortFromList (pRefPic, iFrameNum);
if (pPic) {
SetUnRef (pPic);
}
return pPic;
}
static PPicture WelsDelLongFromList (PRefPic pRefPic, uint32_t uiLongTermFrameIdx) {
PPicture pPic = NULL;
int32_t i = 0;
for (i = 0; i < pRefPic->uiLongRefCount[LIST_0]; i++) {
pPic = pRefPic->pLongRefList[LIST_0][i];
if (pPic->iLongTermFrameIdx == (int32_t)uiLongTermFrameIdx) {
int32_t iMoveSize = pRefPic->uiLongRefCount[LIST_0] - i - 1;
pPic->bUsedAsRef = false;
pPic->bIsLongRef = false;
if (iMoveSize > 0) {
memmove (&pRefPic->pLongRefList[LIST_0][i], &pRefPic->pLongRefList[LIST_0][i + 1],
iMoveSize * sizeof (PPicture)); //confirmed_safe_unsafe_usage
}
pRefPic->uiLongRefCount[LIST_0]--;
pRefPic->pLongRefList[LIST_0][pRefPic->uiLongRefCount[LIST_0]] = NULL;
return pPic;
}
}
return NULL;
}
static PPicture WelsDelLongFromListSetUnref (PRefPic pRefPic, uint32_t uiLongTermFrameIdx) {
PPicture pPic = WelsDelLongFromList (pRefPic, uiLongTermFrameIdx);
if (pPic) {
SetUnRef (pPic);
}
return pPic;
}
static int32_t AddShortTermToList (PRefPic pRefPic, PPicture pPic) {
pPic->bUsedAsRef = true;
pPic->bIsLongRef = false;
pPic->iLongTermFrameIdx = -1;
if (pRefPic->uiShortRefCount[LIST_0] > 0) {
memmove (&pRefPic->pShortRefList[LIST_0][1], &pRefPic->pShortRefList[LIST_0][0],
pRefPic->uiShortRefCount[LIST_0]*sizeof (PPicture));//confirmed_safe_unsafe_usage
}
pRefPic->pShortRefList[LIST_0][0] = pPic;
pRefPic->uiShortRefCount[LIST_0]++;
return ERR_NONE;
}
static int32_t AddLongTermToList (PRefPic pRefPic, PPicture pPic, int32_t iLongTermFrameIdx) {
int32_t i = 0;
pPic->bUsedAsRef = true;
pPic->bIsLongRef = true;
pPic->iLongTermFrameIdx = iLongTermFrameIdx;
if (pRefPic->uiLongRefCount[LIST_0] == 0) {
pRefPic->pLongRefList[LIST_0][pRefPic->uiLongRefCount[LIST_0]] = pPic;
} else {
for (i = 0; i < pRefPic->uiLongRefCount[LIST_0]; i++) {
if (pRefPic->pLongRefList[LIST_0][i]->iLongTermFrameIdx > pPic->iLongTermFrameIdx) {
break;
}
}
memmove (&pRefPic->pLongRefList[LIST_0][i + 1], &pRefPic->pLongRefList[LIST_0][i],
(pRefPic->uiLongRefCount[LIST_0] - i)*sizeof (PPicture)); //confirmed_safe_unsafe_usage
pRefPic->pLongRefList[LIST_0][i] = pPic;
}
pRefPic->uiLongRefCount[LIST_0]++;
return ERR_NONE;
}
static int32_t MarkAsLongTerm (PRefPic pRefPic, int32_t iFrameNum, int32_t iLongTermFrameIdx) {
PPicture pPic = NULL;
int32_t i = 0;
int32_t iRet = ERR_NONE;
WelsDelLongFromListSetUnref (pRefPic, iLongTermFrameIdx);
for (i = 0; i < pRefPic->uiRefCount[LIST_0]; i++) {
pPic = pRefPic->pRefList[LIST_0][i];
if (pPic->iFrameNum == iFrameNum && !pPic->bIsLongRef) {
iRet = AddLongTermToList (pRefPic, pPic, iLongTermFrameIdx);
break;
}
}
return iRet;
}
#ifdef LONG_TERM_REF
int32_t GetLTRFrameIndex (PRefPic pRefPic, int32_t iAncLTRFrameNum) {
int32_t iLTRFrameIndex = -1;
PPicture pPic;
for (int i = 0; i < pRefPic->uiLongRefCount[0]; ++i) {
pPic = pRefPic->pLongRefList[LIST_0][i];
if (pPic->iFrameNum == iAncLTRFrameNum) {
return (pPic->iLongTermFrameIdx);
}
}
return iLTRFrameIndex;
}
#endif
static int32_t RemainOneBufferInDpbForEC (PWelsDecoderContext pCtx) {
int32_t iRet = ERR_NONE;
PRefPic pRefPic = &pCtx->sRefPic;
if (pRefPic->uiShortRefCount[0] + pRefPic->uiLongRefCount[0] < pCtx->pSps->iNumRefFrames)
return iRet;
if (pRefPic->uiShortRefCount[0] > 0) {
iRet = SlidingWindow (pCtx);
} else { //all LTR, remove the smallest long_term_frame_idx
uint32_t uiLongTermFrameIdx = 0;
uint32_t uiMaxLongTermFrameIdx = pRefPic->iMaxLongTermFrameIdx;
#ifdef LONG_TERM_REF
uint32_t uiCurrLTRFrameIdx = GetLTRFrameIndex (pRefPic, pCtx->iFrameNumOfAuMarkedLtr);
#endif
while ((pRefPic->uiLongRefCount[0] >= pCtx->pSps->iNumRefFrames) && (uiLongTermFrameIdx <= uiMaxLongTermFrameIdx)) {
#ifdef LONG_TERM_REF
if (uiLongTermFrameIdx == uiCurrLTRFrameIdx) {
uiLongTermFrameIdx++;
continue;
}
#endif
WelsDelLongFromListSetUnref (pRefPic, uiLongTermFrameIdx);
uiLongTermFrameIdx++;
}
}
if (pRefPic->uiShortRefCount[0] + pRefPic->uiLongRefCount[0] >=
pCtx->pSps->iNumRefFrames) { //fail to remain one empty buffer in DPB
WelsLog (pCtx, WELS_LOG_WARNING, "RemainOneBufferInDpbForEC(): empty one DPB failed for EC!\n");
iRet = ERR_INFO_REF_COUNT_OVERFLOW;
}
return iRet;
}
} // namespace WelsDec