HEVC代码学习13:predInterSearch函数

来源:互联网 发布:淘宝店铺怎样关闭 编辑:程序博客网 时间:2024/06/03 09:25

在上一章的xCheckRDCostInter学习中,我们知道了,进行帧间搜索的入口实际是predInterSearch,今天我们就来对他进行学习。
推荐看大神博客
http://blog.csdn.net/nb_vol_1/article/details/51162391

predInterSearch主要作用是进行运动估计和运动补偿。
1.对CU的每一个PU遍历参考列表中的参考图像,进行运动估计,找到最优参考帧和MV。
2.对于B帧,需要对后向参考预测块进行运动补偿,在运动补偿之后重新进行运动估计,找到最优MV。
3.对于非2Nx2N的分块,需要计算并合并他们的运动估计代价。
4.最后进行运动补偿,设置加权预测。

其中涉及了广义B帧的处理,前后参考列表中的参考图像都是用当前图像之前的图像,且两个参考列表完全一致,因此list0和list1相同。

使用到了以下重要函数:
1.xEstimateMvPredAMVP:AMVP的入口函数,执行AMVP操作。
2.xMotionEstimation:运动估计的入口函数,进行运动搜索,找到MV。
3.motionCompensation:运动补偿的入口函数,进行运动补偿,构造匹配块信息。

这里补充一下AMVP与运动估计的关系。AMVP会为运动估计ME提供候选MVP,ME会选择其中率失真代价最小的MVP作为起点,进行搜索,找到最优的MV。

另外MVD也是在predInterSearch函数中计算的,找到最优MV后,会根据MVD = MV - MVP计算MVD。

//帧间搜索最佳候选//! search of the best candidate for inter prediction#if AMP_MRGVoid TEncSearch::predInterSearch( TComDataCU* pcCU, TComYuv* pcOrgYuv, TComYuv* pcPredYuv, TComYuv* pcResiYuv, TComYuv* pcRecoYuv DEBUG_STRING_FN_DECLARE(sDebug), Bool bUseRes, Bool bUseMRG )#elseVoid TEncSearch::predInterSearch( TComDataCU* pcCU, TComYuv* pcOrgYuv, TComYuv* pcPredYuv, TComYuv* pcResiYuv, TComYuv* pcRecoYuv, Bool bUseRes )#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();      //分块数  Int          iNumPredDir = pcCU->getSlice()->isInterP() ? 1 : 2;    //预测方向,P帧为1,B帧为2  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];      //记录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();    //将失真置为最大  TComMvField 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;    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块的bitpcCU->getPartIndexAndSize( iPartIdx, uiPartAddr, iRoiWidth, iRoiHeight );    //获取CU的宽、高、起始地址信息#if AMP_MRG    Bool bTestNormalMC = true;      //bTestNormalMC指示是否进行正常的MC(ME+MC)    if ( bUseMRG && pcCU->getWidth( 0 ) > 8 && iNumPart == 2 )      //bUseMRG为真、CU大于8且分块为SIZE_2NxN时,不能进行正常的MC    {      bTestNormalMC = false;            }    /*********************************************************正常MC*****************************************************************/    if (bTestNormalMC)    {#endif    //建立参考列表,P帧只有一个,B帧有两个    //  Uni-directional prediction    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];    //存储参考列表的bitif ( pcCU->getSlice()->getNumRefIdx(eRefPicList) > 1 )      //如果参考列表中的帧数大于1,计算所有参考帧的总bit数        {          uiBitsTemp += iRefIdxTemp+1;          if ( iRefIdxTemp == pcCU->getSlice()->getNumRefIdx(eRefPicList)-1 )   //最后一帧bit数-1          {            uiBitsTemp--;          }        }        //执行AMVP,进行MV预测和AMVP计算        xEstimateMvPredAMVP( pcCU, pcOrgYuv, iPartIdx, eRefPicList, iRefIdxTemp, cMvPred[iRefList][iRefIdxTemp], false, &biPDistTemp);        aaiMvpIdx[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];    //记录bitif ( m_pcEncCfg->getFastMEForGenBLowDelayEnabled() && iRefList == 1 )      //对于list1B帧)        {          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      //不使用广义B帧就直接进行运动估计xMotionEstimation          {            xMotionEstimation ( pcCU, pcOrgYuv, iPartIdx, eRefPicList, &cMvPred[iRefList][iRefIdxTemp], iRefIdxTemp, cMvTemp[iRefList][iRefIdxTemp], uiBitsTemp, uiCostTemp );          }        }        else        //对于list0,直接进行运动估计xMotionEstimation        {          xMotionEstimation ( pcCU, pcOrgYuv, iPartIdx, eRefPicList, &cMvPred[iRefList][iRefIdxTemp], iRefIdxTemp, cMvTemp[iRefList][iRefIdxTemp], uiBitsTemp, uiCostTemp );        }        //将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);        //更新失真和bit信息        if ( iRefList == 0 )             {          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 == 1 && uiCostTemp < costValidList1 && pcCU->getSlice()->getList1IdxToList0Idx( iRefIdxTemp ) < 0 )        {          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[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帧,则进行运动补偿motionCompensation      if(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 iteration      if ( 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];          //更新bit信息          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 );          //找最优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[2] - uiMotBits[1-iRefList];            uiBits[2]           = uiBitsTemp;            if(iNumIter!=1)            {              //  Set motion              pcCU->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选出最优MVP。        if ( !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 AMP_MRG    } //end if bTestNormalMC#endif    //设置MV信息    //  Clear Motion Field    pcCU->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 ( 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 );      //计算并存储MVD      TempMv = 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块*************************************************************/    //如果不是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 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[0] );      pcCU->getMvField( pcCU, uiPartAddr, REF_PIC_LIST_1, cMEMvField[1] );      // 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[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 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[0], ePartSize, uiPartAddr, 0, iPartIdx );        pcCU->getCUMvField( REF_PIC_LIST_1 )->setAllMvField( cMEMvField[1], ePartSize, uiPartAddr, 0, iPartIdx );      }    }    //  MC 运动补偿    motionCompensation ( pcCU, pcPredYuv, REF_PIC_LIST_X, iPartIdx );  } //  end of for ( Int iPartIdx = 0; iPartIdx < iNumPart; iPartIdx++ )  //设置加权预测  setWpScalingDistParam( pcCU, -1, REF_PIC_LIST_X );  return;}