在上一章的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_MRG
Void TEncSearch::predInterSearch( TComDataCU* pcCU, TComYuv* pcOrgYuv, TComYuv* pcPredYuv, TComYuv* pcResiYuv, TComYuv* pcRecoYuv DEBUG_STRING_FN_DECLARE(sDebug), Bool bUseRes, Bool bUseMRG )
#else
Void 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; //kolyaTComMv       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();    //将失真置为最大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块的bit数pcCU->getPartIndexAndSize( iPartIdx, uiPartAddr, iRoiWidth, iRoiHeight );    //获取CU的宽、高、起始地址信息#if AMP_MRGBool 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 predictionfor ( 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];    //存储参考列表的bit数if ( 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];    //记录bit数if ( m_pcEncCfg->getFastMEForGenBLowDelayEnabled() && iRefList == 1 )      //对于list1(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      //不使用广义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,并检查是否是最优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);//更新失真和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 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];//更新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 );//找最优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选出最优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 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){
#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块*************************************************************///如果不是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, pcPredYuv, REF_PIC_LIST_X, iPartIdx );} //  end of for ( Int iPartIdx = 0; iPartIdx < iNumPart; iPartIdx++ )//设置加权预测setWpScalingDistParam( pcCU, -1, REF_PIC_LIST_X );return;
}

HEVC代码学习13:predInterSearch函数相关推荐

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

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

  2. HEVC代码学习42:estIntraPredLumaQT函数

    在之前的 HEVC代码学习37:帧内预测代码整体学习 中已经提到,estIntraPredLumaQT是亮度帧内预测的入口函数,下面将对该函数进行详细学习. estIntraPredLumaQT中完成 ...

  3. HEVC代码学习39:decodeCtu和xDecodeCU函数

    在之前 HEVC代码学习38:decompressSlice函数 学习中提到,解码slice会遍历所有CTU,调用decodeCtu和decompressCtu解码每一个CTU.下面就来学习一下dec ...

  4. HEVC代码学习——帧间预测:预测MV获取(xEstimateMvPredAMVP、fillMVPCand)

    HEVC帧间预测在AMVP模式下是依靠xEstimateMvPredAMVP函数获取预测MV(MVP)的. 这部分内容的学习还可以参考这两篇博客: HEVC代码学习15:AMVP相关函数 HM编码器代 ...

  5. H.266代码学习:xEncodeCU函数

    之前在HEVC代码学习35:xEncodeCU函数中介绍过xEncodeCU函数,今天来看JEM中的xEncodeCU,其中难点在于QTBT编码结构. HM中使用compressCtu对每个CTU进行 ...

  6. H.266代码学习:estIntraPredLumaQT函数

    之前 HEVC代码学习42:estIntraPredLumaQT函数 对HM中的estIntraPredLumaQT函数进行了学习,下面将对JEM中的该函数进行学习. estIntraPredLuma ...

  7. H.266代码学习:xIntraCodingTUBlock函数

    今天来继续学习帧内编码的重要函数xIntraCodingTUBlock,上次 H.266代码学习:xRecurIntraCodingLumaQT函数 学习中提到,xIntraCodingTUBlock ...

  8. HEVC代码学习19:MV、MVD、MVP概念解析

    在代码阅读中,可以看到MV.MVD.MVP三个概念,在开始学习的时候就很糊涂,一直买具体来看下,也找不到具体在哪里有讲解,现在来关注学习一下. 先来逗比一下,名词解析: MVP--most valua ...

  9. HEVC代码学习6:filterHor和filterVer函数

    帧间预测分为运动估计ME和运动补偿MV,其中用到了MV的亚像素搜索,需要使用filterHor和filterVer进行插值. 这里使用的是HM16,在之前版本中分为filterHorLuma.filt ...

最新文章

  1. 深度学习在工业推荐如何work?Netflix这篇论文「深度学习推荐系统Netflix案例分析」阐述DL在RS的优劣与经验教训...
  2. android ImageButton显示本地图片
  3. 测试思想-好东西与大家分享-1
  4. LAN远程重启server安全方法
  5. 结队项目之需求分析与原型设计
  6. QT的事件分发、事件过滤器详解
  7. oracle rman在线备份,Oracle之RMAN备份及还原
  8. php版ueditor配置_ThinkPHP配置UEditor
  9. photoshop7.0绿色迷你免安装版
  10. HDFS 的权限管理不可怕,一篇文章搞懂它
  11. 如何用OCR文字识别软件将PDF转换成Excel
  12. Google 再被欧盟调查,安卓系统是如何建立垄断的?
  13. npm list 报错 extraneous
  14. python多边形的绘制教程_绘制最新:python绘制封闭多边形教程_爱安网 LoveAn.com
  15. 进制转换(二进制,八进制,十进制)
  16. Windows XP仿苹果工具栏—RocketDock
  17. python求长整数_python 长整数
  18. WLAN 无线网络 09 - 管理帧 zz
  19. 常微分方程解法(2)例题
  20. 自学CFD:我在实习岗速成无人机设计和仿真的故事

热门文章

  1. QD77MS4 RD77MS4 运动控制模块凸轮曲线样例程序
  2. oracle学号查询平均成绩,orcal数据库中查询出平均成绩大于60分的同学的学号和平均成绩...
  3. 【NLP】词法分析和词性标注
  4. 亚马逊测评自养号技能知识共享
  5. 阿里P8架构师深度概述分布式架构
  6. CSK跟踪算法简介及代码的解读
  7. matlab - 特殊矩阵、矩阵求值、稀疏矩阵
  8. uniapp报错 -4048
  9. 多测师肖sir_高级金牌讲师_app测试之环境安装(001)
  10. 数据库mysql表常见字段大小_常用的数据库的字段类型及大小