在上一章的xCheckRDCostInter学习中,我们知道了,进行帧间搜索的入口实际是predInterSearch,今天我们就来对他进行学习。
推荐看大神博客
http://blog.csdn.net/nb_vol_1/article/details/51162391
predInterSearch主要作用是进行运动估计和运动补偿。
1.对CU的每一个PU遍历参考列表中的参考图像,进行运动估计,找到最优参考帧和MV。
2.对于B帧,需要对后向参考预测块进行运动补偿,在运动补偿之后重新进行运动估计,找到最优MV。
3.对于非2Nx2N的分块,需要计算并合并他们的运动估计代价。
4.最后进行运动补偿,设置加权预测。
其中涉及了广义B帧的处理,前后参考列表中的参考图像都是用当前图像之前的图像,且两个参考列表完全一致,因此list0和list1相同。
使用到了以下重要函数:
1.xEstimateMvPredAMVP:AMVP的入口函数,执行AMVP操作。
2.xMotionEstimation:运动估计的入口函数,进行运动搜索,找到MV。
3.motionCompensation:运动补偿的入口函数,进行运动补偿,构造匹配块信息。
这里补充一下AMVP与运动估计的关系。AMVP会为运动估计ME提供候选MVP,ME会选择其中率失真代价最小的MVP作为起点,进行搜索,找到最优的MV。
另外MVD也是在predInterSearch函数中计算的,找到最优MV后,会根据MVD = MV - MVP计算MVD。
//帧间搜索最佳候选
//! search of the best candidate for inter prediction
#if AMP_MRG
Void TEncSearch::predInterSearch( TComDataCU* pcCU, TComYuv* pcOrgYuv, TComYuv* pcPredYuv, TComYuv* pcResiYuv, TComYuv* pcRecoYuv DEBUG_STRING_FN_DECLARE(sDebug), Bool bUseRes, Bool bUseMRG )
#else
Void TEncSearch::predInterSearch( TComDataCU* pcCU, TComYuv* pcOrgYuv, TComYuv* pcPredYuv, TComYuv* pcResiYuv, TComYuv* pcRecoYuv, Bool bUseRes )
#endif
{
for(UInt i=0; iclear();
if ( !bUseRes )
{
pcResiYuv->clear();
}
pcRecoYuv->clear();
TComMv cMvSrchRngLT; //左上
TComMv cMvSrchRngRB; //右下
TComMv cMvZero;
TComMv TempMv; //kolya
TComMv cMv[2];
TComMv cMvBi[2];
TComMv cMvTemp[2][33];
Int iNumPart = pcCU->getNumPartitions(); //分块数
Int iNumPredDir = pcCU->getSlice()->isInterP() ? 1 : 2; //预测方向,P帧为1,B帧为2
TComMv cMvPred[2][33]; //记录前向参考帧的MV
TComMv cMvPredBi[2][33]; //记录后向参考帧的MV
Int aaiMvpIdxBi[2][33]; //记录后向参考帧的MVP索引
Int aaiMvpIdx[2][33]; //记录前向参考帧的MVP索引
Int aaiMvpNum[2][33]; //记录MVP的数量
AMVPInfo aacAMVPInfo[2][33]; //记录AMVP的信息
Int iRefIdx[2]={0,0}; //If un-initialized, may cause SEGV in bi-directional prediction iterative stage.
Int iRefIdxBi[2];
UInt uiPartAddr;
Int iRoiWidth, iRoiHeight;
UInt uiMbBits[3] = {1, 1, 0};
UInt uiLastMode = 0;
Int iRefStart, iRefEnd;
PartSize ePartSize = pcCU->getPartitionSize( 0 );
Int bestBiPRefIdxL1 = 0;
Int bestBiPMvpL1 = 0;
Distortion biPDistTemp = std::numeric_limits::max(); //将失真置为最大
TComMvField cMvFieldNeighbours[MRG_MAX_NUM_CANDS << 1]; // double length for mv of both lists 为了双向MV,长度为2倍
UChar uhInterDirNeighbours[MRG_MAX_NUM_CANDS];
Int numValidMergeCand = 0 ;
//初始化,将所有分块的失真都置为最大
for ( Int iPartIdx = 0; iPartIdx < iNumPart; iPartIdx++ )
{
Distortion uiCost[2] = { std::numeric_limits::max(), std::numeric_limits::max() };
Distortion uiCostBi = std::numeric_limits::max();
Distortion uiCostTemp;
UInt uiBits[3];
UInt uiBitsTemp;
Distortion bestBiPDist = std::numeric_limits::max();
Distortion uiCostTempL0[MAX_NUM_REF];
for (Int iNumRef=0; iNumRef < MAX_NUM_REF; iNumRef++) //将各参考图像的失真置为最大
{
uiCostTempL0[iNumRef] = std::numeric_limits::max();
}
UInt uiBitsTempL0[MAX_NUM_REF];
TComMv mvValidList1;
Int refIdxValidList1 = 0;
UInt bitsValidList1 = MAX_UINT;
Distortion costValidList1 = std::numeric_limits::max();
xGetBlkBits( ePartSize, pcCU->getSlice()->isInterP(), iPartIdx, uiLastMode, uiMbBits); //获取CU块的bit数
pcCU->getPartIndexAndSize( iPartIdx, uiPartAddr, iRoiWidth, iRoiHeight ); //获取CU的宽、高、起始地址信息
#if AMP_MRG
Bool bTestNormalMC = true; //bTestNormalMC指示是否进行正常的MC(ME+MC)
if ( bUseMRG && pcCU->getWidth( 0 ) > 8 && iNumPart == 2 ) //bUseMRG为真、CU大于8且分块为SIZE_2NxN时,不能进行正常的MC
{
bTestNormalMC = false;
}
/*********************************************************正常MC*****************************************************************/
if (bTestNormalMC)
{
#endif
//建立参考列表,P帧只有一个,B帧有两个
// Uni-directional prediction
for ( Int iRefList = 0; iRefList < iNumPredDir; iRefList++ ) //iRefList为当前参考列表
{
RefPicList eRefPicList = ( iRefList ? REF_PIC_LIST_1 : REF_PIC_LIST_0 ); //前向后参考列表
//遍历这个参考列表的所有参考帧
for ( Int iRefIdxTemp = 0; iRefIdxTemp < pcCU->getSlice()->getNumRefIdx(eRefPicList); iRefIdxTemp++ ) //iRefIdxTemp为当前参考帧索引
{
uiBitsTemp = uiMbBits[iRefList]; //存储参考列表的bit数
if ( pcCU->getSlice()->getNumRefIdx(eRefPicList) > 1 ) //如果参考列表中的帧数大于1,计算所有参考帧的总bit数
{
uiBitsTemp += iRefIdxTemp+1;
if ( iRefIdxTemp == pcCU->getSlice()->getNumRefIdx(eRefPicList)-1 ) //最后一帧bit数-1
{
uiBitsTemp--;
}
}
//执行AMVP,进行MV预测和AMVP计算
xEstimateMvPredAMVP( pcCU, pcOrgYuv, iPartIdx, eRefPicList, iRefIdxTemp, cMvPred[iRefList][iRefIdxTemp], false, &biPDistTemp);
aaiMvpIdx[iRefList][iRefIdxTemp] = pcCU->getMVPIdx(eRefPicList, uiPartAddr); //获取MVP索引
aaiMvpNum[iRefList][iRefIdxTemp] = pcCU->getMVPNum(eRefPicList, uiPartAddr); //获取MVP数量
//使用广义帧且失真小于最优失真时,更新最优参数。
if(pcCU->getSlice()->getMvdL1ZeroFlag() && iRefList==1 && biPDistTemp < bestBiPDist)
{
bestBiPDist = biPDistTemp;
bestBiPMvpL1 = aaiMvpIdx[iRefList][iRefIdxTemp];
bestBiPRefIdxL1 = iRefIdxTemp;
}
uiBitsTemp += m_auiMVPIdxCost[aaiMvpIdx[iRefList][iRefIdxTemp]][AMVP_MAX_NUM_CANDS]; //记录bit数
if ( m_pcEncCfg->getFastMEForGenBLowDelayEnabled() && iRefList == 1 ) //对于list1(B帧)
{
if ( pcCU->getSlice()->getList1IdxToList0Idx( iRefIdxTemp ) >= 0 ) //如果使用广义B帧,则list1直接复制list0的信息;
{
cMvTemp[1][iRefIdxTemp] = cMvTemp[0][pcCU->getSlice()->getList1IdxToList0Idx( iRefIdxTemp )];
uiCostTemp = uiCostTempL0[pcCU->getSlice()->getList1IdxToList0Idx( iRefIdxTemp )];
/*first subtract the bit-rate part of the cost of the other list*/
uiCostTemp -= m_pcRdCost->getCost( uiBitsTempL0[pcCU->getSlice()->getList1IdxToList0Idx( iRefIdxTemp )] );
/*correct the bit-rate part of the current ref*/
m_pcRdCost->setPredictor ( cMvPred[iRefList][iRefIdxTemp] );
uiBitsTemp += m_pcRdCost->getBits( cMvTemp[1][iRefIdxTemp].getHor(), cMvTemp[1][iRefIdxTemp].getVer() );
/*calculate the correct cost*/
uiCostTemp += m_pcRdCost->getCost( uiBitsTemp );
}
else //不使用广义B帧就直接进行运动估计xMotionEstimation
{
xMotionEstimation ( pcCU, pcOrgYuv, iPartIdx, eRefPicList, &cMvPred[iRefList][iRefIdxTemp], iRefIdxTemp, cMvTemp[iRefList][iRefIdxTemp], uiBitsTemp, uiCostTemp );
}
}
else //对于list0,直接进行运动估计xMotionEstimation
{
xMotionEstimation ( pcCU, pcOrgYuv, iPartIdx, eRefPicList, &cMvPred[iRefList][iRefIdxTemp], iRefIdxTemp, cMvTemp[iRefList][iRefIdxTemp], uiBitsTemp, uiCostTemp );
}
//将AMVP信息写入当前CU,并检查是否是最优MVP
xCopyAMVPInfo(pcCU->getCUMvField(eRefPicList)->getAMVPInfo(), &aacAMVPInfo[iRefList][iRefIdxTemp]); // must always be done ( also when AMVP_MODE = AM_NONE )
xCheckBestMVP(pcCU, eRefPicList, cMvTemp[iRefList][iRefIdxTemp], cMvPred[iRefList][iRefIdxTemp], aaiMvpIdx[iRefList][iRefIdxTemp], uiBitsTemp, uiCostTemp);
//更新失真和bit信息
if ( iRefList == 0 )
{
uiCostTempL0[iRefIdxTemp] = uiCostTemp;
uiBitsTempL0[iRefIdxTemp] = uiBitsTemp;
}
if ( uiCostTemp < uiCost[iRefList] )
{
uiCost[iRefList] = uiCostTemp;
uiBits[iRefList] = uiBitsTemp; // storing for bi-prediction
// set motion
cMv[iRefList] = cMvTemp[iRefList][iRefIdxTemp];
iRefIdx[iRefList] = iRefIdxTemp;
}
if ( iRefList == 1 && uiCostTemp < costValidList1 && pcCU->getSlice()->getList1IdxToList0Idx( iRefIdxTemp ) < 0 )
{
costValidList1 = uiCostTemp;
bitsValidList1 = uiBitsTemp;
// set motion
mvValidList1 = cMvTemp[iRefList][iRefIdxTemp];
refIdxValidList1 = iRefIdxTemp;
}
}
}
// Bi-directional prediction 双向预测
if ( (pcCU->getSlice()->isInterB()) && (pcCU->isBipredRestriction(iPartIdx) == false) ) //isBipredRestriction(用来判断当前PU尺寸是否为8,而且划分模式是不是2Nx2N)
{
cMvBi[0] = cMv[0]; cMvBi[1] = cMv[1];
iRefIdxBi[0] = iRefIdx[0]; iRefIdxBi[1] = iRefIdx[1];
::memcpy(cMvPredBi, cMvPred, sizeof(cMvPred));
::memcpy(aaiMvpIdxBi, aaiMvpIdx, sizeof(aaiMvpIdx));
UInt uiMotBits[2];
//使用广义B帧,则进行运动补偿motionCompensation
if(pcCU->getSlice()->getMvdL1ZeroFlag())
{
xCopyAMVPInfo(&aacAMVPInfo[1][bestBiPRefIdxL1], pcCU->getCUMvField(REF_PIC_LIST_1)->getAMVPInfo());
pcCU->setMVPIdxSubParts( bestBiPMvpL1, REF_PIC_LIST_1, uiPartAddr, iPartIdx, pcCU->getDepth(uiPartAddr));
aaiMvpIdxBi[1][bestBiPRefIdxL1] = bestBiPMvpL1;
cMvPredBi[1][bestBiPRefIdxL1] = pcCU->getCUMvField(REF_PIC_LIST_1)->getAMVPInfo()->m_acMvCand[bestBiPMvpL1];
cMvBi[1] = cMvPredBi[1][bestBiPRefIdxL1];
iRefIdxBi[1] = bestBiPRefIdxL1;
pcCU->getCUMvField( REF_PIC_LIST_1 )->setAllMv( cMvBi[1], ePartSize, uiPartAddr, 0, iPartIdx );
pcCU->getCUMvField( REF_PIC_LIST_1 )->setAllRefIdx( iRefIdxBi[1], ePartSize, uiPartAddr, 0, iPartIdx );
TComYuv* pcYuvPred = &m_acYuvPred[REF_PIC_LIST_1];
motionCompensation( pcCU, pcYuvPred, REF_PIC_LIST_1, iPartIdx );
uiMotBits[0] = uiBits[0] - uiMbBits[0];
uiMotBits[1] = uiMbBits[1];
if ( pcCU->getSlice()->getNumRefIdx(REF_PIC_LIST_1) > 1 )
{
uiMotBits[1] += bestBiPRefIdxL1+1;
if ( bestBiPRefIdxL1 == pcCU->getSlice()->getNumRefIdx(REF_PIC_LIST_1)-1 )
{
uiMotBits[1]--;
}
}
uiMotBits[1] += m_auiMVPIdxCost[aaiMvpIdxBi[1][bestBiPRefIdxL1]][AMVP_MAX_NUM_CANDS];
uiBits[2] = uiMbBits[2] + uiMotBits[0] + uiMotBits[1];
cMvTemp[1][bestBiPRefIdxL1] = cMvBi[1];
}
else
{
uiMotBits[0] = uiBits[0] - uiMbBits[0];
uiMotBits[1] = uiBits[1] - uiMbBits[1];
uiBits[2] = uiMbBits[2] + uiMotBits[0] + uiMotBits[1];
}
// 4-times iteration (default) 默认4次迭代
Int iNumIter = 4;
//如果不使用广义B帧技术,且是第一次迭代,则进行运动补偿
// fast encoder setting: only one iteration
if ( m_pcEncCfg->getUseFastEnc() || pcCU->getSlice()->getMvdL1ZeroFlag())
{
iNumIter = 1;
}
for ( Int iIter = 0; iIter < iNumIter; iIter++ )
{
Int iRefList = iIter % 2;
if ( m_pcEncCfg->getUseFastEnc() ) //使用快速编码,则选择代价大的list
{
if( uiCost[0] <= uiCost[1] )
{
iRefList = 1;
}
else
{
iRefList = 0;
}
}
else if ( iIter == 0 ) //如果是整个子块,则选择list0
{
iRefList = 0;
}
if ( iIter == 0 && !pcCU->getSlice()->getMvdL1ZeroFlag()) //如果是第一个子块且list1不为空,进行list0的运动补偿
{
pcCU->getCUMvField(RefPicList(1-iRefList))->setAllMv( cMv[1-iRefList], ePartSize, uiPartAddr, 0, iPartIdx );
pcCU->getCUMvField(RefPicList(1-iRefList))->setAllRefIdx( iRefIdx[1-iRefList], ePartSize, uiPartAddr, 0, iPartIdx );
TComYuv* pcYuvPred = &m_acYuvPred[1-iRefList];
motionCompensation ( pcCU, pcYuvPred, RefPicList(1-iRefList), iPartIdx );
}
RefPicList eRefPicList = ( iRefList ? REF_PIC_LIST_1 : REF_PIC_LIST_0 );
if(pcCU->getSlice()->getMvdL1ZeroFlag())
{
iRefList = 0;
eRefPicList = REF_PIC_LIST_0;
}
Bool bChanged = false;
iRefStart = 0; //起始参考帧
iRefEnd = pcCU->getSlice()->getNumRefIdx(eRefPicList)-1; //结束参考帧
//遍历所有参考帧进行运动估计
for ( Int iRefIdxTemp = iRefStart; iRefIdxTemp <= iRefEnd; iRefIdxTemp++ )
{
uiBitsTemp = uiMbBits[2] + uiMotBits[1-iRefList];
//更新bit信息
if ( pcCU->getSlice()->getNumRefIdx(eRefPicList) > 1 )
{
uiBitsTemp += iRefIdxTemp+1;
if ( iRefIdxTemp == pcCU->getSlice()->getNumRefIdx(eRefPicList)-1 )
{
uiBitsTemp--;
}
}
uiBitsTemp += m_auiMVPIdxCost[aaiMvpIdxBi[iRefList][iRefIdxTemp]][AMVP_MAX_NUM_CANDS];
// call ME 运动估计
xMotionEstimation ( pcCU, pcOrgYuv, iPartIdx, eRefPicList, &cMvPredBi[iRefList][iRefIdxTemp], iRefIdxTemp, cMvTemp[iRefList][iRefIdxTemp], uiBitsTemp, uiCostTemp, true );
//找最优MVP
xCopyAMVPInfo(&aacAMVPInfo[iRefList][iRefIdxTemp], pcCU->getCUMvField(eRefPicList)->getAMVPInfo());
xCheckBestMVP(pcCU, eRefPicList, cMvTemp[iRefList][iRefIdxTemp], cMvPredBi[iRefList][iRefIdxTemp], aaiMvpIdxBi[iRefList][iRefIdxTemp], uiBitsTemp, uiCostTemp);
//如果代价更小,且不是第一个子块,则进行运动补偿
if ( uiCostTemp < uiCostBi )
{
bChanged = true;
cMvBi[iRefList] = cMvTemp[iRefList][iRefIdxTemp];
iRefIdxBi[iRefList] = iRefIdxTemp;
uiCostBi = uiCostTemp;
uiMotBits[iRefList] = uiBitsTemp - uiMbBits[2] - uiMotBits[1-iRefList];
uiBits[2] = uiBitsTemp;
if(iNumIter!=1)
{
// Set motion
pcCU->getCUMvField( eRefPicList )->setAllMv( cMvBi[iRefList], ePartSize, uiPartAddr, 0, iPartIdx );
pcCU->getCUMvField( eRefPicList )->setAllRefIdx( iRefIdxBi[iRefList], ePartSize, uiPartAddr, 0, iPartIdx );
TComYuv* pcYuvPred = &m_acYuvPred[iRefList];
motionCompensation( pcCU, pcYuvPred, eRefPicList, iPartIdx );
}
}
} // for loop-iRefIdxTemp
//如果找到更优的代价,则复制AMVP选出最优MVP。
if ( !bChanged )
{
if ( uiCostBi <= uiCost[0] && uiCostBi <= uiCost[1] )
{
xCopyAMVPInfo(&aacAMVPInfo[0][iRefIdxBi[0]], pcCU->getCUMvField(REF_PIC_LIST_0)->getAMVPInfo());
xCheckBestMVP(pcCU, REF_PIC_LIST_0, cMvBi[0], cMvPredBi[0][iRefIdxBi[0]], aaiMvpIdxBi[0][iRefIdxBi[0]], uiBits[2], uiCostBi);
if(!pcCU->getSlice()->getMvdL1ZeroFlag())
{
xCopyAMVPInfo(&aacAMVPInfo[1][iRefIdxBi[1]], pcCU->getCUMvField(REF_PIC_LIST_1)->getAMVPInfo());
xCheckBestMVP(pcCU, REF_PIC_LIST_1, cMvBi[1], cMvPredBi[1][iRefIdxBi[1]], aaiMvpIdxBi[1][iRefIdxBi[1]], uiBits[2], uiCostBi);
}
}
break;
}
} // for loop-iter
} // if (B_SLICE)
#if AMP_MRG
} //end if bTestNormalMC
#endif
//设置MV信息
// Clear Motion Field
pcCU->getCUMvField(REF_PIC_LIST_0)->setAllMvField( TComMvField(), ePartSize, uiPartAddr, 0, iPartIdx );
pcCU->getCUMvField(REF_PIC_LIST_1)->setAllMvField( TComMvField(), ePartSize, uiPartAddr, 0, iPartIdx );
pcCU->getCUMvField(REF_PIC_LIST_0)->setAllMvd ( cMvZero, ePartSize, uiPartAddr, 0, iPartIdx );
pcCU->getCUMvField(REF_PIC_LIST_1)->setAllMvd ( cMvZero, ePartSize, uiPartAddr, 0, iPartIdx );
pcCU->setMVPIdxSubParts( -1, REF_PIC_LIST_0, uiPartAddr, iPartIdx, pcCU->getDepth(uiPartAddr));
pcCU->setMVPNumSubParts( -1, REF_PIC_LIST_0, uiPartAddr, iPartIdx, pcCU->getDepth(uiPartAddr));
pcCU->setMVPIdxSubParts( -1, REF_PIC_LIST_1, uiPartAddr, iPartIdx, pcCU->getDepth(uiPartAddr));
pcCU->setMVPNumSubParts( -1, REF_PIC_LIST_1, uiPartAddr, iPartIdx, pcCU->getDepth(uiPartAddr));
UInt uiMEBits = 0;
// Set Motion Field_
cMv[1] = mvValidList1;
iRefIdx[1] = refIdxValidList1;
uiBits[1] = bitsValidList1;
uiCost[1] = costValidList1;
#if AMP_MRG
//设置MV、MVP、MVD信息
if (bTestNormalMC)
{
#endif
if ( uiCostBi <= uiCost[0] && uiCostBi <= uiCost[1])
{
uiLastMode = 2;
pcCU->getCUMvField(REF_PIC_LIST_0)->setAllMv( cMvBi[0], ePartSize, uiPartAddr, 0, iPartIdx );
pcCU->getCUMvField(REF_PIC_LIST_0)->setAllRefIdx( iRefIdxBi[0], ePartSize, uiPartAddr, 0, iPartIdx );
pcCU->getCUMvField(REF_PIC_LIST_1)->setAllMv( cMvBi[1], ePartSize, uiPartAddr, 0, iPartIdx );
pcCU->getCUMvField(REF_PIC_LIST_1)->setAllRefIdx( iRefIdxBi[1], ePartSize, uiPartAddr, 0, iPartIdx );
//计算并存储MVD
TempMv = cMvBi[0] - cMvPredBi[0][iRefIdxBi[0]];
pcCU->getCUMvField(REF_PIC_LIST_0)->setAllMvd ( TempMv, ePartSize, uiPartAddr, 0, iPartIdx );
TempMv = cMvBi[1] - cMvPredBi[1][iRefIdxBi[1]];
pcCU->getCUMvField(REF_PIC_LIST_1)->setAllMvd ( TempMv, ePartSize, uiPartAddr, 0, iPartIdx );
pcCU->setInterDirSubParts( 3, uiPartAddr, iPartIdx, pcCU->getDepth(0) );
pcCU->setMVPIdxSubParts( aaiMvpIdxBi[0][iRefIdxBi[0]], REF_PIC_LIST_0, uiPartAddr, iPartIdx, pcCU->getDepth(uiPartAddr));
pcCU->setMVPNumSubParts( aaiMvpNum[0][iRefIdxBi[0]], REF_PIC_LIST_0, uiPartAddr, iPartIdx, pcCU->getDepth(uiPartAddr));
pcCU->setMVPIdxSubParts( aaiMvpIdxBi[1][iRefIdxBi[1]], REF_PIC_LIST_1, uiPartAddr, iPartIdx, pcCU->getDepth(uiPartAddr));
pcCU->setMVPNumSubParts( aaiMvpNum[1][iRefIdxBi[1]], REF_PIC_LIST_1, uiPartAddr, iPartIdx, pcCU->getDepth(uiPartAddr));
uiMEBits = uiBits[2];
}
else if ( uiCost[0] <= uiCost[1] )
{
uiLastMode = 0;
pcCU->getCUMvField(REF_PIC_LIST_0)->setAllMv( cMv[0], ePartSize, uiPartAddr, 0, iPartIdx );
pcCU->getCUMvField(REF_PIC_LIST_0)->setAllRefIdx( iRefIdx[0], ePartSize, uiPartAddr, 0, iPartIdx );
TempMv = cMv[0] - cMvPred[0][iRefIdx[0]];
pcCU->getCUMvField(REF_PIC_LIST_0)->setAllMvd ( TempMv, ePartSize, uiPartAddr, 0, iPartIdx );
pcCU->setInterDirSubParts( 1, uiPartAddr, iPartIdx, pcCU->getDepth(0) );
pcCU->setMVPIdxSubParts( aaiMvpIdx[0][iRefIdx[0]], REF_PIC_LIST_0, uiPartAddr, iPartIdx, pcCU->getDepth(uiPartAddr));
pcCU->setMVPNumSubParts( aaiMvpNum[0][iRefIdx[0]], REF_PIC_LIST_0, uiPartAddr, iPartIdx, pcCU->getDepth(uiPartAddr));
uiMEBits = uiBits[0];
}
else
{
uiLastMode = 1;
pcCU->getCUMvField(REF_PIC_LIST_1)->setAllMv( cMv[1], ePartSize, uiPartAddr, 0, iPartIdx );
pcCU->getCUMvField(REF_PIC_LIST_1)->setAllRefIdx( iRefIdx[1], ePartSize, uiPartAddr, 0, iPartIdx );
TempMv = cMv[1] - cMvPred[1][iRefIdx[1]];
pcCU->getCUMvField(REF_PIC_LIST_1)->setAllMvd ( TempMv, ePartSize, uiPartAddr, 0, iPartIdx );
pcCU->setInterDirSubParts( 2, uiPartAddr, iPartIdx, pcCU->getDepth(0) );
pcCU->setMVPIdxSubParts( aaiMvpIdx[1][iRefIdx[1]], REF_PIC_LIST_1, uiPartAddr, iPartIdx, pcCU->getDepth(uiPartAddr));
pcCU->setMVPNumSubParts( aaiMvpNum[1][iRefIdx[1]], REF_PIC_LIST_1, uiPartAddr, iPartIdx, pcCU->getDepth(uiPartAddr));
uiMEBits = uiBits[1];
}
#if AMP_MRG
} // end if bTestNormalMC
#endif
/**********************************************************非2Nx2N块*************************************************************/
//如果不是2Nx2N,即一个CU会被划分为多个PU,则应该计算并合并它们的运动估计代价
if ( pcCU->getPartitionSize( uiPartAddr ) != SIZE_2Nx2N )
{
UInt uiMRGInterDir = 0;
TComMvField cMRGMvField[2];
UInt uiMRGIndex = 0;
UInt uiMEInterDir = 0;
TComMvField cMEMvField[2];
m_pcRdCost->getMotionCost( true, 0, pcCU->getCUTransquantBypass(uiPartAddr) );
#if AMP_MRG
// calculate ME cost
Distortion uiMEError = std::numeric_limits::max();
Distortion uiMECost = std::numeric_limits::max();
if (bTestNormalMC)
{
//xGetInterPredictionError中进行了运动补偿
xGetInterPredictionError( pcCU, pcOrgYuv, iPartIdx, uiMEError, m_pcEncCfg->getUseHADME() );
uiMECost = uiMEError + m_pcRdCost->getCost( uiMEBits );
}
#else
// calculate ME cost
Distortion uiMEError = std::numeric_limits::max();
xGetInterPredictionError( pcCU, pcOrgYuv, iPartIdx, uiMEError, m_pcEncCfg->getUseHADME() );
Distortion uiMECost = uiMEError + m_pcRdCost->getCost( uiMEBits );
#endif
// save ME result.
uiMEInterDir = pcCU->getInterDir( uiPartAddr );
pcCU->getMvField( pcCU, uiPartAddr, REF_PIC_LIST_0, cMEMvField[0] );
pcCU->getMvField( pcCU, uiPartAddr, REF_PIC_LIST_1, cMEMvField[1] );
// find Merge result
Distortion uiMRGCost = std::numeric_limits::max();
//合并估计信息
xMergeEstimation( pcCU, pcOrgYuv, iPartIdx, uiMRGInterDir, cMRGMvField, uiMRGIndex, uiMRGCost, cMvFieldNeighbours, uhInterDirNeighbours, numValidMergeCand);
//设置运动估计的结果
if ( uiMRGCost < uiMECost )
{
// set Merge result
pcCU->setMergeFlagSubParts ( true, uiPartAddr, iPartIdx, pcCU->getDepth( uiPartAddr ) );
pcCU->setMergeIndexSubParts( uiMRGIndex, uiPartAddr, iPartIdx, pcCU->getDepth( uiPartAddr ) );
pcCU->setInterDirSubParts ( uiMRGInterDir, uiPartAddr, iPartIdx, pcCU->getDepth( uiPartAddr ) );
pcCU->getCUMvField( REF_PIC_LIST_0 )->setAllMvField( cMRGMvField[0], ePartSize, uiPartAddr, 0, iPartIdx );
pcCU->getCUMvField( REF_PIC_LIST_1 )->setAllMvField( cMRGMvField[1], ePartSize, uiPartAddr, 0, iPartIdx );
pcCU->getCUMvField(REF_PIC_LIST_0)->setAllMvd ( cMvZero, ePartSize, uiPartAddr, 0, iPartIdx );
pcCU->getCUMvField(REF_PIC_LIST_1)->setAllMvd ( cMvZero, ePartSize, uiPartAddr, 0, iPartIdx );
pcCU->setMVPIdxSubParts( -1, REF_PIC_LIST_0, uiPartAddr, iPartIdx, pcCU->getDepth(uiPartAddr));
pcCU->setMVPNumSubParts( -1, REF_PIC_LIST_0, uiPartAddr, iPartIdx, pcCU->getDepth(uiPartAddr));
pcCU->setMVPIdxSubParts( -1, REF_PIC_LIST_1, uiPartAddr, iPartIdx, pcCU->getDepth(uiPartAddr));
pcCU->setMVPNumSubParts( -1, REF_PIC_LIST_1, uiPartAddr, iPartIdx, pcCU->getDepth(uiPartAddr));
}
else
{
// set ME result
pcCU->setMergeFlagSubParts( false, uiPartAddr, iPartIdx, pcCU->getDepth( uiPartAddr ) );
pcCU->setInterDirSubParts ( uiMEInterDir, uiPartAddr, iPartIdx, pcCU->getDepth( uiPartAddr ) );
pcCU->getCUMvField( REF_PIC_LIST_0 )->setAllMvField( cMEMvField[0], ePartSize, uiPartAddr, 0, iPartIdx );
pcCU->getCUMvField( REF_PIC_LIST_1 )->setAllMvField( cMEMvField[1], ePartSize, uiPartAddr, 0, iPartIdx );
}
}
// MC 运动补偿
motionCompensation ( pcCU, pcPredYuv, REF_PIC_LIST_X, iPartIdx );
} // end of for ( Int iPartIdx = 0; iPartIdx < iNumPart; iPartIdx++ )
//设置加权预测
setWpScalingDistParam( pcCU, -1, REF_PIC_LIST_X );
return;
}