#if AMP_MRG
Void TEncSearch::predInterSearch( TComDataCU* pcCU, TComYuv* pcOrgYuv, TComYuv*& rpcPredYuv, TComYuv*& rpcResiYuv, TComYuv*& rpcRecoYuv, Bool bUseRes, Bool bUseMRG )
#else
Void TEncSearch::predInterSearch( TComDataCU* pcCU, TComYuv* pcOrgYuv, TComYuv*& rpcPredYuv, TComYuv*& rpcResiYuv, TComYuv*& rpcRecoYuv, Bool bUseRes )
#endif
{
// ---------删除无关代码
// 当前CU下的所有PU,请注意PU是由CU划分得到的!
for ( Int iPartIdx = 0; iPartIdx < iNumPart; iPartIdx++ )
{
// ---------删除无关代码
// 得到某种模式下CU块的比特数
xGetBlkBits( ePartSize, pcCU->getSlice()->isInterP(), iPartIdx, uiLastMode, uiMbBits);
// 得到当前PU的索引和大小
pcCU->getPartIndexAndSize( iPartIdx, uiPartAddr, iRoiWidth, iRoiHeight );
#if AMP_MRG
Bool bTestNormalMC = true;
if ( bUseMRG && pcCU->getWidth( 0 ) > 8 && iNumPart == 2 )
{
bTestNormalMC = false;
}
if (bTestNormalMC)
{
#endif
// Uni-directional prediction
// 遍历两个参考图像列表(如果是P帧,只参考一个列表;如果是B帧,会参考两个列表)
// 过这里就找到了应该使用哪个参考帧以及以及对应的MV
for ( Int iRefList = 0; iRefList < iNumPredDir; iRefList++ )
{
// 选出参考列表
RefPicList eRefPicList = ( iRefList ? REF_PIC_LIST_1 : REF_PIC_LIST_0 );
// 遍历这个参考列表的所有参考帧
for ( Int iRefIdxTemp = 0; iRefIdxTemp < pcCU->getSlice()->getNumRefIdx(eRefPicList); iRefIdxTemp++ )
{
// ---------删除无关代码
// AMVP处理
xEstimateMvPredAMVP( pcCU, pcOrgYuv, iPartIdx, eRefPicList, iRefIdxTemp, cMvPred[iRefList][iRefIdxTemp], false, &biPDistTemp);
// ---------删除无关代码
// 更新最优的参数
// ---------删除无关代码
#if GPB_SIMPLE_UNI // 广义B帧技术GPB,相关细节可以参考http://blog.csdn.net/yangxiao_xiang/article/details/9045777
// list1(只有B帧使用)
if ( iRefList == 1 ) // list 1
{
// 表示广义B帧技术GPB
if ( pcCU->getSlice()->getList1IdxToList0Idx( iRefIdxTemp ) >= 0 )
{
// 对于使用了广义的B帧技术,不再进行运动估计,而是直接计算代价
// ---------删除无关代码
}
// 普通的B帧
else
{
// 运动估计
xMotionEstimation ( pcCU, pcOrgYuv, iPartIdx, eRefPicList, &cMvPred[iRefList][iRefIdxTemp], iRefIdxTemp, cMvTemp[iRefList][iRefIdxTemp], uiBitsTemp, uiCostTemp );
}
}
// list0(P帧或者B帧使用)
else
{
// 直接进行运动估计
xMotionEstimation ( pcCU, pcOrgYuv, iPartIdx, eRefPicList, &cMvPred[iRefList][iRefIdxTemp], iRefIdxTemp, cMvTemp[iRefList][iRefIdxTemp], uiBitsTemp, uiCostTemp );
}
#else // else of GPB_SIMPLE_UNI
// 没有使用广义B帧技术
xMotionEstimation ( pcCU, pcOrgYuv, iPartIdx, eRefPicList, &cMvPred[iRefList][iRefIdxTemp], iRefIdxTemp, cMvTemp[iRefList][iRefIdxTemp], uiBitsTemp, uiCostTemp );
#endif // end of GPB_SIMPLE_UNI
xCopyAMVPInfo(pcCU->getCUMvField(eRefPicList)->getAMVPInfo(), &aacAMVPInfo[iRefList][iRefIdxTemp]); // must always be done ( also when AMVP_MODE = AM_NONE )
// 选择最优的MVP
xCheckBestMVP(pcCU, eRefPicList, cMvTemp[iRefList][iRefIdxTemp], cMvPred[iRefList][iRefIdxTemp], aaiMvpIdx[iRefList][iRefIdxTemp], uiBitsTemp, uiCostTemp);
// ---------删除无关代码
}
}
// Bi-directional prediction
// 如果是B帧,且isBipredRestriction(用来判断当前PU尺寸是否为8,而且划分模式是不是2Nx2N),那么进入
if ( (pcCU->getSlice()->isInterB()) && (pcCU->isBipredRestriction(iPartIdx) == false) )
{
// ---------删除无关代码
// MvdL1ZeroFlag这个东西也是和GPB相关的,那么进行运动补偿
if(pcCU->getSlice()->getMvdL1ZeroFlag())
{
// ---------删除无关代码
// 运动补偿
motionCompensation( pcCU, pcYuvPred, REF_PIC_LIST_1, iPartIdx );
// ---------删除无关代码
}
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)
Int iNumIter = 4;
// fast encoder setting: only one iteration
if ( m_pcEncCfg->getUseFastEnc() || pcCU->getSlice()->getMvdL1ZeroFlag())
{
iNumIter = 1;
}
// 遍历1次或者4次
for ( Int iIter = 0; iIter < iNumIter; iIter++ )
{
Int iRefList = iIter % 2;
if ( m_pcEncCfg->getUseFastEnc() )
{
if( uiCost[0] <= uiCost[1] )
{
iRefList = 1;
}
else
{
iRefList = 0;
}
}
else if ( iIter == 0 )
{
iRefList = 0;
}
// 如果不使用GPB技术,且是第一次迭代,那么进行运动补偿
if ( iIter == 0 && !pcCU->getSlice()->getMvdL1ZeroFlag())
{
// ---------删除无关代码
// 运动补偿
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++ )
{
// ---------删除无关代码
// call ME
// 运动估计
xMotionEstimation ( pcCU, pcOrgYuv, iPartIdx, eRefPicList, &cMvPredBi[iRefList][iRefIdxTemp], iRefIdxTemp, cMvTemp[iRefList][iRefIdxTemp], uiBitsTemp, uiCostTemp, true );
xCopyAMVPInfo(&aacAMVPInfo[iRefList][iRefIdxTemp], pcCU->getCUMvField(eRefPicList)->getAMVPInfo());
// 检查最好的MVP
xCheckBestMVP(pcCU, eRefPicList, cMvTemp[iRefList][iRefIdxTemp], cMvPredBi[iRefList][iRefIdxTemp], aaiMvpIdxBi[iRefList][iRefIdxTemp], uiBitsTemp, uiCostTemp);
// 如果找到了一个代价更小的方式,那么更新
if ( uiCostTemp < uiCostBi )
{
// ---------删除无关代码
}
} // for loop-iRefIdxTemp
if ( !bChanged )
{
// ---------删除无关代码
}
} // for loop-iter
} // if (B_SLICE)
#if AMP_MRG
} //end if bTestNormalMC
#endif
// ---------删除无关代码
#if AMP_MRG
// 这个if里面只是保存了一些MV的信息
if (bTestNormalMC)
{
#endif
// ---------删除无关代码
#if AMP_MRG
} // end if bTestNormalMC
#endif
// 如果分割类型不是2Nx2N,即一个CU会被划分成为多个PU
// 那么应该计算并合并它们的运动估计代价
if ( pcCU->getPartitionSize( uiPartAddr ) != SIZE_2Nx2N )
{
// ---------删除无关代码
#if AMP_MRG
// calculate ME cost
// ---------删除无关代码
if (bTestNormalMC)
{
xGetInterPredictionError( pcCU, pcOrgYuv, iPartIdx, uiMEError, m_pcEncCfg->getUseHADME() );
uiMECost = uiMEError + m_pcRdCost->getCost( uiMEBits );
}
#else
// calculate ME cost
// 计算运动估计的代价
UInt uiMEError = MAX_UINT;
xGetInterPredictionError( pcCU, pcOrgYuv, iPartIdx, uiMEError, m_pcEncCfg->getUseHADME() );
// ---------删除无关代码
#endif
// save ME result.
// ---------删除无关代码
// find Merge result
UInt uiMRGCost = MAX_UINT;
// 合并估计信息
xMergeEstimation( pcCU, pcOrgYuv, iPartIdx, uiMRGInterDir, cMRGMvField, uiMRGIndex, uiMRGCost, cMvFieldNeighbours, uhInterDirNeighbours, numValidMergeCand);
// 设置运动估计的结果
if ( uiMRGCost < uiMECost )
{
// set Merge result
// ---------删除无关代码
}
else
{
// set ME result
// ---------删除无关代码
}
}
// MC
// 运动补偿
motionCompensation ( pcCU, rpcPredYuv, REF_PIC_LIST_X, iPartIdx );
} // end of for ( Int iPartIdx = 0; iPartIdx < iNumPart; iPartIdx++ )
setWpScalingDistParam( pcCU, -1, REF_PIC_LIST_X );
return;
}