predInterSearch主要的工作是ME(运动估计)和MC(运动补偿)。
函数中有一个bTestNormalMC变量,它表示是否进行正常的MC过程,正常的MC过程就是进行ME再进行MC。
正常的MC流程是,遍历所有的参考帧,进行ME(运动估计:xEstimateMvPredAMVP和xMotionEstimation),然后记录AVP或者MV的信息,进行MC(运动补偿,目的是选出最优的参数),然后更新最优的参数,遍历完所有的参考帧之后,就选出了最优的参数了;然后循环结束,接着进行正式的MC(运动补偿)。
TEncSearch::predInterSearch的详解:
(1)定义若干变量,注意AMVPInfo和TComMv等信息,它保存者运动信息
(2)遍历当前CU被分成的若干个PU
1)一个帧最多可以参考16个其他的帧
2)调用xGetBlkBits,计算CU在ePartSize模式下所需要消耗的比特数
3)计算当前PU的索引和大小
4)遍历两个参考图像列表(list0和list1)
a)遍历当前帧的所有参考帧:
①调用xEstimateMvPredAMVP,进行MV预测和AMVP的计算
②记录这个参考帧计算出来的MVP索引,数量等信息
③更新最优的参数
④计算比特数
⑤如果使用了list1(即B帧)
Ⅰ)如果list0和list1之间有映射(即这个帧同时出现在list0和list1中),那么直接把在list0中的计算信息复制过来就行了。
Ⅱ)如果没有映射,那么调用xMotionEstimation进行运动估计。
⑥如果对于使用list0的帧(P帧和B帧),调用xMotionEstimation进行运动估计。
⑦复制AMVP信息
⑧选择最优的MVP
⑨设置各种计算出来的运动信息
5)如果当前帧是B帧
a)并且list1是空的(getMvdL1ZeroFlag标志为真),那么调用motionCompensation进行运动补偿运算
b)对当前CU的4个子CU进行遍历计算:
①如果是第一个子CU,并且getMvdL1ZeroFlag为false,那么调用motionCompensation进行运动补偿计算
②遍历当前帧的所有参考帧:
Ⅰ)调用xMotionEstimation,进行运动估计
Ⅱ)调用xCopyAMVPInfo复制AMVP信息,调用xCheckBestMVP选择最好的MVP
Ⅲ)如果找到了更优的方式,那么更新信息,并且如果不是第一个子CU的话,还需要调用motionCompensation进行运动补偿
③如果没有选择出更优的代价,那么复制AMVP信息,选择最优的MVP等
6)设置各种MV的信息
7)同样,还是设置各种MVP以及MV的信息
8)对于分割类型不是2Nx2N(即当前CU没有划分)
a)调用xGetInterPredictionError进行运动补偿(该函数内部实质是调用motionCompensation)
b)调用xMergeEstimation,合并估计信息
9)调用motionCompensation进行运动补偿计算
(3)调用setWpScalingDistParam,设置wp(加权预测)参数
//! search of the best candidate for inter prediction
#if AMP_MRG
#if NH_3D_FAST_TEXTURE_ENCODING
Void TEncSearch::predInterSearch( TComDataCU* pcCU, TComYuv* pcOrgYuv, TComYuv* pcPredYuv, TComYuv* pcResiYuv, TComYuv* pcRecoYuv DEBUG_STRING_FN_DECLARE(sDebug), Bool bFMD, Bool bUseRes, Bool bUseMRG )
#else
Void TEncSearch::predInterSearch( TComDataCU* pcCU, TComYuv* pcOrgYuv, TComYuv* pcPredYuv, TComYuv* pcResiYuv, TComYuv* pcRecoYuv DEBUG_STRING_FN_DECLARE(sDebug), Bool bUseRes, Bool bUseMRG )
#endif
#else
Void TEncSearch::predInterSearch( TComDataCU* pcCU, TComYuv* pcOrgYuv, TComYuv* pcPredYuv, TComYuv* pcResiYuv, TComYuv* pcRecoYuv, Bool bUseRes )
#endif
{
#if NH_MV
D_PRINT_INC_INDENT(g_traceModeCheck, "predInterSearch");
#endif
for(UInt i=0; i<NUM_REF_PIC_LIST_01; i++)
{
m_acYuvPred[i].clear();
}
m_cYuvPredTemp.clear();
pcPredYuv->clear();
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();//PU的个数
Int iNumPredDir = pcCU->getSlice()->isInterP() ? 1 : 2;//预测的方向的个数(B帧有两个,前向和后向;P帧有一个,前向)
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];// 记录每一个帧的MVP的信息
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<Distortion>::max();
#if NH_3D_IV_MERGE
TComMvField cMvFieldNeighbours[MRG_MAX_NUM_CANDS_MEM << 1]; // double length for mv of both lists
UChar uhInterDirNeighbours[MRG_MAX_NUM_CANDS_MEM];
#else
TComMvField cMvFieldNeighbours[MRG_MAX_NUM_CANDS << 1]; // double length for mv of both lists
UChar uhInterDirNeighbours[MRG_MAX_NUM_CANDS];
#endif
Int numValidMergeCand = 0 ;
for ( Int iPartIdx = 0; iPartIdx < iNumPart; iPartIdx++ )// 遍历当前块被分成的各个PU
{
#if NH_MV
D_PRINT_INC_INDENT(g_traceModeCheck, "iPartIdx: " + n2s(iPartIdx) );
#endif
Distortion uiCost[2] = { std::numeric_limits<Distortion>::max(), std::numeric_limits<Distortion>::max() };
Distortion uiCostBi = std::numeric_limits<Distortion>::max();
Distortion uiCostTemp;
UInt uiBits[3];
UInt 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();
}
UInt uiBitsTempL0[MAX_NUM_REF];
TComMv mvValidList1;
Int refIdxValidList1 = 0;
UInt bitsValidList1 = MAX_UINT;
Distortion costValidList1 = std::numeric_limits<Distortion>::max();
xGetBlkBits( ePartSize, pcCU->getSlice()->isInterP(), iPartIdx, uiLastMode, uiMbBits);//计算CU在ePartSize模式下所需要消耗的比特数
pcCU->getPartIndexAndSize( iPartIdx, uiPartAddr, iRoiWidth, iRoiHeight );// 得到当前PU的索引和大小
#if NH_3D_VSP
pcCU->setVSPFlagSubParts( 0, uiPartAddr, iPartIdx, pcCU->getDepth(uiPartAddr) );
#endif
#if AMP_MRG
Bool bTestNormalMC = true;//bTestNormalMC表示是否进行正常的MC过程,正常的MC过程就是进行ME再进行MC
#if NH_3D_FAST_TEXTURE_ENCODING
if (bFMD||( bUseMRG && pcCU->getWidth( 0 ) > 8 && iNumPart == 2 ))
#else
if ( bUseMRG && pcCU->getWidth( 0 ) > 8 && iNumPart == 2 )
#endif
{
bTestNormalMC = false;
}
if (bTestNormalMC)
{
#endif
// Uni-directional prediction
for ( Int iRefList = 0; iRefList < iNumPredDir; iRefList++ )// 遍历两个参考图像列表(如果是P帧,只参考一个列表;如果是B帧,会参考两个列表)
{
#if NH_MV
D_PRINT_INC_INDENT(g_traceModeCheck, "iRefList: " + n2s(iRefList) );
#endif
RefPicList eRefPicList = ( iRefList ? REF_PIC_LIST_1 : REF_PIC_LIST_0 ); // 选出参考列表
for ( Int iRefIdxTemp = 0; iRefIdxTemp < pcCU->getSlice()->getNumRefIdx(eRefPicList); iRefIdxTemp++ )// 遍历这个参考列表的所有参考帧
{
#if NH_MV
D_PRINT_INC_INDENT(g_traceModeCheck, "iRefIdxTemp: " + n2s(iRefIdxTemp) );
#endif
uiBitsTemp = uiMbBits