shithub: openh264

ref: 3331ff656676a43e5fd97327c569734399d5fa40
dir: /codec/decoder/core/src/manage_dec_ref.cpp/

View raw version
/*!
 * \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 <string.h>

#include "manage_dec_ref.h"
#include "error_code.h"
#include "utils.h"
#include "as264_common.h" // for LTR macro can be delete later

namespace WelsDec {

static void_t SetUnRef(PPicture pRef)
{
    if( NULL != pRef)
    {
	    pRef->bUsedAsRef = false;
	    pRef->bIsLongRef = false;
	    pRef->iFrameNum = -1;
	    pRef->iFramePoc = 0;
	    pRef->iLongTermFrameIdx = -1;
	    pRef->bRefBaseFlag = 0;
	    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_t WelsResetRefPic(PWelsDecoderContext pCtx)
{
	int32_t i = 0;
	PRefPic pRefPic = &pCtx->sRefPic;
	pCtx->sRefPic.uiLongRefCount[0] = pCtx->sRefPic.uiShortRefCount[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,j, iCount=0;
	const bool_t kbUseRefBasePicFlag = pCtx->pCurDqLayer->bUseRefBasePicFlag;
	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){	
		if( kbUseRefBasePicFlag == ppShoreRefList[i]->bRefBaseFlag ) {
			pCtx->sRefPic.pRefList[LIST_0][iCount++ ]= ppShoreRefList[i];	
		}else{
			for ( j = 0;j<pCtx->sRefPic.uiShortRefCount[LIST_0];++j)
			{
				if (ppShoreRefList[j]->iFrameNum == ppShoreRefList[i]->iFrameNum && ppShoreRefList[j]->bRefBaseFlag == kbUseRefBasePicFlag)
				{
					break;
				}
			}
			if (j == pCtx->sRefPic.uiShortRefCount[LIST_0])
			{
				pCtx->sRefPic.pRefList[LIST_0][iCount++] = ppShoreRefList[i];
			}
		}
	}
				
	//long
	j = 0;
	for(i=0; i< pCtx->sRefPic.uiLongRefCount[LIST_0] ; ++i){
		if(kbUseRefBasePicFlag == ppLongRefList[i]->bRefBaseFlag){
			pCtx->sRefPic.pRefList[LIST_0][iCount++  ]= ppLongRefList[i];
		}else{
			for ( j = 0;j<pCtx->sRefPic.uiLongRefCount[LIST_0];++j)
			{
				if (ppLongRefList[j]->iLongTermFrameIdx == ppLongRefList[i]->iLongTermFrameIdx && ppLongRefList[j]->bRefBaseFlag == kbUseRefBasePicFlag)
				{
					break;
				}
			}
			if (j == pCtx->sRefPic.uiLongRefCount[LIST_0])
			{
				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 < 0)	{	
				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, const bool_t kbRefBaseMarkingFlag)
{
	PRefPic pRefPic = &pCtx->sRefPic;
	PRefPicMarking pRefPicMarking = pCtx->pCurDqLayer->pRefPicMarking;
	PRefBasePicMarking pRefPicBaseMarking =pCtx->pCurDqLayer->pRefPicBaseMarking;
	PAccessUnit pCurAU = pCtx->pAccessUnitList;
	bool_t bIsIDRAU = FALSE;
	uint32_t j;

	int32_t iRet = ERR_NONE;
	if(pCtx->pCurDqLayer->bStoreRefBasePicFlag && (pCtx->pSps->iNumRefFrames<2)){
		return ERR_INFO_INVALID_MMCO_REF_NUM_NOT_ENOUGH;
	}
	
	pCtx->pDec->bUsedAsRef = TRUE;
	pCtx->pDec->uiQualityId = pCtx->pCurDqLayer->sLayerInfo.sNalHeaderExt.uiQualityId;
	pCtx->pDec->uiTemporalId = pCtx->pCurDqLayer->sLayerInfo.sNalHeaderExt.uiTemporalId;
	pCtx->pDec->bRefBaseFlag = kbRefBaseMarkingFlag;

	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 (pRefPicBaseMarking->bAdaptiveRefBasePicMarkingModeFlag){
			iRet = MMCOBase(pCtx,pRefPicBaseMarking);
		}

		if (iRet != ERR_NONE){
			return iRet;
		}

		if (pRefPicMarking->bAdaptiveRefPicMarkingModeFlag){
			iRet = MMCO(pCtx,pRefPicMarking);
            if( pCtx->bLastHasMmco5 )
            {
                pCtx->pDec->iFrameNum = 0;
                pCtx->pDec->iFramePoc = 0;
            }
			if (pRefPic->uiLongRefCount[LIST_0]+pRefPic->uiShortRefCount[LIST_0] > pCtx->pSps->iNumRefFrames){
				return ERR_INFO_INVALID_MMCO_REF_NUM_OVERFLOW;
			}
		}else{	
			iRet = SlidingWindow(pCtx);
		}
	}
	
	if (!pCtx->pDec->bIsLongRef){
		AddShortTermToList(pRefPic,pCtx->pDec);
	}

	return iRet;
}

static int32_t MMCOBase(PWelsDecoderContext pCtx,PRefBasePicMarking pRefPicBaseMarking)
{
	PSps pSps = pCtx->pCurDqLayer->sLayerInfo.pSps;
	int32_t i = 0;
	int32_t iRet = ERR_NONE;

	for ( i = 0 ; pRefPicBaseMarking->mmco_base[i].uiMmcoType != MMCO_END; i++){
		uint32_t uiMmcoType = pRefPicBaseMarking->mmco_base[i].uiMmcoType;			
		int32_t iShortFrameNum = (pCtx->iFrameNum - pRefPicBaseMarking->mmco_base[i].uiDiffOfPicNums) &((1<<pSps->uiLog2MaxFrameNum)-1);
		uint32_t uiLongTermPicNum = pRefPicBaseMarking->mmco_base[i].uiLongTermPicNum;
		if ( uiMmcoType > MMCO_LONG2UNUSED)	{
			return ERR_INFO_INVALID_MMCO_OPCODE_BASE;
		}
		iRet = MMCOProcess(pCtx,uiMmcoType,TRUE,iShortFrameNum,uiLongTermPicNum,0,0);

		if (iRet != ERR_NONE){
			return iRet;
		}
	}

	return ERR_NONE;
}

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,FALSE,iShortFrameNum,uiLongTermPicNum,iLongTermFrameIdx,iMaxLongTermFrameIdx);
		if (iRet != ERR_NONE){
			return iRet;
		}
	}

	return ERR_NONE;
}
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;
}

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,REMOVE_BASE_FIRST);
			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, ERemoveFlag eRemoveFlag)
{
	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)
		{
			if(   ( eRemoveFlag == REMOVE_TARGET && !pRefPic->pShortRefList[LIST_0][i]->bRefBaseFlag )	
				||( eRemoveFlag == REMOVE_BASE && pRefPic->pShortRefList[LIST_0][i]->bRefBaseFlag) 
				||(eRemoveFlag == REMOVE_BASE_FIRST ) )
			{
				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[0]] = NULL;
				break;
			}
		}
	}

	return pPic;
}

static PPicture WelsDelShortFromListSetUnref(PRefPic pRefPic, int32_t iFrameNum, ERemoveFlag eRemoveFlag)
{
	PPicture pPic = WelsDelShortFromList(pRefPic,iFrameNum,eRemoveFlag);
	if (pPic){	
		SetUnRef(pPic);
	}
	return pPic;
}

static PPicture WelsDelLongFromList(PRefPic pRefPic, uint32_t uiLongTermFrameIdx, ERemoveFlag eRemoveFlag)
{
	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)
		{
			if( ((eRemoveFlag == REMOVE_TARGET) && !(pPic->bRefBaseFlag)) || ((eRemoveFlag == REMOVE_BASE) && pPic->bRefBaseFlag) )
			{
				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, ERemoveFlag eRemoveFlag)
{
	PPicture pPic = WelsDelLongFromList(pRefPic,uiLongTermFrameIdx,eRemoveFlag);
	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 if (pRefPic->uiLongRefCount[LIST_0] >0){
		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;	
	}else{
		return ERR_INFO_REF_COUNT_OVERFLOW;
	}


	pRefPic->uiLongRefCount[LIST_0]++;
	return ERR_NONE;
}

static int32_t AssignLongTermIdx(PRefPic pRefPic,int32_t iFrameNum,int32_t iLongTermFrameIdx )
{
	PPicture pPic = NULL;
	int32_t iRet = ERR_NONE;
	WelsDelLongFromListSetUnref(pRefPic,iLongTermFrameIdx,REMOVE_TARGET);
	WelsDelLongFromListSetUnref(pRefPic,iLongTermFrameIdx,REMOVE_BASE);

	pPic = WelsDelShortFromList(pRefPic,iFrameNum,REMOVE_TARGET);
	if (pPic){
		iRet = AddLongTermToList(pRefPic,pPic,iLongTermFrameIdx);
	}else{	
		return ERR_INFO_INVALID_REF_MARKING;	
	}
	
	pPic = NULL;
	pPic = WelsDelShortFromList(pRefPic,iFrameNum,REMOVE_BASE);
	if (pPic){	
		iRet = AddLongTermToList(pRefPic,pPic,iLongTermFrameIdx);	
	}

	return iRet;
}

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,REMOVE_TARGET);
	WelsDelLongFromListSetUnref(pRefPic,iLongTermFrameIdx,REMOVE_BASE);

	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);
		}
	}
	
	return iRet;
}

} // namespace WelsDec