参考:https://blog.csdn.net/nb_vol_1/article/category/6179825/1?

1、源代码:

#if AMP_MRG
Void TEncCu::xCheckRDCostInter( TComDataCU*& rpcBestCU, TComDataCU*& rpcTempCU, PartSize ePartSize DEBUG_STRING_FN_DECLARE(sDebug), Bool bUseMRG)
#else
Void TEncCu::xCheckRDCostInter( TComDataCU*& rpcBestCU, TComDataCU*& rpcTempCU, PartSize ePartSize )
#endif
{
DEBUG_STRING_NEW(sTest)

// 对rpcTempCU进行初始化
UChar uhDepth = rpcTempCU->getDepth( ); rpcTempCU->setDepthSubParts( uhDepth, ); rpcTempCU->setSkipFlagSubParts( false, , uhDepth ); rpcTempCU->setPartSizeSubParts ( ePartSize, , uhDepth );
rpcTempCU->setPredModeSubParts ( MODE_INTER, , uhDepth );
rpcTempCU->setChromaQpAdjSubParts( rpcTempCU->getCUTransquantBypass() ? : m_ChromaQpAdjIdc, , uhDepth ); #if AMP_MRG // 进行Inter整像素搜索
rpcTempCU->setMergeAMP (true);
m_pcPredSearch->predInterSearch ( rpcTempCU, m_ppcOrigYuv[uhDepth], m_ppcPredYuvTemp[uhDepth], m_ppcResiYuvTemp[uhDepth], m_ppcRecoYuvTemp[uhDepth] DEBUG_STRING_PASS_INTO(sTest), false, bUseMRG );
#else
m_pcPredSearch->predInterSearch ( rpcTempCU, m_ppcOrigYuv[uhDepth], m_ppcPredYuvTemp[uhDepth], m_ppcResiYuvTemp[uhDepth], m_ppcRecoYuvTemp[uhDepth] );
#endif #if AMP_MRG
if ( !rpcTempCU->getMergeAMP() )
{
return;
}
#endif

// 计算普通Inter模式残差及RDCost
m_pcPredSearch->encodeResAndCalcRdInterCU( rpcTempCU, m_ppcOrigYuv[uhDepth], m_ppcPredYuvTemp[uhDepth], m_ppcResiYuvTemp[uhDepth], m_ppcResiYuvBest[uhDepth], m_ppcRecoYuvTemp[uhDepth], false DEBUG_STRING_PASS_INTO(sTest) );
// 存储总代价
rpcTempCU->getTotalCost() = m_pcRdCost->calcRdCost( rpcTempCU->getTotalBits(), rpcTempCU->getTotalDistortion() ); #ifdef DEBUG_STRING
DebugInterPredResiReco(sTest, *(m_ppcPredYuvTemp[uhDepth]), *(m_ppcResiYuvBest[uhDepth]), *(m_ppcRecoYuvTemp[uhDepth]), DebugStringGetPredModeMask(rpcTempCU->getPredictionMode()));
#endif

// DeltaQP检测
xCheckDQP( rpcTempCU );
// 检测并设置最优模式
xCheckBestMode(rpcBestCU, rpcTempCU, uhDepth DEBUG_STRING_PASS_INTO(sDebug) DEBUG_STRING_PASS_INTO(sTest));
}

2、PartSize:

/// supported partition shape
/// AMP (SIZE_2NxnU, SIZE_2NxnD, SIZE_nLx2N, SIZE_nRx2N)
enum PartSize
{
SIZE_2Nx2N = , ///< symmetric motion partition, 2Nx2N
SIZE_2NxN = 1, ///< symmetric motion partition, 2Nx N
SIZE_Nx2N = 2, ///< symmetric motion partition, Nx2N
SIZE_NxN = 3, ///< symmetric motion partition, Nx N
SIZE_2NxnU = 4, ///< asymmetric motion partition, 2Nx( N/2) + 2Nx(3N/2)
SIZE_2NxnD = 5, ///< asymmetric motion partition, 2Nx(3N/2) + 2Nx( N/2)
SIZE_nLx2N = 6, ///< asymmetric motion partition, ( N/2)x2N + (3N/2)x2N
SIZE_nRx2N = 7, ///< asymmetric motion partition, (3N/2)x2N + ( N/2)x2N
NUMBER_OF_PART_SIZES = 8
};

3、帧间搜索predInterSearch:

// predInterSearch函数的主要工作是ME(运动估计)和MC(运动补偿)
// 帧间搜索最佳候选
/** search of the best candidate for inter prediction
* \param pcCU
* \param pcOrgYuv
* \param rpcPredYuv
* \param rpcResiYuv
* \param rpcRecoYuv
* \param bUseRes
* \returns Void
*/
#if AMP_MRG
Void TEncSearch::predInterSearch( TComDataCU* pcCU, TComYuv* pcOrgYuv, TComYuv*& rpcPredYuv, TComYuv*& rpcResiYuv, TComYuv*& rpcRecoYuv DEBUG_STRING_FN_DECLARE(sDebug), Bool bUseRes, Bool bUseMRG )
#else
Void TEncSearch::predInterSearch( TComDataCU* pcCU, TComYuv* pcOrgYuv, TComYuv*& rpcPredYuv, TComYuv*& rpcResiYuv, TComYuv*& rpcRecoYuv, Bool bUseRes )
#endif
{
for(UInt i=; i<NUM_REF_PIC_LIST_01; i++)
{
m_acYuvPred[i].clear();
}
m_cYuvPredTemp.clear();
rpcPredYuv->clear(); if ( !bUseRes )
{
rpcResiYuv->clear();
} rpcRecoYuv->clear(); TComMv cMvSrchRngLT; // 左上
TComMv cMvSrchRngRB; // 右下 TComMv cMvZero;
TComMv TempMv; //kolya TComMv cMv[];
TComMv cMvBi[];
TComMv cMvTemp[][]; Int iNumPart = pcCU->getNumPartitions(); // 分块数
Int iNumPredDir = pcCU->getSlice()->isInterP() ? : ; // 预测方向,P帧为1,B帧为2 TComMv cMvPred[][]; // 记录前向参考帧的MV TComMv cMvPredBi[][]; // 记录后向参考帧的MV
Int aaiMvpIdxBi[][]; // 记录后向参考帧的MVP索引 Int aaiMvpIdx[][]; // 记录前向参考帧的MVP索引
Int aaiMvpNum[][]; // 记录MVP的数量 AMVPInfo aacAMVPInfo[][]; // 记录AMVP的信息 Int iRefIdx[]={,}; //If un-initialized, may cause SEGV in bi-directional prediction iterative stage.
Int iRefIdxBi[]; UInt uiPartAddr;
Int iRoiWidth, iRoiHeight; UInt uiMbBits[] = {, , }; UInt uiLastMode = ;
Int iRefStart, iRefEnd; PartSize ePartSize = pcCU->getPartitionSize( ); Int bestBiPRefIdxL1 = ;
Int bestBiPMvpL1 = ;
Distortion biPDistTemp = std::numeric_limits<Distortion>::max(); // 将失真置为最大 #if ZERO_MVD_EST
Int aiZeroMvdMvpIdx[] = {-, -};
Int aiZeroMvdRefIdx[] = {, };
Int iZeroMvdDir = -;
#endif TComMvField cMvFieldNeighbours[MRG_MAX_NUM_CANDS << ]; // double length for mv of both lists 为了双向MV,长度为2倍
UChar uhInterDirNeighbours[MRG_MAX_NUM_CANDS];
Int numValidMergeCand = ;

// 初始化,将所有分块的失真都置为最大
for ( Int iPartIdx = ; iPartIdx < iNumPart; iPartIdx++ )
{
Distortion uiCost[] = { std::numeric_limits<Distortion>::max(), std::numeric_limits<Distortion>::max() };
Distortion uiCostBi = std::numeric_limits<Distortion>::max();
Distortion uiCostTemp; UInt uiBits[];
UInt uiBitsTemp;
#if ZERO_MVD_EST
Distortion uiZeroMvdCost = std::numeric_limits<Distortion>::max();
Distortion uiZeroMvdCostTemp;
UInt uiZeroMvdBitsTemp;
Distortion uiZeroMvdDistTemp = std::numeric_limits<Distortion>::max();
UInt auiZeroMvdBits[];
#endif
Distortion bestBiPDist = std::numeric_limits<Distortion>::max(); Distortion uiCostTempL0[MAX_NUM_REF];
for (Int iNumRef=; iNumRef < MAX_NUM_REF; iNumRef++) // 将各参考图像的失真置为最大
{
uiCostTempL0[iNumRef] = std::numeric_limits<Distortion>::max();
}
UInt uiBitsTempL0[MAX_NUM_REF]; TComMv mvValidList1;
Int refIdxValidList1 = ;
UInt bitsValidList1 = MAX_UINT;
Distortion costValidList1 = std::numeric_limits<Distortion>::max();

// 获取CU块的比特数
xGetBlkBits( ePartSize, pcCU->getSlice()->isInterP(), iPartIdx, uiLastMode, uiMbBits);

// 获取CU的宽、高、起始地址信息
pcCU->getPartIndexAndSize( iPartIdx, uiPartAddr, iRoiWidth, iRoiHeight ); #if AMP_MRG
Bool bTestNormalMC = true; // 指示是否进行正常的MC(ME+MC)

// bUseMRG为真、CU大于8且分块为SIZE_2NxN时,不能进行正常的MC
if ( bUseMRG && pcCU->getWidth( ) > && iNumPart == )
{
bTestNormalMC = false;
}

// 正常MC
if (bTestNormalMC)
{
#endif // Uni-directional prediction
// 建立参考列表,P帧只有一个,B帧有两个
for ( Int iRefList = ; iRefList < iNumPredDir; iRefList++ ) // iRefList为当前参考列表
{
RefPicList eRefPicList = ( iRefList ? REF_PIC_LIST_1 : REF_PIC_LIST_0 ); // 前向后参考列表

// 遍历这个参考列表的所有参考帧
for ( Int iRefIdxTemp = ; iRefIdxTemp < pcCU->getSlice()->getNumRefIdx(eRefPicList); iRefIdxTemp++ ) // iRefIdxTemp为当前参考帧索引
{
uiBitsTemp = uiMbBits[iRefList]; // 存储参考列表的比特数
if ( pcCU->getSlice()->getNumRefIdx(eRefPicList) > ) // 如果参考列表中的帧数大于1,计算所有参考帧的总比特数
{
uiBitsTemp += iRefIdxTemp+;
// 最后一帧比特数减1
if ( iRefIdxTemp == pcCU->getSlice()->getNumRefIdx(eRefPicList)- ) uiBitsTemp--;
}
#if ZERO_MVD_EST
xEstimateMvPredAMVP( pcCU, pcOrgYuv, iPartIdx, eRefPicList, iRefIdxTemp, cMvPred[iRefList][iRefIdxTemp], false, &biPDistTemp, &uiZeroMvdDistTemp);
#else
// 执行AMVP,进行MV预测和AMVP计算
xEstimateMvPredAMVP( pcCU, pcOrgYuv, iPartIdx, eRefPicList, iRefIdxTemp, cMvPred[iRefList][iRefIdxTemp], false, &biPDistTemp);
#endif
aaiMvpIdx[iRefList][iRefIdxTemp] = pcCU->getMVPIdx(eRefPicList, uiPartAddr); // 获取MVP索引
aaiMvpNum[iRefList][iRefIdxTemp] = pcCU->getMVPNum(eRefPicList, uiPartAddr); // 获取MVP数量

// 使用广义帧且失真小于最优失真时,更新最优参数
if(pcCU->getSlice()->getMvdL1ZeroFlag() && iRefList== && biPDistTemp < bestBiPDist)
{
bestBiPDist = biPDistTemp;
bestBiPMvpL1 = aaiMvpIdx[iRefList][iRefIdxTemp];
bestBiPRefIdxL1 = iRefIdxTemp;
} uiBitsTemp += m_auiMVPIdxCost[aaiMvpIdx[iRefList][iRefIdxTemp]][AMVP_MAX_NUM_CANDS]; // 记录比特数
#if ZERO_MVD_EST
if ( iRefList == || pcCU->getSlice()->getList1IdxToList0Idx( iRefIdxTemp ) < )
{
uiZeroMvdBitsTemp = uiBitsTemp;
uiZeroMvdBitsTemp += ; //zero mvd bits m_pcRdCost->getMotionCost( true, , pcCU->getCUTransquantBypass(uiPartAddr) ); uiZeroMvdCostTemp = uiZeroMvdDistTemp + m_pcRdCost->getCost(uiZeroMvdBitsTemp); if (uiZeroMvdCostTemp < uiZeroMvdCost)
{
uiZeroMvdCost = uiZeroMvdCostTemp;
iZeroMvdDir = iRefList + ;
aiZeroMvdRefIdx[iRefList] = iRefIdxTemp;
aiZeroMvdMvpIdx[iRefList] = aaiMvpIdx[iRefList][iRefIdxTemp];
auiZeroMvdBits[iRefList] = uiZeroMvdBitsTemp;
}
}
#endif #if GPB_SIMPLE_UNI
if ( iRefList == ) // list 1(B帧)
{
if ( pcCU->getSlice()->getList1IdxToList0Idx( iRefIdxTemp ) >= ) // 如果使用广义B帧,则list1直接复制list0的信息
{
cMvTemp[][iRefIdxTemp] = cMvTemp[][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[][iRefIdxTemp].getHor(), cMvTemp[][iRefIdxTemp].getVer() );
/*calculate the correct cost*/
uiCostTemp += m_pcRdCost->getCost( uiBitsTemp );
}
else
{
xMotionEstimation ( pcCU, pcOrgYuv, iPartIdx, eRefPicList, &cMvPred[iRefList][iRefIdxTemp], iRefIdxTemp, cMvTemp[iRefList][iRefIdxTemp], uiBitsTemp, uiCostTemp );
}
}
// 不使用广义B帧就直接进行运动估计xMotionEstimation
else
{
xMotionEstimation ( pcCU, pcOrgYuv, iPartIdx, eRefPicList, &cMvPred[iRefList][iRefIdxTemp], iRefIdxTemp, cMvTemp[iRefList][iRefIdxTemp], uiBitsTemp, uiCostTemp );
}
#else
xMotionEstimation ( pcCU, pcOrgYuv, iPartIdx, eRefPicList, &cMvPred[iRefList][iRefIdxTemp], iRefIdxTemp, cMvTemp[iRefList][iRefIdxTemp], uiBitsTemp, uiCostTemp );
#endif
// 将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);

// 更新失真和比特信息
if ( iRefList == )
{
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 == && uiCostTemp < costValidList1 && pcCU->getSlice()->getList1IdxToList0Idx( iRefIdxTemp ) < )
{
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[] = cMv[]; cMvBi[] = cMv[];
iRefIdxBi[] = iRefIdx[]; iRefIdxBi[] = iRefIdx[]; ::memcpy(cMvPredBi, cMvPred, sizeof(cMvPred));
::memcpy(aaiMvpIdxBi, aaiMvpIdx, sizeof(aaiMvpIdx)); UInt uiMotBits[];

// 使用广义B帧,则进行运动补偿motionCompensation
if(pcCU->getSlice()->getMvdL1ZeroFlag())
{
xCopyAMVPInfo(&aacAMVPInfo[][bestBiPRefIdxL1], pcCU->getCUMvField(REF_PIC_LIST_1)->getAMVPInfo());
pcCU->setMVPIdxSubParts( bestBiPMvpL1, REF_PIC_LIST_1, uiPartAddr, iPartIdx, pcCU->getDepth(uiPartAddr));
aaiMvpIdxBi[][bestBiPRefIdxL1] = bestBiPMvpL1;
cMvPredBi[][bestBiPRefIdxL1] = pcCU->getCUMvField(REF_PIC_LIST_1)->getAMVPInfo()->m_acMvCand[bestBiPMvpL1]; cMvBi[] = cMvPredBi[][bestBiPRefIdxL1];
iRefIdxBi[] = bestBiPRefIdxL1;
pcCU->getCUMvField( REF_PIC_LIST_1 )->setAllMv( cMvBi[], ePartSize, uiPartAddr, , iPartIdx );
pcCU->getCUMvField( REF_PIC_LIST_1 )->setAllRefIdx( iRefIdxBi[], ePartSize, uiPartAddr, , iPartIdx );
TComYuv* pcYuvPred = &m_acYuvPred[REF_PIC_LIST_1];
motionCompensation( pcCU, pcYuvPred, REF_PIC_LIST_1, iPartIdx ); uiMotBits[] = uiBits[] - uiMbBits[];
uiMotBits[] = uiMbBits[]; if ( pcCU->getSlice()->getNumRefIdx(REF_PIC_LIST_1) > )
{
uiMotBits[] += bestBiPRefIdxL1+;
if ( bestBiPRefIdxL1 == pcCU->getSlice()->getNumRefIdx(REF_PIC_LIST_1)- ) uiMotBits[]--;
} uiMotBits[] += m_auiMVPIdxCost[aaiMvpIdxBi[][bestBiPRefIdxL1]][AMVP_MAX_NUM_CANDS]; uiBits[] = uiMbBits[] + uiMotBits[] + uiMotBits[]; cMvTemp[][bestBiPRefIdxL1] = cMvBi[];
}
else
{
uiMotBits[] = uiBits[] - uiMbBits[];
uiMotBits[] = uiBits[] - uiMbBits[];
uiBits[] = uiMbBits[] + uiMotBits[] + uiMotBits[];
} // 4-times iteration (default) 默认4次迭代
Int iNumIter = ;

// 如果不使用广义B帧技术,且是第一次迭代,则进行运动补偿
// fast encoder setting: only one iteration
if ( m_pcEncCfg->getUseFastEnc() || pcCU->getSlice()->getMvdL1ZeroFlag())
{
iNumIter = ;
} for ( Int iIter = ; iIter < iNumIter; iIter++ )
{
Int iRefList = iIter % ; if ( m_pcEncCfg->getUseFastEnc() ) // 使用快速编码,则选择代价大的list
{
if( uiCost[] <= uiCost[] )
{
iRefList = ;
}
else
{
iRefList = ;
}
}
else if ( iIter == ) // 如果是整个子块,则选择list0
{
iRefList = ;
}
if ( iIter == && !pcCU->getSlice()->getMvdL1ZeroFlag()) // 如果是第一个子块且list1不为空,进行list0的运动补偿
{
pcCU->getCUMvField(RefPicList(-iRefList))->setAllMv( cMv[-iRefList], ePartSize, uiPartAddr, , iPartIdx );
pcCU->getCUMvField(RefPicList(-iRefList))->setAllRefIdx( iRefIdx[-iRefList], ePartSize, uiPartAddr, , iPartIdx );
TComYuv* pcYuvPred = &m_acYuvPred[-iRefList];
motionCompensation ( pcCU, pcYuvPred, RefPicList(-iRefList), iPartIdx );
} RefPicList eRefPicList = ( iRefList ? REF_PIC_LIST_1 : REF_PIC_LIST_0 ); if(pcCU->getSlice()->getMvdL1ZeroFlag())
{
iRefList = ;
eRefPicList = REF_PIC_LIST_0;
} Bool bChanged = false; iRefStart = ; // 起始参考帧
iRefEnd = pcCU->getSlice()->getNumRefIdx(eRefPicList)-; // 结束参考帧

// 遍历所有参考帧进行运动估计
for ( Int iRefIdxTemp = iRefStart; iRefIdxTemp <= iRefEnd; iRefIdxTemp++ )
{
uiBitsTemp = uiMbBits[] + uiMotBits[-iRefList];
// 更新比特信息
if ( pcCU->getSlice()->getNumRefIdx(eRefPicList) > )
{
uiBitsTemp += iRefIdxTemp+;
if ( iRefIdxTemp == pcCU->getSlice()->getNumRefIdx(eRefPicList)- ) 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[] - uiMotBits[-iRefList];
uiBits[] = uiBitsTemp; if(iNumIter!=)
{
// Set motion
pcCU->getCUMvField( eRefPicList )->setAllMv( cMvBi[iRefList], ePartSize, uiPartAddr, , iPartIdx );
pcCU->getCUMvField( eRefPicList )->setAllRefIdx( iRefIdxBi[iRefList], ePartSize, uiPartAddr, , iPartIdx ); TComYuv* pcYuvPred = &m_acYuvPred[iRefList];
motionCompensation( pcCU, pcYuvPred, eRefPicList, iPartIdx );
}
}
} // for loop-iRefIdxTemp

// 如果找到更优的代价,则复制AMVP选出最优的MVP
if ( !bChanged )
{
if ( uiCostBi <= uiCost[] && uiCostBi <= uiCost[] )
{
xCopyAMVPInfo(&aacAMVPInfo[][iRefIdxBi[]], pcCU->getCUMvField(REF_PIC_LIST_0)->getAMVPInfo());
xCheckBestMVP(pcCU, REF_PIC_LIST_0, cMvBi[], cMvPredBi[][iRefIdxBi[]], aaiMvpIdxBi[][iRefIdxBi[]], uiBits[], uiCostBi);
if(!pcCU->getSlice()->getMvdL1ZeroFlag())
{
xCopyAMVPInfo(&aacAMVPInfo[][iRefIdxBi[]], pcCU->getCUMvField(REF_PIC_LIST_1)->getAMVPInfo());
xCheckBestMVP(pcCU, REF_PIC_LIST_1, cMvBi[], cMvPredBi[][iRefIdxBi[]], aaiMvpIdxBi[][iRefIdxBi[]], uiBits[], uiCostBi);
}
}
break;
}
} // for loop-iter
} // if (B_SLICE)
#if ZERO_MVD_EST
if ( (pcCU->getSlice()->isInterB()) && (pcCU->isBipredRestriction(iPartIdx) == false) )
{
m_pcRdCost->getMotionCost( true, , pcCU->getCUTransquantBypass(uiPartAddr) ); for ( Int iL0RefIdxTemp = ; iL0RefIdxTemp <= pcCU->getSlice()->getNumRefIdx(REF_PIC_LIST_0)-; iL0RefIdxTemp++ )
for ( Int iL1RefIdxTemp = ; iL1RefIdxTemp <= pcCU->getSlice()->getNumRefIdx(REF_PIC_LIST_1)-; iL1RefIdxTemp++ )
{
UInt uiRefIdxBitsTemp = ;
if ( pcCU->getSlice()->getNumRefIdx(REF_PIC_LIST_0) > )
{
uiRefIdxBitsTemp += iL0RefIdxTemp+;
if ( iL0RefIdxTemp == pcCU->getSlice()->getNumRefIdx(REF_PIC_LIST_0)- ) uiRefIdxBitsTemp--;
}
if ( pcCU->getSlice()->getNumRefIdx(REF_PIC_LIST_1) > )
{
uiRefIdxBitsTemp += iL1RefIdxTemp+;
if ( iL1RefIdxTemp == pcCU->getSlice()->getNumRefIdx(REF_PIC_LIST_1)- ) uiRefIdxBitsTemp--;
} Int iL0MVPIdx = ;
Int iL1MVPIdx = ; for (iL0MVPIdx = ; iL0MVPIdx < aaiMvpNum[][iL0RefIdxTemp]; iL0MVPIdx++)
{
for (iL1MVPIdx = ; iL1MVPIdx < aaiMvpNum[][iL1RefIdxTemp]; iL1MVPIdx++)
{
uiZeroMvdBitsTemp = uiRefIdxBitsTemp;
uiZeroMvdBitsTemp += uiMbBits[];
uiZeroMvdBitsTemp += m_auiMVPIdxCost[iL0MVPIdx][aaiMvpNum[][iL0RefIdxTemp]] + m_auiMVPIdxCost[iL1MVPIdx][aaiMvpNum[][iL1RefIdxTemp]];
uiZeroMvdBitsTemp += ; //zero mvd for both directions
pcCU->getCUMvField( REF_PIC_LIST_0 )->setAllMvField( aacAMVPInfo[][iL0RefIdxTemp].m_acMvCand[iL0MVPIdx], iL0RefIdxTemp, ePartSize, uiPartAddr, iPartIdx, );
pcCU->getCUMvField( REF_PIC_LIST_1 )->setAllMvField( aacAMVPInfo[][iL1RefIdxTemp].m_acMvCand[iL1MVPIdx], iL1RefIdxTemp, ePartSize, uiPartAddr, iPartIdx, ); xGetInterPredictionError( pcCU, pcOrgYuv, iPartIdx, uiZeroMvdDistTemp, m_pcEncCfg->getUseHADME() );
uiZeroMvdCostTemp = uiZeroMvdDistTemp + m_pcRdCost->getCost( uiZeroMvdBitsTemp );
if (uiZeroMvdCostTemp < uiZeroMvdCost)
{
uiZeroMvdCost = uiZeroMvdCostTemp;
iZeroMvdDir = ;
aiZeroMvdMvpIdx[] = iL0MVPIdx;
aiZeroMvdMvpIdx[] = iL1MVPIdx;
aiZeroMvdRefIdx[] = iL0RefIdxTemp;
aiZeroMvdRefIdx[] = iL1RefIdxTemp;
auiZeroMvdBits[] = uiZeroMvdBitsTemp;
}
}
}
}
}
#endif #if AMP_MRG
} //end if bTestNormalMC
#endif
// 设置MV信息
// Clear Motion Field
pcCU->getCUMvField(REF_PIC_LIST_0)->setAllMvField( TComMvField(), ePartSize, uiPartAddr, , iPartIdx );
pcCU->getCUMvField(REF_PIC_LIST_1)->setAllMvField( TComMvField(), ePartSize, uiPartAddr, , iPartIdx );
pcCU->getCUMvField(REF_PIC_LIST_0)->setAllMvd ( cMvZero, ePartSize, uiPartAddr, , iPartIdx );
pcCU->getCUMvField(REF_PIC_LIST_1)->setAllMvd ( cMvZero, ePartSize, uiPartAddr, , iPartIdx ); pcCU->setMVPIdxSubParts( -, REF_PIC_LIST_0, uiPartAddr, iPartIdx, pcCU->getDepth(uiPartAddr));
pcCU->setMVPNumSubParts( -, REF_PIC_LIST_0, uiPartAddr, iPartIdx, pcCU->getDepth(uiPartAddr));
pcCU->setMVPIdxSubParts( -, REF_PIC_LIST_1, uiPartAddr, iPartIdx, pcCU->getDepth(uiPartAddr));
pcCU->setMVPNumSubParts( -, REF_PIC_LIST_1, uiPartAddr, iPartIdx, pcCU->getDepth(uiPartAddr)); UInt uiMEBits = ;
// Set Motion Field_
cMv[] = mvValidList1;
iRefIdx[] = refIdxValidList1;
uiBits[] = bitsValidList1;
uiCost[] = costValidList1; #if AMP_MRG
// 设置MV、MVP、MVD信息
if (bTestNormalMC)
{
#endif
#if ZERO_MVD_EST
if (uiZeroMvdCost <= uiCostBi && uiZeroMvdCost <= uiCost[] && uiZeroMvdCost <= uiCost[])
{
if (iZeroMvdDir == )
{
uiLastMode = ; pcCU->getCUMvField(REF_PIC_LIST_0)->setAllMvField( aacAMVPInfo[][aiZeroMvdRefIdx[]].m_acMvCand[aiZeroMvdMvpIdx[]], aiZeroMvdRefIdx[], ePartSize, uiPartAddr, iPartIdx, );
pcCU->getCUMvField(REF_PIC_LIST_1)->setAllMvField( aacAMVPInfo[][aiZeroMvdRefIdx[]].m_acMvCand[aiZeroMvdMvpIdx[]], aiZeroMvdRefIdx[], ePartSize, uiPartAddr, iPartIdx, ); pcCU->setInterDirSubParts( , uiPartAddr, iPartIdx, pcCU->getDepth() ); pcCU->setMVPIdxSubParts( aiZeroMvdMvpIdx[], REF_PIC_LIST_0, uiPartAddr, iPartIdx, pcCU->getDepth(uiPartAddr));
pcCU->setMVPNumSubParts( aaiMvpNum[][aiZeroMvdRefIdx[]], REF_PIC_LIST_0, uiPartAddr, iPartIdx, pcCU->getDepth(uiPartAddr));
pcCU->setMVPIdxSubParts( aiZeroMvdMvpIdx[], REF_PIC_LIST_1, uiPartAddr, iPartIdx, pcCU->getDepth(uiPartAddr));
pcCU->setMVPNumSubParts( aaiMvpNum[][aiZeroMvdRefIdx[]], REF_PIC_LIST_1, uiPartAddr, iPartIdx, pcCU->getDepth(uiPartAddr));
uiMEBits = auiZeroMvdBits[];
}
else if (iZeroMvdDir == )
{
uiLastMode = ; pcCU->getCUMvField(REF_PIC_LIST_0)->setAllMvField( aacAMVPInfo[][aiZeroMvdRefIdx[]].m_acMvCand[aiZeroMvdMvpIdx[]], aiZeroMvdRefIdx[], ePartSize, uiPartAddr, iPartIdx, ); pcCU->setInterDirSubParts( , uiPartAddr, iPartIdx, pcCU->getDepth() ); pcCU->setMVPIdxSubParts( aiZeroMvdMvpIdx[], REF_PIC_LIST_0, uiPartAddr, iPartIdx, pcCU->getDepth(uiPartAddr));
pcCU->setMVPNumSubParts( aaiMvpNum[][aiZeroMvdRefIdx[]], REF_PIC_LIST_0, uiPartAddr, iPartIdx, pcCU->getDepth(uiPartAddr));
uiMEBits = auiZeroMvdBits[];
}
else if (iZeroMvdDir == )
{
uiLastMode = ; pcCU->getCUMvField(REF_PIC_LIST_1)->setAllMvField( aacAMVPInfo[][aiZeroMvdRefIdx[]].m_acMvCand[aiZeroMvdMvpIdx[]], aiZeroMvdRefIdx[], ePartSize, uiPartAddr, iPartIdx, ); pcCU->setInterDirSubParts( , uiPartAddr, iPartIdx, pcCU->getDepth() ); pcCU->setMVPIdxSubParts( aiZeroMvdMvpIdx[], REF_PIC_LIST_1, uiPartAddr, iPartIdx, pcCU->getDepth(uiPartAddr));
pcCU->setMVPNumSubParts( aaiMvpNum[][aiZeroMvdRefIdx[]], REF_PIC_LIST_1, uiPartAddr, iPartIdx, pcCU->getDepth(uiPartAddr));
uiMEBits = auiZeroMvdBits[];
}
else
{
assert();
}
}
else
#endif
if ( uiCostBi <= uiCost[] && uiCostBi <= uiCost[])
{
uiLastMode = ;
pcCU->getCUMvField(REF_PIC_LIST_0)->setAllMv( cMvBi[], ePartSize, uiPartAddr, , iPartIdx );
pcCU->getCUMvField(REF_PIC_LIST_0)->setAllRefIdx( iRefIdxBi[], ePartSize, uiPartAddr, , iPartIdx );
pcCU->getCUMvField(REF_PIC_LIST_1)->setAllMv( cMvBi[], ePartSize, uiPartAddr, , iPartIdx );
pcCU->getCUMvField(REF_PIC_LIST_1)->setAllRefIdx( iRefIdxBi[], ePartSize, uiPartAddr, , iPartIdx );

// 计算并存储MVD
TempMv = cMvBi[] - cMvPredBi[][iRefIdxBi[]];
pcCU->getCUMvField(REF_PIC_LIST_0)->setAllMvd ( TempMv, ePartSize, uiPartAddr, , iPartIdx ); TempMv = cMvBi[] - cMvPredBi[][iRefIdxBi[]];
pcCU->getCUMvField(REF_PIC_LIST_1)->setAllMvd ( TempMv, ePartSize, uiPartAddr, , iPartIdx ); pcCU->setInterDirSubParts( , uiPartAddr, iPartIdx, pcCU->getDepth() ); pcCU->setMVPIdxSubParts( aaiMvpIdxBi[][iRefIdxBi[]], REF_PIC_LIST_0, uiPartAddr, iPartIdx, pcCU->getDepth(uiPartAddr));
pcCU->setMVPNumSubParts( aaiMvpNum[][iRefIdxBi[]], REF_PIC_LIST_0, uiPartAddr, iPartIdx, pcCU->getDepth(uiPartAddr));
pcCU->setMVPIdxSubParts( aaiMvpIdxBi[][iRefIdxBi[]], REF_PIC_LIST_1, uiPartAddr, iPartIdx, pcCU->getDepth(uiPartAddr));
pcCU->setMVPNumSubParts( aaiMvpNum[][iRefIdxBi[]], REF_PIC_LIST_1, uiPartAddr, iPartIdx, pcCU->getDepth(uiPartAddr)); uiMEBits = uiBits[];
}
else if ( uiCost[] <= uiCost[] )
{
uiLastMode = ;
pcCU->getCUMvField(REF_PIC_LIST_0)->setAllMv( cMv[], ePartSize, uiPartAddr, , iPartIdx );
pcCU->getCUMvField(REF_PIC_LIST_0)->setAllRefIdx( iRefIdx[], ePartSize, uiPartAddr, , iPartIdx ); TempMv = cMv[] - cMvPred[][iRefIdx[]];
pcCU->getCUMvField(REF_PIC_LIST_0)->setAllMvd ( TempMv, ePartSize, uiPartAddr, , iPartIdx ); pcCU->setInterDirSubParts( , uiPartAddr, iPartIdx, pcCU->getDepth() ); pcCU->setMVPIdxSubParts( aaiMvpIdx[][iRefIdx[]], REF_PIC_LIST_0, uiPartAddr, iPartIdx, pcCU->getDepth(uiPartAddr));
pcCU->setMVPNumSubParts( aaiMvpNum[][iRefIdx[]], REF_PIC_LIST_0, uiPartAddr, iPartIdx, pcCU->getDepth(uiPartAddr)); uiMEBits = uiBits[];
}
else
{
uiLastMode = ;
pcCU->getCUMvField(REF_PIC_LIST_1)->setAllMv( cMv[], ePartSize, uiPartAddr, , iPartIdx );
pcCU->getCUMvField(REF_PIC_LIST_1)->setAllRefIdx( iRefIdx[], ePartSize, uiPartAddr, , iPartIdx ); TempMv = cMv[] - cMvPred[][iRefIdx[]];
pcCU->getCUMvField(REF_PIC_LIST_1)->setAllMvd ( TempMv, ePartSize, uiPartAddr, , iPartIdx ); pcCU->setInterDirSubParts( , uiPartAddr, iPartIdx, pcCU->getDepth() ); pcCU->setMVPIdxSubParts( aaiMvpIdx[][iRefIdx[]], REF_PIC_LIST_1, uiPartAddr, iPartIdx, pcCU->getDepth(uiPartAddr));
pcCU->setMVPNumSubParts( aaiMvpNum[][iRefIdx[]], REF_PIC_LIST_1, uiPartAddr, iPartIdx, pcCU->getDepth(uiPartAddr)); uiMEBits = uiBits[];
}
#if AMP_MRG
} // end if bTestNormalMC
#endif

// 如果不是2Nx2N,即一个CU会被划分为多个PU,则应该计算并合并它们的运动估计代价
if ( pcCU->getPartitionSize( uiPartAddr ) != SIZE_2Nx2N )
{
UInt uiMRGInterDir = ;
TComMvField cMRGMvField[];
UInt uiMRGIndex = ; UInt uiMEInterDir = ;
TComMvField cMEMvField[]; m_pcRdCost->getMotionCost( true, , pcCU->getCUTransquantBypass(uiPartAddr) ); #if AMP_MRG
// calculate ME cost
Distortion uiMEError = std::numeric_limits<Distortion>::max();
Distortion uiMECost = std::numeric_limits<Distortion>::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<Distortion>::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[] );
pcCU->getMvField( pcCU, uiPartAddr, REF_PIC_LIST_1, cMEMvField[] ); // find Merge result
Distortion uiMRGCost = std::numeric_limits<Distortion>::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[], ePartSize, uiPartAddr, , iPartIdx );
pcCU->getCUMvField( REF_PIC_LIST_1 )->setAllMvField( cMRGMvField[], ePartSize, uiPartAddr, , iPartIdx ); pcCU->getCUMvField(REF_PIC_LIST_0)->setAllMvd ( cMvZero, ePartSize, uiPartAddr, , iPartIdx );
pcCU->getCUMvField(REF_PIC_LIST_1)->setAllMvd ( cMvZero, ePartSize, uiPartAddr, , iPartIdx ); pcCU->setMVPIdxSubParts( -, REF_PIC_LIST_0, uiPartAddr, iPartIdx, pcCU->getDepth(uiPartAddr));
pcCU->setMVPNumSubParts( -, REF_PIC_LIST_0, uiPartAddr, iPartIdx, pcCU->getDepth(uiPartAddr));
pcCU->setMVPIdxSubParts( -, REF_PIC_LIST_1, uiPartAddr, iPartIdx, pcCU->getDepth(uiPartAddr));
pcCU->setMVPNumSubParts( -, 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[], ePartSize, uiPartAddr, , iPartIdx );
pcCU->getCUMvField( REF_PIC_LIST_1 )->setAllMvField( cMEMvField[], ePartSize, uiPartAddr, , iPartIdx );
}
} // MC 运动补偿
motionCompensation ( pcCU, rpcPredYuv, REF_PIC_LIST_X, iPartIdx ); } // end of for ( Int iPartIdx = 0; iPartIdx < iNumPart; iPartIdx++ )

// 设置加权预测
setWpScalingDistParam( pcCU, -, REF_PIC_LIST_X ); return;
}

4、xEstimateMvPredAMVP(AMVP的入口函数,执行AMVP操作):

// AMVP
#if ZERO_MVD_EST
Void TEncSearch::xEstimateMvPredAMVP( TComDataCU* pcCU, TComYuv* pcOrgYuv, UInt uiPartIdx, RefPicList eRefPicList, Int iRefIdx, TComMv& rcMvPred, Bool bFilled, Distortion* puiDistBiP, Distortion* puiDist )
#else
Void TEncSearch::xEstimateMvPredAMVP( TComDataCU* pcCU, TComYuv* pcOrgYuv, UInt uiPartIdx, RefPicList eRefPicList, Int iRefIdx, TComMv& rcMvPred, Bool bFilled, Distortion* puiDistBiP )
#endif
{
AMVPInfo* pcAMVPInfo = pcCU->getCUMvField(eRefPicList)->getAMVPInfo(); TComMv cBestMv;
Int iBestIdx = ;
TComMv cZeroMv;
TComMv cMvPred;
Distortion uiBestCost = std::numeric_limits<Distortion>::max();
UInt uiPartAddr = ;
Int iRoiWidth, iRoiHeight;
Int i;

// 得到此次分割的索引和大小
pcCU->getPartIndexAndSize( uiPartIdx, uiPartAddr, iRoiWidth, iRoiHeight );
// Fill the MV Candidates
// 获取MVP(即预测的MV),MVP存放在pcAMVPInfo中
if (!bFilled)
{
pcCU->fillMvpCand( uiPartIdx, uiPartAddr, eRefPicList, iRefIdx, pcAMVPInfo );
} // initialize Mvp index & Mvp
// 最优MVP的默认索引为0
iBestIdx = ;
// 最优MVP默认是列表第一个
cBestMv = pcAMVPInfo->m_acMvCand[];
#if !ZERO_MVD_EST
// 如果MVP候选列表中MVP的数量是0或者1
if (pcAMVPInfo->iN <= )
{
// 得到了最优的MVP
rcMvPred = cBestMv; pcCU->setMVPIdxSubParts( iBestIdx, eRefPicList, uiPartAddr, uiPartIdx, pcCU->getDepth(uiPartAddr));
pcCU->setMVPNumSubParts( pcAMVPInfo->iN, eRefPicList, uiPartAddr, uiPartIdx, pcCU->getDepth(uiPartAddr));

// 如果参考列表是list1(表示这是B Slice)
if(pcCU->getSlice()->getMvdL1ZeroFlag() && eRefPicList==REF_PIC_LIST_1)
{
(*puiDistBiP) = xGetTemplateCost( pcCU, uiPartIdx, uiPartAddr, pcOrgYuv, &m_cYuvPredTemp, rcMvPred, , AMVP_MAX_NUM_CANDS, eRefPicList, iRefIdx, iRoiWidth, iRoiHeight);
}
return;
}
#endif
// 如果MVP候选列表已经填充完毕,那么直接返回MVP就行了
// 注意:fillMvpCand并不会修改bFilled的值,bFilled的值是函数传进来的
if (bFilled)
{
assert(pcCU->getMVPIdx(eRefPicList,uiPartAddr) >= );
// 选择相应的MVP
rcMvPred = pcAMVPInfo->m_acMvCand[pcCU->getMVPIdx(eRefPicList,uiPartAddr)];
return;
} m_cYuvPredTemp.clear();
#if ZERO_MVD_EST
Distortion uiDist;
#endif
//-- Check Minimum Cost.
// 遍历每一个MVP,选出代价最小的那个
for ( i = ; i < pcAMVPInfo->iN; i++)
{
Distortion uiTmpCost;
#if ZERO_MVD_EST
uiTmpCost = xGetTemplateCost( pcCU, uiPartIdx, uiPartAddr, pcOrgYuv, &m_cYuvPredTemp, pcAMVPInfo->m_acMvCand[i], i, AMVP_MAX_NUM_CANDS, eRefPicList, iRefIdx, iRoiWidth, iRoiHeight, uiDist );
#else
uiTmpCost = xGetTemplateCost( pcCU, uiPartIdx, uiPartAddr, pcOrgYuv, &m_cYuvPredTemp, pcAMVPInfo->m_acMvCand[i], i, AMVP_MAX_NUM_CANDS, eRefPicList, iRefIdx, iRoiWidth, iRoiHeight);
#endif
if ( uiBestCost > uiTmpCost )
{
uiBestCost = uiTmpCost;
cBestMv = pcAMVPInfo->m_acMvCand[i];
iBestIdx = i;
(*puiDistBiP) = uiTmpCost;
#if ZERO_MVD_EST
(*puiDist) = uiDist;
#endif
}
} m_cYuvPredTemp.clear(); // Setting Best MVP
rcMvPred = cBestMv;
pcCU->setMVPIdxSubParts( iBestIdx, eRefPicList, uiPartAddr, uiPartIdx, pcCU->getDepth(uiPartAddr));
pcCU->setMVPNumSubParts( pcAMVPInfo->iN, eRefPicList, uiPartAddr, uiPartIdx, pcCU->getDepth(uiPartAddr));
return;
}

5、xMotionEstimation(运动估计的入口函数,进行运动搜索,找到MV):

Void TEncSearch::xMotionEstimation( TComDataCU* pcCU, TComYuv* pcYuvOrg, Int iPartIdx, RefPicList eRefPicList, TComMv* pcMvPred, Int iRefIdxPred, TComMv& rcMv, UInt& ruiBits, Distortion& ruiCost, Bool bBi  )
{
UInt uiPartAddr;
Int iRoiWidth;
Int iRoiHeight; TComMv cMvHalf, cMvQter; // 定义1/2和1/4精度MV
TComMv cMvSrchRngLT;
TComMv cMvSrchRngRB; TComYuv* pcYuv = pcYuvOrg; // 图像首地址 assert(eRefPicList < MAX_NUM_REF_LIST_ADAPT_SR && iRefIdxPred<Int(MAX_IDX_ADAPT_SR));
m_iSearchRange = m_aaiAdaptSR[eRefPicList][iRefIdxPred]; // 根据参考帧列表类型、参考帧序号自适应设置搜索范围 Int iSrchRng = ( bBi ? m_bipredSearchRange : m_iSearchRange ); // 根据是否是双向预测设置搜索范围
TComPattern tmpPattern;
TComPattern* pcPatternKey = &tmpPattern; // TComPattern是用于访问相邻块/像素的一个工具类,用于获取neighbor的信息 Double fWeight = 1.0; pcCU->getPartIndexAndSize( iPartIdx, uiPartAddr, iRoiWidth, iRoiHeight ); // 获取PU的地址,宽度和高度 if ( bBi ) // B帧
{
TComYuv* pcYuvOther = &m_acYuvPred[-(Int)eRefPicList];
pcYuv = &m_cYuvPredTemp; pcYuvOrg->copyPartToPartYuv( pcYuv, uiPartAddr, iRoiWidth, iRoiHeight ); pcYuv->removeHighFreq( pcYuvOther, uiPartAddr, iRoiWidth, iRoiHeight ); fWeight = 0.5;
} // Search key pattern initialization
// 初始化待搜索的PU的首地址,宽度,高度,跨度,比特深度
pcPatternKey->initPattern( pcYuv->getAddr ( COMPONENT_Y, uiPartAddr ),
iRoiWidth,
iRoiHeight,
pcYuv->getStride(COMPONENT_Y) );

// 获取参考图像首地址和跨度
Pel* piRefY = pcCU->getSlice()->getRefPic( eRefPicList, iRefIdxPred )->getPicYuvRec()->getAddr( COMPONENT_Y, pcCU->getAddr(), pcCU->getZorderIdxInCU() + uiPartAddr );
Int iRefStride = pcCU->getSlice()->getRefPic( eRefPicList, iRefIdxPred )->getPicYuvRec()->getStride(COMPONENT_Y); TComMv cMvPred = *pcMvPred; // 设置运动估计的搜索范围,LeftTop & RightBottom if ( bBi ) xSetSearchRange ( pcCU, rcMv , iSrchRng, cMvSrchRngLT, cMvSrchRngRB );
else xSetSearchRange ( pcCU, cMvPred, iSrchRng, cMvSrchRngLT, cMvSrchRngRB ); m_pcRdCost->getMotionCost( true, , pcCU->getCUTransquantBypass(uiPartAddr) ); // 计算率失真代价 m_pcRdCost->setPredictor ( *pcMvPred ); // 设置预测得到的MV
m_pcRdCost->setCostScale ( ); setWpScalingDistParam( pcCU, iRefIdxPred, eRefPicList ); // 设置跟weighted prediction相关的参数
// Do integer search
// 整像素搜索
if ( !m_iFastSearch || bBi )
{
// 如果是B帧或者不是快速搜索模式,进行常规搜索
xPatternSearch ( pcPatternKey, piRefY, iRefStride, &cMvSrchRngLT, &cMvSrchRngRB, rcMv, ruiCost );
}
else
{
// 进行快速搜索
rcMv = *pcMvPred;
const TComMv *pIntegerMv2Nx2NPred=;
if (pcCU->getPartitionSize() != SIZE_2Nx2N || pcCU->getDepth() != )
{
#if RExt__BACKWARDS_COMPATIBILITY_MOTION_ESTIMATION_R0105
const Profile::Name profileIdc=pcCU->getSlice()->getSPS()->getPTL()->getGeneralPTL()->getProfileIdc(); // TODO: RExt - temporary profile check to ensure backwards compatibility with HM.
if (profileIdc != Profile::MAIN && profileIdc != Profile::MAIN10 && profileIdc != Profile::MAINSTILLPICTURE)
#endif
pIntegerMv2Nx2NPred = &(m_integerMv2Nx2N[eRefPicList][iRefIdxPred]);
}
xPatternSearchFast ( pcCU, pcPatternKey, piRefY, iRefStride, &cMvSrchRngLT, &cMvSrchRngRB, rcMv, ruiCost, pIntegerMv2Nx2NPred );
if (pcCU->getPartitionSize() == SIZE_2Nx2N)
{
m_integerMv2Nx2N[eRefPicList][iRefIdxPred] = rcMv;
}
} m_pcRdCost->getMotionCost( true, , pcCU->getCUTransquantBypass(uiPartAddr) );
m_pcRdCost->setCostScale ( ); const Bool bIsLosslessCoded = pcCU->getCUTransquantBypass(uiPartAddr) != ;
xPatternSearchFracDIF( bIsLosslessCoded, pcPatternKey, piRefY, iRefStride, &rcMv, cMvHalf, cMvQter, ruiCost ,bBi ); // 分像素搜索 m_pcRdCost->setCostScale( );
rcMv <<= ; // 整像素
rcMv += (cMvHalf <<= ); // 1/2像素
rcMv += cMvQter; // 1/4像素,最终MV单位为1/4精度 UInt uiMvBits = m_pcRdCost->getBits( rcMv.getHor(), rcMv.getVer() ); ruiBits += uiMvBits;
ruiCost = (Distortion)( floor( fWeight * ( (Double)ruiCost - (Double)m_pcRdCost->getCost( uiMvBits ) ) ) + (Double)m_pcRdCost->getCost( ruiBits ) );
}

6、motionCompensation(运动补偿的入口函数,进行运动补偿,构造匹配块信息):

Void TComPrediction::motionCompensation ( TComDataCU* pcCU, TComYuv* pcYuvPred, RefPicList eRefPicList, Int iPartIdx )
{
Int iWidth;
Int iHeight;
UInt uiPartAddr;

// 如果PU的索引是有效值,那么直接处理该PU,然后返回
if ( iPartIdx >= )
{
pcCU->getPartIndexAndSize( iPartIdx, uiPartAddr, iWidth, iHeight );
// 有效的参考列表,即明确地标明了使用哪个参考列表,那么就在对应方向上进行单向预测
if ( eRefPicList != REF_PIC_LIST_X )
{
// 先进行插值操作
if( pcCU->getSlice()->getPPS()->getUseWP())
{
xPredInterUni (pcCU, uiPartAddr, iWidth, iHeight, eRefPicList, pcYuvPred, true );
}
else
{
xPredInterUni (pcCU, uiPartAddr, iWidth, iHeight, eRefPicList, pcYuvPred );
}
// 加权预测
if ( pcCU->getSlice()->getPPS()->getUseWP() )
{
xWeightedPredictionUni( pcCU, pcYuvPred, uiPartAddr, iWidth, iHeight, eRefPicList, pcYuvPred );
}
}
// 没有指明明确的参考列表,那么判断PU两个方向上的参考帧是否一样
else
{
// 如果PU的两个参考列表是相同的,即它们的运动是一致的,那么直接使用单向预测
if ( xCheckIdenticalMotion( pcCU, uiPartAddr ) )
{
xPredInterUni (pcCU, uiPartAddr, iWidth, iHeight, REF_PIC_LIST_0, pcYuvPred );
}
// 否则使用双向预测
else
{
xPredInterBi (pcCU, uiPartAddr, iWidth, iHeight, pcYuvPred );
}
}
return;
}

// 否则处理CU下的所有PU
for ( iPartIdx = ; iPartIdx < pcCU->getNumPartitions(); iPartIdx++ )
{
pcCU->getPartIndexAndSize( iPartIdx, uiPartAddr, iWidth, iHeight ); if ( eRefPicList != REF_PIC_LIST_X )
{
if( pcCU->getSlice()->getPPS()->getUseWP())
{
xPredInterUni (pcCU, uiPartAddr, iWidth, iHeight, eRefPicList, pcYuvPred, true );
}
else
{
xPredInterUni (pcCU, uiPartAddr, iWidth, iHeight, eRefPicList, pcYuvPred );
}
if ( pcCU->getSlice()->getPPS()->getUseWP() )
{
xWeightedPredictionUni( pcCU, pcYuvPred, uiPartAddr, iWidth, iHeight, eRefPicList, pcYuvPred );
}
}
else
{
if ( xCheckIdenticalMotion( pcCU, uiPartAddr ) )
{
xPredInterUni (pcCU, uiPartAddr, iWidth, iHeight, REF_PIC_LIST_0, pcYuvPred );
}
else
{
xPredInterBi (pcCU, uiPartAddr, iWidth, iHeight, pcYuvPred );
}
}
}
return;
}

HM16.0之帧间预测——xCheckRDCostInter()函数的更多相关文章

  1. HM16.0之帧间Merge模式——xCheckRDCostMerge2Nx2N

    参考:https://blog.csdn.net/nb_vol_1/article/details/51163625 1.源代码: /** check RD costs for a CU block ...

  2. HM16.0帧内预测重要函数笔记

    Void TEncSearch::estIntraPredQT   亮度块的帧内预测入口函数 Void TComPrediction::initAdiPatternChType 获取参考样本点并滤波 ...

  3. x264代码剖析(十三):核心算法之帧间预測函数x264_mb_analyse_inter_*()

    x264代码剖析(十三):核心算法之帧间预測函数x264_mb_analyse_inter_*() 帧间预測是指利用视频时间域相关性,使用临近已编码图像像素预測当前图像的像素,以达到有效去除视频时域冗 ...

  4. 【HEVC帧间预测论文】P1.9 Coding Tree Depth Estimation for Complexity Reduction of HEVC

    Coding Tree Depth Estimation for Complexity Reduction of HEVC <HEVC标准介绍.HEVC帧间预测论文笔记>系列博客,目录见: ...

  5. 【HEVC帧间预测论文】P1.8 Complexity Control of High Efficiency Video Encoders for Power-Constrained Devices

    参考:Complexity Control of High Efficiency Video Encoders for Power-Constrained Devices <HEVC标准介绍.H ...

  6. 【HEVC帧间预测论文】P1.7 Content Based Hierarchical Fast Coding Unit Decision Algorithm

    Content Based Hierarchical Fast Coding Unit Decision Algorithm For HEVC <HEVC标准介绍.HEVC帧间预测论文笔记> ...

  7. 【HEVC帧间预测论文】P1.6 A Fast HEVC Inter CU Selection Method Based on Pyramid Motion Divergence

    A Fast HEVC Inter CU Selection Method Based on Pyramid Motion Divergence <HEVC标准介绍.HEVC帧间预测论文笔记&g ...

  8. 【HEVC帧间预测论文】P1.5 Fast Coding Unit Size Selection for HEVC based on Bayesian Decision Rule

    Fast Coding Unit Size Selection for HEVC based on Bayesian Decision Rule <HEVC标准介绍.HEVC帧间预测论文笔记&g ...

  9. 【HEVC帧间预测论文】P1.3 Fast Inter-Frame Prediction Algorithm of HEVC Based on Graphic Information

    基于图形信息的HEVC帧间预测快速算法/Fast Inter-Frame Prediction Algorithm of HEVC Based on Graphic Information <H ...

随机推荐

  1. Markdown简洁语法说明

    学于黑马和传智播客联合做的教学项目 感谢 黑马官网 传智播客官网 微信搜索"艺术行者",关注并回复关键词"乐优商城"获取视频和教程资料! b站在线视频 0.前言 ...

  2. 撸了一个 Feign 增强包

    前言 最近准备将公司的一个核心业务系统用 Java 进行重构,大半年没写 Java ,JDK 都更新到 14 了,考虑到稳定性等问题最终还是选择的 JDK11. 在整体架构选型时,由于是一个全新的系统 ...

  3. PHP 标量类型与返回值类型声明

    标量类型声明 默认情况下,所有的PHP文件都处于弱类型校验模式. PHP 7 增加了标量类型声明的特性,标量类型声明有两种模式: 强制模式 (默认) 严格模式 标量类型声明语法格式: declare( ...

  4. PHP str_word_count() 函数

    实例 计算字符串 "Hello World!" 中的单词数: <?php高佣联盟 www.cgewang.comecho str_word_count("Hello ...

  5. PHP mysqli_select_db() 函数

    更改连接的默认数据库: 删除数据库 <?php高佣联盟 www.cgewang.com // 假定数据库用户名:root,密码:123456,数据库:RUNOOB $con=mysqli_con ...

  6. loj #6247. 九个太阳 k次单位根 神仙构造 FFT求和原理

    LINK:九个太阳 不可做系列. 构造比较神仙. 考虑FFT的求和原理有 \(\frac{1}{k}\sum_{j=0}^{k-1}(w_k^j)^n=[k|n]\) 带入这道题的式子. 有\(\su ...

  7. 5.29 省选模拟赛 波波老师 SAM 线段树 单调队列 并查集

    LINK:波波老师 LINK:同bzoj 1396 识别子串 不过前者要求线性做法 后者可以log过.实际上前者也被我一个log给水过了. 其实不算很水 我自认跑的很快罢了. 都是求经过一个位置的最短 ...

  8. .Net Core 3.0依赖注入替换 Autofac

    今天早上,喜庆的更新VS2019,终于3.0正式版了呀~ 有小伙伴问了一句Autofac怎么接入,因为Startup.ConfigureServices不能再把返回值改成IServiceProvide ...

  9. canvas小画板--(1)平滑曲线

    功能需求 项目需求:需要实现一个可以自由书写的小画板 简单实现 对于熟悉canvas的同学来说,这个需求很简单,短短几十行代码就能实现: <!doctype html> <html& ...

  10. Pytorch_第五篇_深度学习 (DeepLearning) 基础 [1]---监督学习与无监督学习

    深度学习 (DeepLearning) 基础 [1]---监督学习与无监督学习 Introduce 学习了Pytorch基础之后,在利用Pytorch搭建各种神经网络模型解决问题之前,我们需要了解深度 ...