xCheckRDCostMerge2Nx2N在xCompressCU函数中调用,用来测试Merge模式、mmvd模式以及CIIP模式。
首先由getInterMergeCandidates获取merge候选模式信息,存储于,mergeCtx。同时由merge列表获取MMVD模式的两个baseMV。
如果不进行fastMerge,则跳过SATD直接进行RDO选最优
fastMerge时,对7个merge候选模式进行SATD,分别进行MC获得pred像素,选取cost最小的4个merge候选;对于MMVD模式分别以这两个mv为中心进行4方向8步长的计算,得到最优的baseMV、方向和步长。CIIP模式则选择经过SATD之后的前4个merge模式,分别于帧内模式结合,选取最优的merge模式和帧内模式。
对RdModeList中的merge候选、MMVD模式以及CIIP模式,统一进行RDO选择最优。

void EncCu::xCheckRDCostMerge2Nx2N( CodingStructure *&tempCS, CodingStructure *&bestCS, Partitioner &partitioner, const EncTestMode& encTestMode )
{const Slice &slice = *tempCS->slice;CHECK( slice.getSliceType() == I_SLICE, "Merge modes not available for I-slices" );tempCS->initStructData( encTestMode.qp, encTestMode.lossless );      //tempCS清空初始化MergeCtx mergeCtx;const SPS &sps = *tempCS->sps;if( sps.getSpsNext().getUseSubPuMvp() ){Size bufSize = g_miScaling.scale( tempCS->area.lumaSize() );mergeCtx.subPuMvpMiBuf    = MotionBuf( m_SubPuMiBuf,    bufSize );}#if JVET_L0124_L0208_TRIANGLEsetMergeBestSATDCost( MAX_DOUBLE );
#endif{// first get merge candidatesCodingUnit cu( tempCS->area );           //创建cu、pu用来获得merge列表cu.cs       = tempCS;cu.partSize = SIZE_2Nx2N;cu.predMode = MODE_INTER;cu.slice    = tempCS->slice;
#if HEVC_TILES_WPPcu.tileIdx  = tempCS->picture->tileMap->getTileIdxMap(tempCS->area.lumaPos());
#endifPredictionUnit pu( tempCS->area );pu.cu = &cu;pu.cs = tempCS;PU::getInterMergeCandidates(pu, mergeCtx        //获取merge列表,其中包含7个merge候选信息,存储于mergeCtx
#if JVET_L0054_MMVD, 0
#endif);PU::restrictBiPredMergeCands(pu, mergeCtx);
#if JVET_L0054_MMVDPU::getInterMMVDMergeCandidates(pu, mergeCtx);   //MMVD选择merge列表的前两个候选,作为baseMV
#endif}bool candHasNoResidual[MRG_MAX_NUM_CANDS + MMVD_ADD_NUM];       //若merge模式没有resi,则为skip模式for (uint32_t ui = 0; ui < MRG_MAX_NUM_CANDS + MMVD_ADD_NUM; ui++){candHasNoResidual[ui] = false;}bool                                        bestIsSkip = false;bool                                        bestIsMMVDSkip = true;
#if JVET_L0100_MULTI_HYPOTHESIS_INTRAPelUnitBuf                                  acMergeBuffer[MRG_MAX_NUM_CANDS];  //里面存储的是:merge列表里面候选模式0~6顺序排列的各模式的pred像素
#endifPelUnitBuf                                  acMergeRealBuffer[MMVD_MRG_MAX_RD_BUF_NUM];//存储RDModeList前7个mode的pred像素PelUnitBuf *                                acMergeTempBuffer[MMVD_MRG_MAX_RD_NUM];    //acMergeTempBuffer中始终存储的是RDModeList前几个模式的pred像素PelUnitBuf *                                singleMergeTempBuffer;                  //这两个是指针int                                         insertPos;unsigned                                    uiNumMrgSATDCand = mergeCtx.numValidMergeCand + MMVD_ADD_NUM;static_vector<unsigned, MRG_MAX_NUM_CANDS + MMVD_ADD_NUM>  RdModeList;bool                                        mrgTempBufSet = false;for (unsigned i = 0; i < MRG_MAX_NUM_CANDS + MMVD_ADD_NUM; i++){RdModeList.push_back(i);        //如果不进行SATD,那么RdModeList中存放7+64个merge候选,直接进行最后的RDO}const UnitArea localUnitArea(tempCS->area.chromaFormat, Area(0, 0, tempCS->area.Y().width, tempCS->area.Y().height));for (unsigned i = 0; i < MMVD_MRG_MAX_RD_BUF_NUM; i++){acMergeRealBuffer[i] = m_acMergeBuffer[i].getBuf(localUnitArea);if (i < MMVD_MRG_MAX_RD_NUM){acMergeTempBuffer[i] = acMergeRealBuffer + i;}else{singleMergeTempBuffer = acMergeRealBuffer + i;}}/以上为初始化,并获取Merge列表#if JVET_L0100_MULTI_HYPOTHESIS_INTRA
#if JVET_L0054_MMVDstatic_vector<unsigned, MRG_MAX_NUM_CANDS + MMVD_ADD_NUM>  RdModeList2; // store the Intra mode for Intrainter
#elsestatic_vector<unsigned, MRG_MAX_NUM_CANDS>  RdModeList2; // store the Intra mode for Intrainter
#endifRdModeList2.clear();bool isIntrainterEnabled = sps.getSpsNext().getUseMHIntra();if (bestCS->area.lwidth() * bestCS->area.lheight() < 64 || bestCS->area.lwidth() >= MAX_CU_SIZE || bestCS->area.lheight() >= MAX_CU_SIZE){isIntrainterEnabled = false;}bool isTestSkipMerge[MRG_MAX_NUM_CANDS]; // record if the merge candidate has tried skip mode for (uint32_t idx = 0; idx < MRG_MAX_NUM_CANDS; idx++){isTestSkipMerge[idx] = false;}
#endif
#if JVET_L0100_MULTI_HYPOTHESIS_INTRAif( m_pcEncCfg->getUseFastMerge() || isIntrainterEnabled)           // FastMerge || CIIP
#elseif( m_pcEncCfg->getUseFastMerge() )
#endif{uiNumMrgSATDCand = NUM_MRG_SATD_CAND;       //SATD粗选择后的merge候选数目,4
#if JVET_L0100_MULTI_HYPOTHESIS_INTRAif (isIntrainterEnabled){uiNumMrgSATDCand += 1;          //4加一个CIIP模式}
#endifbestIsSkip       = false;if( auto blkCache = dynamic_cast< CacheBlkInfoCtrl* >( m_modeCtrl ) ){#if JVET_L0293_CPRif (slice.getSPS()->getSpsNext().getCPRMode()){ComprCUCtx cuECtx = m_modeCtrl->getComprCUCtx();bestIsSkip = blkCache->isSkip(tempCS->area) && cuECtx.bestCU;}else
#endifbestIsSkip = blkCache->isSkip( tempCS->area );
#if JVET_L0054_MMVDbestIsMMVDSkip = blkCache->isMMVDSkip(tempCS->area);
#endif}#if JVET_L0100_MULTI_HYPOTHESIS_INTRAif (isIntrainterEnabled) // always perform low complexity check{bestIsSkip = false;}
#endif#if JVET_L0054_MMVDstatic_vector<double, MRG_MAX_NUM_CANDS + MMVD_ADD_NUM> candCostList;       //存放SATD时得到的7+64个候选的cost
#elsestatic_vector<double, MRG_MAX_NUM_CANDS> candCostList;
#endif// 1. Pass: get SATD-cost for selected candidates and reduce their countif( !bestIsSkip )             //不是skip模式,对7+64个merge候选模式进行SATD粗选择{RdModeList.clear();         //RdModeList前面有压栈操作,这里清空mrgTempBufSet       = true;const double sqrtLambdaForFirstPass = m_pcRdCost->getMotionLambda( encTestMode.lossless );CodingUnit &cu      = tempCS->addCU( tempCS->area, partitioner.chType );        //tempCS添加cu和pu
#if JVET_L0100_MULTI_HYPOTHESIS_INTRAconst double sqrtLambdaForFirstPassIntra = m_pcRdCost->getMotionLambda(cu.transQuantBypass) / double(1 << SCALE_BITS);
#endifpartitioner.setCUData( cu );cu.slice            = tempCS->slice;
#if HEVC_TILES_WPPcu.tileIdx          = tempCS->picture->tileMap->getTileIdxMap( tempCS->area.lumaPos() );
#endifcu.skip             = false;
#if JVET_L0054_MMVDcu.mmvdSkip        = false;
#endif
#if JVET_L0124_L0208_TRIANGLEcu.triangle         = false;
#endifcu.partSize         = SIZE_2Nx2N;//cu.affinecu.predMode         = MODE_INTER;//cu.LICFlagcu.transQuantBypass = encTestMode.lossless;cu.chromaQpAdj      = cu.transQuantBypass ? 0 : m_cuChromaQpOffsetIdxPlus1;cu.qp               = encTestMode.qp;//cu.emtFlag  is set belowPredictionUnit &pu  = tempCS->addPU( cu, partitioner.chType );DistParam distParam;const bool bUseHadamard= !encTestMode.lossless; //用来计算失真的pred像素存储在m_acMergeBuffer[0].Y()//设置计算失真的类:distParam 的各项参数m_pcRdCost->setDistParam (distParam, tempCS->getOrgBuf().Y(), m_acMergeBuffer[0].Y(), sps.getBitDepth (CHANNEL_TYPE_LUMA), COMPONENT_Y, bUseHadamard);const UnitArea localUnitArea( tempCS->area.chromaFormat, Area( 0, 0, tempCS->area.Y().width, tempCS->area.Y().height) );
#if JVET_L0293_CPRuint32_t cprCand = 0;uint32_t numValidMv = mergeCtx.numValidMergeCand;
#endiffor( uint32_t uiMergeCand = 0; uiMergeCand < mergeCtx.numValidMergeCand; uiMergeCand++ )    //Merge列表的loop,merge候选进行SATD{#if JVET_L0293_CPRif ((mergeCtx.interDirNeighbours[uiMergeCand] == 1 || mergeCtx.interDirNeighbours[uiMergeCand] == 3) && tempCS->slice->getRefPic(REF_PIC_LIST_0, mergeCtx.mvFieldNeighbours[uiMergeCand << 1].refIdx)->getPOC() == tempCS->slice->getPOC()){cprCand++;numValidMv--;continue;}
#endif
#if !JVET_L0054_MMVDacMergeBuffer[uiMergeCand] = m_acMergeBuffer[uiMergeCand].getBuf( localUnitArea );
#endifmergeCtx.setMergeInfo( pu, uiMergeCand );PU::spanMotionInfo( pu, mergeCtx );
#if JVET_L0054_MMVDdistParam.cur = singleMergeTempBuffer->Y();      //MMVD模式中MC得到的pred像素存储在singleMergeTempBuffer->Y()中m_pcInterSearch->motionCompensation(pu, *singleMergeTempBuffer);        // MC
#if JVET_L0100_MULTI_HYPOTHESIS_INTRAacMergeBuffer[uiMergeCand] = m_acRealMergeBuffer[uiMergeCand].getBuf(localUnitArea);acMergeBuffer[uiMergeCand].copyFrom(*singleMergeTempBuffer);  //acMergeBuffer存储merge列表0~6的pred像素,用于最后CIIP和普通merge的处理
#endif
#elsedistParam.cur = acMergeBuffer[uiMergeCand].Y();m_pcInterSearch->motionCompensation( pu,  acMergeBuffer[uiMergeCand] );
#endifif( mergeCtx.interDirNeighbours[uiMergeCand] == 3 && mergeCtx.mrgTypeNeighbours[uiMergeCand] == MRG_TYPE_DEFAULT_N ){mergeCtx.mvFieldNeighbours[2*uiMergeCand].mv   = pu.mv[0];      //双向预测时mergeCtx.mvFieldNeighbours[2*uiMergeCand+1].mv = pu.mv[1];
#if DMVR_JVET_LOW_LATENCY_K0217refinedMvdL0[uiMergeCand] = pu.mvd[0];
#endif}Distortion uiSad = distParam.distFunc(distParam);       //计算失真uint32_t uiBitsCand = uiMergeCand + 1;if( uiMergeCand == tempCS->slice->getMaxNumMergeCand() - 1 ){uiBitsCand--;}
#if JVET_L0054_MMVDuiBitsCand++; // for mmvd_flag
#endifdouble cost     = (double)uiSad + (double)uiBitsCand * sqrtLambdaForFirstPass;      //cost
#if JVET_L0054_MMVDinsertPos = -1;
#if JVET_L0100_MULTI_HYPOTHESIS_INTRA   //当前mode按cost大小顺序插入RdModeListupdateDoubleCandList(uiMergeCand, cost, RdModeList, candCostList, RdModeList2, (uint32_t)NUM_LUMA_MODE, uiNumMrgSATDCand, &insertPos);
#else
#if JVET_L0283_MULTI_REF_LINEstatic_vector<int, MRG_MAX_NUM_CANDS + MMVD_ADD_NUM> * nullList = nullptr;
#endifupdateCandList(uiMergeCand, cost, RdModeList, candCostList
#if JVET_L0283_MULTI_REF_LINE, *nullList, -1
#endif          , uiNumMrgSATDCand, &insertPos);
#endifif (insertPos != -1) //acMergeTempBuffer中始终存储的是RDModeList前几个模式的pred像素{if (insertPos == RdModeList.size() - 1)//若插入到vector的最后时,直接将MC得到的pred像素放到tempBuffer的最后一个{swap(singleMergeTempBuffer, acMergeTempBuffer[insertPos]);}else{for (uint32_t i = uint32_t(RdModeList.size()) - 1; i > insertPos; i--){swap(acMergeTempBuffer[i - 1], acMergeTempBuffer[i]);}swap(singleMergeTempBuffer, acMergeTempBuffer[insertPos]);}}
#else#if JVET_L0100_MULTI_HYPOTHESIS_INTRAupdateDoubleCandList(uiMergeCand, cost, RdModeList, candCostList, RdModeList2, (uint32_t)NUM_LUMA_MODE, uiNumMrgSATDCand);
#else
#if JVET_L0283_MULTI_REF_LINEstatic_vector<int, MRG_MAX_NUM_CANDS> * nullList = nullptr;
#endifupdateCandList( uiMergeCand, cost, RdModeList, candCostList
#if JVET_L0283_MULTI_REF_LINE, *nullList, -1
#endif, uiNumMrgSATDCand );
#endif
#endif
#if JVET_L0293_CPRCHECK(std::min(uiMergeCand + 1 - cprCand, uiNumMrgSATDCand) != RdModeList.size(), "");
#else        CHECK( std::min( uiMergeCand + 1, uiNumMrgSATDCand ) != RdModeList.size(), "" );
#endif}     //MergeCand 的loop结束,对Merge列表中的模式都进行了运动补偿,计算cost,排序
#if JVET_L0293_CPRif (numValidMv < uiNumMrgSATDCand)uiNumMrgSATDCand = numValidMv;if (numValidMv == 0)return;
#endif#if JVET_L0100_MULTI_HYPOTHESIS_INTRAif (isIntrainterEnabled)                     // CIIP{int numTestIntraMode = 4;// prepare for Intra bits calculationconst TempCtx ctxStart(m_CtxCache, m_CABACEstimator->getCtx());const TempCtx ctxStartIntraMode(m_CtxCache, SubCtx(Ctx::MHIntraPredMode, m_CABACEstimator->getCtx()));// for Intrainter fast, recored the best intra mode during the first round for mrege 0int bestMHIntraMode = -1;double bestMHIntraCost = MAX_DOUBLE;pu.mhIntraFlag = true;// save the to-be-tested merge candidatesuint32_t MHIntraMergeCand[NUM_MRG_SATD_CAND];
#if JVET_L0293_CPRfor (uint32_t mergeCnt = 0; mergeCnt < std::min(NUM_MRG_SATD_CAND, (const int) uiNumMrgSATDCand); mergeCnt++)
#elsefor (uint32_t mergeCnt = 0; mergeCnt < NUM_MRG_SATD_CAND; mergeCnt++)
#endif{MHIntraMergeCand[mergeCnt] = RdModeList[mergeCnt];      //CIIP的inter模式,取SATD后的前4个MergeMode}
#if JVET_L0293_CPRfor (uint32_t mergeCnt = 0; mergeCnt < std::min( std::min(NUM_MRG_SATD_CAND, (const int)uiNumMrgSATDCand), 4); mergeCnt++)
#elsefor (uint32_t mergeCnt = 0; mergeCnt < std::min(NUM_MRG_SATD_CAND, 4); mergeCnt++)
#endif                                                                      //4个mergeMode loop,选最优{uint32_t mergeCand = MHIntraMergeCand[mergeCnt];
#if JVET_L0054_MMVDacMergeBuffer[mergeCand] = m_acRealMergeBuffer[mergeCand].getBuf(localUnitArea);
#elseacMergeBuffer[mergeCand] = m_acMergeBuffer[mergeCand].getBuf(localUnitArea);
#endif// estimate merge bitsuint32_t bitsCand = mergeCand + 1;if (mergeCand == pu.cs->slice->getMaxNumMergeCand() - 1){bitsCand--;}// first roundfor (uint32_t intraCnt = 0; intraCnt < numTestIntraMode; intraCnt++)       //4个帧内预测模式loop{pu.intraDir[0] = (intraCnt < 2) ? intraCnt : ((intraCnt == 2) ? HOR_IDX : VER_IDX);// fast 2if (mergeCnt > 0 && bestMHIntraMode != pu.intraDir[0]) //只对第一个merge模式执行全面的4个intra模式的check{                                     //对于剩下的3个merge模式,只检查第一个merge模式中所选择的最优的那个intra模式continue;}int narrowCase = PU::getNarrowShape(pu.lwidth(), pu.lheight());if (narrowCase == 1 && pu.intraDir[0] == HOR_IDX)   //W >> H{continue;}if (narrowCase == 2 && pu.intraDir[0] == VER_IDX)  //H >> W{continue;}// generate intrainter Y prediction//只对第一个merge执行4次intra预测,预测结果保存在m_pcIntraSearch->getPredictorPtr2(COMPONENT_Y, intraCnt),所以后面的3个merge模式直接取用,不用再预测if (mergeCnt == 0){bool isUseFilter = IntraPrediction::useFilteredIntraRefSamples(COMPONENT_Y, pu, true, pu);m_pcIntraSearch->initIntraPatternChType(*pu.cu, pu.Y(), isUseFilter);m_pcIntraSearch->predIntraAng(COMPONENT_Y, pu.cs->getPredBuf(pu).Y(), pu, isUseFilter);m_pcIntraSearch->switchBuffer(pu, COMPONENT_Y, pu.cs->getPredBuf(pu).Y(), m_pcIntraSearch->getPredictorPtr2(COMPONENT_Y, intraCnt));}pu.cs->getPredBuf(pu).copyFrom(acMergeBuffer[mergeCand]); //pred像素copy入merge模式像素m_pcIntraSearch->geneWeightedPred(COMPONENT_Y, pu.cs->getPredBuf(pu).Y(), pu, m_pcIntraSearch->getPredictorPtr2(COMPONENT_Y, intraCnt));//CIIP模式中的intra和inter的加权平均// calculate costdistParam.cur = pu.cs->getPredBuf(pu).Y();    //此时pred存储的是intrainter加权像素Distortion sadValue = distParam.distFunc(distParam);                             //计算失真和costm_CABACEstimator->getCtx() = SubCtx(Ctx::MHIntraPredMode, ctxStartIntraMode);uint64_t fracModeBits = m_pcIntraSearch->xFracModeBitsIntra(pu, pu.intraDir[0], CHANNEL_TYPE_LUMA);double cost = (double)sadValue + (double)(bitsCand + 1) * sqrtLambdaForFirstPass + (double)fracModeBits * sqrtLambdaForFirstPassIntra;
#if JVET_L0054_MMVDinsertPos = -1;         //加入RDModeList时,mergeCand的基础上加了7+64,绕开普通merge和MMVDupdateDoubleCandList(mergeCand + MRG_MAX_NUM_CANDS + MMVD_ADD_NUM, cost, RdModeList, candCostList, RdModeList2, pu.intraDir[0], uiNumMrgSATDCand, &insertPos);
#elseupdateDoubleCandList(mergeCand + MRG_MAX_NUM_CANDS + MRG_MAX_NUM_CANDS, cost, RdModeList, candCostList, RdModeList2, pu.intraDir[0], uiNumMrgSATDCand);
#endif
#if JVET_L0054_MMVDif (insertPos != -1){for (int i = int(RdModeList.size()) - 1; i > insertPos; i--){swap(acMergeTempBuffer[i - 1], acMergeTempBuffer[i]);}swap(singleMergeTempBuffer, acMergeTempBuffer[insertPos]);}
#endif// fast 2 记录第一个merge模式中4个intra模式最优的那个if (mergeCnt == 0 && cost < bestMHIntraCost){bestMHIntraMode = pu.intraDir[0];bestMHIntraCost = cost;}}}pu.mhIntraFlag = false;m_CABACEstimator->getCtx() = ctxStart;}
#endif#if JVET_L0054_MMVD                                   // MMVDcu.mmvdSkip = true;int tempNum = 0;tempNum = MMVD_ADD_NUM;bool allowDirection[4] = { true, true, true, true };for (uint32_t mergeCand = mergeCtx.numValidMergeCand; mergeCand < mergeCtx.numValidMergeCand + tempNum; mergeCand++){                                                           //64个mvd进行loop,选取最优的mvdconst int mmvdMergeCand = mergeCand - mergeCtx.numValidMergeCand;int bitsBaseIdx = 0;int bitsRefineStep = 0;int bitsDirection = 2;int bitsCand = 0;int baseIdx;int refineStep;int direction;baseIdx = mmvdMergeCand / MMVD_MAX_REFINE_NUM;          //baseMV是第一个mergeMode还是第二个refineStep = (mmvdMergeCand - (baseIdx * MMVD_MAX_REFINE_NUM)) / 4;                  //步长direction = (mmvdMergeCand - baseIdx * MMVD_MAX_REFINE_NUM - refineStep * 4) % 4;  //mvd的方向if (refineStep == 0){allowDirection[direction] = true;}if (allowDirection[direction] == false){continue;}bitsBaseIdx = baseIdx + 1;if (baseIdx == MMVD_BASE_MV_NUM - 1){bitsBaseIdx--;}bitsRefineStep = refineStep + 1;if (refineStep == MMVD_REFINE_STEP - 1){bitsRefineStep--;}bitsCand = bitsBaseIdx + bitsRefineStep + bitsDirection;bitsCand++; // for mmvd_flag#if !JVET_L0054_MMVDacMergeBuffer[mergeCand] = m_acMergeBuffer[mergeCand].getBuf(localUnitArea);
#endifmergeCtx.setMmvdMergeCandiInfo(pu, mmvdMergeCand);        //由mmvdMergeCand获取mvd,从而得到pu的motioninfo信息PU::spanMotionInfo(pu, mergeCtx);
#if JVET_L0054_MMVDdistParam.cur = singleMergeTempBuffer->Y();m_pcInterSearch->motionCompensation(pu, *singleMergeTempBuffer);   //MC
#elsedistParam.cur = acMergeBuffer[mergeCand].Y();m_pcInterSearch->motionCompensation(pu, acMergeBuffer[mergeCand]);
#endifDistortion uiSad = distParam.distFunc(distParam);        //失真#if !JVET_L0054_MMVDuint32_t bitsCand = mergeCand + 1;if (mergeCand == tempCS->slice->getMaxNumMergeCand() - 1){bitsCand--;}
#endifdouble cost = (double)uiSad + (double)bitsCand * sqrtLambdaForFirstPass;    //cost
#if JVET_L0054_MMVDallowDirection[direction] = cost >  1.3 * candCostList[0] ? 0 : 1;   //只要一个方向上的8个点中有一个不达标,该方向剩下的点就不用测了
#endif
#if JVET_L0054_MMVDinsertPos = -1;
#if JVET_L0100_MULTI_HYPOTHESIS_INTRA       //MMVD插入RDModelList的模式是mergeCand,即7~71updateDoubleCandList(mergeCand, cost, RdModeList, candCostList, RdModeList2, (uint32_t)NUM_LUMA_MODE, uiNumMrgSATDCand, &insertPos);
#else
#if JVET_L0283_MULTI_REF_LINEstatic_vector<int, MRG_MAX_NUM_CANDS + MMVD_ADD_NUM> * nullList = nullptr;
#endifupdateCandList(mergeCand, cost, RdModeList, candCostList
#if JVET_L0283_MULTI_REF_LINE, *nullList, -1
#endif, uiNumMrgSATDCand, &insertPos);
#endifif (insertPos != -1){for (int i = int(RdModeList.size()) - 1; i > insertPos; i--){swap(acMergeTempBuffer[i - 1], acMergeTempBuffer[i]);}swap(singleMergeTempBuffer, acMergeTempBuffer[insertPos]);}
#elseupdateCandList(mergeCand, cost, RdModeList, candCostList, uiNumMrgSATDCand);
#endif
#if !JVET_L0054_MMVDCHECK(std::min(mergeCand + 1, uiNumMrgSATDCand) != RdModeList.size(), "");
#endif}
#endif// Try to limit number of candidates using SATD-costsfor( uint32_t i = 1; i < uiNumMrgSATDCand; i++ ){if( candCostList[i] > MRG_FAST_RATIO * candCostList[0] ){uiNumMrgSATDCand = i;break;}}#if JVET_L0124_L0208_TRIANGLEsetMergeBestSATDCost( candCostList[0] );
#endif#if JVET_L0100_MULTI_HYPOTHESIS_INTRAif (isIntrainterEnabled)                         // CIIP   帧内色度模式{pu.mhIntraFlag = true;for (uint32_t mergeCnt = 0; mergeCnt < uiNumMrgSATDCand; mergeCnt++){#if JVET_L0054_MMVDif (RdModeList[mergeCnt] >= (MRG_MAX_NUM_CANDS + MMVD_ADD_NUM))
#elseif (RdModeList[mergeCnt] >= (MRG_MAX_NUM_CANDS + MRG_MAX_NUM_CANDS))
#endif{pu.intraDir[0] = RdModeList2[mergeCnt];pu.intraDir[1] = DM_CHROMA_IDX;uint32_t bufIdx = (pu.intraDir[0] > 1) ? (pu.intraDir[0] == HOR_IDX ? 2 : 3) : pu.intraDir[0];bool isUseFilter = IntraPrediction::useFilteredIntraRefSamples(COMPONENT_Cb, pu, true, pu);         //Cbm_pcIntraSearch->initIntraPatternChType(*pu.cu, pu.Cb(), isUseFilter);m_pcIntraSearch->predIntraAng(COMPONENT_Cb, pu.cs->getPredBuf(pu).Cb(), pu, isUseFilter);m_pcIntraSearch->switchBuffer(pu, COMPONENT_Cb, pu.cs->getPredBuf(pu).Cb(), m_pcIntraSearch->getPredictorPtr2(COMPONENT_Cb, bufIdx));isUseFilter = IntraPrediction::useFilteredIntraRefSamples(COMPONENT_Cr, pu, true, pu);               //Crm_pcIntraSearch->initIntraPatternChType(*pu.cu, pu.Cr(), isUseFilter);m_pcIntraSearch->predIntraAng(COMPONENT_Cr, pu.cs->getPredBuf(pu).Cr(), pu, isUseFilter);m_pcIntraSearch->switchBuffer(pu, COMPONENT_Cr, pu.cs->getPredBuf(pu).Cr(), m_pcIntraSearch->getPredictorPtr2(COMPONENT_Cr, bufIdx));}}pu.mhIntraFlag = false;}
#endiftempCS->initStructData( encTestMode.qp, encTestMode.lossless );}else               // bestIsSkip = true{#if JVET_L0054_MMVDif (bestIsMMVDSkip){uiNumMrgSATDCand = mergeCtx.numValidMergeCand + MMVD_ADD_NUM;}else{uiNumMrgSATDCand = mergeCtx.numValidMergeCand;}
#elseuiNumMrgSATDCand = mergeCtx.numValidMergeCand;
#endif}}const uint32_t iteration = encTestMode.lossless ? 1 : 2;// 2. Pass: check candidates using full RD testfor( uint32_t uiNoResidualPass = 0; uiNoResidualPass < iteration; uiNoResidualPass++ ){for( uint32_t uiMrgHADIdx = 0; uiMrgHADIdx < uiNumMrgSATDCand; uiMrgHADIdx++ ){uint32_t uiMergeCand = RdModeList[uiMrgHADIdx];  //对RdModeList中的所有模式,进行计算选最优(普通merge CIIP和MMVD平等竞争)#if JVET_L0293_CPR
#if JVET_L0054_MMVDif(uiMergeCand < mergeCtx.numValidMergeCand)
#endifif ((mergeCtx.interDirNeighbours[uiMergeCand] == 1 || mergeCtx.interDirNeighbours[uiMergeCand] == 3) && tempCS->slice->getRefPic(REF_PIC_LIST_0, mergeCtx.mvFieldNeighbours[uiMergeCand << 1].refIdx)->getPOC() == tempCS->slice->getPOC()){continue;              //一些特殊情况,该模式跳过}
#endif#if JVET_L0100_MULTI_HYPOTHESIS_INTRA
#if JVET_L0054_MMVDif (uiNoResidualPass != 0 && uiMergeCand >= (MRG_MAX_NUM_CANDS + MMVD_ADD_NUM)) // intrainter does not support skip mode
#elseif (uiNoResidualPass != 0 && uiMergeCand >= (MRG_MAX_NUM_CANDS + MRG_MAX_NUM_CANDS)) // intrainter does not support skip mode
#endif{#if JVET_L0054_MMVDuiMergeCand -= (MRG_MAX_NUM_CANDS + MMVD_ADD_NUM); // for skip, map back to normal merge candidate idx and try RDO
#elseuiMergeCand -= (MRG_MAX_NUM_CANDS + MRG_MAX_NUM_CANDS); // for skip, map back to normal merge candidate idx and try RDO
#endifif (isTestSkipMerge[uiMergeCand]){continue;               //一些特殊情况,该模式跳过}}
#endif#if JVET_L0054_MMVDif (((uiNoResidualPass != 0) && candHasNoResidual[uiMrgHADIdx])
#elseif( ( (uiNoResidualPass != 0) && candHasNoResidual[uiMergeCand] )
#endif|| ( (uiNoResidualPass == 0) && bestIsSkip ) ){continue;                //一些特殊情况,该模式跳过}// first get merge candidatesCodingUnit &cu      = tempCS->addCU( tempCS->area, partitioner.chType );partitioner.setCUData( cu );cu.slice            = tempCS->slice;
#if HEVC_TILES_WPPcu.tileIdx          = tempCS->picture->tileMap->getTileIdxMap( tempCS->area.lumaPos() );
#endifcu.skip             = false;
#if JVET_L0054_MMVDcu.mmvdSkip = false;
#endif
#if JVET_L0124_L0208_TRIANGLEcu.triangle         = false;
#endifcu.partSize         = SIZE_2Nx2N;//cu.affinecu.predMode         = MODE_INTER;//cu.LICFlagcu.transQuantBypass = encTestMode.lossless;cu.chromaQpAdj      = cu.transQuantBypass ? 0 : m_cuChromaQpOffsetIdxPlus1;cu.qp               = encTestMode.qp;PredictionUnit &pu  = tempCS->addPU( cu, partitioner.chType );//下面分CIIP、MMVD和普通merge三种情况分别对pu进行设置
#if JVET_L0100_MULTI_HYPOTHESIS_INTRA
#if JVET_L0054_MMVD                         // CIIPif (uiNoResidualPass == 0 && uiMergeCand >= (MRG_MAX_NUM_CANDS + MMVD_ADD_NUM))
#elseif (uiNoResidualPass == 0 && uiMergeCand >= (MRG_MAX_NUM_CANDS + MRG_MAX_NUM_CANDS))
#endif{#if JVET_L0054_MMVDuiMergeCand -= (MRG_MAX_NUM_CANDS + MMVD_ADD_NUM);cu.mmvdSkip = false;mergeCtx.setMergeInfo(pu, uiMergeCand);
#elseuiMergeCand -= (MRG_MAX_NUM_CANDS + MRG_MAX_NUM_CANDS);
#endifpu.mhIntraFlag = true;pu.intraDir[0] = RdModeList2[uiMrgHADIdx];CHECK(pu.intraDir[0]<0 || pu.intraDir[0]>(NUM_LUMA_MODE - 1), "out of intra mode");pu.intraDir[1] = DM_CHROMA_IDX;}
#endif#if JVET_L0054_MMVD
#if JVET_L0100_MULTI_HYPOTHESIS_INTRA       // MMVDelse if (uiMergeCand >= mergeCtx.numValidMergeCand && uiMergeCand < MRG_MAX_NUM_CANDS + MMVD_ADD_NUM)
#elseif (uiMergeCand >= mergeCtx.numValidMergeCand)
#endif{cu.mmvdSkip = true;mergeCtx.setMmvdMergeCandiInfo(pu, uiMergeCand - mergeCtx.numValidMergeCand);}else{cu.mmvdSkip = false;             //普通mergemergeCtx.setMergeInfo(pu, uiMergeCand);}
#elsemergeCtx.setMergeInfo( pu, uiMergeCand );
#endifPU::spanMotionInfo( pu, mergeCtx );if( mrgTempBufSet )    //bestIsSkip为false时,mrgTempBufSet为true{                      //skip为false,表明已经进行过上面各种模式的pred像素的计算,所以不用下面else的MC
#if DMVR_JVET_LOW_LATENCY_K0217pu.mvd[0] = refinedMvdL0[uiMergeCand];
#endif
#if JVET_L0100_MULTI_HYPOTHESIS_INTRAif (pu.mhIntraFlag)                //CIIP  分别对YUV的inter和inter加权平均,存入tempCS的predBuf{uint32_t bufIdx = (pu.intraDir[0] > 1) ? (pu.intraDir[0] == HOR_IDX ? 2 : 3) : pu.intraDir[0];PelBuf tmpBuf = tempCS->getPredBuf(pu).Y();tmpBuf.copyFrom(acMergeBuffer[uiMergeCand].Y());m_pcIntraSearch->geneWeightedPred(COMPONENT_Y, tmpBuf, pu, m_pcIntraSearch->getPredictorPtr2(COMPONENT_Y, bufIdx));tmpBuf = tempCS->getPredBuf(pu).Cb();tmpBuf.copyFrom(acMergeBuffer[uiMergeCand].Cb());m_pcIntraSearch->geneWeightedPred(COMPONENT_Cb, tmpBuf, pu, m_pcIntraSearch->getPredictorPtr2(COMPONENT_Cb, bufIdx));tmpBuf = tempCS->getPredBuf(pu).Cr();tmpBuf.copyFrom(acMergeBuffer[uiMergeCand].Cr());m_pcIntraSearch->geneWeightedPred(COMPONENT_Cr, tmpBuf, pu, m_pcIntraSearch->getPredictorPtr2(COMPONENT_Cr, bufIdx));}else{#if JVET_L0054_MMVD     //MMVD只需在tempCS的predBuf中存储inter像素if (uiNoResidualPass != 0 && uiMergeCand < mergeCtx.numValidMergeCand && RdModeList[uiMrgHADIdx] >= (MRG_MAX_NUM_CANDS + MMVD_ADD_NUM)){tempCS->getPredBuf().copyFrom(acMergeBuffer[uiMergeCand]);         //普通merge}else{tempCS->getPredBuf().copyFrom(*acMergeTempBuffer[uiMrgHADIdx]);       //MMVD}
#elsetempCS->getPredBuf().copyFrom(acMergeBuffer[uiMergeCand]);
#endif}
#else
#if JVET_L0054_MMVDtempCS->getPredBuf().copyFrom(*acMergeTempBuffer[uiMrgHADIdx]);
#elsetempCS->getPredBuf().copyFrom( acMergeBuffer[ uiMergeCand ]);
#endif
#endif}else             //如果上面执行的是skip模式,那么就需要MC来计算pred像素{m_pcInterSearch->motionCompensation( pu );  //MC,skip模式时才进行MC,由运动信息获取pred像素}
#if JVET_L0100_MULTI_HYPOTHESIS_INTRA
#if JVET_L0054_MMVDif (!cu.mmvdSkip && !pu.mhIntraFlag && uiNoResidualPass != 0)
#elseif (!pu.mhIntraFlag && uiNoResidualPass != 0)
#endif{CHECK(uiMergeCand >= mergeCtx.numValidMergeCand, "out of normal merge");isTestSkipMerge[uiMergeCand] = true;}
#endif#if JVET_L0054_MMVD                   //由orig和pred像素信息,获得resi,可得到reco像素//分别处理无残差的skip模式和merge模式,得到cost,最终xCheckBestMode将最优merge信息存储于bestCSxEncodeInterResidual(tempCS, bestCS, partitioner, encTestMode, uiNoResidualPass, NULL, 1, uiNoResidualPass == 0 ? &candHasNoResidual[uiMrgHADIdx] : NULL);
#elsexEncodeInterResidual( tempCS, bestCS, partitioner, encTestMode, uiNoResidualPass, NULL, 1, uiNoResidualPass == 0 ? &candHasNoResidual[uiMergeCand] : NULL );
#endif#if JVET_L0100_MULTI_HYPOTHESIS_INTRAif( m_pcEncCfg->getUseFastDecisionForMerge() && !bestIsSkip && !pu.mhIntraFlag)
#elseif( m_pcEncCfg->getUseFastDecisionForMerge() && !bestIsSkip )
#endif{bestIsSkip = bestCS->getCU( partitioner.chType )->rootCbf == 0;}tempCS->initStructData( encTestMode.qp, encTestMode.lossless );      //tempCS清空初始化,进行下一个merge候选}// end loop uiMrgHADIdxif( uiNoResidualPass == 0 && m_pcEncCfg->getUseEarlySkipDetection() ) //判断skip模式{const CodingUnit     &bestCU = *bestCS->getCU( partitioner.chType );const PredictionUnit &bestPU = *bestCS->getPU( partitioner.chType );if( bestCU.rootCbf == 0 ){if( bestPU.mergeFlag ){m_modeCtrl->setEarlySkipDetected();            //skip模式}else if( m_pcEncCfg->getMotionEstimationSearchMethod() != MESEARCH_SELECTIVE ){int absolute_MV = 0;for( uint32_t uiRefListIdx = 0; uiRefListIdx < 2; uiRefListIdx++ ){if( slice.getNumRefIdx( RefPicList( uiRefListIdx ) ) > 0 ){absolute_MV += bestPU.mvd[uiRefListIdx].getAbsHor() + bestPU.mvd[uiRefListIdx].getAbsVer();}}if( absolute_MV == 0 ){m_modeCtrl->setEarlySkipDetected();}}}}}
}

VTM3.0代码阅读:xCheckRDCostMerge2Nx2N函数相关推荐

  1. VTM3.0代码阅读:xEstimateMvPredAMVP函数

    AMVP运用于inter_ME模式的时候. xEstimateMvPredAMVP进行AMVP,获得当前pu的相邻运动信息,构建AMVP列表,最终选择出最优的MVP.AMVP最终获得的MVP作为ME的 ...

  2. VTM3.0代码阅读:xDeriveCUMV函数

    xDeriveCUMV函数根据解码得到的预测参数数据,计算得到mv. 函数内根据解码得到的各个模式的数据,获取到MMVD.三角预测.AffineMerge.普通merge.AffineME.普通int ...

  3. VVC 代码阅读 compressCtu()函数

    void EncCu::compressCtu( CodingStructure& cs, const UnitArea& area, const unsigned ctuRsAddr ...

  4. VTM1.0代码阅读:CodingStructure类主要函数

    CodingStructure类中的各个函数对于cu.pu和tu的函数处理,其实大致流程都是差不多一样的,所以这里只对cu的相应函数进行分析. 对于下面CodingStructure类中的各个函数的阅 ...

  5. yii 2.0 代码阅读 小记

    1.\yii\base\object 设置了get/set属性...使用getName()获取属性名..构造函数中使用config初始化属性 2.\yii\base\Component 继承自Obje ...

  6. VVC代码阅读 xCheckModeSplit()函数 (中间CABAC还没看)最后代码还没看完

    //当前测试qpconst int qp = encTestMode.qp;//当前sliceconst Slice &slice = *tempCS->slice;// 之前的QPco ...

  7. VTM1.0代码阅读:CU、PU、TU

    VTM中的cu.pu和tu在使用时都是作为CodingStructure类的成员变量来使用的,即作为CS中cus.pus和tus数组中的一个变量来使用的,毕竟VTM中的操作都是以CS作为最基本的类来执 ...

  8. Apollo 3.0代码浅析(一)

    0.写在前面 因为工作中的项目使用到ros,因此本次对于apollo的分析是基于apollo 3.0 代码阅读工具为understand 1.目录结构 1.1 根目录 docker:容器相关 docs ...

  9. HM代码阅读0:Win10下安装HM16.23,编码一个视频,main函数阅读

    HEVC理论知识的学习告了一段落了,说实话脑子里还是嗡嗡的,剩下的部分就一边阅读代码一边掌握吧. 1. HM16.23安装 首先需要安装Cmake,参考以下博客,照步骤安装即可 https://blo ...

  10. ORB-SLAM2代码阅读笔记(五):Tracking线程3——Track函数中单目相机初始化

    Table of Contents 1.特征点匹配相关理论简介 2.ORB-SLAM2中特征匹配代码分析 (1)Tracking线程中的状态机 (2)单目相机初始化函数MonocularInitial ...

最新文章

  1. onethink php7.1,海豚PHP开发框架下载
  2. 成为Java高手的25个学习要点
  3. js实现随机选取[10,100)中的10个整数,存入一个数组,并排序。 另考虑(10,100]和[10,100]两种情况。...
  4. 用Tableau制作10种漂亮的柱形图
  5. 5自适应单页源码_超详细!如何建立一个CPA单页网站,附高转化CPA模板源码
  6. java comparator_一个Java程序员的成长历程(012)天
  7. QQ批量自动登录程序的设计
  8. 「一本通 6.5 练习 3」迷路
  9. 各种开源协议介绍 BSD、Apache Licence、GPLv2 、v3 、LGPL、MIT
  10. C#并发编程实例讲解-概述(01)
  11. matlab fft没有误差,matlab仿真FFT结果幅值比实际的略有降低?
  12. 在UI设计中用什么样的字体?
  13. 基于python车牌号识别_python中使用Opencv进行车牌号检测——2018.10.24
  14. gif透明背景动画_汉服美女表情包(PS做GIF动图简易教程分享)
  15. BOM有效日期的设置
  16. TS 版 Promise 详解
  17. 移动H60G改为桥接
  18. 计算请假时间(不算节假日)
  19. 华为机试-题目核心考点
  20. AUTOCAD——隔离

热门文章

  1. flightgear_使用FlightGear进入虚拟天空
  2. 系统集成项目管理工程师计算题(三点估算)
  3. 学会python可以上天!20行代码获取斗鱼平台房间数据,就是这么牛逼!
  4. 计算机组成原理第五版(白中英)第三章多层次存储器 习题
  5. 计算机win7截长屏,电脑截长图【应对法子】
  6. C 语言 运算符 全网最全整理
  7. 电力-104规约实际测试1
  8. 基于同一主机配置 Oracle 11g Data Guard
  9. 如何用minitab检测一组数据是否服从正态分布
  10. SVN客户端安装及汉化