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

时间:2022-01-12 11:34:42
参考帧是怎么来的以及如何设置这个问题困扰了我很久,现在理出了一点头绪。 参考帧的选择主要涉及几个函数: 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_RAPVoid TComSlice::createExplicitReferencePictureSetFromReference( TComList<TComPic*>& rcListPic, TComReferencePictureSet *pReferencePictureSet, Bool isRAP, Int pocRandomAccess, Bool bUseRecoveryPoint)#elseVoid 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 bufferTComList<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个图像的相对pocpcRPS->setDeltaPOC(k, pReferencePictureSet->getDeltaPOC(i));                // 设置该参考图像是否允许被使用pcRPS->setUsed(k, pReferencePictureSet->getUsed(i) && (!isRAP));#if ALLOW_RECOVERY_POINT_AS_RAPpcRPS->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++) {            // 得到相对的pocInt deltaPOC = ((i != iRefPics)? pcRefRPS->getDeltaPOC(i) : 0);  // check if the reference abs POC is >= 0Int 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;}}}            // 设置本地参考图像集的这一帧的idcpcRPS->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 bufferTComList<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 pictureif(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 referenceif(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;}}}}