https://blog.youkuaiyun.com/NB_vol_1/article/details/51135715
参考帧是怎么来的以及如何设置这个问题困扰了我很久,现在理出了一点头绪。
参考帧的选择主要涉及几个函数:
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;
-
}
-
}
-
}
-
}