HM16.0之帧间预测——xCheckRDCostInter()函数
参考: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()函数的更多相关文章
- HM16.0之帧间Merge模式——xCheckRDCostMerge2Nx2N
参考:https://blog.csdn.net/nb_vol_1/article/details/51163625 1.源代码: /** check RD costs for a CU block ...
- HM16.0帧内预测重要函数笔记
Void TEncSearch::estIntraPredQT 亮度块的帧内预测入口函数 Void TComPrediction::initAdiPatternChType 获取参考样本点并滤波 ...
- x264代码剖析(十三):核心算法之帧间预測函数x264_mb_analyse_inter_*()
x264代码剖析(十三):核心算法之帧间预測函数x264_mb_analyse_inter_*() 帧间预測是指利用视频时间域相关性,使用临近已编码图像像素预測当前图像的像素,以达到有效去除视频时域冗 ...
- 【HEVC帧间预测论文】P1.9 Coding Tree Depth Estimation for Complexity Reduction of HEVC
Coding Tree Depth Estimation for Complexity Reduction of HEVC <HEVC标准介绍.HEVC帧间预测论文笔记>系列博客,目录见: ...
- 【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 ...
- 【HEVC帧间预测论文】P1.7 Content Based Hierarchical Fast Coding Unit Decision Algorithm
Content Based Hierarchical Fast Coding Unit Decision Algorithm For HEVC <HEVC标准介绍.HEVC帧间预测论文笔记> ...
- 【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 ...
- 【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 ...
- 【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 ...
随机推荐
- Markdown简洁语法说明
学于黑马和传智播客联合做的教学项目 感谢 黑马官网 传智播客官网 微信搜索"艺术行者",关注并回复关键词"乐优商城"获取视频和教程资料! b站在线视频 0.前言 ...
- 撸了一个 Feign 增强包
前言 最近准备将公司的一个核心业务系统用 Java 进行重构,大半年没写 Java ,JDK 都更新到 14 了,考虑到稳定性等问题最终还是选择的 JDK11. 在整体架构选型时,由于是一个全新的系统 ...
- PHP 标量类型与返回值类型声明
标量类型声明 默认情况下,所有的PHP文件都处于弱类型校验模式. PHP 7 增加了标量类型声明的特性,标量类型声明有两种模式: 强制模式 (默认) 严格模式 标量类型声明语法格式: declare( ...
- PHP str_word_count() 函数
实例 计算字符串 "Hello World!" 中的单词数: <?php高佣联盟 www.cgewang.comecho str_word_count("Hello ...
- PHP mysqli_select_db() 函数
更改连接的默认数据库: 删除数据库 <?php高佣联盟 www.cgewang.com // 假定数据库用户名:root,密码:123456,数据库:RUNOOB $con=mysqli_con ...
- loj #6247. 九个太阳 k次单位根 神仙构造 FFT求和原理
LINK:九个太阳 不可做系列. 构造比较神仙. 考虑FFT的求和原理有 \(\frac{1}{k}\sum_{j=0}^{k-1}(w_k^j)^n=[k|n]\) 带入这道题的式子. 有\(\su ...
- 5.29 省选模拟赛 波波老师 SAM 线段树 单调队列 并查集
LINK:波波老师 LINK:同bzoj 1396 识别子串 不过前者要求线性做法 后者可以log过.实际上前者也被我一个log给水过了. 其实不算很水 我自认跑的很快罢了. 都是求经过一个位置的最短 ...
- .Net Core 3.0依赖注入替换 Autofac
今天早上,喜庆的更新VS2019,终于3.0正式版了呀~ 有小伙伴问了一句Autofac怎么接入,因为Startup.ConfigureServices不能再把返回值改成IServiceProvide ...
- canvas小画板--(1)平滑曲线
功能需求 项目需求:需要实现一个可以自由书写的小画板 简单实现 对于熟悉canvas的同学来说,这个需求很简单,短短几十行代码就能实现: <!doctype html> <html& ...
- Pytorch_第五篇_深度学习 (DeepLearning) 基础 [1]---监督学习与无监督学习
深度学习 (DeepLearning) 基础 [1]---监督学习与无监督学习 Introduce 学习了Pytorch基础之后,在利用Pytorch搭建各种神经网络模型解决问题之前,我们需要了解深度 ...