H.266/VVC代码学习:predInterSearch函数

编程入门 行业动态 更新时间:2024-10-27 23:19:21

H.266/VVC代码学习:predInterSearch<a href=https://www.elefans.com/category/jswz/34/1771370.html style=函数"/>

H.266/VVC代码学习:predInterSearch函数

predInterSearch函数主要是由xCheckRDCostInter调用来获取帧间常规AMVP模式和Affine AMVP模式的最优运动信息和预测值。

首先判断是否检查Affine AMVP模式和常规AMVP模式,如下代码所述,其中checkAffine为真表示检查Affine AMVP模式,checkNonAffine为真表示检查常规AMVP模式。

其中 pu.cu->imv表示MVD精度,在VVC中,采用采用自适应运动矢量精度方法AMVR编码MVD

  bool checkAffine    = (pu.cu->imv == 0 || pu.cu->slice->getSPS()->getAffineAmvrEnabledFlag()) && pu.cu->imv != IMV_HPEL;bool checkNonAffine = pu.cu->imv == 0 || pu.cu->imv == IMV_HPEL || (pu.cu->slice->getSPS()->getAMVREnabledFlag() &&pu.cu->imv <= (pu.cu->slice->getSPS()->getAMVREnabledFlag() ? IMV_4PEL : 0));CodingUnit *bestCU  = pu.cu->cs->bestCS != nullptr ? pu.cu->cs->bestCS->getCU( CHANNEL_TYPE_LUMA ) : nullptr;bool trySmvd        = ( bestCU != nullptr && pu.cu->imv == 2 && checkAffine ) ? ( !bestCU->firstPU->mergeFlag && !bestCU->affine ) : true;if ( pu.cu->imv && bestCU != nullptr && checkAffine ){checkAffine = !( bestCU->firstPU->mergeFlag || !bestCU->affine );}if ( pu.cu->imv == 2 && checkNonAffine && pu.cu->slice->getSPS()->getAffineAmvrEnabledFlag() ){checkNonAffine = m_affineMotion.hevcCost[1] < m_affineMotion.hevcCost[0] * 1.06f;}

整个函数的流程如下:

一、检查常规AMVP模式

常规AMVP模式原理参考:高级运动矢量预测(Advanced Motion Vector Prediction)

对于常规AMVP模式,检查步骤如下:

  1. 首先检查单向预测模式:对前向参考帧列表L0和后向参考帧列表L1中的所有参考帧进行遍历,分别进行AMVP,选出最佳预测MV(MVP),之后在最佳MVP基础上调用xMotionEstimation函数进行运动估计选出最佳MV,并记录单向预测中最佳的运动信息及RD Cost
  2. 检查双向预测模式(对于4x4、4x8和8x4PU禁用双向预测):
    1. 使用单向预测得到的最佳运动信息,进行四次迭代,调用调用xMotionEstimation函数进行运动估计,得到每个参考帧下最优的运动信息(在双向预测进行运动估计前,需要先计算另一个反向参考帧得到的预测块,然后在运动估计中,从原始块减去另一方向的预测块),然后进行四次迭代,分别选出参考帧L0 L1在双向预测时的最佳MV
    2. 检查对称MVD模式(symmetric MVD):使用之前单向预测和双向预测得到的参考帧L0的最优运动信息,选出最优的MVP,再通过对称运动估计选出最佳MV,如果所得Cost小于之前双向预测模式的Cost,则记录所得最优运动信息及相关代价信息
  3. 比较单向预测和双向预测模式的Cost,并记录最优模式信息存入在PU中

这里pu.interDir,值为1时表示前向预测,为2时表示后向预测,为3时表示双向预测

其中,对于广义B帧需要做特殊处理,对于广义B帧,可以参考:HEVC参考图像列表(二)之广义B帧技术GPB

  int                         getList1IdxToList0Idx( int list1Idx ) const            { return m_list1IdxToList0Idx[list1Idx];                        }
int                        m_list1IdxToList0Idx[MAX_NUM_REF]; //如果该值不是-1,则表示List1和List0对应的参考帧索引指向的是同一个参考帧

二、检查Affine AMVP模式

Affine AMVP模式相关原理参考:仿射运动补偿预测(Affine motion compensated prediction)

对于Affine AMVP模式(CU尺寸宽度和高度均大于8),

检查步骤如下:

  1. 先检查4参数模型,调用xPredAffineInterSearch函数进行运动估计并计算相关Cost
  2. 如果四参数模型的Cost小于1.05倍的常规AMVP的Cost,则检查6参数模型

三、进行运动补偿motionCompensation得到预测值

四、设置加权预测的参数

代码及注释如下:

void InterSearch::predInterSearch(CodingUnit& cu, Partitioner& partitioner)
{CodingStructure& cs = *cu.cs;AMVPInfo     amvp[2]; //AMVP候选列表,前向列表或者后向列表 存储一帧经过ME后的最优amvp信息。AMVP选择的运动信息为ME起始点Mv           cMvSrchRngLT;Mv           cMvSrchRngRB;Mv           cMvZero;Mv           cMv[2];//两个单向预测的最优mv(运动估计得到)Mv           cMvBi[2];//双向预测的最优mvMv           cMvTemp[2][33];Mv           cMvHevcTemp[2][33];//从cMvTemp复制int          iNumPredDir = cs.slice->isInterP() ? 1 : 2; // 参考帧数目Mv           cMvPred[2][33]; //存储AMVP得到的最优mvpMv           cMvPredBi[2][33];//双向预测时,ME的起点mvint          aaiMvpIdxBi[2][33];int          aaiMvpIdx[2][33];//2表示前向后向预测,33表示L0、L1参考列表中最多33帧int          aaiMvpNum[2][33];//AMVP后得到的最优MvpIdx和MvpNumAMVPInfo     aacAMVPInfo[2][33];//存储每一帧的最优AMVP信息int          iRefIdx[2]={0,0}; //If un-initialized, may cause SEGV in bi-directional prediction iterative stage.int          iRefIdxBi[2] = { -1, -1 };uint32_t         uiMbBits[3] = {1, 1, 0};uint32_t         uiLastMode = 0;uint32_t         uiLastModeTemp = 0;int          iRefStart, iRefEnd;int          symMode = 0;int          bestBiPRefIdxL1 = 0;int          bestBiPMvpL1    = 0;Distortion   biPDistTemp     = std::numeric_limits<Distortion>::max();uint8_t      bcwIdx          = (cu.cs->slice->isInterB() ? cu.BcwIdx : BCW_DEFAULT);bool         enforceBcwPred = false;MergeCtx     mergeCtx;// Loop over Prediction UnitsCHECK(!cu.firstPU, "CU does not contain any PUs");uint32_t         puIdx = 0;auto &pu = *cu.firstPU;//xCheckRDCostInter函数中添加的puWPScalingParam *wp0;WPScalingParam *wp1;int tryBipred = 0;bool checkAffine    = (pu.cu->imv == 0 || pu.cu->slice->getSPS()->getAffineAmvrEnabledFlag()) && pu.cu->imv != IMV_HPEL;bool checkNonAffine = pu.cu->imv == 0 || pu.cu->imv == IMV_HPEL || (pu.cu->slice->getSPS()->getAMVREnabledFlag() &&pu.cu->imv <= (pu.cu->slice->getSPS()->getAMVREnabledFlag() ? IMV_4PEL : 0));CodingUnit *bestCU  = pu.cu->cs->bestCS != nullptr ? pu.cu->cs->bestCS->getCU( CHANNEL_TYPE_LUMA ) : nullptr;bool trySmvd        = ( bestCU != nullptr && pu.cu->imv == 2 && checkAffine ) ? ( !bestCU->firstPU->mergeFlag && !bestCU->affine ) : true;if ( pu.cu->imv && bestCU != nullptr && checkAffine ){checkAffine = !( bestCU->firstPU->mergeFlag || !bestCU->affine );}if ( pu.cu->imv == 2 && checkNonAffine && pu.cu->slice->getSPS()->getAffineAmvrEnabledFlag() ){checkNonAffine = m_affineMotion.hevcCost[1] < m_affineMotion.hevcCost[0] * 1.06f;}{if (pu.cu->cs->bestParent != nullptr && pu.cu->cs->bestParent->getCU(CHANNEL_TYPE_LUMA) != nullptr && pu.cu->cs->bestParent->getCU(CHANNEL_TYPE_LUMA)->affine == false){m_skipPROF = true;}m_encOnly = true;// motion estimation only evaluates luma component 运动估计只计算luma分量m_maxCompIDToPred = MAX_NUM_COMPONENT;
//    m_maxCompIDToPred = COMPONENT_Y;CHECK(pu.cu != &cu, "PU is contained in another CU");if (cu.cs->sps->getSbTMVPEnabledFlag()){Size bufSize = g_miScaling.scale(pu.lumaSize());mergeCtx.subPuMvpMiBuf = MotionBuf(m_SubPuMiBuf, bufSize);}PU::spanMotionInfo( pu );Distortion   uiHevcCost = std::numeric_limits<Distortion>::max();Distortion   uiAffineCost = std::numeric_limits<Distortion>::max();Distortion   uiCost[2] = { std::numeric_limits<Distortion>::max(), std::numeric_limits<Distortion>::max() };Distortion   uiCostBi  =   std::numeric_limits<Distortion>::max();Distortion   uiCostTemp;uint32_t         uiBits[3];uint32_t         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();//失真都设为最大值}uint32_t         uiBitsTempL0[MAX_NUM_REF];Mv           mvValidList1;int          refIdxValidList1 = 0;uint32_t         bitsValidList1   = MAX_UINT;Distortion   costValidList1   = std::numeric_limits<Distortion>::max();PelUnitBuf origBuf = pu.cs->getOrgBuf( pu ); //原始像素xGetBlkBits( cs.slice->isInterP(), puIdx, uiLastMode, uiMbBits );m_pcRdCost->selectMotionLambda( );unsigned imvShift = pu.cu->imv == IMV_HPEL ? 1 : (pu.cu->imv << 1);if ( checkNonAffine ) //常规AMVP模式{/*=========================单向预测================================*///  Uni-directional prediction 单向预测,遍历参考帧列表(前向和后向)for ( int iRefList = 0; iRefList < iNumPredDir; iRefList++ ){RefPicList  eRefPicList = ( iRefList ? REF_PIC_LIST_1 : REF_PIC_LIST_0 ); //前向列表或者后向列表// 遍历参考帧列表中的参考帧(对于多参考帧来说) 参考帧索引iRefIdxTempfor (int iRefIdxTemp = 0; iRefIdxTemp < cs.slice->getNumRefIdx(eRefPicList); iRefIdxTemp++){uiBitsTemp = uiMbBits[iRefList];if ( cs.slice->getNumRefIdx(eRefPicList) > 1 ) //多参考帧{uiBitsTemp += iRefIdxTemp+1;if ( iRefIdxTemp == cs.slice->getNumRefIdx(eRefPicList)-1 ){uiBitsTemp--;}}//  AMVP,选出最佳MVP,作为ME起点xEstimateMvPredAMVP( pu, origBuf, eRefPicList, iRefIdxTemp, cMvPred[iRefList][iRefIdxTemp], amvp[eRefPicList], false, &biPDistTemp);aaiMvpIdx[iRefList][iRefIdxTemp] = pu.mvpIdx[eRefPicList]; //相应参考列表中的参考帧的最佳MVP索引值aaiMvpNum[iRefList][iRefIdxTemp] = pu.mvpNum[eRefPicList]; //MVP数目if(cs.picHeader->getMvdL1ZeroFlag() && iRefList==1 && biPDistTemp < bestBiPDist)//广义B帧时,L1信息直接复制L0{bestBiPDist = biPDistTemp;bestBiPMvpL1 = aaiMvpIdx[iRefList][iRefIdxTemp]; //记录最佳候选MV索引bestBiPRefIdxL1 = iRefIdxTemp; //记录最佳的参考帧索引}uiBitsTemp += m_auiMVPIdxCost[aaiMvpIdx[iRefList][iRefIdxTemp]][AMVP_MAX_NUM_CANDS];if ( m_pcEncCfg->getFastMEForGenBLowDelayEnabled() && iRefList == 1 )    // list 1{if ( cs.slice->getList1IdxToList0Idx( iRefIdxTemp ) >= 0 )//如果使用广义B帧,则list1直接复制list0的信息{// 针对参考帧列表L1的快速算法,根据L0的Cost可以估计出L1列表中参考帧的Cost// 此时,List1的iRefIdxTemp参考帧和List0的iRefIdxTemp参考帧是同一帧(POC相同)cMvTemp[1][iRefIdxTemp] = cMvTemp[0][cs.slice->getList1IdxToList0Idx( iRefIdxTemp )];uiCostTemp = uiCostTempL0[cs.slice->getList1IdxToList0Idx( iRefIdxTemp )];/*first subtract the bit-rate part of the cost of the other list*/// 首先减去另一个列表成本的比特率部分uiCostTemp -= m_pcRdCost->getCost( uiBitsTempL0[cs.slice->getList1IdxToList0Idx( iRefIdxTemp )] );/*correct the bit-rate part of the current ref*//*更正当前ref的比特率部分*/m_pcRdCost->setPredictor  ( cMvPred[iRefList][iRefIdxTemp] );uiBitsTemp += m_pcRdCost->getBitsOfVectorWithPredictor( cMvTemp[1][iRefIdxTemp].getHor(), cMvTemp[1][iRefIdxTemp].getVer(), imvShift + MV_FRACTIONAL_BITS_DIFF );/*calculate the correct cost 计算正确的成本*/uiCostTemp += m_pcRdCost->getCost( uiBitsTemp );}else{// 运动估计xMotionEstimation( pu, origBuf, eRefPicList, cMvPred[iRefList][iRefIdxTemp], iRefIdxTemp, cMvTemp[iRefList][iRefIdxTemp], aaiMvpIdx[iRefList][iRefIdxTemp], uiBitsTemp, uiCostTemp, amvp[eRefPicList] );}}else{// 运动估计xMotionEstimation( pu, origBuf, eRefPicList, cMvPred[iRefList][iRefIdxTemp], iRefIdxTemp, cMvTemp[iRefList][iRefIdxTemp], aaiMvpIdx[iRefList][iRefIdxTemp], uiBitsTemp, uiCostTemp, amvp[eRefPicList] );}if( cu.cs->sps->getUseBcw() && cu.BcwIdx == BCW_DEFAULT && cu.cs->slice->isInterB() ){const bool checkIdentical = true;m_uniMotions.setReadMode(checkIdentical, (uint32_t)iRefList, (uint32_t)iRefIdxTemp);m_uniMotions.copyFrom(cMvTemp[iRefList][iRefIdxTemp], uiCostTemp - m_pcRdCost->getCost(uiBitsTemp), (uint32_t)iRefList, (uint32_t)iRefIdxTemp);}// 保存最优AMVP信息,并检查是否是最优MVPxCopyAMVPInfo( &amvp[eRefPicList], &aacAMVPInfo[iRefList][iRefIdxTemp]); // must always be done ( also when AMVP_MODE = AM_NONE )xCheckBestMVP( eRefPicList, cMvTemp[iRefList][iRefIdxTemp], cMvPred[iRefList][iRefIdxTemp], aaiMvpIdx[iRefList][iRefIdxTemp], amvp[eRefPicList], uiBitsTemp, uiCostTemp, pu.cu->imv );//更新记录最优的运动信息if ( iRefList == 0 ){uiCostTempL0[iRefIdxTemp] = uiCostTemp;uiBitsTempL0[iRefIdxTemp] = uiBitsTemp;}if ( uiCostTemp < uiCost[iRefList] ) //设置单向预测最佳的参考帧和MV信息以及RD Cost{uiCost[iRefList] = uiCostTemp;uiBits[iRefList] = uiBitsTemp; // storing for bi-prediction// set motioncMv    [iRefList] = cMvTemp[iRefList][iRefIdxTemp];iRefIdx[iRefList] = iRefIdxTemp;}if ( iRefList == 1 && uiCostTemp < costValidList1 && cs.slice->getList1IdxToList0Idx( iRefIdxTemp ) < 0 ){costValidList1 = uiCostTemp;bitsValidList1 = uiBitsTemp;// set motionmvValidList1     = cMvTemp[iRefList][iRefIdxTemp];refIdxValidList1 = iRefIdxTemp;}}}// for ( int iRefList = 0; iRefList < iNumPredDir; iRefList++ )::memcpy(cMvHevcTemp, cMvTemp, sizeof(cMvTemp));if (cu.imv == 0 && (!cu.slice->getSPS()->getUseBcw() || bcwIdx == BCW_DEFAULT)){insertUniMvCands(pu.Y(), cMvTemp);unsigned idx1, idx2, idx3, idx4;getAreaIdx(cu.Y(), *cu.slice->getPPS()->pcv, idx1, idx2, idx3, idx4);::memcpy(&(g_reusedUniMVs[idx1][idx2][idx3][idx4][0][0]), cMvTemp, 2 * 33 * sizeof(Mv));g_isReusedUniMVsFilled[idx1][idx2][idx3][idx4] = true;}/*==========================双向预测========================*///  Bi-predictive Motion estimation 双向预测运动估计 对于4x4 4x8和8x4PU禁用双向预测if( ( cs.slice->isInterB() ) && ( PU::isBipredRestriction( pu ) == false )&& (cu.slice->getCheckLDC() || bcwIdx == BCW_DEFAULT || !m_affineModeSelected || !m_pcEncCfg->getUseBcwFast())){bool doBiPred = true;tryBipred = 1;// 将双向MV初始化为最佳的单向预测MV和单向参考帧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 ) );uint32_t uiMotBits[2];if(cs.picHeader->getMvdL1ZeroFlag()) // L1 MVD设为零标志{//L1为空,则使用广义B帧//广义B帧,需要对后向参考预测块进行运动补偿,在运动补偿之后重新进行运动估计,找到最优MVxCopyAMVPInfo(&aacAMVPInfo[1][bestBiPRefIdxL1], &amvp[REF_PIC_LIST_1]);aaiMvpIdxBi[1][bestBiPRefIdxL1] = bestBiPMvpL1;cMvPredBi  [1][bestBiPRefIdxL1] = amvp[REF_PIC_LIST_1].mvCand[bestBiPMvpL1];cMvBi    [1] = cMvPredBi[1][bestBiPRefIdxL1];iRefIdxBi[1] = bestBiPRefIdxL1;pu.mv    [REF_PIC_LIST_1] = cMvBi[1];pu.refIdx[REF_PIC_LIST_1] = iRefIdxBi[1];pu.mvpIdx[REF_PIC_LIST_1] = bestBiPMvpL1;if( m_pcEncCfg->getMCTSEncConstraint() ){Mv restrictedMv = pu.mv[REF_PIC_LIST_1];Area curTileAreaRestricted;curTileAreaRestricted = pu.cs->picture->mctsInfo.getTileAreaSubPelRestricted( pu );MCTSHelper::clipMvToArea( restrictedMv, pu.cu->Y(), curTileAreaRestricted, *pu.cs->sps );// If sub-pel filter samples are not inside of allowed areaif( restrictedMv != pu.mv[REF_PIC_LIST_1] ){uiCostBi = std::numeric_limits<Distortion>::max();doBiPred = false;}}PelUnitBuf predBufTmp = m_tmpPredStorage[REF_PIC_LIST_1].getBuf( UnitAreaRelative(cu, pu) );motionCompensation( pu, predBufTmp, REF_PIC_LIST_1 );uiMotBits[0] = uiBits[0] - uiMbBits[0];uiMotBits[1] = uiMbBits[1];if ( cs.slice->getNumRefIdx(REF_PIC_LIST_1) > 1 ){uiMotBits[1] += bestBiPRefIdxL1 + 1;if ( bestBiPRefIdxL1 == cs.slice->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];}if( doBiPred ) //进行双向预测{// 4-times iteration (default) 默认四次迭代int iNumIter = 4;// fast encoder setting: only one iteration 快速算法:仅一次迭代if ( m_pcEncCfg->getFastInterSearchMode()==FASTINTERSEARCH_MODE1 || m_pcEncCfg->getFastInterSearchMode()==FASTINTERSEARCH_MODE2 || cs.picHeader->getMvdL1ZeroFlag() ){iNumIter = 1;}enforceBcwPred = (bcwIdx != BCW_DEFAULT); //强制使用BCWfor ( int iIter = 0; iIter < iNumIter; iIter++ ){int         iRefList    = iIter % 2; // 0 1if ( m_pcEncCfg->getFastInterSearchMode()==FASTINTERSEARCH_MODE1 || m_pcEncCfg->getFastInterSearchMode()==FASTINTERSEARCH_MODE2 ){if( uiCost[0] <= uiCost[1] ){iRefList = 1;}else{iRefList = 0;}if( bcwIdx != BCW_DEFAULT ){iRefList = ( abs( getBcwWeight(bcwIdx, REF_PIC_LIST_0 ) ) > abs( getBcwWeight(bcwIdx, REF_PIC_LIST_1 ) ) ? 1 : 0 );}}else if ( iIter == 0 ){iRefList = 0;}// 第一次迭代且L1的MVD不为零if ( iIter == 0 && !cs.picHeader->getMvdL1ZeroFlag()){pu.mv    [1 - iRefList] = cMv    [1 - iRefList];pu.refIdx[1 - iRefList] = iRefIdx[1 - iRefList];PelUnitBuf predBufTmp = m_tmpPredStorage[1 - iRefList].getBuf( UnitAreaRelative(cu, pu) );motionCompensation( pu, predBufTmp, RefPicList(1 - iRefList) );}RefPicList  eRefPicList = ( iRefList ? REF_PIC_LIST_1 : REF_PIC_LIST_0 );if(cs.picHeader->getMvdL1ZeroFlag()) // L1的MVD为零{iRefList = 0;eRefPicList = REF_PIC_LIST_0;}bool bChanged = false;iRefStart = 0;iRefEnd   = cs.slice->getNumRefIdx(eRefPicList)-1;//起始参考帧和最后参考帧// 遍历所有的参考帧for (int iRefIdxTemp = iRefStart; iRefIdxTemp <= iRefEnd; iRefIdxTemp++){if( m_pcEncCfg->getUseBcwFast() && (bcwIdx != BCW_DEFAULT)&& (pu.cu->slice->getRefPic(eRefPicList, iRefIdxTemp)->getPOC() == pu.cu->slice->getRefPic(RefPicList(1 - iRefList), pu.refIdx[1 - iRefList])->getPOC())&& (!pu.cu->imv && pu.cu->slice->getTLayer()>1)){continue;}uiBitsTemp = uiMbBits[2] + uiMotBits[1-iRefList];uiBitsTemp += ((cs.slice->getSPS()->getUseBcw() == true) ? getWeightIdxBits(bcwIdx) : 0);if ( cs.slice->getNumRefIdx(eRefPicList) > 1 ){uiBitsTemp += iRefIdxTemp+1;if ( iRefIdxTemp == cs.slice->getNumRefIdx(eRefPicList)-1 ){uiBitsTemp--;}}uiBitsTemp += m_auiMVPIdxCost[aaiMvpIdxBi[iRefList][iRefIdxTemp]][AMVP_MAX_NUM_CANDS];if ( cs.slice->getBiDirPred() ){uiBitsTemp += 1; // add one bit for symmetrical MVD mode}// call ME 运动估计xCopyAMVPInfo(&aacAMVPInfo[iRefList][iRefIdxTemp], &amvp[eRefPicList] );xMotionEstimation ( pu, origBuf, eRefPicList, cMvPredBi[iRefList][iRefIdxTemp], iRefIdxTemp, cMvTemp[iRefList][iRefIdxTemp], aaiMvpIdxBi[iRefList][iRefIdxTemp], uiBitsTemp, uiCostTemp, amvp[eRefPicList], true );xCheckBestMVP( eRefPicList, cMvTemp[iRefList][iRefIdxTemp], cMvPredBi[iRefList][iRefIdxTemp], aaiMvpIdxBi[iRefList][iRefIdxTemp], amvp[eRefPicList], uiBitsTemp, uiCostTemp, pu.cu->imv);if ( uiCostTemp < uiCostBi ) {bChanged = true;cMvBi[iRefList]     = cMvTemp[iRefList][iRefIdxTemp];iRefIdxBi[iRefList] = iRefIdxTemp;uiCostBi            = uiCostTemp;uiMotBits[iRefList] = uiBitsTemp - uiMbBits[2] - uiMotBits[1-iRefList];uiMotBits[iRefList] -= ((cs.slice->getSPS()->getUseBcw() == true) ? getWeightIdxBits(bcwIdx) : 0);uiBits[2]           = uiBitsTemp;if(iNumIter!=1){//  Set motionpu.mv    [eRefPicList] = cMvBi    [iRefList];pu.refIdx[eRefPicList] = iRefIdxBi[iRefList];PelUnitBuf predBufTmp = m_tmpPredStorage[iRefList].getBuf( UnitAreaRelative(cu, pu) );motionCompensation( pu, predBufTmp, eRefPicList );}}} // for loop-iRefIdxTempif ( !bChanged ){if ((uiCostBi <= uiCost[0] && uiCostBi <= uiCost[1]) || enforceBcwPred){xCopyAMVPInfo(&aacAMVPInfo[0][iRefIdxBi[0]], &amvp[REF_PIC_LIST_0]);xCheckBestMVP( REF_PIC_LIST_0, cMvBi[0], cMvPredBi[0][iRefIdxBi[0]], aaiMvpIdxBi[0][iRefIdxBi[0]], amvp[REF_PIC_LIST_0], uiBits[2], uiCostBi, pu.cu->imv);if(!cs.picHeader->getMvdL1ZeroFlag()){xCopyAMVPInfo(&aacAMVPInfo[1][iRefIdxBi[1]], &amvp[REF_PIC_LIST_1]);xCheckBestMVP( REF_PIC_LIST_1, cMvBi[1], cMvPredBi[1][iRefIdxBi[1]], aaiMvpIdxBi[1][iRefIdxBi[1]], amvp[REF_PIC_LIST_1], uiBits[2], uiCostBi, pu.cu->imv);}}break;}} // for loop-iter}cu.refIdxBi[0] = iRefIdxBi[0];cu.refIdxBi[1] = iRefIdxBi[1];/*==================对称MVD模式=====================*/if ( cs.slice->getBiDirPred() && trySmvd ) {Distortion symCost;Mv cMvPredSym[2];int mvpIdxSym[2];int curRefList = REF_PIC_LIST_0; //将当前参考帧列表设置为List0int tarRefList = 1 - curRefList; //目标参考帧列表设置为List1,到时候不需要传List1对应的MVDRefPicList eCurRefList = (curRefList ? REF_PIC_LIST_1 : REF_PIC_LIST_0);int refIdxCur = cs.slice->getSymRefIdx( curRefList ); //List-0的参考帧索引int refIdxTar = cs.slice->getSymRefIdx( tarRefList ); //List-1的参考帧索引CHECK (refIdxCur==-1 || refIdxTar==-1, "Uninitialized reference index not allowed");if ( aacAMVPInfo[curRefList][refIdxCur].mvCand[0] == aacAMVPInfo[curRefList][refIdxCur].mvCand[1] )aacAMVPInfo[curRefList][refIdxCur].numCand = 1;if ( aacAMVPInfo[tarRefList][refIdxTar].mvCand[0] == aacAMVPInfo[tarRefList][refIdxTar].mvCand[1] )aacAMVPInfo[tarRefList][refIdxTar].numCand = 1;MvField cCurMvField, cTarMvField;Distortion costStart = std::numeric_limits<Distortion>::max();for ( int i = 0; i < aacAMVPInfo[curRefList][refIdxCur].numCand; i++ ){for ( int j = 0; j < aacAMVPInfo[tarRefList][refIdxTar].numCand; j++ ){cCurMvField.setMvField( aacAMVPInfo[curRefList][refIdxCur].mvCand[i], refIdxCur );cTarMvField.setMvField( aacAMVPInfo[tarRefList][refIdxTar].mvCand[j], refIdxTar );Distortion cost = xGetSymmetricCost( pu, origBuf, eCurRefList, cCurMvField, cTarMvField, bcwIdx );if ( cost < costStart ){costStart = cost;cMvPredSym[curRefList] = aacAMVPInfo[curRefList][refIdxCur].mvCand[i];cMvPredSym[tarRefList] = aacAMVPInfo[tarRefList][refIdxTar].mvCand[j];mvpIdxSym[curRefList] = i;mvpIdxSym[tarRefList] = j;}}}cCurMvField.mv = cMvPredSym[curRefList];cTarMvField.mv = cMvPredSym[tarRefList];m_pcRdCost->setCostScale(0);Mv pred = cMvPredSym[curRefList];pred.changeTransPrecInternal2Amvr(pu.cu->imv);m_pcRdCost->setPredictor(pred);Mv mv = cCurMvField.mv;mv.changeTransPrecInternal2Amvr(pu.cu->imv);uint32_t bits = m_pcRdCost->getBitsOfVectorWithPredictor(mv.hor, mv.ver, 0);bits += m_auiMVPIdxCost[mvpIdxSym[curRefList]][AMVP_MAX_NUM_CANDS];bits += m_auiMVPIdxCost[mvpIdxSym[tarRefList]][AMVP_MAX_NUM_CANDS];costStart += m_pcRdCost->getCost(bits);std::vector<Mv> symmvdCands; //对称MVD候选MV列表auto smmvdCandsGen = [&](Mv mvCand, bool mvPrecAdj) //定义对称MVD添加候选MV函数{if (mvPrecAdj && pu.cu->imv){mvCand.roundTransPrecInternal2Amvr(pu.cu->imv);}bool toAddMvCand = true;for (std::vector<Mv>::iterator pos = symmvdCands.begin(); pos != symmvdCands.end(); pos++){if (*pos == mvCand){toAddMvCand = false;break;}}if (toAddMvCand){symmvdCands.push_back(mvCand);}};smmvdCandsGen(cMvHevcTemp[curRefList][refIdxCur], false);smmvdCandsGen(cMvTemp[curRefList][refIdxCur], false);if (iRefIdxBi[curRefList] == refIdxCur){smmvdCandsGen(cMvBi[curRefList], false);}for (int i = 0; i < m_uniMvListSize; i++){if ( symmvdCands.size() >= 5 )break;BlkUniMvInfo* curMvInfo = m_uniMvList + ((m_uniMvListIdx - 1 - i + m_uniMvListMaxSize) % (m_uniMvListMaxSize));smmvdCandsGen(curMvInfo->uniMvs[curRefList][refIdxCur], true);} for (auto mvStart : symmvdCands) //遍历候选列表,选出最佳的候选MVP{bool checked = false; //if it has been checkin in the mvPred.for (int i = 0; i < aacAMVPInfo[curRefList][refIdxCur].numCand && !checked; i++){checked |= (mvStart == aacAMVPInfo[curRefList][refIdxCur].mvCand[i]);}if (checked){continue;}Distortion bestCost = costStart;symmvdCheckBestMvp(pu, origBuf, mvStart, (RefPicList)curRefList, aacAMVPInfo, bcwIdx, cMvPredSym, mvpIdxSym, costStart);if (costStart < bestCost){cCurMvField.setMvField(mvStart, refIdxCur);cTarMvField.setMvField(mvStart.getSymmvdMv(cMvPredSym[curRefList], cMvPredSym[tarRefList]), refIdxTar);}}Mv startPtMv = cCurMvField.mv;Distortion mvpCost = m_pcRdCost->getCost(m_auiMVPIdxCost[mvpIdxSym[curRefList]][AMVP_MAX_NUM_CANDS] + m_auiMVPIdxCost[mvpIdxSym[tarRefList]][AMVP_MAX_NUM_CANDS]);symCost = costStart - mvpCost;// ME 对称运动估计xSymmetricMotionEstimation( pu, origBuf, cMvPredSym[curRefList], cMvPredSym[tarRefList], eCurRefList, cCurMvField, cTarMvField, symCost, bcwIdx );symCost += mvpCost;if (startPtMv != cCurMvField.mv){ // if ME change MV, run a final check for best MVP.symmvdCheckBestMvp(pu, origBuf, cCurMvField.mv, (RefPicList)curRefList, aacAMVPInfo, bcwIdx, cMvPredSym, mvpIdxSym, symCost, true);}bits = uiMbBits[2];bits += 1; // add one bit for #symmetrical MVD modebits += ((cs.slice->getSPS()->getUseBcw() == true) ? getWeightIdxBits(bcwIdx) : 0);symCost += m_pcRdCost->getCost(bits);cTarMvField.setMvField(cCurMvField.mv.getSymmvdMv(cMvPredSym[curRefList], cMvPredSym[tarRefList]), refIdxTar);if( m_pcEncCfg->getMCTSEncConstraint() ){if( !( MCTSHelper::checkMvForMCTSConstraint( pu, cCurMvField.mv ) && MCTSHelper::checkMvForMCTSConstraint( pu, cTarMvField.mv ) ) )symCost = std::numeric_limits<Distortion>::max();}// save resultsif ( symCost < uiCostBi ){uiCostBi = symCost;symMode = 1 + curRefList;cMvBi[curRefList] = cCurMvField.mv;iRefIdxBi[curRefList] = cCurMvField.refIdx;aaiMvpIdxBi[curRefList][cCurMvField.refIdx] = mvpIdxSym[curRefList];cMvPredBi[curRefList][iRefIdxBi[curRefList]] = cMvPredSym[curRefList];cMvBi[tarRefList] = cTarMvField.mv;iRefIdxBi[tarRefList] = cTarMvField.refIdx;aaiMvpIdxBi[tarRefList][cTarMvField.refIdx] = mvpIdxSym[tarRefList];cMvPredBi[tarRefList][iRefIdxBi[tarRefList]] = cMvPredSym[tarRefList];}}} // if (B_SLICE)//  Clear Motion Field 清空pu中的运动信息pu.mv    [REF_PIC_LIST_0] = Mv();pu.mv    [REF_PIC_LIST_1] = Mv();pu.mvd   [REF_PIC_LIST_0] = cMvZero;pu.mvd   [REF_PIC_LIST_1] = cMvZero;pu.refIdx[REF_PIC_LIST_0] = NOT_VALID;pu.refIdx[REF_PIC_LIST_1] = NOT_VALID;pu.mvpIdx[REF_PIC_LIST_0] = NOT_VALID;pu.mvpIdx[REF_PIC_LIST_1] = NOT_VALID;pu.mvpNum[REF_PIC_LIST_0] = NOT_VALID;pu.mvpNum[REF_PIC_LIST_1] = NOT_VALID;// Set Motion FieldcMv    [1] = mvValidList1;iRefIdx[1] = refIdxValidList1;uiBits [1] = bitsValidList1;uiCost [1] = costValidList1;if (cu.cs->pps->getWPBiPred() == true && tryBipred && (bcwIdx != BCW_DEFAULT)){CHECK(iRefIdxBi[0]<0, "Invalid picture reference index");CHECK(iRefIdxBi[1]<0, "Invalid picture reference index");wp0 = cu.cs->slice->getWpScaling(REF_PIC_LIST_0, iRefIdxBi[0]);wp1 = cu.cs->slice->getWpScaling(REF_PIC_LIST_1, iRefIdxBi[1]);if (WPScalingParam::isWeighted(wp0) || WPScalingParam::isWeighted(wp1)){uiCostBi = MAX_UINT;enforceBcwPred = false;}}if( enforceBcwPred ){uiCost[0] = uiCost[1] = MAX_UINT;}uiLastModeTemp = uiLastMode;if ( uiCostBi <= uiCost[0] && uiCostBi <= uiCost[1]) //双向预测的Cost小于前后单向预测的Cost{uiLastMode = 2;pu.mv    [REF_PIC_LIST_0] = cMvBi[0];pu.mv    [REF_PIC_LIST_1] = cMvBi[1];pu.mvd   [REF_PIC_LIST_0] = cMvBi[0] - cMvPredBi[0][iRefIdxBi[0]];pu.mvd   [REF_PIC_LIST_1] = cMvBi[1] - cMvPredBi[1][iRefIdxBi[1]];pu.refIdx[REF_PIC_LIST_0] = iRefIdxBi[0];pu.refIdx[REF_PIC_LIST_1] = iRefIdxBi[1];pu.mvpIdx[REF_PIC_LIST_0] = aaiMvpIdxBi[0][iRefIdxBi[0]];pu.mvpIdx[REF_PIC_LIST_1] = aaiMvpIdxBi[1][iRefIdxBi[1]];pu.mvpNum[REF_PIC_LIST_0] = aaiMvpNum[0][iRefIdxBi[0]];pu.mvpNum[REF_PIC_LIST_1] = aaiMvpNum[1][iRefIdxBi[1]];pu.interDir = 3;pu.cu->smvdMode = symMode;}else if ( uiCost[0] <= uiCost[1] ) //前向预测的Cost小于后向预测的Cost{uiLastMode = 0;pu.mv    [REF_PIC_LIST_0] = cMv[0];pu.mvd   [REF_PIC_LIST_0] = cMv[0] - cMvPred[0][iRefIdx[0]];pu.refIdx[REF_PIC_LIST_0] = iRefIdx[0];pu.mvpIdx[REF_PIC_LIST_0] = aaiMvpIdx[0][iRefIdx[0]];pu.mvpNum[REF_PIC_LIST_0] = aaiMvpNum[0][iRefIdx[0]];pu.interDir = 1;}else{uiLastMode = 1;pu.mv    [REF_PIC_LIST_1] = cMv[1];pu.mvd   [REF_PIC_LIST_1] = cMv[1] - cMvPred[1][iRefIdx[1]];pu.refIdx[REF_PIC_LIST_1] = iRefIdx[1];pu.mvpIdx[REF_PIC_LIST_1] = aaiMvpIdx[1][iRefIdx[1]];pu.mvpNum[REF_PIC_LIST_1] = aaiMvpNum[1][iRefIdx[1]];pu.interDir = 2;}if( bcwIdx != BCW_DEFAULT ){cu.BcwIdx = BCW_DEFAULT; // Reset to default for the Non-NormalMC modes.}uiHevcCost = ( uiCostBi <= uiCost[0] && uiCostBi <= uiCost[1] ) ? uiCostBi : ( ( uiCost[0] <= uiCost[1] ) ? uiCost[0] : uiCost[1] );}if (cu.Y().width > 8 && cu.Y().height > 8 && cu.slice->getSPS()->getUseAffine()&& checkAffine&& (bcwIdx == BCW_DEFAULT || m_affineModeSelected || !m_pcEncCfg->getUseBcwFast())) //Affine AMVP模式{m_hevcCost = uiHevcCost;// save normal hevc resultuint32_t uiMRGIndex = pu.mergeIdx;bool bMergeFlag = pu.mergeFlag;uint32_t uiInterDir = pu.interDir;int  iSymMode = cu.smvdMode;Mv cMvd[2];uint32_t uiMvpIdx[2], uiMvpNum[2];uiMvpIdx[0] = pu.mvpIdx[REF_PIC_LIST_0];uiMvpIdx[1] = pu.mvpIdx[REF_PIC_LIST_1];uiMvpNum[0] = pu.mvpNum[REF_PIC_LIST_0];uiMvpNum[1] = pu.mvpNum[REF_PIC_LIST_1];cMvd[0]     = pu.mvd[REF_PIC_LIST_0];cMvd[1]     = pu.mvd[REF_PIC_LIST_1];MvField cHevcMvField[2];cHevcMvField[0].setMvField( pu.mv[REF_PIC_LIST_0], pu.refIdx[REF_PIC_LIST_0] );cHevcMvField[1].setMvField( pu.mv[REF_PIC_LIST_1], pu.refIdx[REF_PIC_LIST_1] );// do affine ME & Merge// 先检查4参数cu.affineType = AFFINEMODEL_4PARAM;Mv acMvAffine4Para[2][33][3];int refIdx4Para[2] = { -1, -1 };xPredAffineInterSearch(pu, origBuf, puIdx, uiLastModeTemp, uiAffineCost, cMvHevcTemp, acMvAffine4Para, refIdx4Para, bcwIdx, enforceBcwPred,((cu.slice->getSPS()->getUseBcw() == true) ? getWeightIdxBits(bcwIdx) : 0));if ( pu.cu->imv == 0 ){storeAffineMotion( pu.mvAffi, pu.refIdx, AFFINEMODEL_4PARAM, bcwIdx );}if ( cu.slice->getSPS()->getUseAffineType() ){if ( uiAffineCost < uiHevcCost * 1.05 ) ///< condition for 6 parameter affine ME 如果四参数模型的Cost小于1.05倍的常规AMVP的Cost{// save 4 parameter resultsMv bestMv[2][3], bestMvd[2][3];int bestMvpIdx[2], bestMvpNum[2], bestRefIdx[2];uint8_t bestInterDir;bestInterDir = pu.interDir;bestRefIdx[0] = pu.refIdx[0];bestRefIdx[1] = pu.refIdx[1];bestMvpIdx[0] = pu.mvpIdx[0];bestMvpIdx[1] = pu.mvpIdx[1];bestMvpNum[0] = pu.mvpNum[0];bestMvpNum[1] = pu.mvpNum[1];for ( int refList = 0; refList < 2; refList++ ){bestMv[refList][0] = pu.mvAffi[refList][0];bestMv[refList][1] = pu.mvAffi[refList][1];bestMv[refList][2] = pu.mvAffi[refList][2];bestMvd[refList][0] = pu.mvdAffi[refList][0];bestMvd[refList][1] = pu.mvdAffi[refList][1];bestMvd[refList][2] = pu.mvdAffi[refList][2];}refIdx4Para[0] = bestRefIdx[0];refIdx4Para[1] = bestRefIdx[1];// 六参数模型运动估计Distortion uiAffine6Cost = std::numeric_limits<Distortion>::max();cu.affineType = AFFINEMODEL_6PARAM;xPredAffineInterSearch(pu, origBuf, puIdx, uiLastModeTemp, uiAffine6Cost, cMvHevcTemp, acMvAffine4Para, refIdx4Para, bcwIdx, enforceBcwPred,((cu.slice->getSPS()->getUseBcw() == true) ? getWeightIdxBits(bcwIdx) : 0));if ( pu.cu->imv == 0 ){storeAffineMotion( pu.mvAffi, pu.refIdx, AFFINEMODEL_6PARAM, bcwIdx );}// reset to 4 parameter affine inter mode if ( uiAffineCost <= uiAffine6Cost ){cu.affineType = AFFINEMODEL_4PARAM;pu.interDir = bestInterDir;pu.refIdx[0] = bestRefIdx[0];pu.refIdx[1] = bestRefIdx[1];pu.mvpIdx[0] = bestMvpIdx[0];pu.mvpIdx[1] = bestMvpIdx[1];pu.mvpNum[0] = bestMvpNum[0];pu.mvpNum[1] = bestMvpNum[1];for ( int verIdx = 0; verIdx < 3; verIdx++ ){pu.mvdAffi[REF_PIC_LIST_0][verIdx] = bestMvd[0][verIdx];pu.mvdAffi[REF_PIC_LIST_1][verIdx] = bestMvd[1][verIdx];}PU::setAllAffineMv( pu, bestMv[0][0], bestMv[0][1], bestMv[0][2], REF_PIC_LIST_0);PU::setAllAffineMv( pu, bestMv[1][0], bestMv[1][1], bestMv[1][2], REF_PIC_LIST_1);}else{uiAffineCost = uiAffine6Cost;}}uiAffineCost += m_pcRdCost->getCost( 1 ); // add one bit for affine_type}if( uiAffineCost < uiHevcCost ){if( m_pcEncCfg->getMCTSEncConstraint() && !MCTSHelper::checkMvBufferForMCTSConstraint( pu ) ){uiAffineCost = std::numeric_limits<Distortion>::max();}}if ( uiHevcCost <= uiAffineCost ){// set hevc me resultcu.affine = false;pu.mergeFlag = bMergeFlag;pu.regularMergeFlag = false;pu.mergeIdx = uiMRGIndex;pu.interDir = uiInterDir;cu.smvdMode = iSymMode;pu.mv    [REF_PIC_LIST_0] = cHevcMvField[0].mv;pu.refIdx[REF_PIC_LIST_0] = cHevcMvField[0].refIdx;pu.mv    [REF_PIC_LIST_1] = cHevcMvField[1].mv;pu.refIdx[REF_PIC_LIST_1] = cHevcMvField[1].refIdx;pu.mvpIdx[REF_PIC_LIST_0] = uiMvpIdx[0];pu.mvpIdx[REF_PIC_LIST_1] = uiMvpIdx[1];pu.mvpNum[REF_PIC_LIST_0] = uiMvpNum[0];pu.mvpNum[REF_PIC_LIST_1] = uiMvpNum[1];pu.mvd[REF_PIC_LIST_0] = cMvd[0];pu.mvd[REF_PIC_LIST_1] = cMvd[1];}else{cu.smvdMode = 0;CHECK( !cu.affine, "Wrong." );uiLastMode = uiLastModeTemp;}}if( cu.firstPU->interDir == 3 && !cu.firstPU->mergeFlag ){if (bcwIdx != BCW_DEFAULT){cu.BcwIdx = bcwIdx;}}m_maxCompIDToPred = MAX_NUM_COMPONENT;{PU::spanMotionInfo( pu, mergeCtx );}m_skipPROF = false;m_encOnly = false;//  MC 运动补偿PelUnitBuf predBuf = pu.cs->getPredBuf(pu);if ( bcwIdx == BCW_DEFAULT || !m_affineMotion.affine4ParaAvail || !m_affineMotion.affine6ParaAvail ){m_affineMotion.hevcCost[pu.cu->imv] = uiHevcCost;}motionCompensation( pu, predBuf, REF_PIC_LIST_X );puIdx++;}setWpScalingDistParam( -1, REF_PIC_LIST_X, cu.cs->slice );return;
}

更多推荐

H.266/VVC代码学习:predInterSearch函数

本文发布于:2024-02-06 10:09:00,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1747853.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:函数   代码   VVC   predInterSearch

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!