ref: 0ffc5ea47d09778a50edafed29a3a664c2f4f3f3
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_dec_ref.cpp
*
* Abstract
* Implementation for managing reference picture
*
* History
* 07/21/2008 Created
*
*****************************************************************************/
#include "manage_dec_ref.h"
#include "error_concealment.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, uint32_t uiLongTermPicNum);
static int32_t MarkAsLongTerm (PRefPic pRefPic, int32_t iFrameNum, int32_t iLongTermFrameIdx,
uint32_t uiLongTermPicNum);
static int32_t WelsCheckAndRecoverForFutureDecoding (PWelsDecoderContext pCtx);
#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->iFrameWrapNum = -1;
//pRef->iFramePoc = 0;
pRef->iLongTermFrameIdx = -1;
pRef->uiLongTermPicNum = 0;
pRef->uiQualityId = -1;
pRef->uiTemporalId = -1;
pRef->uiSpatialId = -1;
pRef->iSpsId = -1;
pRef->bIsComplete = false;
for (int32_t i = 0; i < MAX_DPB_COUNT; ++i) {
pRef->pRefPic[LIST_0][i] = NULL;
pRef->pRefPic[LIST_1][i] = NULL;
}
}
}
//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;
pRefPic->uiRefCount[LIST_1] = 0;
for (i = 0; i < MAX_DPB_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_DPB_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;
}
static int32_t WelsCheckAndRecoverForFutureDecoding (PWelsDecoderContext pCtx) {
if ((pCtx->sRefPic.uiShortRefCount[LIST_0] + pCtx->sRefPic.uiLongRefCount[LIST_0] <= 0) && (pCtx->eSliceType != I_SLICE
&& pCtx->eSliceType != SI_SLICE)) {
if (pCtx->pParam->eEcActiveIdc !=
ERROR_CON_DISABLE) { //IDR lost!, recover it for future decoding with data all set to 0
PPicture pRef = PrefetchPic (pCtx->pPicBuff);
if (pRef != NULL) {
// IDR lost, set new
pRef->bIsComplete = false; // Set complete flag to false for lost IDR ref picture
pRef->iSpsId = pCtx->pSps->iSpsId;
pRef->iPpsId = pCtx->pPps->iPpsId;
pCtx->iErrorCode |= dsDataErrorConcealed;
bool bCopyPrevious = ((ERROR_CON_FRAME_COPY_CROSS_IDR == pCtx->pParam->eEcActiveIdc)
|| (ERROR_CON_SLICE_COPY_CROSS_IDR == pCtx->pParam->eEcActiveIdc)
|| (ERROR_CON_SLICE_COPY_CROSS_IDR_FREEZE_RES_CHANGE == pCtx->pParam->eEcActiveIdc)
|| (ERROR_CON_SLICE_MV_COPY_CROSS_IDR == pCtx->pParam->eEcActiveIdc)
|| (ERROR_CON_SLICE_MV_COPY_CROSS_IDR_FREEZE_RES_CHANGE == pCtx->pParam->eEcActiveIdc))
&& (NULL != pCtx->pPreviousDecodedPictureInDpb);
bCopyPrevious = bCopyPrevious && (pRef->iWidthInPixel == pCtx->pPreviousDecodedPictureInDpb->iWidthInPixel)
&& (pRef->iHeightInPixel == pCtx->pPreviousDecodedPictureInDpb->iHeightInPixel);
if (!bCopyPrevious) {
memset (pRef->pData[0], 128, pRef->iLinesize[0] * pRef->iHeightInPixel);
memset (pRef->pData[1], 128, pRef->iLinesize[1] * pRef->iHeightInPixel / 2);
memset (pRef->pData[2], 128, pRef->iLinesize[2] * pRef->iHeightInPixel / 2);
} else if (pRef == pCtx->pPreviousDecodedPictureInDpb) {
WelsLog (& (pCtx->sLogCtx), WELS_LOG_WARNING, "WelsInitRefList()::EC memcpy overlap.");
} else {
memcpy (pRef->pData[0], pCtx->pPreviousDecodedPictureInDpb->pData[0], pRef->iLinesize[0] * pRef->iHeightInPixel);
memcpy (pRef->pData[1], pCtx->pPreviousDecodedPictureInDpb->pData[1], pRef->iLinesize[1] * pRef->iHeightInPixel / 2);
memcpy (pRef->pData[2], pCtx->pPreviousDecodedPictureInDpb->pData[2], pRef->iLinesize[2] * pRef->iHeightInPixel / 2);
}
pRef->iFrameNum = 0;
pRef->iFramePoc = 0;
pRef->uiTemporalId = pRef->uiQualityId = 0;
ExpandReferencingPicture (pRef->pData, pRef->iWidthInPixel, pRef->iHeightInPixel, pRef->iLinesize,
pCtx->sExpandPicFunc.pfExpandLumaPicture, pCtx->sExpandPicFunc.pfExpandChromaPicture);
AddShortTermToList (&pCtx->sRefPic, pRef);
} else {
WelsLog (& (pCtx->sLogCtx), WELS_LOG_ERROR, "WelsInitRefList()::PrefetchPic for EC errors.");
pCtx->iErrorCode |= dsOutOfMemory;
return ERR_INFO_REF_COUNT_OVERFLOW;
}
}
}
return ERR_NONE;
}
static void WrapShortRefPicNum (PWelsDecoderContext pCtx) {
int32_t i;
PSliceHeader pSliceHeader = &pCtx->pCurDqLayer->sLayerInfo.sSliceInLayer.sSliceHeaderExt.sSliceHeader;
int32_t iMaxPicNum = 1 << pSliceHeader->pSps->uiLog2MaxFrameNum;
PPicture* ppShoreRefList = pCtx->sRefPic.pShortRefList[LIST_0];
int32_t iShortRefCount = pCtx->sRefPic.uiShortRefCount[LIST_0];
//wrap pic num
for (i = 0; i < iShortRefCount; i++) {
if (ppShoreRefList[i]) {
if (ppShoreRefList[i]->iFrameNum > pSliceHeader->iFrameNum)
ppShoreRefList[i]->iFrameWrapNum = ppShoreRefList[i]->iFrameNum - iMaxPicNum;
else
ppShoreRefList[i]->iFrameWrapNum = ppShoreRefList[i]->iFrameNum;
}
}
}
/**
* fills the pRefPic.pRefList LIST_0 and LIST_0 for B-Slice.
*/
int32_t WelsInitBSliceRefList (PWelsDecoderContext pCtx, int32_t iPoc) {
int32_t err = WelsCheckAndRecoverForFutureDecoding (pCtx);
if (err != ERR_NONE) return err;
WrapShortRefPicNum (pCtx);
PPicture* ppShoreRefList = pCtx->sRefPic.pShortRefList[LIST_0];
PPicture* ppLongRefList = pCtx->sRefPic.pLongRefList[LIST_0];
memset (pCtx->sRefPic.pRefList[LIST_0], 0, MAX_DPB_COUNT * sizeof (PPicture));
memset (pCtx->sRefPic.pRefList[LIST_1], 0, MAX_DPB_COUNT * sizeof (PPicture));
int32_t iLSCurrPocCount = 0;
int32_t iLTCurrPocCount = 0;
PPicture pLSCurrPocList0[MAX_DPB_COUNT];
PPicture pLTCurrPocList0[MAX_DPB_COUNT];
for (int32_t i = 0; i < pCtx->sRefPic.uiShortRefCount[LIST_0]; ++i) {
if (ppShoreRefList[i]->iFramePoc < iPoc) {
pLSCurrPocList0[iLSCurrPocCount++] = ppShoreRefList[i];
}
}
for (int32_t i = pCtx->sRefPic.uiShortRefCount[LIST_0] - 1; i >= 0; --i) {
if (ppShoreRefList[i]->iFramePoc > iPoc) {
pLTCurrPocList0[iLTCurrPocCount++] = ppShoreRefList[i];
}
}
if (pCtx->sRefPic.uiLongRefCount[LIST_0] > 1) {
//long sorts in increasing order
PPicture pTemp;
for (int32_t i = 0; i < pCtx->sRefPic.uiLongRefCount[LIST_0]; ++i) {
for (int32_t j = i + 1; j < pCtx->sRefPic.uiLongRefCount[LIST_0]; ++j) {
if (ppLongRefList[j]->iFramePoc < ppLongRefList[i]->iFramePoc) {
pTemp = ppLongRefList[i];
ppLongRefList[i] = ppLongRefList[j];
ppLongRefList[j] = pTemp;
}
}
}
}
int32_t iCurrPocCount = iLSCurrPocCount + iLTCurrPocCount;
int32_t iCount = 0;
//LIST_0
//short
//It may need to sort LIST_0 and LIST_1 so that they will have the right default orders.
for (int32_t i = 0; i < iLSCurrPocCount; ++i) {
pCtx->sRefPic.pRefList[LIST_0][iCount++] = pLSCurrPocList0[i];
}
if (iLSCurrPocCount > 1) {
//LIST_0 short sorts in decreasing order
PPicture pTemp;
for (int32_t i = 0; i < iLSCurrPocCount; ++i) {
for (int32_t j = i + 1; j < iLSCurrPocCount; ++j) {
if (pCtx->sRefPic.pRefList[LIST_0][j]->iFramePoc > pCtx->sRefPic.pRefList[LIST_0][i]->iFramePoc) {
pTemp = pCtx->sRefPic.pRefList[LIST_0][i];
pCtx->sRefPic.pRefList[LIST_0][i] = pCtx->sRefPic.pRefList[LIST_0][j];
pCtx->sRefPic.pRefList[LIST_0][j] = pTemp;
}
}
}
}
for (int32_t i = 0; i < iLTCurrPocCount; ++i) {
pCtx->sRefPic.pRefList[LIST_0][iCount++] = pLTCurrPocList0[i];
}
if (iLTCurrPocCount > 1) {
//LIST_0 short sorts in increasing order
PPicture pTemp;
for (int32_t i = iLSCurrPocCount; i < iCurrPocCount; ++i) {
for (int32_t j = i + 1; j < iCurrPocCount; ++j) {
if (pCtx->sRefPic.pRefList[LIST_0][j]->iFramePoc < pCtx->sRefPic.pRefList[LIST_0][i]->iFramePoc) {
pTemp = pCtx->sRefPic.pRefList[LIST_0][i];
pCtx->sRefPic.pRefList[LIST_0][i] = pCtx->sRefPic.pRefList[LIST_0][j];
pCtx->sRefPic.pRefList[LIST_0][j] = pTemp;
}
}
}
}
//long
for (int32_t i = 0; i < pCtx->sRefPic.uiLongRefCount[LIST_0]; ++i) {
pCtx->sRefPic.pRefList[LIST_0][iCount++] = ppLongRefList[i];
}
pCtx->sRefPic.uiRefCount[LIST_0] = iCount;
iCount = 0;
//LIST_1
//short
for (int32_t i = 0; i < iLTCurrPocCount; ++i) {
pCtx->sRefPic.pRefList[LIST_1][iCount++] = pLTCurrPocList0[i];
}
if (iLTCurrPocCount > 1) {
//LIST_1 short sorts in increasing order
PPicture pTemp;
for (int32_t i = 0; i < iLTCurrPocCount; ++i) {
for (int32_t j = i + 1; j < iLTCurrPocCount; ++j) {
if (pCtx->sRefPic.pRefList[LIST_1][j]->iFramePoc < pCtx->sRefPic.pRefList[LIST_1][i]->iFramePoc) {
pTemp = pCtx->sRefPic.pRefList[LIST_1][i];
pCtx->sRefPic.pRefList[LIST_1][i] = pCtx->sRefPic.pRefList[LIST_1][j];
pCtx->sRefPic.pRefList[LIST_1][j] = pTemp;
}
}
}
}
for (int32_t i = 0; i < iLSCurrPocCount; ++i) {
pCtx->sRefPic.pRefList[LIST_1][iCount++] = pLSCurrPocList0[i];
}
if (iLSCurrPocCount > 1) {
//LIST_1 short sorts in decreasing order
PPicture pTemp;
for (int32_t i = iLTCurrPocCount; i < iCurrPocCount; ++i) {
for (int32_t j = i + 1; j < iCurrPocCount; ++j) {
if (pCtx->sRefPic.pRefList[LIST_1][j]->iFramePoc > pCtx->sRefPic.pRefList[LIST_1][i]->iFramePoc) {
pTemp = pCtx->sRefPic.pRefList[LIST_1][i];
pCtx->sRefPic.pRefList[LIST_1][i] = pCtx->sRefPic.pRefList[LIST_1][j];
pCtx->sRefPic.pRefList[LIST_1][j] = pTemp;
}
}
}
}
//long
for (int32_t i = 0; i < pCtx->sRefPic.uiLongRefCount[LIST_0]; ++i) {
pCtx->sRefPic.pRefList[LIST_1][iCount++] = ppLongRefList[i];
}
pCtx->sRefPic.uiRefCount[LIST_1] = iCount;
return ERR_NONE;
}
/**
* fills the pRefPic.pRefList.
*/
int32_t WelsInitRefList (PWelsDecoderContext pCtx, int32_t iPoc) {
int32_t err = WelsCheckAndRecoverForFutureDecoding (pCtx);
if (err != ERR_NONE) return err;
WrapShortRefPicNum (pCtx);
PPicture* ppShoreRefList = pCtx->sRefPic.pShortRefList[LIST_0];
PPicture* ppLongRefList = pCtx->sRefPic.pLongRefList[LIST_0];
memset (pCtx->sRefPic.pRefList[LIST_0], 0, MAX_DPB_COUNT * sizeof (PPicture));
int32_t i, iCount = 0;
//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) {
if (pCtx->eSliceType == I_SLICE || pCtx->eSliceType == SI_SLICE) {
return ERR_NONE;
}
PRefPicListReorderSyn pRefPicListReorderSyn = pCtx->pCurDqLayer->pRefPicListReordering;
PNalUnitHeaderExt pNalHeaderExt = &pCtx->pCurDqLayer->sLayerInfo.sNalHeaderExt;
PSliceHeader pSliceHeader = &pCtx->pCurDqLayer->sLayerInfo.sSliceInLayer.sSliceHeaderExt.sSliceHeader;
int32_t ListCount = 1;
if (pCtx->eSliceType == B_SLICE) ListCount = 2;
for (int32_t listIdx = 0; listIdx < ListCount; ++listIdx) {
PPicture pPic = NULL;
PPicture* ppRefList = pCtx->sRefPic.pRefList[listIdx];
int32_t iMaxRefIdx = pCtx->iPicQueueNumber;
int32_t iRefCount = pSliceHeader->uiRefCount[listIdx];
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 (iRefCount <= 0) {
pCtx->iErrorCode = dsNoParamSets; //No any reference for decoding, SHOULD request IDR
return ERR_INFO_REFERENCE_PIC_LOST;
}
if (pRefPicListReorderSyn->bRefPicListReorderingFlag[listIdx]) {
while ((iReorderingIndex < iMaxRefIdx)
&& (pRefPicListReorderSyn->sReorderingSyn[listIdx][iReorderingIndex].uiReorderingOfPicNumsIdc != 3)) {
uint16_t uiReorderingOfPicNumsIdc =
pRefPicListReorderSyn->sReorderingSyn[listIdx][iReorderingIndex].uiReorderingOfPicNumsIdc;
if (uiReorderingOfPicNumsIdc < 2) {
iAbsDiffPicNum = pRefPicListReorderSyn->sReorderingSyn[listIdx][iReorderingIndex].uiAbsDiffPicNumMinus1 + 1;
if (uiReorderingOfPicNumsIdc == 0) {
iPredFrameNum -= iAbsDiffPicNum;
} else {
iPredFrameNum += iAbsDiffPicNum;
}
iPredFrameNum &= iMaxPicNum - 1;
for (i = iMaxRefIdx - 1; i >= 0; i--) {
if (ppRefList[i] != NULL && ppRefList[i]->iFrameNum == iPredFrameNum && !ppRefList[i]->bIsLongRef) {
if ((pNalHeaderExt->uiQualityId == ppRefList[i]->uiQualityId)
&& (pSliceHeader->iSpsId != ppRefList[i]->iSpsId)) { //check;
WelsLog (& (pCtx->sLogCtx), WELS_LOG_WARNING, "WelsReorderRefList()::::BASE LAYER::::iSpsId:%d, ref_sps_id:%d",
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 = iMaxRefIdx - 1; i >= 0; i--) {
if (ppRefList[i] != NULL && ppRefList[i]->bIsLongRef
&& ppRefList[i]->iLongTermFrameIdx ==
pRefPicListReorderSyn->sReorderingSyn[listIdx][iReorderingIndex].uiLongTermPicNum) {
if ((pNalHeaderExt->uiQualityId == ppRefList[i]->uiQualityId)
&& (pSliceHeader->iSpsId != ppRefList[i]->iSpsId)) { //check;
WelsLog (& (pCtx->sLogCtx), WELS_LOG_WARNING, "WelsReorderRefList()::::BASE LAYER::::iSpsId:%d, ref_sps_id:%d",
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 < 0) {
return ERR_INFO_REFERENCE_PIC_LOST;
}
pPic = ppRefList[i];
if (i > iReorderingIndex) {
memmove (&ppRefList[1 + iReorderingIndex], &ppRefList[iReorderingIndex],
(i - iReorderingIndex) * sizeof (PPicture)); //confirmed_safe_unsafe_usage
} else if (i < iReorderingIndex) {
memmove (&ppRefList[1 + iReorderingIndex], &ppRefList[iReorderingIndex],
(iMaxRefIdx - iReorderingIndex) * sizeof (PPicture));
}
ppRefList[iReorderingIndex] = pPic;
iReorderingIndex++;
}
}
}
return ERR_NONE;
}
//WelsReorderRefList2 is the test code
int32_t WelsReorderRefList2 (PWelsDecoderContext pCtx) {
if (pCtx->eSliceType == I_SLICE || pCtx->eSliceType == SI_SLICE) {
return ERR_NONE;
}
PRefPicListReorderSyn pRefPicListReorderSyn = pCtx->pCurDqLayer->pRefPicListReordering;
PSliceHeader pSliceHeader = &pCtx->pCurDqLayer->sLayerInfo.sSliceInLayer.sSliceHeaderExt.sSliceHeader;
PPicture* ppShoreRefList = pCtx->sRefPic.pShortRefList[LIST_0];
int32_t iShortRefCount = pCtx->sRefPic.uiShortRefCount[LIST_0];
PPicture* ppLongRefList = pCtx->sRefPic.pLongRefList[LIST_0];
int32_t iLongRefCount = pCtx->sRefPic.uiLongRefCount[LIST_0];
int32_t i = 0;
int32_t j = 0;
int32_t k = 0;
int32_t iMaxRefIdx = pCtx->pSps->iNumRefFrames;
const int32_t iCurFrameNum = pSliceHeader->iFrameNum;
const int32_t iMaxPicNum = 1 << pSliceHeader->pSps->uiLog2MaxFrameNum;
int32_t iListCount = 1;
if (pCtx->eSliceType == B_SLICE) iListCount = 2;
for (int32_t listIdx = 0; listIdx < iListCount; ++listIdx) {
PPicture* ppRefList = pCtx->sRefPic.pRefList[listIdx];
int32_t iCount = 0;
int32_t iRefCount = pSliceHeader->uiRefCount[listIdx];
int32_t iAbsDiffPicNum = -1;
if (pRefPicListReorderSyn->bRefPicListReorderingFlag[listIdx]) {
int32_t iPredFrameNum = iCurFrameNum;
for (i = 0; pRefPicListReorderSyn->sReorderingSyn[listIdx][i].uiReorderingOfPicNumsIdc != 3; i++) {
if (iCount >= iMaxRefIdx)
break;
for (j = iRefCount; j > iCount; j--)
ppRefList[j] = ppRefList[j - 1];
uint16_t uiReorderingOfPicNumsIdc =
pRefPicListReorderSyn->sReorderingSyn[listIdx][i].uiReorderingOfPicNumsIdc;
if (uiReorderingOfPicNumsIdc < 2) { // reorder short references
iAbsDiffPicNum = (int32_t) (pRefPicListReorderSyn->sReorderingSyn[listIdx][i].uiAbsDiffPicNumMinus1 + 1);
if (uiReorderingOfPicNumsIdc == 0) {
if (iPredFrameNum - iAbsDiffPicNum < 0)
iPredFrameNum -= (iAbsDiffPicNum - iMaxPicNum);
else
iPredFrameNum -= iAbsDiffPicNum;
} else {
if (iPredFrameNum + iAbsDiffPicNum >= iMaxPicNum)
iPredFrameNum += (iAbsDiffPicNum - iMaxPicNum);
else
iPredFrameNum += iAbsDiffPicNum;
}
if (iPredFrameNum > iCurFrameNum) {
iPredFrameNum -= iMaxPicNum;
}
for (j = 0; j < iShortRefCount; j++) {
if (ppShoreRefList[j]) {
if (ppShoreRefList[j]->iFrameWrapNum == iPredFrameNum) {
ppRefList[iCount++] = ppShoreRefList[j];
break;
}
}
}
k = iCount;
for (j = k; j <= iRefCount; j++) {
if (ppRefList[j] != NULL) {
if (ppRefList[j]->bIsLongRef || ppRefList[j]->iFrameWrapNum != iPredFrameNum)
ppRefList[k++] = ppRefList[j];
}
}
} else { // reorder long term references uiReorderingOfPicNumsIdc == 2
iPredFrameNum = pRefPicListReorderSyn->sReorderingSyn[listIdx][i].uiLongTermPicNum;
for (j = 0; j < iLongRefCount; j++) {
if (ppLongRefList[j] != NULL) {
if (ppLongRefList[j]->uiLongTermPicNum == (uint32_t)iPredFrameNum) {
ppRefList[iCount++] = ppLongRefList[j];
break;
}
}
}
k = iCount;
for (j = k; j <= iRefCount; j++) {
if (ppRefList[j] != NULL) {
if (!ppRefList[j]->bIsLongRef || ppLongRefList[j]->uiLongTermPicNum != (uint32_t)iPredFrameNum)
ppRefList[k++] = ppRefList[j];
}
}
}
}
}
for (i = WELS_MAX (1, WELS_MAX (iCount, pCtx->sRefPic.uiRefCount[listIdx])); i < iRefCount; i++)
ppRefList[i] = ppRefList[i - 1];
pCtx->sRefPic.uiRefCount[listIdx] = (uint8_t)WELS_MIN (WELS_MAX (iCount, pCtx->sRefPic.uiRefCount[listIdx]), iRefCount);
}
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;
pCtx->pDec->iSpsId = pCtx->pSps->iSpsId;
pCtx->pDec->iPpsId = pCtx->pPps->iPpsId;
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, 0);
} else {
pCtx->sRefPic.iMaxLongTermFrameIdx = -1;
}
} else {
if (pRefPicMarking->bAdaptiveRefPicMarkingModeFlag) {
iRet = MMCO (pCtx, pRefPicMarking);
if (iRet != ERR_NONE) {
if (pCtx->pParam->eEcActiveIdc != ERROR_CON_DISABLE) {
iRet = RemainOneBufferInDpbForEC (pCtx);
WELS_VERIFY_RETURN_IF (iRet, iRet);
} else {
return iRet;
}
}
if (pCtx->bLastHasMmco5) {
pCtx->pDec->iFrameNum = 0;
pCtx->pDec->iFramePoc = 0;
}
} else {
iRet = SlidingWindow (pCtx);
if (iRet != ERR_NONE) {
if (pCtx->pParam->eEcActiveIdc != ERROR_CON_DISABLE) {
iRet = RemainOneBufferInDpbForEC (pCtx);
WELS_VERIFY_RETURN_IF (iRet, iRet);
} else {
return iRet;
}
}
}
}
if (!pCtx->pDec->bIsLongRef) {
if (pRefPic->uiLongRefCount[LIST_0] + pRefPic->uiShortRefCount[LIST_0] >= WELS_MAX (1, pCtx->pSps->iNumRefFrames)) {
if (pCtx->pParam->eEcActiveIdc != ERROR_CON_DISABLE) {
iRet = RemainOneBufferInDpbForEC (pCtx);
WELS_VERIFY_RETURN_IF (iRet, iRet);
} else {
return ERR_INFO_INVALID_MMCO_REF_NUM_OVERFLOW;
}
}
iRet = 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; i < MAX_MMCO_COUNT && 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;
}
}
if (i == MAX_MMCO_COUNT) { //although Rec does not handle this condition, we here prohibit too many MMCO op
return ERR_INFO_INVALID_MMCO_NUM;
}
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->sLogCtx), WELS_LOG_WARNING, "MMCO_SHORT2UNUSED: delete an 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 an 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 an 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, uiLongTermPicNum);
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, uiLongTermPicNum);
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) {
if (pCtx->sRefPic.uiShortRefCount[LIST_0] == 0) {
WelsLog (& (pCtx->sLogCtx), WELS_LOG_ERROR, "No reference picture in short term list when sliding window");
return ERR_INFO_INVALID_MMCO_REF_NUM_NOT_ENOUGH;
}
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) {
// Check the duplicate frame_num in short ref list
for (int32_t iPos = 0; iPos < pRefPic->uiShortRefCount[LIST_0]; iPos++) {
if (pPic->iFrameNum == pRefPic->pShortRefList[LIST_0][iPos]->iFrameNum) {
// Replace the previous ref pic with the new one with the same frame_num
pRefPic->pShortRefList[LIST_0][iPos] = pPic;
return ERR_INFO_DUPLICATE_FRAME_NUM;
}
}
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,
uint32_t uiLongTermPicNum) {
int32_t i = 0;
pPic->bUsedAsRef = true;
pPic->bIsLongRef = true;
pPic->iLongTermFrameIdx = iLongTermFrameIdx;
pPic->uiLongTermPicNum = uiLongTermPicNum;
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,
uint32_t uiLongTermPicNum) {
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, uiLongTermPicNum);
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
int32_t iLongTermFrameIdx = 0;
int32_t iMaxLongTermFrameIdx = pRefPic->iMaxLongTermFrameIdx;
#ifdef LONG_TERM_REF
int32_t iCurrLTRFrameIdx = GetLTRFrameIndex (pRefPic, pCtx->iFrameNumOfAuMarkedLtr);
#endif
while ((pRefPic->uiLongRefCount[0] >= pCtx->pSps->iNumRefFrames) && (iLongTermFrameIdx <= iMaxLongTermFrameIdx)) {
#ifdef LONG_TERM_REF
if (iLongTermFrameIdx == iCurrLTRFrameIdx) {
iLongTermFrameIdx++;
continue;
}
#endif
WelsDelLongFromListSetUnref (pRefPic, iLongTermFrameIdx);
iLongTermFrameIdx++;
}
}
if (pRefPic->uiShortRefCount[0] + pRefPic->uiLongRefCount[0] >=
pCtx->pSps->iNumRefFrames) { //fail to remain one empty buffer in DPB
WelsLog (& (pCtx->sLogCtx), WELS_LOG_WARNING, "RemainOneBufferInDpbForEC(): empty one DPB failed for EC!");
iRet = ERR_INFO_REF_COUNT_OVERFLOW;
}
return iRet;
}
} // namespace WelsDec