predInterSearch函数主要是由xCheckRDCostInter调用来获取帧间常规AMVP模式和Affine AMVP模式的最优运动信息和预测值。
首先判断是否检查Affine AMVP模式和常规AMVP模式,如下代码所述,其中checkAffine为真表示检查Affine AMVP模式,checkNonAffine为真表示检查常规AMVP模式。
其中 pu.cu->imv表示MVD精度,在VVC中,采用采用自适应运动矢量精度方法AMVR编码MVD
bool checkAffine = (pu.cu->imv == 0 || pu.cu->slice->getSPS()->getAffineAmvrEnabledFlag()) && pu.cu->imv != IMV_HPEL;
bool checkNonAffine = pu.cu->imv == 0 || pu.cu->imv == IMV_HPEL || (pu.cu->slice->getSPS()->getAMVREnabledFlag() &&
pu.cu->imv <= (pu.cu->slice->getSPS()->getAMVREnabledFlag() ? IMV_4PEL : 0));
CodingUnit *bestCU = pu.cu->cs->bestCS != nullptr ? pu.cu->cs->bestCS->getCU( CHANNEL_TYPE_LUMA ) : nullptr;
bool trySmvd = ( bestCU != nullptr && pu.cu->imv == 2 && checkAffine ) ? ( !bestCU->firstPU->mergeFlag && !bestCU->affine ) : true;
if ( pu.cu->imv && bestCU != nullptr && checkAffine )
{
checkAffine = !( bestCU->firstPU->mergeFlag || !bestCU->affine );
}
if ( pu.cu->imv == 2 && checkNonAffine && pu.cu->slice->getSPS()->getAffineAmvrEnabledFlag() )
{
checkNonAffine = m_affineMotion.hevcCost[1] < m_affineMotion.hevcCost[0] * 1.06f;
}
整个函数的流程如下:
一、检查常规AMVP模式
常规AMVP模式原理参考:高级运动矢量预测(Advanced Motion Vector Prediction)
对于常规AMVP模式,检查步骤如下:
- 首先检查单向预测模式:对前向参考帧列表L0和后向参考帧列表L1中的所有参考帧进行遍历,分别进行AMVP,选出最佳预测MV(MVP),之后在最佳MVP基础上调用xMotionEstimation函数进行运动估计选出最佳MV,并记录单向预测中最佳的运动信息及RD Cost
- 检查双向预测模式(对于4x4、4x8和8x4PU禁用双向预测):
- 使用单向预测得到的最佳运动信息,进行四次迭代,调用调用xMotionEstimation函数进行运动估计,得到每个参考帧下最优的运动信息(在双向预测进行运动估计前,需要先计算另一个反向参考帧得到的预测块,然后在运动估计中,从原始块减去另一方向的预测块),然后进行四次迭代,分别选出参考帧L0 L1在双向预测时的最佳MV
- 检查对称MVD模式(symmetric MVD):使用之前单向预测和双向预测得到的参考帧L0的最优运动信息,选出最优的MVP,再通过对称运动估计选出最佳MV,如果所得Cost小于之前双向预测模式的Cost,则记录所得最优运动信息及相关代价信息
- 比较单向预测和双向预测模式的Cost,并记录最优模式信息存入在PU中
这里pu.interDir,值为1时表示前向预测,为2时表示后向预测,为3时表示双向预测
其中,对于广义B帧需要做特殊处理,对于广义B帧,可以参考:HEVC参考图像列表(二)之广义B帧技术GPB
int getList1IdxToList0Idx( int list1Idx ) const { return m_list1IdxToList0Idx[list1Idx]; }
int m_list1IdxToList0Idx[MAX_NUM_REF]; //如果该值不是-1,则表示List1和List0对应的参考帧索引指向的是同一个参考帧
二、检查Affine AMVP模式
Affine AMVP模式相关原理参考:仿射运动补偿预测(Affine motion compensated prediction)
对于Affine AMVP模式(CU尺寸宽度和高度均大于8),
检查步骤如下:
- 先检查4参数模型,调用xPredAffineInterSearch函数进行运动估计并计算相关Cost
- 如果四参数模型的Cost小于1.05倍的常规AMVP的Cost,则检查6参数模型
三、进行运动补偿motionCompensation得到预测值
四、设置加权预测的参数
代码及注释如下:
void InterSearch::predInterSearch(CodingUnit& cu, Partitioner& partitioner)
{
CodingStructure& cs = *cu.cs;
AMVPInfo amvp[2]; //AMVP候选列表,前向列表或者后向列表 存储一帧经过ME后的最优amvp信息。AMVP选择的运动信息为ME起始点
Mv cMvSrchRngLT;
Mv cMvSrchRngRB;
Mv cMvZero;
Mv cMv[2];//两个单向预测的最优mv(运动估计得到)
Mv cMvBi[2];//双向预测的最优mv
Mv cMvTemp[2][33];
Mv cMvHevcTemp[2][33];//从cMvTemp复制
int iNumPredDir = cs.slice->isInterP() ? 1 : 2; // 参考帧数目
Mv cMvPred[2][33]; //存储AMVP得到的最优mvp
Mv cMvPredBi[2][33];//双向预测时,ME的起点mv
int aaiMvpIdxBi[2][33];
int aaiMvpIdx[2][33];//2表示前向后向预测,33表示L0、L1参考列表中最多33帧
int aaiMvpNum[2][33];//AMVP后得到的最优MvpIdx和MvpNum
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] = { -1, -1 };
uint32_t uiMbBits[3] = {1, 1, 0};
uint32_t uiLastMode = 0;
uint32_t uiLastModeTemp = 0;
int iRefStart, iRefEnd;
int symMode = 0;
int bestBiPRefIdxL1 = 0;
int bestBiPMvpL1 = 0;
Distortion biPDistTemp = std::numeric_limits<Distortion>::max();
uint8_t bcwIdx = (cu.cs->slice->isInterB() ? cu.BcwIdx : BCW_DEFAULT);
bool enforceBcwPred = false;
MergeCtx mergeCtx;
// Loop over Prediction Units
CHECK(!cu.firstPU, "CU does not contain any PUs");
uint32_t puIdx = 0;
auto &pu = *cu.firstPU;//xCheckRDCostInter函数中添加的pu
WPScalingParam *wp0;
WPScalingParam *wp1;
int tryBipred = 0;
bool checkAffine = (pu.cu->imv == 0 || pu.cu->slice->getSPS()->getAffineAmvrEnabledFlag()) && pu.cu->imv != IMV_HPEL;
bool checkNonAffine = pu.cu->imv == 0 || pu.cu->imv == IMV_HPEL || (pu.cu->slice->getSPS()->getAMVREnabledFlag() &&
pu.cu->imv <= (pu.cu->slice->getSPS()->getAMVREnabledFlag() ? IMV_4PEL : 0));
CodingUnit *bestCU = pu.cu->cs->bestCS != nullptr ? pu.cu->cs->bestCS->getCU( CHANNEL_TYPE_LUMA ) : nullptr;
bool trySmvd = ( bestCU != nullptr && pu.cu->imv == 2 && checkAffine ) ? ( !bestCU->firstPU->mergeFlag && !bestCU->affine ) : true;
if ( pu.cu->imv && bestCU != nullptr && checkAffine )
{
checkAffine = !( bestCU->firstPU->mergeFlag || !bestCU->affine );
}
if ( pu.cu->imv == 2 && checkNonAffine && pu.cu->slice->getSPS()->getAffineAmvrEnabledFlag() )
{
checkNonAffine = m_affineMotion.hevcCost[1] < m_affineMotion.hevcCost[0] * 1.06f;
}
{
if (pu.cu->cs->bestParent != nullptr && pu.cu->cs->bestParent->getCU(CHANNEL_TYPE_LUMA) != nullptr && pu.cu->cs->bestParent->getCU(CHANNEL_TYPE_LUMA)->affine == false)
{
m_skipPROF = true;
}
m_encOnly = true;
// motion estimation only evaluates luma component 运动估计只计算luma分量
m_maxCompIDToPred = MAX_NUM_COMPONENT;
// m_maxCompIDToPred = COMPONENT_Y;
CHECK(pu.cu != &cu, "PU is contained in another CU");
if (cu.cs->sps->getSbTMVPEnabledFlag())
{
Size bufSize = g_miScaling.scale(pu.lumaSize());
mergeCtx.subPuMvpMiBuf = MotionBuf(m_SubPuMiBuf, bufSize);
}
PU::spanMotionInfo( pu );
Distortion uiHevcCost = std::numeric_limits<Distortion>::max();
Distortion uiAffineCost = std::numeric_limits<Distortion>::max();
Distortion uiCost[2] = { std::numeric_limits<Distortion>::max(), std::numeric_limits<Distortion>::max() };
Distortion uiCostBi = std::numeric_limits<Distortion>::max();
Distortion uiCostTemp;
uint32_t uiBits[3];
uint32_t uiBitsTemp;
Distortion bestBiPDist = std::numeric_limits<Distortion>::max();
Distortion uiCostTempL0[MAX_NUM_REF];
for (int iNumRef=0; iNumRef < MAX_NUM_REF; iNumRef++)
{
uiCostTempL0[iNumRef] = std::numeric_limits<Distortion>::max();//失真都设为最大值
}
uint32_t uiBitsTempL0[MAX_NUM_REF];
Mv mvValidList1;
int refIdxValidList1 = 0;
uint32_t bitsValidList1 = MAX_UINT;
Distortion costValidList1 = std::numeric_limits<Distortion>::max();
PelUnitBuf origBuf = pu.cs->getOrgBuf( pu ); //原始像素
xGetBlkBits( cs.slice->isInterP(), puIdx, uiLastMode, uiMbBits );
m_pcRdCost->selectMotionLambda( );
unsigned imvShift = pu.cu->imv == IMV_HPEL ? 1 : (pu.cu->imv << 1);
if ( checkNonAffine ) //常规AMVP模式
{
/*=========================单向预测================================*/
// Uni-directional prediction 单向预测,遍历参考帧列表(前向和后向)
for ( int iRefList = 0; iRefList < iNumPredDir; iRefList++ )
{
RefPicList eRefPicList = ( iRefList ? REF_PIC_LIST_1 : REF_PIC_LIST_0 ); //前向列表或者后向列表
// 遍历参考帧列表中的参考帧(对于多参考帧来说) 参考帧索引iRefIdxTemp
for (int iRefIdxTemp = 0; iRefIdxTemp < cs.slice->getNumRefIdx(eRefPicList); iRefIdxTemp++)
{
uiBitsTemp = uiMbBits[iRefList];
if ( cs.slice->getNumRefIdx(eRefPicList) > 1 ) //多参考帧
{
uiBitsTemp += iRefIdxTemp+1;
if ( iRefIdxTemp == cs.slice->getNumRefIdx(eRefPicList)-1 )
{
uiBitsTemp--;
}
}
// AMVP,选出最佳MVP,作为ME起点
xEstimateMvPredAMVP( pu, origBuf, eRefPicList, iRefIdxTemp, cMvPred[iRefList][iRefIdxTemp], amvp[eRefPicList], false, &biPDistTemp);
aaiMvpIdx[iRefList][iRefIdxTemp] = pu.mvpIdx[eRefPicList]; //相应参考列表中的参考帧的最佳MVP索引值
aaiMvpNum[iRefList][iRefIdxTemp] = pu.mvpNum[eRefPicList]; //MVP数目
if(cs.picHeader->getMvdL1ZeroFlag() && iRefList==1 && biPDistTemp < bestBiPDist)//广义B帧时,L1信息直接复制L0
{
bestBiPDist = biPDistTemp;
bestBiPMvpL1 = aaiMvpIdx[iRefList][iRefIdxTemp]; //记录最佳候选MV索引
bestBiPRefIdxL1 = iRefIdxTemp; //记录最佳的参考帧索引
}
uiBitsTemp += m_auiMVPIdxCost[aaiMvpIdx[iRefList][iRefIdxTemp]][AMVP_MAX_NUM_CANDS];
if ( m_pcEncCfg->getFastMEForGenBLowDelayEnabled() && iRefList == 1 ) // list 1
{
if ( cs.slice->getList1IdxToList0Idx( iRefIdxTemp ) >= 0 )//如果使用广义B帧,则list1直接复制list0的信息
{
// 针对参考帧列表L1的快速算法,根据L0的Cost可以估计出L1列表中参考帧的Cost
// 此时,List1的iRefIdxTemp参考帧和List0的iRefIdxTemp参考帧是同一帧(POC相同)
cMvTemp[1][iRefIdxTemp] = cMvTemp[0][cs.slice->getList1IdxToList0Idx( iRefIdxTemp )];
uiCostTemp = uiCostTempL0[cs.slice->getList1IdxToList0Idx( iRefIdxTemp )];
/*first subtract the bit-rate part of the cost of the other list*/
// 首先减去另一个列表成本的比特率部分
uiCostTemp -= m_pcRdCost->getCost( uiBitsTempL0[cs.slice->getList1IdxToList0Idx( iRefIdxTemp )] );
/*correct the bit-rate part of the current ref*/
/*更正当前ref的比特率部分*/
m_pcRdCost->setPredictor ( cMvPred[iRefList][iRefIdxTemp] );
uiBitsTemp += m_pcRdCost->getBitsOfVectorWithPredictor( cMvTemp[1][iRefIdxTemp].getHor(), cMvTemp[1][iRefIdxTemp].getVer(), imvShift + MV_FRACTIONAL_BITS_DIFF );
/*calculate the correct cost 计算正确的成本*/
uiCostTemp += m_pcRdCost->getCost( uiBitsTemp );
}
else
{
// 运动估计
xMotionEstimation( pu, origBuf, eRefPicList, cMvPred[iRefList][iRefIdxTemp], iRefIdxTemp, cMvTemp[iRefList][iRefIdxTemp], aaiMvpIdx[iRefList][iRefIdxTemp], uiBitsTemp, uiCostTemp, amvp[eRefPicList] );
}
}
else
{
// 运动估计
xMotionEstimation( pu, origBuf, eRefPicList, cMvPred[iRefList][iRefIdxTemp], iRefIdxTemp, cMvTemp[iRefList][iRefIdxTemp], aaiMvpIdx[iRefList][iRefIdxTemp], uiBitsTemp, uiCostTemp, amvp[eRefPicList] );
}
if( cu.cs->sps->getUseBcw() && cu.BcwIdx == BCW_DEFAULT && cu.cs->slice->isInterB() )
{
const bool checkIdentical = true;
m_uniMotions.setReadMode(checkIdentical, (uint32_t)iRefList, (uint32_t)iRefIdxTemp);
m_uniMotions.copyFrom(cMvTemp[iRefList][iRefIdxTemp], uiCostTemp - m_pcRdCost->getCost(uiBitsTemp), (uint32_t)iRefList, (uint32_t)iRefIdxTemp);
}
// 保存最优AMVP信息,并检查是否是最优MVP
xCopyAMVPInfo( &amvp[eRefPicList], &aacAMVPInfo[iRefList][iRefIdxTemp]); // must always be done ( also when AMVP_MODE = AM_NONE )
xCheckBestMVP( eRefPicList, cMvTemp[iRefList][iRefIdxTemp], cMvPred[iRefList][iRefIdxTemp], aaiMvpIdx[iRefList][iRefIdxTemp], amvp[eRefPicList], uiBitsTemp, uiCostTemp, pu.cu->imv );
//更新记录最优的运动信息
if ( iRefList == 0 )
{
uiCostTempL0[iRefIdxTemp] = uiCostTemp;
uiBitsTempL0[iRefIdxTemp] = uiBitsTemp;
}
if ( uiCostTemp < uiCost[iRefList] ) //设置单向预测最佳的参考帧和MV信息以及RD Cost
{
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 && cs.slice->getList1IdxToList0Idx( iRefIdxTemp ) < 0 )
{
costValidList1 = uiCostTemp;
bitsValidList1 = uiBitsTemp;
// set motion
mvValidList1 = cMvTemp[iRefList][iRefIdxTemp];
refIdxValidList1 = iRefIdxTemp;
}
}
}// for ( int iRefList = 0; iRefList < iNumPredDir; iRefList++ )
::memcpy(cMvHevcTemp, cMvTemp, sizeof(cMvTemp));
if (cu.imv == 0 && (!cu.slice->getSPS()->getUseBcw() || bcwIdx == BCW_DEFAULT))
{
insertUniMvCands(pu.Y(), cMvTemp);
unsigned idx1, idx2, idx3, idx4;
getAreaIdx(cu.Y(), *cu.slice->getPPS()->pcv, idx1, idx2, idx3, idx4);
::memcpy(&(g_reusedUniMVs[idx1][idx2][idx3][idx4][0][0]), cMvTemp, 2 * 33 * sizeof(Mv));
g_isReusedUniMVsFilled[idx1][idx2][idx3][idx4] = true;
}
/*==========================双向预测========================*/
// Bi-predictive Motion estimation 双向预测运动估计 对于4x4 4x8和8x4PU禁用双向预测
if( ( cs.slice->isInterB() ) && ( PU::isBipredRestriction( pu ) == false )
&& (cu.slice->getCheckLDC() || bcwIdx == BCW_DEFAULT || !m_affineModeSelected || !m_pcEncCfg->getUseBcwFast())
)
{
bool doBiPred = true;
tryBipred = 1;
// 将双向MV初始化为最佳的单向预测MV和单向参考帧
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 ) );
uint32_t uiMotBits[2];
if(cs.picHeader->getMvdL1ZeroFlag()) // L1 MVD设为零标志
{
//L1为空,则使用广义B帧
//广义B帧,需要对后向参考预测块进行运动补偿,在运动补偿之后重新进行运动估计,找到最优MV
xCopyAMVPInfo(&aacAMVPInfo[1][bestBiPRefIdxL1], &amvp[REF_PIC_LIST_1]);
aaiMvpIdxBi[1][bestBiPRefIdxL1] = bestBiPMvpL1;
cMvPredBi [1][bestBiPRefIdxL1] = amvp[REF_PIC_LIST_1].mvCand[bestBiPMvpL1];
cMvBi [1] = cMvPredBi[1][bestBiPRefIdxL1];
iRefIdxBi[1] = bestBiPRefIdxL1;
pu.mv [REF_PIC_LIST_1] = cMvBi[1];
pu.refIdx[REF_PIC_LIST_1] = iRefIdxBi[1];
pu.mvpIdx[REF_PIC_LIST_1] = bestBiPMvpL1;
if( m_pcEncCfg->getMCTSEncConstraint() )
{
Mv restrictedMv = pu.mv[REF_PIC_LIST_1];
Area curTileAreaRestricted;
curTileAreaRestricted = pu.cs->picture->mctsInfo.getTileAreaSubPelRestricted( pu );
MCTSHelper::clipMvToArea( restrictedMv, pu.cu->Y(), curTileAreaRestricted, *pu.cs->sps );
// If sub-pel filter samples are not inside of allowed area
if( restrictedMv != pu.mv[REF_PIC_LIST_1] )
{
uiCostBi = std::numeric_limits<Distortion>::max();
doBiPred = false;
}
}
PelUnitBuf predBufTmp = m_tmpPredStorage[REF_PIC_LIST_1].getBuf( UnitAreaRelative(cu, pu) );
motionCompensation( pu, predBufTmp, REF_PIC_LIST_1 );
uiMotBits[0] = uiBits[0] - uiMbBits[0];
uiMotBits[1] = uiMbBits[1];
if ( cs.slice->getNumRefIdx(REF_PIC_LIST_1) > 1 )
{
uiMotBits[1] += bestBiPRefIdxL1 + 1;
if ( bestBiPRefIdxL1 == cs.slice->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];
}
if( doBiPred ) //进行双向预测
{
// 4-times iteration (default) 默认四次迭代
int iNumIter = 4;
// fast encoder setting: only one iteration 快速算法:仅一次迭代
if ( m_pcEncCfg->getFastInterSearchMode()==FASTINTERSEARCH_MODE1 || m_pcEncCfg->getFastInterSearchMode()==FASTINTERSEARCH_MODE2 || cs.picHeader->getMvdL1ZeroFlag() )
{
iNumIter = 1;
}
enforceBcwPred = (bcwIdx != BCW_DEFAULT); //强制使用BCW
for ( int iIter = 0; iIter < iNumIter; iIter++ )
{
int iRefList = iIter % 2; // 0 1
if ( m_pcEncCfg->getFastInterSearchMode()==FASTINTERSEARCH_MODE1 || m_pcEncCfg->getFastInterSearchMode()==FASTINTERSEARCH_MODE2 )
{
if( uiCost[0] <= uiCost[1] )
{
iRefList = 1;
}
else
{
iRefList = 0;
}
if( bcwIdx != BCW_DEFAULT )
{
iRefList = ( abs( getBcwWeight(bcwIdx, REF_PIC_LIST_0 ) ) > abs( getBcwWeight(bcwIdx, REF_PIC_LIST_1 ) ) ? 1 : 0 );
}
}
else if ( iIter == 0 )
{
iRefList = 0;
}
// 第一次迭代且L1的MVD不为零
if ( iIter == 0 && !cs.picHeader->getMvdL1ZeroFlag())
{
pu.mv [1 - iRefList] = cMv [1 - iRefList];
pu.refIdx[1 - iRefList] = iRefIdx[1 - iRefList];
PelUnitBuf predBufTmp = m_tmpPredStorage[1 - iRefList].getBuf( UnitAreaRelative(cu, pu) );
motionCompensation( pu, predBufTmp, RefPicList(1 - iRefList) );
}
RefPicList eRefPicList = ( iRefList ? REF_PIC_LIST_1 : REF_PIC_LIST_0 );
if(cs.picHeader->getMvdL1ZeroFlag()) // L1的MVD为零
{
iRefList = 0;
eRefPicList = REF_PIC_LIST_0;
}
bool bChanged = false;
iRefStart = 0;
iRefEnd = cs.slice->getNumRefIdx(eRefPicList)-1;//起始参考帧和最后参考帧
// 遍历所有的参考帧
for (int iRefIdxTemp = iRefStart; iRefIdxTemp <= iRefEnd; iRefIdxTemp++)
{
if( m_pcEncCfg->getUseBcwFast() && (bcwIdx != BCW_DEFAULT)
&& (pu.cu->slice->getRefPic(eRefPicList, iRefIdxTemp)->getPOC() == pu.cu->slice->getRefPic(RefPicList(1 - iRefList), pu.refIdx[1 - iRefList])->getPOC())
&& (!pu.cu->imv && pu.cu->slice->getTLayer()>1))
{
continue;
}
uiBitsTemp = uiMbBits[2] + uiMotBits[1-iRefList];
uiBitsTemp += ((cs.slice->getSPS()->getUseBcw() == true) ? getWeightIdxBits(bcwIdx) : 0);
if ( cs.slice->getNumRefIdx(eRefPicList) > 1 )
{
uiBitsTemp += iRefIdxTemp+1;
if ( iRefIdxTemp == cs.slice->getNumRefIdx(eRefPicList)-1 )
{
uiBitsTemp--;
}
}
uiBitsTemp += m_auiMVPIdxCost[aaiMvpIdxBi[iRefList][iRefIdxTemp]][AMVP_MAX_NUM_CANDS];
if ( cs.slice->getBiDirPred() )
{
uiBitsTemp += 1; // add one bit for symmetrical MVD mode
}
// call ME 运动估计
xCopyAMVPInfo(&aacAMVPInfo[iRefList][iRefIdxTemp], &amvp[eRefPicList] );
xMotionEstimation ( pu, origBuf, eRefPicList, cMvPredBi[iRefList][iRefIdxTemp], iRefIdxTemp, cMvTemp[iRefList][iRefIdxTemp], aaiMvpIdxBi[iRefList][iRefIdxTemp], uiBitsTemp, uiCostTemp, amvp[eRefPicList], true );
xCheckBestMVP( eRefPicList, cMvTemp[iRefList][iRefIdxTemp], cMvPredBi[iRefList][iRefIdxTemp], aaiMvpIdxBi[iRefList][iRefIdxTemp], amvp[eRefPicList], uiBitsTemp, uiCostTemp, pu.cu->imv);
if ( uiCostTemp < uiCostBi )
{
bChanged = true;
cMvBi[iRefList] = cMvTemp[iRefList][iRefIdxTemp];
iRefIdxBi[iRefList] = iRefIdxTemp;
uiCostBi = uiCostTemp;
uiMotBits[iRefList] = uiBitsTemp - uiMbBits[2] - uiMotBits[1-iRefList];
uiMotBits[iRefList] -= ((cs.slice->getSPS()->getUseBcw() == true) ? getWeightIdxBits(bcwIdx) : 0);
uiBits[2] = uiBitsTemp;
if(iNumIter!=1)
{
// Set motion
pu.mv [eRefPicList] = cMvBi [iRefList];
pu.refIdx[eRefPicList] = iRefIdxBi[iRefList];
PelUnitBuf predBufTmp = m_tmpPredStorage[iRefList].getBuf( UnitAreaRelative(cu, pu) );
motionCompensation( pu, predBufTmp, eRefPicList );
}
}
} // for loop-iRefIdxTemp
if ( !bChanged )
{
if ((uiCostBi <= uiCost[0] && uiCostBi <= uiCost[1]) || enforceBcwPred)
{
xCopyAMVPInfo(&aacAMVPInfo[0][iRefIdxBi[0]], &amvp[REF_PIC_LIST_0]);
xCheckBestMVP( REF_PIC_LIST_0, cMvBi[0], cMvPredBi[0][iRefIdxBi[0]], aaiMvpIdxBi[0][iRefIdxBi[0]], amvp[REF_PIC_LIST_0], uiBits[2], uiCostBi, pu.cu->imv);
if(!cs.picHeader->getMvdL1ZeroFlag())
{
xCopyAMVPInfo(&aacAMVPInfo[1][iRefIdxBi[1]], &amvp[REF_PIC_LIST_1]);
xCheckBestMVP( REF_PIC_LIST_1, cMvBi[1], cMvPredBi[1][iRefIdxBi[1]], aaiMvpIdxBi[1][iRefIdxBi[1]], amvp[REF_PIC_LIST_1], uiBits[2], uiCostBi, pu.cu->imv);
}
}
break;
}
} // for loop-iter
}
cu.refIdxBi[0] = iRefIdxBi[0];
cu.refIdxBi[1] = iRefIdxBi[1];
/*==================对称MVD模式=====================*/
if ( cs.slice->getBiDirPred() && trySmvd )
{
Distortion symCost;
Mv cMvPredSym[2];
int mvpIdxSym[2];
int curRefList = REF_PIC_LIST_0; //将当前参考帧列表设置为List0
int tarRefList = 1 - curRefList; //目标参考帧列表设置为List1,到时候不需要传List1对应的MVD
RefPicList eCurRefList = (curRefList ? REF_PIC_LIST_1 : REF_PIC_LIST_0);
int refIdxCur = cs.slice->getSymRefIdx( curRefList ); //List-0的参考帧索引
int refIdxTar = cs.slice->getSymRefIdx( tarRefList ); //List-1的参考帧索引
CHECK (refIdxCur==-1 || refIdxTar==-1, "Uninitialized reference index not allowed");
if ( aacAMVPInfo[curRefList][refIdxCur].mvCand[0] == aacAMVPInfo[curRefList][refIdxCur].mvCand[1] )
aacAMVPInfo[curRefList][refIdxCur].numCand = 1;
if ( aacAMVPInfo[tarRefList][refIdxTar].mvCand[0] == aacAMVPInfo[tarRefList][refIdxTar].mvCand[1] )
aacAMVPInfo[tarRefList][refIdxTar].numCand = 1;
MvField cCurMvField, cTarMvField;
Distortion costStart = std::numeric_limits<Distortion>::max();
for ( int i = 0; i < aacAMVPInfo[curRefList][refIdxCur].numCand; i++ )
{
for ( int j = 0; j < aacAMVPInfo[tarRefList][refIdxTar].numCand; j++ )
{
cCurMvField.setMvField( aacAMVPInfo[curRefList][refIdxCur].mvCand[i], refIdxCur );
cTarMvField.setMvField( aacAMVPInfo[tarRefList][refIdxTar].mvCand[j], refIdxTar );
Distortion cost = xGetSymmetricCost( pu, origBuf, eCurRefList, cCurMvField, cTarMvField, bcwIdx );
if ( cost < costStart )
{
costStart = cost;
cMvPredSym[curRefList] = aacAMVPInfo[curRefList][refIdxCur].mvCand[i];
cMvPredSym[tarRefList] = aacAMVPInfo[tarRefList][refIdxTar].mvCand[j];
mvpIdxSym[curRefList] = i;
mvpIdxSym[tarRefList] = j;
}
}
}
cCurMvField.mv = cMvPredSym[curRefList];
cTarMvField.mv = cMvPredSym[tarRefList];
m_pcRdCost->setCostScale(0);
Mv pred = cMvPredSym[curRefList];
pred.changeTransPrecInternal2Amvr(pu.cu->imv);
m_pcRdCost->setPredictor(pred);
Mv mv = cCurMvField.mv;
mv.changeTransPrecInternal2Amvr(pu.cu->imv);
uint32_t bits = m_pcRdCost->getBitsOfVectorWithPredictor(mv.hor, mv.ver, 0);
bits += m_auiMVPIdxCost[mvpIdxSym[curRefList]][AMVP_MAX_NUM_CANDS];
bits += m_auiMVPIdxCost[mvpIdxSym[tarRefList]][AMVP_MAX_NUM_CANDS];
costStart += m_pcRdCost->getCost(bits);
std::vector<Mv> symmvdCands; //对称MVD候选MV列表
auto smmvdCandsGen = [&](Mv mvCand, bool mvPrecAdj) //定义对称MVD添加候选MV函数
{
if (mvPrecAdj && pu.cu->imv)
{
mvCand.roundTransPrecInternal2Amvr(pu.cu->imv);
}
bool toAddMvCand = true;
for (std::vector<Mv>::iterator pos = symmvdCands.begin(); pos != symmvdCands.end(); pos++)
{
if (*pos == mvCand)
{
toAddMvCand = false;
break;
}
}
if (toAddMvCand)
{
symmvdCands.push_back(mvCand);
}
};
smmvdCandsGen(cMvHevcTemp[curRefList][refIdxCur], false);
smmvdCandsGen(cMvTemp[curRefList][refIdxCur], false);
if (iRefIdxBi[curRefList] == refIdxCur)
{
smmvdCandsGen(cMvBi[curRefList], false);
}
for (int i = 0; i < m_uniMvListSize; i++)
{
if ( symmvdCands.size() >= 5 )
break;
BlkUniMvInfo* curMvInfo = m_uniMvList + ((m_uniMvListIdx - 1 - i + m_uniMvListMaxSize) % (m_uniMvListMaxSize));
smmvdCandsGen(curMvInfo->uniMvs[curRefList][refIdxCur], true);
}
for (auto mvStart : symmvdCands) //遍历候选列表,选出最佳的候选MVP
{
bool checked = false; //if it has been checkin in the mvPred.
for (int i = 0; i < aacAMVPInfo[curRefList][refIdxCur].numCand && !checked; i++)
{
checked |= (mvStart == aacAMVPInfo[curRefList][refIdxCur].mvCand[i]);
}
if (checked)
{
continue;
}
Distortion bestCost = costStart;
symmvdCheckBestMvp(pu, origBuf, mvStart, (RefPicList)curRefList, aacAMVPInfo, bcwIdx, cMvPredSym, mvpIdxSym, costStart);
if (costStart < bestCost)
{
cCurMvField.setMvField(mvStart, refIdxCur);
cTarMvField.setMvField(mvStart.getSymmvdMv(cMvPredSym[curRefList], cMvPredSym[tarRefList]), refIdxTar);
}
}
Mv startPtMv = cCurMvField.mv;
Distortion mvpCost = m_pcRdCost->getCost(m_auiMVPIdxCost[mvpIdxSym[curRefList]][AMVP_MAX_NUM_CANDS] + m_auiMVPIdxCost[mvpIdxSym[tarRefList]][AMVP_MAX_NUM_CANDS]);
symCost = costStart - mvpCost;
// ME 对称运动估计
xSymmetricMotionEstimation( pu, origBuf, cMvPredSym[curRefList], cMvPredSym[tarRefList], eCurRefList, cCurMvField, cTarMvField, symCost, bcwIdx );
symCost += mvpCost;
if (startPtMv != cCurMvField.mv)
{ // if ME change MV, run a final check for best MVP.
symmvdCheckBestMvp(pu, origBuf, cCurMvField.mv, (RefPicList)curRefList, aacAMVPInfo, bcwIdx, cMvPredSym, mvpIdxSym, symCost, true);
}
bits = uiMbBits[2];
bits += 1; // add one bit for #symmetrical MVD mode
bits += ((cs.slice->getSPS()->getUseBcw() == true) ? getWeightIdxBits(bcwIdx) : 0);
symCost += m_pcRdCost->getCost(bits);
cTarMvField.setMvField(cCurMvField.mv.getSymmvdMv(cMvPredSym[curRefList], cMvPredSym[tarRefList]), refIdxTar);
if( m_pcEncCfg->getMCTSEncConstraint() )
{
if( !( MCTSHelper::checkMvForMCTSConstraint( pu, cCurMvField.mv ) && MCTSHelper::checkMvForMCTSConstraint( pu, cTarMvField.mv ) ) )
symCost = std::numeric_limits<Distortion>::max();
}
// save results
if ( symCost < uiCostBi )
{
uiCostBi = symCost;
symMode = 1 + curRefList;
cMvBi[curRefList] = cCurMvField.mv;
iRefIdxBi[curRefList] = cCurMvField.refIdx;
aaiMvpIdxBi[curRefList][cCurMvField.refIdx] = mvpIdxSym[curRefList];
cMvPredBi[curRefList][iRefIdxBi[curRefList]] = cMvPredSym[curRefList];
cMvBi[tarRefList] = cTarMvField.mv;
iRefIdxBi[tarRefList] = cTarMvField.refIdx;
aaiMvpIdxBi[tarRefList][cTarMvField.refIdx] = mvpIdxSym[tarRefList];
cMvPredBi[tarRefList][iRefIdxBi[tarRefList]] = cMvPredSym[tarRefList];
}
}
} // if (B_SLICE)
// Clear Motion Field 清空pu中的运动信息
pu.mv [REF_PIC_LIST_0] = Mv();
pu.mv [REF_PIC_LIST_1] = Mv();
pu.mvd [REF_PIC_LIST_0] = cMvZero;
pu.mvd [REF_PIC_LIST_1] = cMvZero;
pu.refIdx[REF_PIC_LIST_0] = NOT_VALID;
pu.refIdx[REF_PIC_LIST_1] = NOT_VALID;
pu.mvpIdx[REF_PIC_LIST_0] = NOT_VALID;
pu.mvpIdx[REF_PIC_LIST_1] = NOT_VALID;
pu.mvpNum[REF_PIC_LIST_0] = NOT_VALID;
pu.mvpNum[REF_PIC_LIST_1] = NOT_VALID;
// Set Motion Field
cMv [1] = mvValidList1;
iRefIdx[1] = refIdxValidList1;
uiBits [1] = bitsValidList1;
uiCost [1] = costValidList1;
if (cu.cs->pps->getWPBiPred() == true && tryBipred && (bcwIdx != BCW_DEFAULT))
{
CHECK(iRefIdxBi[0]<0, "Invalid picture reference index");
CHECK(iRefIdxBi[1]<0, "Invalid picture reference index");
wp0 = cu.cs->slice->getWpScaling(REF_PIC_LIST_0, iRefIdxBi[0]);
wp1 = cu.cs->slice->getWpScaling(REF_PIC_LIST_1, iRefIdxBi[1]);
if (WPScalingParam::isWeighted(wp0) || WPScalingParam::isWeighted(wp1))
{
uiCostBi = MAX_UINT;
enforceBcwPred = false;
}
}
if( enforceBcwPred )
{
uiCost[0] = uiCost[1] = MAX_UINT;
}
uiLastModeTemp = uiLastMode;
if ( uiCostBi <= uiCost[0] && uiCostBi <= uiCost[1]) //双向预测的Cost小于前后单向预测的Cost
{
uiLastMode = 2;
pu.mv [REF_PIC_LIST_0] = cMvBi[0];
pu.mv [REF_PIC_LIST_1] = cMvBi[1];
pu.mvd [REF_PIC_LIST_0] = cMvBi[0] - cMvPredBi[0][iRefIdxBi[0]];
pu.mvd [REF_PIC_LIST_1] = cMvBi[1] - cMvPredBi[1][iRefIdxBi[1]];
pu.refIdx[REF_PIC_LIST_0] = iRefIdxBi[0];
pu.refIdx[REF_PIC_LIST_1] = iRefIdxBi[1];
pu.mvpIdx[REF_PIC_LIST_0] = aaiMvpIdxBi[0][iRefIdxBi[0]];
pu.mvpIdx[REF_PIC_LIST_1] = aaiMvpIdxBi[1][iRefIdxBi[1]];
pu.mvpNum[REF_PIC_LIST_0] = aaiMvpNum[0][iRefIdxBi[0]];
pu.mvpNum[REF_PIC_LIST_1] = aaiMvpNum[1][iRefIdxBi[1]];
pu.interDir = 3;
pu.cu->smvdMode = symMode;
}
else if ( uiCost[0] <= uiCost[1] ) //前向预测的Cost小于后向预测的Cost
{
uiLastMode = 0;
pu.mv [REF_PIC_LIST_0] = cMv[0];
pu.mvd [REF_PIC_LIST_0] = cMv[0] - cMvPred[0][iRefIdx[0]];
pu.refIdx[REF_PIC_LIST_0] = iRefIdx[0];
pu.mvpIdx[REF_PIC_LIST_0] = aaiMvpIdx[0][iRefIdx[0]];
pu.mvpNum[REF_PIC_LIST_0] = aaiMvpNum[0][iRefIdx[0]];
pu.interDir = 1;
}
else
{
uiLastMode = 1;
pu.mv [REF_PIC_LIST_1] = cMv[1];
pu.mvd [REF_PIC_LIST_1] = cMv[1] - cMvPred[1][iRefIdx[1]];
pu.refIdx[REF_PIC_LIST_1] = iRefIdx[1];
pu.mvpIdx[REF_PIC_LIST_1] = aaiMvpIdx[1][iRefIdx[1]];
pu.mvpNum[REF_PIC_LIST_1] = aaiMvpNum[1][iRefIdx[1]];
pu.interDir = 2;
}
if( bcwIdx != BCW_DEFAULT )
{
cu.BcwIdx = BCW_DEFAULT; // Reset to default for the Non-NormalMC modes.
}
uiHevcCost = ( uiCostBi <= uiCost[0] && uiCostBi <= uiCost[1] ) ? uiCostBi : ( ( uiCost[0] <= uiCost[1] ) ? uiCost[0] : uiCost[1] );
}
if (cu.Y().width > 8 && cu.Y().height > 8 && cu.slice->getSPS()->getUseAffine()
&& checkAffine
&& (bcwIdx == BCW_DEFAULT || m_affineModeSelected || !m_pcEncCfg->getUseBcwFast())
) //Affine AMVP模式
{
m_hevcCost = uiHevcCost;
// save normal hevc result
uint32_t uiMRGIndex = pu.mergeIdx;
bool bMergeFlag = pu.mergeFlag;
uint32_t uiInterDir = pu.interDir;
int iSymMode = cu.smvdMode;
Mv cMvd[2];
uint32_t uiMvpIdx[2], uiMvpNum[2];
uiMvpIdx[0] = pu.mvpIdx[REF_PIC_LIST_0];
uiMvpIdx[1] = pu.mvpIdx[REF_PIC_LIST_1];
uiMvpNum[0] = pu.mvpNum[REF_PIC_LIST_0];
uiMvpNum[1] = pu.mvpNum[REF_PIC_LIST_1];
cMvd[0] = pu.mvd[REF_PIC_LIST_0];
cMvd[1] = pu.mvd[REF_PIC_LIST_1];
MvField cHevcMvField[2];
cHevcMvField[0].setMvField( pu.mv[REF_PIC_LIST_0], pu.refIdx[REF_PIC_LIST_0] );
cHevcMvField[1].setMvField( pu.mv[REF_PIC_LIST_1], pu.refIdx[REF_PIC_LIST_1] );
// do affine ME & Merge
// 先检查4参数
cu.affineType = AFFINEMODEL_4PARAM;
Mv acMvAffine4Para[2][33][3];
int refIdx4Para[2] = { -1, -1 };
xPredAffineInterSearch(pu, origBuf, puIdx, uiLastModeTemp, uiAffineCost, cMvHevcTemp, acMvAffine4Para, refIdx4Para, bcwIdx, enforceBcwPred,
((cu.slice->getSPS()->getUseBcw() == true) ? getWeightIdxBits(bcwIdx) : 0));
if ( pu.cu->imv == 0 )
{
storeAffineMotion( pu.mvAffi, pu.refIdx, AFFINEMODEL_4PARAM, bcwIdx );
}
if ( cu.slice->getSPS()->getUseAffineType() )
{
if ( uiAffineCost < uiHevcCost * 1.05 ) ///< condition for 6 parameter affine ME 如果四参数模型的Cost小于1.05倍的常规AMVP的Cost
{
// save 4 parameter results
Mv bestMv[2][3], bestMvd[2][3];
int bestMvpIdx[2], bestMvpNum[2], bestRefIdx[2];
uint8_t bestInterDir;
bestInterDir = pu.interDir;
bestRefIdx[0] = pu.refIdx[0];
bestRefIdx[1] = pu.refIdx[1];
bestMvpIdx[0] = pu.mvpIdx[0];
bestMvpIdx[1] = pu.mvpIdx[1];
bestMvpNum[0] = pu.mvpNum[0];
bestMvpNum[1] = pu.mvpNum[1];
for ( int refList = 0; refList < 2; refList++ )
{
bestMv[refList][0] = pu.mvAffi[refList][0];
bestMv[refList][1] = pu.mvAffi[refList][1];
bestMv[refList][2] = pu.mvAffi[refList][2];
bestMvd[refList][0] = pu.mvdAffi[refList][0];
bestMvd[refList][1] = pu.mvdAffi[refList][1];
bestMvd[refList][2] = pu.mvdAffi[refList][2];
}
refIdx4Para[0] = bestRefIdx[0];
refIdx4Para[1] = bestRefIdx[1];
// 六参数模型运动估计
Distortion uiAffine6Cost = std::numeric_limits<Distortion>::max();
cu.affineType = AFFINEMODEL_6PARAM;
xPredAffineInterSearch(pu, origBuf, puIdx, uiLastModeTemp, uiAffine6Cost, cMvHevcTemp, acMvAffine4Para, refIdx4Para, bcwIdx, enforceBcwPred,
((cu.slice->getSPS()->getUseBcw() == true) ? getWeightIdxBits(bcwIdx) : 0));
if ( pu.cu->imv == 0 )
{
storeAffineMotion( pu.mvAffi, pu.refIdx, AFFINEMODEL_6PARAM, bcwIdx );
}
// reset to 4 parameter affine inter mode
if ( uiAffineCost <= uiAffine6Cost )
{
cu.affineType = AFFINEMODEL_4PARAM;
pu.interDir = bestInterDir;
pu.refIdx[0] = bestRefIdx[0];
pu.refIdx[1] = bestRefIdx[1];
pu.mvpIdx[0] = bestMvpIdx[0];
pu.mvpIdx[1] = bestMvpIdx[1];
pu.mvpNum[0] = bestMvpNum[0];
pu.mvpNum[1] = bestMvpNum[1];
for ( int verIdx = 0; verIdx < 3; verIdx++ )
{
pu.mvdAffi[REF_PIC_LIST_0][verIdx] = bestMvd[0][verIdx];
pu.mvdAffi[REF_PIC_LIST_1][verIdx] = bestMvd[1][verIdx];
}
PU::setAllAffineMv( pu, bestMv[0][0], bestMv[0][1], bestMv[0][2], REF_PIC_LIST_0);
PU::setAllAffineMv( pu, bestMv[1][0], bestMv[1][1], bestMv[1][2], REF_PIC_LIST_1);
}
else
{
uiAffineCost = uiAffine6Cost;
}
}
uiAffineCost += m_pcRdCost->getCost( 1 ); // add one bit for affine_type
}
if( uiAffineCost < uiHevcCost )
{
if( m_pcEncCfg->getMCTSEncConstraint() && !MCTSHelper::checkMvBufferForMCTSConstraint( pu ) )
{
uiAffineCost = std::numeric_limits<Distortion>::max();
}
}
if ( uiHevcCost <= uiAffineCost )
{
// set hevc me result
cu.affine = false;
pu.mergeFlag = bMergeFlag;
pu.regularMergeFlag = false;
pu.mergeIdx = uiMRGIndex;
pu.interDir = uiInterDir;
cu.smvdMode = iSymMode;
pu.mv [REF_PIC_LIST_0] = cHevcMvField[0].mv;
pu.refIdx[REF_PIC_LIST_0] = cHevcMvField[0].refIdx;
pu.mv [REF_PIC_LIST_1] = cHevcMvField[1].mv;
pu.refIdx[REF_PIC_LIST_1] = cHevcMvField[1].refIdx;
pu.mvpIdx[REF_PIC_LIST_0] = uiMvpIdx[0];
pu.mvpIdx[REF_PIC_LIST_1] = uiMvpIdx[1];
pu.mvpNum[REF_PIC_LIST_0] = uiMvpNum[0];
pu.mvpNum[REF_PIC_LIST_1] = uiMvpNum[1];
pu.mvd[REF_PIC_LIST_0] = cMvd[0];
pu.mvd[REF_PIC_LIST_1] = cMvd[1];
}
else
{
cu.smvdMode = 0;
CHECK( !cu.affine, "Wrong." );
uiLastMode = uiLastModeTemp;
}
}
if( cu.firstPU->interDir == 3 && !cu.firstPU->mergeFlag )
{
if (bcwIdx != BCW_DEFAULT)
{
cu.BcwIdx = bcwIdx;
}
}
m_maxCompIDToPred = MAX_NUM_COMPONENT;
{
PU::spanMotionInfo( pu, mergeCtx );
}
m_skipPROF = false;
m_encOnly = false;
// MC 运动补偿
PelUnitBuf predBuf = pu.cs->getPredBuf(pu);
if ( bcwIdx == BCW_DEFAULT || !m_affineMotion.affine4ParaAvail || !m_affineMotion.affine6ParaAvail )
{
m_affineMotion.hevcCost[pu.cu->imv] = uiHevcCost;
}
motionCompensation( pu, predBuf, REF_PIC_LIST_X );
puIdx++;
}
setWpScalingDistParam( -1, REF_PIC_LIST_X, cu.cs->slice );
return;
}