参考: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( 0 );rpcTempCU->setDepthSubParts( uhDepth, 0 );rpcTempCU->setSkipFlagSubParts( false, 0, uhDepth );rpcTempCU->setPartSizeSubParts  ( ePartSize,  0, uhDepth );rpcTempCU->setPredModeSubParts  ( MODE_INTER, 0, uhDepth );rpcTempCU->setChromaQpAdjSubParts( rpcTempCU->getCUTransquantBypass(0) ? 0 : m_ChromaQpAdjIdc, 0, 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 );
#elsem_pcPredSearch->predInterSearch ( rpcTempCU, m_ppcOrigYuv[uhDepth], m_ppcPredYuvTemp[uhDepth], m_ppcResiYuvTemp[uhDepth], m_ppcRecoYuvTemp[uhDepth] );
#endif#if AMP_MRGif ( !rpcTempCU->getMergeAMP() ){return;}
#endif
  // 计算普通Inter模式残差及RDCostm_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_STRINGDebugInterPredResiReco(sTest, *(m_ppcPredYuvTemp[uhDepth]), *(m_ppcResiYuvBest[uhDepth]), *(m_ppcRecoYuvTemp[uhDepth]), DebugStringGetPredModeMask(rpcTempCU->getPredictionMode(0)));
#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           = 0,           ///< 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=0; 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[2];TComMv       cMvBi[2];TComMv       cMvTemp[2][33];Int          iNumPart    = pcCU->getNumPartitions(); // 分块数Int          iNumPredDir = pcCU->getSlice()->isInterP() ? 1 : 2; // 预测方向,P帧为1,B帧为2TComMv       cMvPred[2][33]; // 记录前向参考帧的MVTComMv       cMvPredBi[2][33]; // 记录后向参考帧的MVInt          aaiMvpIdxBi[2][33]; // 记录后向参考帧的MVP索引Int          aaiMvpIdx[2][33]; // 记录前向参考帧的MVP索引Int          aaiMvpNum[2][33]; // 记录MVP的数量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];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 ZERO_MVD_ESTInt          aiZeroMvdMvpIdx[2] = {-1, -1};Int          aiZeroMvdRefIdx[2] = {0, 0};Int          iZeroMvdDir = -1;
#endifTComMvField cMvFieldNeighbours[MRG_MAX_NUM_CANDS << 1]; // double length for mv of both lists 为了双向MV,长度为2倍
  UChar uhInterDirNeighbours[MRG_MAX_NUM_CANDS];Int numValidMergeCand = 0 ;
  // 初始化,将所有分块的失真都置为最大for ( Int iPartIdx = 0; iPartIdx < iNumPart; iPartIdx++ ){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;
#if ZERO_MVD_ESTDistortion   uiZeroMvdCost = std::numeric_limits<Distortion>::max();Distortion   uiZeroMvdCostTemp;UInt         uiZeroMvdBitsTemp;Distortion   uiZeroMvdDistTemp = std::numeric_limits<Distortion>::max();UInt         auiZeroMvdBits[3];
#endifDistortion   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();
    // 获取CU块的比特数xGetBlkBits( ePartSize, pcCU->getSlice()->isInterP(), iPartIdx, uiLastMode, uiMbBits);    // 获取CU的宽、高、起始地址信息pcCU->getPartIndexAndSize( iPartIdx, uiPartAddr, iRoiWidth, iRoiHeight );#if AMP_MRGBool bTestNormalMC = true; // 指示是否进行正常的MC(ME+MC)    // bUseMRG为真、CU大于8且分块为SIZE_2NxN时,不能进行正常的MCif ( bUseMRG && pcCU->getWidth( 0 ) > 8 && iNumPart == 2 ){bTestNormalMC = false;}
    // 正常MCif (bTestNormalMC){
#endif//  Uni-directional prediction    // 建立参考列表,P帧只有一个,B帧有两个for ( Int iRefList = 0; iRefList < iNumPredDir; iRefList++ ) // iRefList为当前参考列表{RefPicList  eRefPicList = ( iRefList ? REF_PIC_LIST_1 : REF_PIC_LIST_0 ); // 前向后参考列表
// 遍历这个参考列表的所有参考帧 for ( Int iRefIdxTemp = 0; iRefIdxTemp < pcCU->getSlice()->getNumRefIdx(eRefPicList); iRefIdxTemp++ ) // iRefIdxTemp为当前参考帧索引{uiBitsTemp = uiMbBits[iRefList]; // 存储参考列表的比特数if ( pcCU->getSlice()->getNumRefIdx(eRefPicList) > 1 ) // 如果参考列表中的帧数大于1,计算所有参考帧的总比特数{uiBitsTemp += iRefIdxTemp+1;          // 最后一帧比特数减1if ( iRefIdxTemp == pcCU->getSlice()->getNumRefIdx(eRefPicList)-1 ) uiBitsTemp--;}
#if ZERO_MVD_ESTxEstimateMvPredAMVP( 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);
#endifaaiMvpIdx[iRefList][iRefIdxTemp] = pcCU->getMVPIdx(eRefPicList, uiPartAddr); // 获取MVP索引aaiMvpNum[iRefList][iRefIdxTemp] = pcCU->getMVPNum(eRefPicList, uiPartAddr); // 获取MVP数量
        // 使用广义帧且失真小于最优失真时,更新最优参数if(pcCU->getSlice()->getMvdL1ZeroFlag() && iRefList==1 && biPDistTemp < bestBiPDist){bestBiPDist = biPDistTemp;bestBiPMvpL1 = aaiMvpIdx[iRefList][iRefIdxTemp];bestBiPRefIdxL1 = iRefIdxTemp;}uiBitsTemp += m_auiMVPIdxCost[aaiMvpIdx[iRefList][iRefIdxTemp]][AMVP_MAX_NUM_CANDS]; // 记录比特数
#if ZERO_MVD_ESTif ( iRefList == 0 || pcCU->getSlice()->getList1IdxToList0Idx( iRefIdxTemp ) < 0 ){uiZeroMvdBitsTemp = uiBitsTemp;uiZeroMvdBitsTemp += 2; //zero mvd bits
m_pcRdCost->getMotionCost( true, 0, pcCU->getCUTransquantBypass(uiPartAddr) );uiZeroMvdCostTemp = uiZeroMvdDistTemp + m_pcRdCost->getCost(uiZeroMvdBitsTemp);if (uiZeroMvdCostTemp < uiZeroMvdCost){uiZeroMvdCost = uiZeroMvdCostTemp;iZeroMvdDir = iRefList + 1;aiZeroMvdRefIdx[iRefList] = iRefIdxTemp;aiZeroMvdMvpIdx[iRefList] = aaiMvpIdx[iRefList][iRefIdxTemp];auiZeroMvdBits[iRefList] = uiZeroMvdBitsTemp;}}
#endif#if GPB_SIMPLE_UNIif ( iRefList == 1 )    // list 1(B帧)
        {if ( pcCU->getSlice()->getList1IdxToList0Idx( iRefIdxTemp ) >= 0 ) // 如果使用广义B帧,则list1直接复制list0的信息{cMvTemp[1][iRefIdxTemp] = cMvTemp[0][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[1][iRefIdxTemp].getHor(), cMvTemp[1][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帧就直接进行运动估计xMotionEstimationelse{xMotionEstimation ( pcCU, pcOrgYuv, iPartIdx, eRefPicList, &cMvPred[iRefList][iRefIdxTemp], iRefIdxTemp, cMvTemp[iRefList][iRefIdxTemp], uiBitsTemp, uiCostTemp );}
#elsexMotionEstimation ( pcCU, pcOrgYuv, iPartIdx, eRefPicList, &cMvPred[iRefList][iRefIdxTemp], iRefIdxTemp, cMvTemp[iRefList][iRefIdxTemp], uiBitsTemp, uiCostTemp );
#endif        // 将AMVP信息写入当前CU,并检查是否是最优MVPxCopyAMVPInfo(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 == 0 ){uiCostTempL0[iRefIdxTemp] = uiCostTemp;uiBitsTempL0[iRefIdxTemp] = uiBitsTemp;}if ( uiCostTemp < uiCost[iRefList] ){uiCost[iRefList] = uiCostTemp;uiBits[iRefList] = uiBitsTemp; // storing for bi-prediction// set motioncMv[iRefList]     = cMvTemp[iRefList][iRefIdxTemp];iRefIdx[iRefList] = iRefIdxTemp;}if ( iRefList == 1 && uiCostTemp < costValidList1 && pcCU->getSlice()->getList1IdxToList0Idx( iRefIdxTemp ) < 0 ){costValidList1 = uiCostTemp;bitsValidList1 = uiBitsTemp;// set motionmvValidList1     = cMvTemp[iRefList][iRefIdxTemp];refIdxValidList1 = iRefIdxTemp;}}}//  Bi-directional prediction 双向预测if ( (pcCU->getSlice()->isInterB()) && (pcCU->isBipredRestriction(iPartIdx) == false) ) // isBipredRestriction(用来判断当前PU尺寸是否为8,而且划分模式是不是2Nx2N){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));UInt uiMotBits[2];
      // 使用广义B帧,则进行运动补偿motionCompensationif(pcCU->getSlice()->getMvdL1ZeroFlag()){xCopyAMVPInfo(&aacAMVPInfo[1][bestBiPRefIdxL1], pcCU->getCUMvField(REF_PIC_LIST_1)->getAMVPInfo());pcCU->setMVPIdxSubParts( bestBiPMvpL1, REF_PIC_LIST_1, uiPartAddr, iPartIdx, pcCU->getDepth(uiPartAddr));aaiMvpIdxBi[1][bestBiPRefIdxL1] = bestBiPMvpL1;cMvPredBi[1][bestBiPRefIdxL1]   = pcCU->getCUMvField(REF_PIC_LIST_1)->getAMVPInfo()->m_acMvCand[bestBiPMvpL1];cMvBi[1] = cMvPredBi[1][bestBiPRefIdxL1];iRefIdxBi[1] = bestBiPRefIdxL1;pcCU->getCUMvField( REF_PIC_LIST_1 )->setAllMv( cMvBi[1], ePartSize, uiPartAddr, 0, iPartIdx );pcCU->getCUMvField( REF_PIC_LIST_1 )->setAllRefIdx( iRefIdxBi[1], ePartSize, uiPartAddr, 0, iPartIdx );TComYuv* pcYuvPred = &m_acYuvPred[REF_PIC_LIST_1];motionCompensation( pcCU, pcYuvPred, REF_PIC_LIST_1, iPartIdx );uiMotBits[0] = uiBits[0] - uiMbBits[0];uiMotBits[1] = uiMbBits[1];if ( pcCU->getSlice()->getNumRefIdx(REF_PIC_LIST_1) > 1 ){uiMotBits[1] += bestBiPRefIdxL1+1;if ( bestBiPRefIdxL1 == pcCU->getSlice()->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];}// 4-times iteration (default) 默认4次迭代Int iNumIter = 4;
      // 如果不使用广义B帧技术,且是第一次迭代,则进行运动补偿// fast encoder setting: only one iterationif ( m_pcEncCfg->getUseFastEnc() || pcCU->getSlice()->getMvdL1ZeroFlag()){iNumIter = 1;}for ( Int iIter = 0; iIter < iNumIter; iIter++ ){Int         iRefList    = iIter % 2;if ( m_pcEncCfg->getUseFastEnc() ) // 使用快速编码,则选择代价大的list{if( uiCost[0] <= uiCost[1] ){iRefList = 1;}else{iRefList = 0;}}else if ( iIter == 0 ) // 如果是整个子块,则选择list0{iRefList = 0;}if ( iIter == 0 && !pcCU->getSlice()->getMvdL1ZeroFlag()) // 如果是第一个子块且list1不为空,进行list0的运动补偿{pcCU->getCUMvField(RefPicList(1-iRefList))->setAllMv( cMv[1-iRefList], ePartSize, uiPartAddr, 0, iPartIdx );pcCU->getCUMvField(RefPicList(1-iRefList))->setAllRefIdx( iRefIdx[1-iRefList], ePartSize, uiPartAddr, 0, iPartIdx );TComYuv*  pcYuvPred = &m_acYuvPred[1-iRefList];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++ ){uiBitsTemp = uiMbBits[2] + uiMotBits[1-iRefList];          // 更新比特信息if ( pcCU->getSlice()->getNumRefIdx(eRefPicList) > 1 ){uiBitsTemp += iRefIdxTemp+1;if ( iRefIdxTemp == pcCU->getSlice()->getNumRefIdx(eRefPicList)-1 ) 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 );
          // 找最优MVPxCopyAMVPInfo(&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[2] - uiMotBits[1-iRefList];uiBits[2]           = uiBitsTemp;if(iNumIter!=1){//  Set motionpcCU->getCUMvField( eRefPicList )->setAllMv( cMvBi[iRefList], ePartSize, uiPartAddr, 0, iPartIdx );pcCU->getCUMvField( eRefPicList )->setAllRefIdx( iRefIdxBi[iRefList], ePartSize, uiPartAddr, 0, iPartIdx );TComYuv* pcYuvPred = &m_acYuvPred[iRefList];motionCompensation( pcCU, pcYuvPred, eRefPicList, iPartIdx );}}} // for loop-iRefIdxTemp
        // 如果找到更优的代价,则复制AMVP选出最优的MVPif ( !bChanged ){if ( uiCostBi <= uiCost[0] && uiCostBi <= uiCost[1] ){xCopyAMVPInfo(&aacAMVPInfo[0][iRefIdxBi[0]], pcCU->getCUMvField(REF_PIC_LIST_0)->getAMVPInfo());xCheckBestMVP(pcCU, REF_PIC_LIST_0, cMvBi[0], cMvPredBi[0][iRefIdxBi[0]], aaiMvpIdxBi[0][iRefIdxBi[0]], uiBits[2], uiCostBi);if(!pcCU->getSlice()->getMvdL1ZeroFlag()){xCopyAMVPInfo(&aacAMVPInfo[1][iRefIdxBi[1]], pcCU->getCUMvField(REF_PIC_LIST_1)->getAMVPInfo());xCheckBestMVP(pcCU, REF_PIC_LIST_1, cMvBi[1], cMvPredBi[1][iRefIdxBi[1]], aaiMvpIdxBi[1][iRefIdxBi[1]], uiBits[2], uiCostBi);}}break;}} // for loop-iter} // if (B_SLICE)
#if ZERO_MVD_ESTif ( (pcCU->getSlice()->isInterB()) && (pcCU->isBipredRestriction(iPartIdx) == false) ){m_pcRdCost->getMotionCost( true, 0, pcCU->getCUTransquantBypass(uiPartAddr) );for ( Int iL0RefIdxTemp = 0; iL0RefIdxTemp <= pcCU->getSlice()->getNumRefIdx(REF_PIC_LIST_0)-1; iL0RefIdxTemp++ )for ( Int iL1RefIdxTemp = 0; iL1RefIdxTemp <= pcCU->getSlice()->getNumRefIdx(REF_PIC_LIST_1)-1; iL1RefIdxTemp++ ){UInt uiRefIdxBitsTemp = 0;if ( pcCU->getSlice()->getNumRefIdx(REF_PIC_LIST_0) > 1 ){uiRefIdxBitsTemp += iL0RefIdxTemp+1;if ( iL0RefIdxTemp == pcCU->getSlice()->getNumRefIdx(REF_PIC_LIST_0)-1 ) uiRefIdxBitsTemp--;}if ( pcCU->getSlice()->getNumRefIdx(REF_PIC_LIST_1) > 1 ){uiRefIdxBitsTemp += iL1RefIdxTemp+1;if ( iL1RefIdxTemp == pcCU->getSlice()->getNumRefIdx(REF_PIC_LIST_1)-1 ) uiRefIdxBitsTemp--;}Int iL0MVPIdx = 0;Int iL1MVPIdx = 0;for (iL0MVPIdx = 0; iL0MVPIdx < aaiMvpNum[0][iL0RefIdxTemp]; iL0MVPIdx++){for (iL1MVPIdx = 0; iL1MVPIdx < aaiMvpNum[1][iL1RefIdxTemp]; iL1MVPIdx++){uiZeroMvdBitsTemp = uiRefIdxBitsTemp;uiZeroMvdBitsTemp += uiMbBits[2];uiZeroMvdBitsTemp += m_auiMVPIdxCost[iL0MVPIdx][aaiMvpNum[0][iL0RefIdxTemp]] + m_auiMVPIdxCost[iL1MVPIdx][aaiMvpNum[1][iL1RefIdxTemp]];uiZeroMvdBitsTemp += 4; //zero mvd for both directionspcCU->getCUMvField( REF_PIC_LIST_0 )->setAllMvField( aacAMVPInfo[0][iL0RefIdxTemp].m_acMvCand[iL0MVPIdx], iL0RefIdxTemp, ePartSize, uiPartAddr, iPartIdx, 0 );pcCU->getCUMvField( REF_PIC_LIST_1 )->setAllMvField( aacAMVPInfo[1][iL1RefIdxTemp].m_acMvCand[iL1MVPIdx], iL1RefIdxTemp, ePartSize, uiPartAddr, iPartIdx, 0 );xGetInterPredictionError( pcCU, pcOrgYuv, iPartIdx, uiZeroMvdDistTemp, m_pcEncCfg->getUseHADME() );uiZeroMvdCostTemp = uiZeroMvdDistTemp + m_pcRdCost->getCost( uiZeroMvdBitsTemp );if (uiZeroMvdCostTemp < uiZeroMvdCost){uiZeroMvdCost = uiZeroMvdCostTemp;iZeroMvdDir = 3;aiZeroMvdMvpIdx[0] = iL0MVPIdx;aiZeroMvdMvpIdx[1] = iL1MVPIdx;aiZeroMvdRefIdx[0] = iL0RefIdxTemp;aiZeroMvdRefIdx[1] = iL1RefIdxTemp;auiZeroMvdBits[2] = uiZeroMvdBitsTemp;}}}}}
#endif#if AMP_MRG} //end if bTestNormalMC
#endif    // 设置MV信息//  Clear Motion FieldpcCU->getCUMvField(REF_PIC_LIST_0)->setAllMvField( TComMvField(), ePartSize, uiPartAddr, 0, iPartIdx );pcCU->getCUMvField(REF_PIC_LIST_1)->setAllMvField( TComMvField(), ePartSize, uiPartAddr, 0, iPartIdx );pcCU->getCUMvField(REF_PIC_LIST_0)->setAllMvd    ( cMvZero,       ePartSize, uiPartAddr, 0, iPartIdx );pcCU->getCUMvField(REF_PIC_LIST_1)->setAllMvd    ( cMvZero,       ePartSize, uiPartAddr, 0, iPartIdx );pcCU->setMVPIdxSubParts( -1, REF_PIC_LIST_0, uiPartAddr, iPartIdx, pcCU->getDepth(uiPartAddr));pcCU->setMVPNumSubParts( -1, REF_PIC_LIST_0, uiPartAddr, iPartIdx, pcCU->getDepth(uiPartAddr));pcCU->setMVPIdxSubParts( -1, REF_PIC_LIST_1, uiPartAddr, iPartIdx, pcCU->getDepth(uiPartAddr));pcCU->setMVPNumSubParts( -1, REF_PIC_LIST_1, uiPartAddr, iPartIdx, pcCU->getDepth(uiPartAddr));UInt uiMEBits = 0;// Set Motion Field_cMv[1] = mvValidList1;iRefIdx[1] = refIdxValidList1;uiBits[1] = bitsValidList1;uiCost[1] = costValidList1;#if AMP_MRG// 设置MV、MVP、MVD信息if (bTestNormalMC){
#endif
#if ZERO_MVD_ESTif (uiZeroMvdCost <= uiCostBi && uiZeroMvdCost <= uiCost[0] && uiZeroMvdCost <= uiCost[1]){if (iZeroMvdDir == 3){uiLastMode = 2;pcCU->getCUMvField(REF_PIC_LIST_0)->setAllMvField( aacAMVPInfo[0][aiZeroMvdRefIdx[0]].m_acMvCand[aiZeroMvdMvpIdx[0]], aiZeroMvdRefIdx[0], ePartSize, uiPartAddr, iPartIdx, 0 );pcCU->getCUMvField(REF_PIC_LIST_1)->setAllMvField( aacAMVPInfo[1][aiZeroMvdRefIdx[1]].m_acMvCand[aiZeroMvdMvpIdx[1]], aiZeroMvdRefIdx[1], ePartSize, uiPartAddr, iPartIdx, 0 );pcCU->setInterDirSubParts( 3, uiPartAddr, iPartIdx, pcCU->getDepth(0) );pcCU->setMVPIdxSubParts( aiZeroMvdMvpIdx[0], REF_PIC_LIST_0, uiPartAddr, iPartIdx, pcCU->getDepth(uiPartAddr));pcCU->setMVPNumSubParts( aaiMvpNum[0][aiZeroMvdRefIdx[0]], REF_PIC_LIST_0, uiPartAddr, iPartIdx, pcCU->getDepth(uiPartAddr));pcCU->setMVPIdxSubParts( aiZeroMvdMvpIdx[1], REF_PIC_LIST_1, uiPartAddr, iPartIdx, pcCU->getDepth(uiPartAddr));pcCU->setMVPNumSubParts( aaiMvpNum[1][aiZeroMvdRefIdx[1]], REF_PIC_LIST_1, uiPartAddr, iPartIdx, pcCU->getDepth(uiPartAddr));uiMEBits = auiZeroMvdBits[2];}else if (iZeroMvdDir == 1){uiLastMode = 0;pcCU->getCUMvField(REF_PIC_LIST_0)->setAllMvField( aacAMVPInfo[0][aiZeroMvdRefIdx[0]].m_acMvCand[aiZeroMvdMvpIdx[0]], aiZeroMvdRefIdx[0], ePartSize, uiPartAddr, iPartIdx, 0 );pcCU->setInterDirSubParts( 1, uiPartAddr, iPartIdx, pcCU->getDepth(0) );pcCU->setMVPIdxSubParts( aiZeroMvdMvpIdx[0], REF_PIC_LIST_0, uiPartAddr, iPartIdx, pcCU->getDepth(uiPartAddr));pcCU->setMVPNumSubParts( aaiMvpNum[0][aiZeroMvdRefIdx[0]], REF_PIC_LIST_0, uiPartAddr, iPartIdx, pcCU->getDepth(uiPartAddr));uiMEBits = auiZeroMvdBits[0];}else if (iZeroMvdDir == 2){uiLastMode = 1;pcCU->getCUMvField(REF_PIC_LIST_1)->setAllMvField( aacAMVPInfo[1][aiZeroMvdRefIdx[1]].m_acMvCand[aiZeroMvdMvpIdx[1]], aiZeroMvdRefIdx[1], ePartSize, uiPartAddr, iPartIdx, 0 );pcCU->setInterDirSubParts( 2, uiPartAddr, iPartIdx, pcCU->getDepth(0) );pcCU->setMVPIdxSubParts( aiZeroMvdMvpIdx[1], REF_PIC_LIST_1, uiPartAddr, iPartIdx, pcCU->getDepth(uiPartAddr));pcCU->setMVPNumSubParts( aaiMvpNum[1][aiZeroMvdRefIdx[1]], REF_PIC_LIST_1, uiPartAddr, iPartIdx, pcCU->getDepth(uiPartAddr));uiMEBits = auiZeroMvdBits[1];}else{assert(0);}}else
#endifif ( uiCostBi <= uiCost[0] && uiCostBi <= uiCost[1]){uiLastMode = 2;pcCU->getCUMvField(REF_PIC_LIST_0)->setAllMv( cMvBi[0], ePartSize, uiPartAddr, 0, iPartIdx );pcCU->getCUMvField(REF_PIC_LIST_0)->setAllRefIdx( iRefIdxBi[0], ePartSize, uiPartAddr, 0, iPartIdx );pcCU->getCUMvField(REF_PIC_LIST_1)->setAllMv( cMvBi[1], ePartSize, uiPartAddr, 0, iPartIdx );pcCU->getCUMvField(REF_PIC_LIST_1)->setAllRefIdx( iRefIdxBi[1], ePartSize, uiPartAddr, 0, iPartIdx );
// 计算并存储MVDTempMv = cMvBi[0] - cMvPredBi[0][iRefIdxBi[0]];pcCU->getCUMvField(REF_PIC_LIST_0)->setAllMvd    ( TempMv,                 ePartSize, uiPartAddr, 0, iPartIdx );TempMv = cMvBi[1] - cMvPredBi[1][iRefIdxBi[1]];pcCU->getCUMvField(REF_PIC_LIST_1)->setAllMvd    ( TempMv,                 ePartSize, uiPartAddr, 0, iPartIdx );pcCU->setInterDirSubParts( 3, uiPartAddr, iPartIdx, pcCU->getDepth(0) );pcCU->setMVPIdxSubParts( aaiMvpIdxBi[0][iRefIdxBi[0]], REF_PIC_LIST_0, uiPartAddr, iPartIdx, pcCU->getDepth(uiPartAddr));pcCU->setMVPNumSubParts( aaiMvpNum[0][iRefIdxBi[0]], REF_PIC_LIST_0, uiPartAddr, iPartIdx, pcCU->getDepth(uiPartAddr));pcCU->setMVPIdxSubParts( aaiMvpIdxBi[1][iRefIdxBi[1]], REF_PIC_LIST_1, uiPartAddr, iPartIdx, pcCU->getDepth(uiPartAddr));pcCU->setMVPNumSubParts( aaiMvpNum[1][iRefIdxBi[1]], REF_PIC_LIST_1, uiPartAddr, iPartIdx, pcCU->getDepth(uiPartAddr));uiMEBits = uiBits[2];}else if ( uiCost[0] <= uiCost[1] ){uiLastMode = 0;pcCU->getCUMvField(REF_PIC_LIST_0)->setAllMv( cMv[0], ePartSize, uiPartAddr, 0, iPartIdx );pcCU->getCUMvField(REF_PIC_LIST_0)->setAllRefIdx( iRefIdx[0], ePartSize, uiPartAddr, 0, iPartIdx );TempMv = cMv[0] - cMvPred[0][iRefIdx[0]];pcCU->getCUMvField(REF_PIC_LIST_0)->setAllMvd    ( TempMv,                 ePartSize, uiPartAddr, 0, iPartIdx );pcCU->setInterDirSubParts( 1, uiPartAddr, iPartIdx, pcCU->getDepth(0) );pcCU->setMVPIdxSubParts( aaiMvpIdx[0][iRefIdx[0]], REF_PIC_LIST_0, uiPartAddr, iPartIdx, pcCU->getDepth(uiPartAddr));pcCU->setMVPNumSubParts( aaiMvpNum[0][iRefIdx[0]], REF_PIC_LIST_0, uiPartAddr, iPartIdx, pcCU->getDepth(uiPartAddr));uiMEBits = uiBits[0];}else{uiLastMode = 1;pcCU->getCUMvField(REF_PIC_LIST_1)->setAllMv( cMv[1], ePartSize, uiPartAddr, 0, iPartIdx );pcCU->getCUMvField(REF_PIC_LIST_1)->setAllRefIdx( iRefIdx[1], ePartSize, uiPartAddr, 0, iPartIdx );TempMv = cMv[1] - cMvPred[1][iRefIdx[1]];pcCU->getCUMvField(REF_PIC_LIST_1)->setAllMvd    ( TempMv,                 ePartSize, uiPartAddr, 0, iPartIdx );pcCU->setInterDirSubParts( 2, uiPartAddr, iPartIdx, pcCU->getDepth(0) );pcCU->setMVPIdxSubParts( aaiMvpIdx[1][iRefIdx[1]], REF_PIC_LIST_1, uiPartAddr, iPartIdx, pcCU->getDepth(uiPartAddr));pcCU->setMVPNumSubParts( aaiMvpNum[1][iRefIdx[1]], REF_PIC_LIST_1, uiPartAddr, iPartIdx, pcCU->getDepth(uiPartAddr));uiMEBits = uiBits[1];}
#if AMP_MRG} // end if bTestNormalMC
#endif
    // 如果不是2Nx2N,即一个CU会被划分为多个PU,则应该计算并合并它们的运动估计代价if ( pcCU->getPartitionSize( uiPartAddr ) != SIZE_2Nx2N ){UInt uiMRGInterDir = 0;TComMvField cMRGMvField[2];UInt uiMRGIndex = 0;UInt uiMEInterDir = 0;TComMvField cMEMvField[2];m_pcRdCost->getMotionCost( true, 0, pcCU->getCUTransquantBypass(uiPartAddr) );#if AMP_MRG// calculate ME costDistortion 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 costDistortion 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[0] );pcCU->getMvField( pcCU, uiPartAddr, REF_PIC_LIST_1, cMEMvField[1] );// find Merge resultDistortion uiMRGCost = std::numeric_limits<Distortion>::max();
// 合并估计信息xMergeEstimation( pcCU, pcOrgYuv, iPartIdx, uiMRGInterDir, cMRGMvField, uiMRGIndex, uiMRGCost, cMvFieldNeighbours, uhInterDirNeighbours, numValidMergeCand);
// 设置运动估计的结果if ( uiMRGCost < uiMECost ){// set Merge resultpcCU->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[0], ePartSize, uiPartAddr, 0, iPartIdx );pcCU->getCUMvField( REF_PIC_LIST_1 )->setAllMvField( cMRGMvField[1], ePartSize, uiPartAddr, 0, iPartIdx );pcCU->getCUMvField(REF_PIC_LIST_0)->setAllMvd    ( cMvZero,            ePartSize, uiPartAddr, 0, iPartIdx );pcCU->getCUMvField(REF_PIC_LIST_1)->setAllMvd    ( cMvZero,            ePartSize, uiPartAddr, 0, iPartIdx );pcCU->setMVPIdxSubParts( -1, REF_PIC_LIST_0, uiPartAddr, iPartIdx, pcCU->getDepth(uiPartAddr));pcCU->setMVPNumSubParts( -1, REF_PIC_LIST_0, uiPartAddr, iPartIdx, pcCU->getDepth(uiPartAddr));pcCU->setMVPIdxSubParts( -1, REF_PIC_LIST_1, uiPartAddr, iPartIdx, pcCU->getDepth(uiPartAddr));pcCU->setMVPNumSubParts( -1, REF_PIC_LIST_1, uiPartAddr, iPartIdx, pcCU->getDepth(uiPartAddr));}else{// set ME resultpcCU->setMergeFlagSubParts( false,        uiPartAddr, iPartIdx, pcCU->getDepth( uiPartAddr ) );pcCU->setInterDirSubParts ( uiMEInterDir, uiPartAddr, iPartIdx, pcCU->getDepth( uiPartAddr ) );pcCU->getCUMvField( REF_PIC_LIST_0 )->setAllMvField( cMEMvField[0], ePartSize, uiPartAddr, 0, iPartIdx );pcCU->getCUMvField( REF_PIC_LIST_1 )->setAllMvField( cMEMvField[1], ePartSize, uiPartAddr, 0, iPartIdx );}}//  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;
}

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   = 0;TComMv     cZeroMv;TComMv     cMvPred;Distortion uiBestCost = std::numeric_limits<Distortion>::max();UInt       uiPartAddr = 0;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的默认索引为0iBestIdx = 0;  // 最优MVP默认是列表第一个cBestMv  = pcAMVPInfo->m_acMvCand[0];
#if !ZERO_MVD_EST  // 如果MVP候选列表中MVP的数量是0或者1if (pcAMVPInfo->iN <= 1){    // 得到了最优的MVPrcMvPred = 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, 0, AMVP_MAX_NUM_CANDS, eRefPicList, iRefIdx, iRoiWidth, iRoiHeight);}return;}
#endif// 如果MVP候选列表已经填充完毕,那么直接返回MVP就行了  // 注意:fillMvpCand并不会修改bFilled的值,bFilled的值是函数传进来的if (bFilled){assert(pcCU->getMVPIdx(eRefPicList,uiPartAddr) >= 0);    // 选择相应的MVPrcMvPred = pcAMVPInfo->m_acMvCand[pcCU->getMVPIdx(eRefPicList,uiPartAddr)];return;}m_cYuvPredTemp.clear();
#if ZERO_MVD_ESTDistortion uiDist;
#endif//-- Check Minimum Cost.  // 遍历每一个MVP,选出代价最小的那个for ( i = 0 ; i < pcAMVPInfo->iN; i++){Distortion uiTmpCost;
#if ZERO_MVD_ESTuiTmpCost = xGetTemplateCost( pcCU, uiPartIdx, uiPartAddr, pcOrgYuv, &m_cYuvPredTemp, pcAMVPInfo->m_acMvCand[i], i, AMVP_MAX_NUM_CANDS, eRefPicList, iRefIdx, iRoiWidth, iRoiHeight, uiDist );
#elseuiTmpCost = xGetTemplateCost( pcCU, uiPartIdx, uiPartAddr, pcOrgYuv, &m_cYuvPredTemp, pcAMVPInfo->m_acMvCand[i], i, AMVP_MAX_NUM_CANDS, eRefPicList, iRefIdx, iRoiWidth, iRoiHeight);
#endifif ( 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 MVPrcMvPred = 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精度MVTComMv        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[1-(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 & RightBottomif ( bBi )  xSetSearchRange   ( pcCU, rcMv   , iSrchRng, cMvSrchRngLT, cMvSrchRngRB );else        xSetSearchRange   ( pcCU, cMvPred, iSrchRng, cMvSrchRngLT, cMvSrchRngRB );m_pcRdCost->getMotionCost( true, 0, pcCU->getCUTransquantBypass(uiPartAddr) ); // 计算率失真代价m_pcRdCost->setPredictor  ( *pcMvPred ); // 设置预测得到的MVm_pcRdCost->setCostScale  ( 2 );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=0;if (pcCU->getPartitionSize(0) != SIZE_2Nx2N || pcCU->getDepth(0) != 0){
#if RExt__BACKWARDS_COMPATIBILITY_MOTION_ESTIMATION_R0105const 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)
#endifpIntegerMv2Nx2NPred = &(m_integerMv2Nx2N[eRefPicList][iRefIdxPred]);}xPatternSearchFast  ( pcCU, pcPatternKey, piRefY, iRefStride, &cMvSrchRngLT, &cMvSrchRngRB, rcMv, ruiCost, pIntegerMv2Nx2NPred );if (pcCU->getPartitionSize(0) == SIZE_2Nx2N){m_integerMv2Nx2N[eRefPicList][iRefIdxPred] = rcMv;}}m_pcRdCost->getMotionCost( true, 0, pcCU->getCUTransquantBypass(uiPartAddr) );m_pcRdCost->setCostScale ( 1 );const Bool bIsLosslessCoded = pcCU->getCUTransquantBypass(uiPartAddr) != 0;xPatternSearchFracDIF( bIsLosslessCoded, pcPatternKey, piRefY, iRefStride, &rcMv, cMvHalf, cMvQter, ruiCost ,bBi ); // 分像素搜索m_pcRdCost->setCostScale( 0 );rcMv <<= 2; // 整像素rcMv += (cMvHalf <<= 1); // 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 >= 0 ){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下的所有PUfor ( iPartIdx = 0; 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;
}

转载于:https://www.cnblogs.com/lucifer1997/p/10993771.html

HM16.0之帧间预测——xCheckRDCostInter()函数相关推荐

  1. HEVC代码学习:帧间预测——MVP过程中MV的获取、传递及存储

    作为一个视频编码小白,最近开始着手啃HEVC帧间预测的代码,想用博客记录一下自己的学习过程,也想与大家分享.交流一下. HEVC代码的学习主要是参考两位大神岳麓吹雪.NB_vol_1的博客以及HM参考 ...

  2. HM编码器代码阅读(32)——帧间预测之AMVP/Merge模式(七)encodeResAndCalcRdInterCU函数:残差计算、变换量化

    encodeResAndCalcRdInterCU 原理和细节 经过运动估计.运动补偿,我们得到了MV以及参考块,那么接下来是计算残差.计算MVD,然后对系数进行变换.量化. encodeResAnd ...

  3. 【VTM10.0代码学习】帧间预测xCheckRdCostMerge2N*2N

      xCheckRdCostMerge函数在xCompressCU中被调用,这里包括了常规Merge模式.CIIP模式和MMVD模式,GPM在xCheckRDCostGeo函数中.也就是说常规Merg ...

  4. SVAC1.0帧间预测技术分析

    ###Date:2017/10/21 ###Content:SVAC1.0帧间预测技术分析 1.参考帧选择 P条带或B条带最多可有两个参考帧或四个参考场.,它们应为最临近当前解码图像的参考帧或参考场. ...

  5. HEVC参考软件HM源码分析--帧间预测(1)--xCompressCU

    本文首先对HM中帧间预测的基本流程作简要介绍,接着对代码中关键变量的用途作出说明,最后以源代码+注释的形式进行具体分析. 备注:这位大神的博客对楼主帮助很大,解决了我的不少疑惑,最后才能顺利写下这篇博 ...

  6. HM编码器代码阅读(13)——帧间预测之AMVP模式(一)总体流程

    帧间预测的原理 AMVP的原理 帧间预测的实质就是为当前的PU在参考帧中寻找一块最相似块(相似度的判断准则有SAD等方法).但是参考图像通常都比较大,我们直接去搜索的话就太费时了,应该使用某种方法在参 ...

  7. H.266/VVC帧间预测总结

    一.帧间预测基本原理 帧间预测是利用视频帧与帧之间的相关性,去除视频帧间的时间冗余信息.统计表明,帧间差绝对值超过3的像素平均不到一帧像素的4%,因此,采用高效的帧间编码方式,可以很大程度上提高视频压 ...

  8. HEVC参考软件HM源码分析--帧间预测(3)--predInterSearch

    帧间预测基本知识 对帧间预测有所了解的同学应该都知道,帧间预测操作一般都是由两个最基本也是最核心的操作组成:运动估计(ME)和运动补偿(MC). 运动估计:负责找到当前帧和参考帧之间的匹配运动矢量(M ...

  9. HM编码器代码阅读(16)——帧间预测之AMVP模式(四)预测MV的获取

    帧间预测的原理 AMVP的原理 帧间预测的实质就是为当前的PU在参考帧中寻找一块最相似块(相似度的判断准则有SAD等方法).但是参考图像通常都比较大,我们直接去搜索的话就太费时了,应该使用某种方法在参 ...

最新文章

  1. ubuntu 使用阿里云 apt 源
  2. Android Json生成及解析实例
  3. winform修改、打开窗体、构造函数传值
  4. jsp:include标签与include指令的区别
  5. websocket python unity_Unity中Websocket的简单使用
  6. 如何在悬停而不是单击时使Twitter Bootstrap菜单下拉列表
  7. linux安装 web2py,TurnkeyLinux上用于Web2Py到MySQL的DAL连接字符串
  8. 《麦肯锡方法》第1章建立解决方案-思维导图
  9. 学习数码相框1.3.0.0在LCD上显示一个矢量字体_在LCD上显示多行文字
  10. 公文排版插件for Word/WPS【快点公文助手——让公文排版更快一点】
  11. Python 爬取科技部计划申报指南pdf文件并作词频分析
  12. 揭秘小红书的种草套路
  13. 嵌入式系统概述3-嵌入式系统的开发流程和学习基础、方法
  14. 数学分析第一型曲面积分2021.6.5
  15. 今日头条Android适配方案,android 今日头条的屏幕适配理解
  16. 【SAMF】A Scale Adaptive Kernel Correlation Filter Tracker with Feature Integration 论文阅读笔记
  17. python如何读取下一行_python读取行停止,然后在下一行继续
  18. 韩信点兵(hanxin)
  19. 微信小程序 自定义tab不煽动
  20. 变色龙哈希函数Chameleon Hash Functions

热门文章

  1. 深入struts2.0(七)--ActionInvocation接口以及3DefaultActionInvocation类
  2. 编写高性能的 Lua 代码
  3. 安卓入门笔记之Activity
  4. UIMenuController的使用,对UILabel拷贝以及定制菜单
  5. 软件随想: 软件 = 程序 + 软件工程
  6. LOCALALLOC和GLOBALLOC有什么区别? 全局内存和局部内存有什么区别?(转)
  7. Java范例集锦(一)
  8. iosanimationWithKeyPath
  9. 数据挖掘经典算法——先验算法
  10. div嵌套div 背景图片 不显示的问题