参考帧是怎么来的以及如何设置这个问题困扰了我很久,现在理出了一点头绪。
参考帧的选择主要涉及几个函数:
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相等来判断。
(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;
}
}
}
}