HM编码器代码阅读(5)——参考帧的选择

参考帧是怎么来的以及如何设置这个问题困扰了我很久,现在理出了一点头绪。
参考帧的选择主要涉及几个函数:
selectReferencePictureSet
createExplicitReferencePictureSetFromReference
applyReferencePictureSet
arrangeLongtermPicturesInRPS
setRefPicList
setRefPOCList
setList1IdxToList0Idx

主要过程:
1、首选调用selectReferencePictureSet来选择一个参考图像集,参考图像集(最多有有9个),全部放在SPS中,可以根据索引来取得
     (1)默认把当前帧在当前GOP中的相对poc设置为参考图像集的索引
     (2)如果当前帧的poc对I帧周期求余等于m_GOPList(注意这个列表存放的是帧对应的GOP信息,以及参考帧等信息)某个元素的gop
     那么就把这个元素的下标设置为参考图像集的索引!
2、每帧的第一个片中包含一个RPS的信息
3、根据步骤1选中的参考图像集,调用createExplicitReferencePictureSetFromReference 创建本地参考图像集,然后把参考的图像集设置为本地参考图像集
     (1)遍历参考集中所有的帧(参考集只存放这些参考帧的相对poc),在图像列表中找到其对应的帧,然后转往(2)
     (2)把相对poc存放到本地参考图像集的m_deltaPOC中
     (3)在本地参考图像集设置该帧(即参考帧)的被使用的标志(在m_used中)
     (4)如果相对poc小于0,那么统计为前向参考帧;如果相对poc大于0,那么统计为后向参考帧
     (5)把本地参考集设置为参考集
4、根据参考图像集调用applyReferencePictureSet 应用参考图像集,主要是设置里面的帧是否允许被参考,是否允许被当前帧所参考
     (1)对图像列表进行遍历,对于图像列表的每一帧pic,进行下面的操作
     (2)遍历参考集中的前向和后向参考帧(前向和后向参考帧的poc都是相对poc),如果pic在参考集中,那么设置pic的被参考标志
     (3)遍历参考集中其他参考帧(即长期参考帧),如果pic在参考集中,那么设置pic被参考的标志
     (4)保证pic所在的时域层比当前帧的时域层小
5、排列参考图像集中的帧,arrangeLongtermPicturesInRPS,主要是对长期参考帧进行排序,并设置相应的标志信息的过程
     (1)在参考图像集中先存放前向参考帧,然后存放后向参考帧,再放长期参考帧
     (2)MSB和LSB分别表示最高有效位和最低有效位,按照MSB从大到小排序长期参考帧
     (3)记录长期参考帧MSB出现的标志
     (4)记录长期参考帧被当前帧使用的情况
     (5)记录长期参考帧的各种信息(即上面出现的标志,使用情况等)
     (6)确保长期参考帧不会重复
6、调用 setRefPicList来设置参考图像列表(m_apcRefPicList),根据参考图像集设置list0和list1
     (1)m_aiNumRefIdx记录两个参考列表的元素个数
     (2)遍历参考集中的每一个前向参考帧,根据相对poc取得真实的帧的指针,然后放入临时的list0中
     (3)遍历每一个后向参考帧,把真实的帧的指针放入临时的list1中
     (4)遍历每一个长期参考帧,把真实的帧的指针放入临时的list中
     (5)按照前向、后向、长期的顺序,把这些参考帧都放进list0和list1中!(list0和list都放了前向和后向、长期参考帧;如果不是B帧,不需要list1)
7、调用setRefPOCList函数,设置m_aiRefPOCList
     (1)m_apcRefPicList中存放的是帧的指针,而m_aiRefPOCList中存放的是帧的poc
     (2)同样m_aiRefPOCList也是列表数组,m_aiRefPOCList[0]表示list0,m_aiRefPOCList[1]表示list1
8、调用setList1IdxToList0Idx,设置list0到list1的映射,根据poc相等来判断。

// 为当前帧选择一个参考图像集
// 额外的参考图像集有9个
Void TEncTop::selectReferencePictureSet(TComSlice* slice, Int POCCurr, Int GOPid )
{
	// GOPid是该帧在GOP中的相对poc
	// POCCurr是该帧的绝对poc
    
	slice->setRPSidx(GOPid); // 设置默认的参考集的索引

    // 对于额外的RPS
	for(Int extraNum=m_iGOPSize; extraNum<m_extraRPSs+m_iGOPSize; extraNum++)
	{    
        // 如果I帧的周期大于0
		if(m_uiIntraPeriod > 0 && getDecodingRefreshType() > 0)
		{
			// 当前帧的poc(这个poc是绝对的poc)对IntraPeriod求余(求余之后就是IntraPeriod周期内的相对poc)
			Int POCIndex = POCCurr%m_uiIntraPeriod;
			if(POCIndex == 0)
			{
				POCIndex = m_uiIntraPeriod;
			}
			if(POCIndex == m_GOPList[extraNum].m_POC)
			{
				slice->setRPSidx(extraNum); // 如果IntraPeriod周期内的相对poc刚好等于额外参考集的poc,那么就把这个额外的参考集选为参考集
			}
		}
		else
		{
			if(POCCurr==m_GOPList[extraNum].m_POC)
			{
				slice->setRPSidx(extraNum);
			}
		}
	}

	if(POCCurr == 1 && slice->getPic()->isField())
	{
		slice->setRPSidx(m_iGOPSize+m_extraRPSs);
	}

	slice->setRPS(getSPS()->getRPSList()->getReferencePictureSet(slice->getRPSidx()));
	slice->getRPS()->setNumberOfPictures(slice->getRPS()->getNumberOfNegativePictures()+slice->getRPS()->getNumberOfPositivePictures());
}
// 明确的创建一个参考图像集(从参考图像中)
#if ALLOW_RECOVERY_POINT_AS_RAP
Void TComSlice::createExplicitReferencePictureSetFromReference( TComList<TComPic*>& rcListPic, TComReferencePictureSet *pReferencePictureSet, Bool isRAP, Int pocRandomAccess, Bool bUseRecoveryPoint)
#else
Void TComSlice::createExplicitReferencePictureSetFromReference( TComList<TComPic*>& rcListPic, TComReferencePictureSet *pReferencePictureSet, Bool isRAP)
#endif
{
	TComPic* rpcPic;
	Int i, j;
    // k就是参考图像的计数
	Int k = 0;
	Int nrOfNegativePictures = 0;
	Int nrOfPositivePictures = 0;

    // 当前帧(片)的参考图像及
	TComReferencePictureSet* pcRPS = this->getLocalRPS();

	// loop through all pictures in the Reference Picture Set
    // 遍历所有的参考图像(存放在参考图像集中的)
	for(i=0;i<pReferencePictureSet->getNumberOfPictures();i++)
	{
		j = 0;
		// loop through all pictures in the reference picture buffer
		TComList<TComPic*>::iterator iterPic = rcListPic.begin();
		while ( iterPic != rcListPic.end())
		{
			j++;
			rpcPic = *(iterPic++);

            // 该条件成立表示找到了参考图像
            // 在图像列表中找到了当前片的参考图像
            if(rpcPic->getPicSym()->getSlice(0)->getPOC() == this->getPOC() + pReferencePictureSet->getDeltaPOC(i)
                    && rpcPic->getSlice(0)->isReferenced())
			{
				// This picture exists as a reference picture
				// and should be added to the explicit Reference Picture Set
                // 设置第k个图像的相对poc
				pcRPS->setDeltaPOC(k, pReferencePictureSet->getDeltaPOC(i));
                // 设置该参考图像是否允许被使用
				pcRPS->setUsed(k, pReferencePictureSet->getUsed(i) && (!isRAP));
#if ALLOW_RECOVERY_POINT_AS_RAP
				pcRPS->setUsed(k, pcRPS->getUsed(k) && !(bUseRecoveryPoint && this->getPOC() > pocRandomAccess && this->getPOC() + pReferencePictureSet->getDeltaPOC(i) < pocRandomAccess) ); 
#endif
                // 如果相对poc小于0,表示是前向参考
				if(pcRPS->getDeltaPOC(k) < 0)
				{
                    // 统计前向参考帧的数量
					nrOfNegativePictures++;
				}
                // 如果相对poc大于0,表示是后向参考
				else
				{
                    // 统计后向参考帧的数量
					nrOfPositivePictures++;
				}
				k++;
			}
		}
	}
#if EFFICIENT_FIELD_IRAP
    // 是否使用新的参考图像集
	Bool useNewRPS = false;
	// if current picture is complimentary field associated to IRAP, add the IRAP to its RPS. 
	if(m_pcPic->isField())
	{
		TComList<TComPic*>::iterator iterPic = rcListPic.begin();
		while ( iterPic != rcListPic.end())
		{
			rpcPic = *(iterPic++);
			if(rpcPic->getPicSym()->getSlice(0)->getPOC() == this->getAssociatedIRAPPOC() && this->getAssociatedIRAPPOC() == this->getPOC()+1)
			{
				pcRPS->setDeltaPOC(k, 1);
				pcRPS->setUsed(k, true);
				nrOfPositivePictures++;
				k ++;
				useNewRPS = true;
			}
		}
	}
#endif // EFFICIENT_FIELD_IRAP
    // 设置前向参考帧的数量,后向参考帧的数量,以及参考帧的总数
	pcRPS->setNumberOfNegativePictures(nrOfNegativePictures);
	pcRPS->setNumberOfPositivePictures(nrOfPositivePictures);
	pcRPS->setNumberOfPictures(nrOfNegativePictures+nrOfPositivePictures);
	// This is a simplistic inter rps example. A smarter encoder will look for a better reference RPS to do the
	// inter RPS prediction with.  Here we just use the reference used by pReferencePictureSet.
	// If pReferencePictureSet is not inter_RPS_predicted, then inter_RPS_prediction is for the current RPS also disabled.
    if (!pReferencePictureSet->getInterRPSPrediction() //如果是帧内预测
#if EFFICIENT_FIELD_IRAP
		|| useNewRPS
#endif
		)
	{
        pcRPS->setInterRPSPrediction(false);    //
        pcRPS->setNumRefIdc(0);
	}
    // 帧间预测
	else
	{
        // 参考图像集的索引,以传进来的参考图像集为基础,得到当前参考图像集的相对索引
		Int rIdx =  this->getRPSidx() - pReferencePictureSet->getDeltaRIdxMinus1() - 1;
        // 相对的参考图像集
		Int deltaRPS = pReferencePictureSet->getDeltaRPS();
        // 根据参考图像集的索引得到参考图像集(参考图像集可能有多个,存放在SPS的列表中),这个得到的图像集就是当前片的参考图像集
		TComReferencePictureSet* pcRefRPS = this->getSPS()->getRPSList()->getReferencePictureSet(rIdx);
        // 得到参考图像集中图像的数量
		Int iRefPics = pcRefRPS->getNumberOfPictures();
		Int iNewIdc=0;
        // 对参考图像集的每一个图像
		for(i=0; i<= iRefPics; i++) 
		{
            // 得到相对的poc
			Int deltaPOC = ((i != iRefPics)? pcRefRPS->getDeltaPOC(i) : 0);  // check if the reference abs POC is >= 0
			Int iRefIdc = 0;

            // 遍历本地的参考图像集的每一帧图像
			for (j=0; j < pcRPS->getNumberOfPictures(); j++) // loop through the  pictures in the new RPS
			{
                // 如果本参考图像集的某一帧和SPS的参考图像集中的某一帧匹配
				if ( (deltaPOC + deltaRPS) == pcRPS->getDeltaPOC(j))
				{
                    // 如果该帧可以被参考
					if (pcRPS->getUsed(j))
					{
						iRefIdc = 1;
					}
					else
					{
						iRefIdc = 2;
					}
				}
			}
            // 设置本地参考图像集的这一帧的idc
			pcRPS->setRefIdc(i, iRefIdc);
			iNewIdc++;
		}
        // 帧间预测
		pcRPS->setInterRPSPrediction(true);
        // 参考帧的数量
		pcRPS->setNumRefIdc(iNewIdc);
        // 相对的参考图像集的
		pcRPS->setDeltaRPS(deltaRPS); 
		pcRPS->setDeltaRIdxMinus1(pReferencePictureSet->getDeltaRIdxMinus1() + this->getSPS()->getRPSList()->getNumberOfReferencePictureSets() - this->getRPSidx());
	}

    // 设置参考图像集
	this->setRPS(pcRPS);
	this->setRPSidx(-1);
}
// 应用参考图像集
Void TComSlice::applyReferencePictureSet( TComList<TComPic*>& rcListPic, TComReferencePictureSet *pReferencePictureSet)
{
	TComPic* rpcPic;
	Int i, isReference;

    // 检测leading 帧的限制
	checkLeadingPictureRestrictions(rcListPic);

	// loop through all pictures in the reference picture buffer
	TComList<TComPic*>::iterator iterPic = rcListPic.begin();
    // 对图像列表的每一帧图像进行循环处理
	while ( iterPic != rcListPic.end())
	{
		rpcPic = *(iterPic++);

        // 如果不能被参考,那么跳过
		if(!rpcPic->getSlice( 0 )->isReferenced())
		{
			continue;
		}

        // 是否参考其他帧 的 标志
		isReference = 0;
		// loop through all pictures in the Reference Picture Set
		// to see if the picture should be kept as reference picture
        // 对于参考图像集的前向参考图像和后向参考图像
		for(i=0;i<pReferencePictureSet->getNumberOfPositivePictures()+pReferencePictureSet->getNumberOfNegativePictures();i++)
		{
            // 如果图像列表中的某一帧不是长期参考的帧 并且 它是当前帧的参考帧
            if(!rpcPic->getIsLongTerm() &&
                    rpcPic->getPicSym()->getSlice(0)->getPOC() == this->getPOC() + pReferencePictureSet->getDeltaPOC(i))
			{
                // 把标志设置为1,表明是参考其他帧的
				isReference = 1;
                // 设置列表中的这一帧被其他人参考
				rpcPic->setUsedByCurr(pReferencePictureSet->getUsed(i));
				rpcPic->setIsLongTerm(0);
			}
		}
        // 对于参考图像集的其他图像(注意i没有设置从0开始)(这些参考帧(属于长期参考帧)的poc都是绝对的poc)
		for(;i<pReferencePictureSet->getNumberOfPictures();i++)
		{
			if(pReferencePictureSet->getCheckLTMSBPresent(i)==true)
			{
				if(rpcPic->getIsLongTerm() && (rpcPic->getPicSym()->getSlice(0)->getPOC()) == pReferencePictureSet->getPOC(i))
				{
					isReference = 1;
					rpcPic->setUsedByCurr(pReferencePictureSet->getUsed(i));
				}
			}
			else 
			{
				Int pocCycle = 1<<rpcPic->getPicSym()->getSlice(0)->getSPS()->getBitsForPOC();
				Int curPoc = rpcPic->getPicSym()->getSlice(0)->getPOC() & (pocCycle-1);
				Int refPoc = pReferencePictureSet->getPOC(i) & (pocCycle-1);
				if(rpcPic->getIsLongTerm() && curPoc == refPoc)
				{
					isReference = 1;
					rpcPic->setUsedByCurr(pReferencePictureSet->getUsed(i));
				}
			}

		}
		// mark the picture as "unused for reference" if it is not in
		// the Reference Picture Set
        // 对参考图像集遍历完成之后,就可以知道这个帧是否被被其他帧参考
		if(rpcPic->getPicSym()->getSlice(0)->getPOC() != this->getPOC() && isReference == 0)
		{            
			rpcPic->getSlice( 0 )->setReferenced( false );
			rpcPic->setUsedByCurr(0);
			rpcPic->setIsLongTerm(0);
		}
		//check that pictures of higher temporal layers are not used
        // 这里保证了当前帧所在的时域层比参考帧的时域层大
		assert(rpcPic->getSlice( 0 )->isReferenced()==0||rpcPic->getUsedByCurr()==0||rpcPic->getTLayer()<=this->getTLayer());
		//check that pictures of higher or equal temporal layer are not in the RPS if the current picture is a TSA picture
		if(this->getNalUnitType() == NAL_UNIT_CODED_SLICE_TSA_R || this->getNalUnitType() == NAL_UNIT_CODED_SLICE_TSA_N)
		{
			assert(rpcPic->getSlice( 0 )->isReferenced()==0||rpcPic->getTLayer()<this->getTLayer());
		}
		//check that pictures marked as temporal layer non-reference pictures are not used for reference
		if(rpcPic->getPicSym()->getSlice(0)->getPOC() != this->getPOC() && rpcPic->getTLayer()==this->getTLayer())
		{
			assert(rpcPic->getSlice( 0 )->isReferenced()==0||rpcPic->getUsedByCurr()==0||rpcPic->getSlice( 0 )->getTemporalLayerNonReferenceFlag()==false);
		}
	}
}
// 对参考图像集中的长期参考图像进行排序
Void TEncGOP::arrangeLongtermPicturesInRPS(TComSlice *pcSlice, TComList<TComPic*>& rcListPic)
{
    TComReferencePictureSet *rps = pcSlice->getRPS();
    if(!rps->getNumberOfLongtermPictures())
    {
        return;
    }

    // Arrange long-term reference pictures in the correct order of LSB and MSB,
    // and assign values for pocLSBLT and MSB present flag
    // 长期参考图像的poc,LSB,索引
    Int longtermPicsPoc[MAX_NUM_REF_PICS], longtermPicsLSB[MAX_NUM_REF_PICS], indices[MAX_NUM_REF_PICS];
    // 长期参考图像的MSB
    Int longtermPicsMSB[MAX_NUM_REF_PICS];
    // msb出现的标志
    Bool mSBPresentFlag[MAX_NUM_REF_PICS];
    ::memset(longtermPicsPoc, 0, sizeof(longtermPicsPoc));    // Store POC values of LTRP
    ::memset(longtermPicsLSB, 0, sizeof(longtermPicsLSB));    // Store POC LSB values of LTRP
    ::memset(longtermPicsMSB, 0, sizeof(longtermPicsMSB));    // Store POC LSB values of LTRP
    ::memset(indices        , 0, sizeof(indices));            // Indices to aid in tracking sorted LTRPs
    ::memset(mSBPresentFlag , 0, sizeof(mSBPresentFlag));     // Indicate if MSB needs to be present

    // Get the long-term reference pictures
    // 注意!!!
    // 各中参考图像在参考图像集中的位置:首先是前向参考帧,然后是后向参考帧,最后是长期参考帧
    // 下面这个变量存放了长期参考图像集的起始位置
    Int offset = rps->getNumberOfNegativePictures() + rps->getNumberOfPositivePictures();
    Int i, ctr = 0;
    Int maxPicOrderCntLSB = 1 << pcSlice->getSPS()->getBitsForPOC();
    // 从后面开始扫描,记录长期参考帧的信息
    for(i = rps->getNumberOfPictures() - 1; i >= offset; i--, ctr++)
    {
        longtermPicsPoc[ctr] = rps->getPOC(i);                                  // LTRP POC
        longtermPicsLSB[ctr] = getLSB(longtermPicsPoc[ctr], maxPicOrderCntLSB); // LTRP POC LSB
        indices[ctr]      = i;
        longtermPicsMSB[ctr] = longtermPicsPoc[ctr] - longtermPicsLSB[ctr];
    }
    Int numLongPics = rps->getNumberOfLongtermPictures();
    assert(ctr == numLongPics);

    // Arrange pictures in decreasing order of MSB;
    // 按照MSB从大到小排序长期参考帧
    for(i = 0; i < numLongPics; i++)
    {
        for(Int j = 0; j < numLongPics - 1; j++)
        {
            if(longtermPicsMSB[j] < longtermPicsMSB[j+1])
            {
                std::swap(longtermPicsPoc[j], longtermPicsPoc[j+1]);
                std::swap(longtermPicsLSB[j], longtermPicsLSB[j+1]);
                std::swap(longtermPicsMSB[j], longtermPicsMSB[j+1]);
                std::swap(indices[j]        , indices[j+1]        );
            }
        }
    }

    // 记录长期参考帧MSB出现的标志
    for(i = 0; i < numLongPics; i++)
    {
        // Check if MSB present flag should be enabled.
        // Check if the buffer contains any pictures that have the same LSB.
        TComList<TComPic*>::iterator  iterPic = rcListPic.begin();
        TComPic*                      pcPic;
        while ( iterPic != rcListPic.end() )
        {
            pcPic = *iterPic;
            if( (getLSB(pcPic->getPOC(), maxPicOrderCntLSB) == longtermPicsLSB[i])   &&     // Same LSB
                (pcPic->getSlice(0)->isReferenced())     &&    // Reference picture
                (pcPic->getPOC() != longtermPicsPoc[i])    )  // Not the LTRP itself
            {
                mSBPresentFlag[i] = true;
                break;
            }
            iterPic++;
        }
    }

    // tempArray for usedByCurr flag
    // 记录长期参考帧被使用的情况
    Bool tempArray[MAX_NUM_REF_PICS]; ::memset(tempArray, 0, sizeof(tempArray));
    for(i = 0; i < numLongPics; i++)
    {
        tempArray[i] = rps->getUsed(indices[i]);
    }
    // Now write the final values;
    ctr = 0;
    Int currMSB = 0, currLSB = 0;
    // currPicPoc = currMSB + currLSB
    currLSB = getLSB(pcSlice->getPOC(), maxPicOrderCntLSB);
    currMSB = pcSlice->getPOC() - currLSB;

    // 设置长期参考帧的各种信息
    for(i = rps->getNumberOfPictures() - 1; i >= offset; i--, ctr++)
    {
        rps->setPOC                   (i, longtermPicsPoc[ctr]);
        rps->setDeltaPOC              (i, - pcSlice->getPOC() + longtermPicsPoc[ctr]);
        rps->setUsed                  (i, tempArray[ctr]);
        rps->setPocLSBLT              (i, longtermPicsLSB[ctr]);
        rps->setDeltaPocMSBCycleLT    (i, (currMSB - (longtermPicsPoc[ctr] - longtermPicsLSB[ctr])) / maxPicOrderCntLSB);
        rps->setDeltaPocMSBPresentFlag(i, mSBPresentFlag[ctr]);

        assert(rps->getDeltaPocMSBCycleLT(i) >= 0);   // Non-negative value
    }

    // 确保长期参考帧不会重复
    for(i = rps->getNumberOfPictures() - 1, ctr = 1; i >= offset; i--, ctr++)
    {
        for(Int j = rps->getNumberOfPictures() - 1 - ctr; j >= offset; j--)
        {
            // Here at the encoder we know that we have set the full POC value for the LTRPs, hence we
            // don't have to check the MSB present flag values for this constraint.
            assert( rps->getPOC(i) != rps->getPOC(j) ); // If assert fails, LTRP entry repeated in RPS!!!
        }
    }
}
// 设置参考图像列表
Void TComSlice::setRefPicList( TComList<TComPic*>& rcListPic, Bool checkNumPocTotalCurr )
{
	if (!checkNumPocTotalCurr)
	{
		if (m_eSliceType == I_SLICE)
		{
			::memset( m_apcRefPicList, 0, sizeof (m_apcRefPicList));
			::memset( m_aiNumRefIdx,   0, sizeof ( m_aiNumRefIdx ));

			return;
		}

		m_aiNumRefIdx[0] = getNumRefIdx(REF_PIC_LIST_0);
		m_aiNumRefIdx[1] = getNumRefIdx(REF_PIC_LIST_1);
	}

	TComPic*  pcRefPic= NULL;
    // 存放前向参考帧(最多16个)
	TComPic*  RefPicSetStCurr0[16];
    // 存放后向参考帧(最多16个)
	TComPic*  RefPicSetStCurr1[16];
    // 存放长期参考帧
	TComPic*  RefPicSetLtCurr[16];
	UInt NumPocStCurr0 = 0;
	UInt NumPocStCurr1 = 0;
	UInt NumPocLtCurr = 0;
	Int i;

    // 遍历每一个前向参考帧
	for(i=0; i < m_pcRPS->getNumberOfNegativePictures(); i++)
	{
		if(m_pcRPS->getUsed(i))
		{
            // 取得该帧
			pcRefPic = xGetRefPic(rcListPic, getPOC()+m_pcRPS->getDeltaPOC(i));
			pcRefPic->setIsLongTerm(0);
            // 扩展图像边界
			pcRefPic->getPicYuvRec()->extendPicBorder();
            // 把这个帧存放起来
			RefPicSetStCurr0[NumPocStCurr0] = pcRefPic;
			NumPocStCurr0++;
			pcRefPic->setCheckLTMSBPresent(false);  
		}
	}

    // 遍历每一个后向参考帧
	for(; i < m_pcRPS->getNumberOfNegativePictures()+m_pcRPS->getNumberOfPositivePictures(); i++)
	{
		if(m_pcRPS->getUsed(i))
		{
			pcRefPic = xGetRefPic(rcListPic, getPOC()+m_pcRPS->getDeltaPOC(i));
			pcRefPic->setIsLongTerm(0);
			pcRefPic->getPicYuvRec()->extendPicBorder();
			RefPicSetStCurr1[NumPocStCurr1] = pcRefPic;
			NumPocStCurr1++;
			pcRefPic->setCheckLTMSBPresent(false);  
		}
	}

    // 遍历每一个长期参考帧
	for(i = m_pcRPS->getNumberOfNegativePictures()+m_pcRPS->getNumberOfPositivePictures()+m_pcRPS->getNumberOfLongtermPictures()-1; i > m_pcRPS->getNumberOfNegativePictures()+m_pcRPS->getNumberOfPositivePictures()-1 ; i--)
	{
		if(m_pcRPS->getUsed(i))
		{
			pcRefPic = xGetLongTermRefPic(rcListPic, m_pcRPS->getPOC(i), m_pcRPS->getCheckLTMSBPresent(i));
			pcRefPic->setIsLongTerm(1);
			pcRefPic->getPicYuvRec()->extendPicBorder();
			RefPicSetLtCurr[NumPocLtCurr] = pcRefPic;
			NumPocLtCurr++;
		}
		if(pcRefPic==NULL) 
		{
			pcRefPic = xGetLongTermRefPic(rcListPic, m_pcRPS->getPOC(i), m_pcRPS->getCheckLTMSBPresent(i));
		}
		pcRefPic->setCheckLTMSBPresent(m_pcRPS->getCheckLTMSBPresent(i));  
	}

	// ref_pic_list_init
    // 两个参考图像列表(list0和list1)
	TComPic*  rpsCurrList0[MAX_NUM_REF+1];
	TComPic*  rpsCurrList1[MAX_NUM_REF+1];
	Int numPocTotalCurr = NumPocStCurr0 + NumPocStCurr1 + NumPocLtCurr;
	if (checkNumPocTotalCurr)
	{
		// The variable NumPocTotalCurr is derived as specified in subclause 7.4.7.2. It is a requirement of bitstream conformance that the following applies to the value of NumPocTotalCurr:
		// - If the current picture is a BLA or CRA picture, the value of NumPocTotalCurr shall be equal to 0.
		// - Otherwise, when the current picture contains a P or B slice, the value of NumPocTotalCurr shall not be equal to 0.
		if (getRapPicFlag())
		{
			assert(numPocTotalCurr == 0);
		}

		if (m_eSliceType == I_SLICE)
		{
			::memset( m_apcRefPicList, 0, sizeof (m_apcRefPicList));
			::memset( m_aiNumRefIdx,   0, sizeof ( m_aiNumRefIdx ));

			return;
		}

		assert(numPocTotalCurr > 0);

		m_aiNumRefIdx[0] = getNumRefIdx(REF_PIC_LIST_0);
		m_aiNumRefIdx[1] = getNumRefIdx(REF_PIC_LIST_1);
	}

    // 按照 前向、后向,长期的顺序存放参考帧
	Int cIdx = 0;
	for ( i=0; i<NumPocStCurr0; i++, cIdx++)
	{
		rpsCurrList0[cIdx] = RefPicSetStCurr0[i];
	}
	for ( i=0; i<NumPocStCurr1; i++, cIdx++)
	{
		rpsCurrList0[cIdx] = RefPicSetStCurr1[i];
	}
	for ( i=0; i<NumPocLtCurr;  i++, cIdx++)
	{
		rpsCurrList0[cIdx] = RefPicSetLtCurr[i];
	}
	assert(cIdx == numPocTotalCurr);

    // 如果是B片(那么需要向后进行参考,即需要list1)
	if (m_eSliceType==B_SLICE)
	{
		cIdx = 0;
		for ( i=0; i<NumPocStCurr1; i++, cIdx++)
		{
			rpsCurrList1[cIdx] = RefPicSetStCurr1[i];
		}
		for ( i=0; i<NumPocStCurr0; i++, cIdx++)
		{
			rpsCurrList1[cIdx] = RefPicSetStCurr0[i];
		}
		for ( i=0; i<NumPocLtCurr;  i++, cIdx++)
		{
			rpsCurrList1[cIdx] = RefPicSetLtCurr[i];
		}
		assert(cIdx == numPocTotalCurr);
	}

	::memset(m_bIsUsedAsLongTerm, 0, sizeof(m_bIsUsedAsLongTerm));

    // 然后把list0和list1(上面的是临时的)放到当前帧的参考列表中
	for (Int rIdx = 0; rIdx < m_aiNumRefIdx[0]; rIdx ++)
	{
		cIdx = m_RefPicListModification.getRefPicListModificationFlagL0() ? m_RefPicListModification.getRefPicSetIdxL0(rIdx) : rIdx % numPocTotalCurr;
		assert(cIdx >= 0 && cIdx < numPocTotalCurr);
		m_apcRefPicList[0][rIdx] = rpsCurrList0[ cIdx ];
		m_bIsUsedAsLongTerm[0][rIdx] = ( cIdx >= NumPocStCurr0 + NumPocStCurr1 );
	}
	if ( m_eSliceType != B_SLICE )
	{
		m_aiNumRefIdx[1] = 0;
		::memset( m_apcRefPicList[1], 0, sizeof(m_apcRefPicList[1]));
	}
	else
	{
		for (Int rIdx = 0; rIdx < m_aiNumRefIdx[1]; rIdx ++)
		{
			cIdx = m_RefPicListModification.getRefPicListModificationFlagL1() ? m_RefPicListModification.getRefPicSetIdxL1(rIdx) : rIdx % numPocTotalCurr;
			assert(cIdx >= 0 && cIdx < numPocTotalCurr);
			m_apcRefPicList[1][rIdx] = rpsCurrList1[ cIdx ];
			m_bIsUsedAsLongTerm[1][rIdx] = ( cIdx >= NumPocStCurr0 + NumPocStCurr1 );
		}
	}
}
Void TComSlice::setRefPOCList()
{
	for (Int iDir = 0; iDir < 2; iDir++)
	{
		for (Int iNumRefIdx = 0; iNumRefIdx < m_aiNumRefIdx[iDir]; iNumRefIdx++)
		{
			m_aiRefPOCList[iDir][iNumRefIdx] = m_apcRefPicList[iDir][iNumRefIdx]->getPOC();
		}
	}

}
Void TComSlice::setList1IdxToList0Idx()
{
	Int idxL0, idxL1;
	for ( idxL1 = 0; idxL1 < getNumRefIdx( REF_PIC_LIST_1 ); idxL1++ )
	{
		m_list1IdxToList0Idx[idxL1] = -1;
		for ( idxL0 = 0; idxL0 < getNumRefIdx( REF_PIC_LIST_0 ); idxL0++ )
		{
			if ( m_apcRefPicList[REF_PIC_LIST_0][idxL0]->getPOC() == m_apcRefPicList[REF_PIC_LIST_1][idxL1]->getPOC() )
			{
				m_list1IdxToList0Idx[idxL1] = idxL0;
				break;
			}
		}
	}
}








  • 16
    点赞
  • 42
    收藏
    觉得还不错? 一键收藏
  • 6
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值