VVC/JEM代码学习6:xCompressCU()

      xCompressCU是一个递归函数,对于每一个CU,该函数都会被调用,主要是计算当前CU编码之后代价,然后再计算当前CU的每一个子CU编码后的代价,和当前CU的编码代价相比较,用来决定是否对当前CU进行分割。这个函数太复杂啦,继续慢慢学习吧。

Void TEncCu::xCompressCU( TComDataCU*& rpcBestCU, TComDataCU*& rpcTempCU, const UInt uiDepth, UInt uiWidth, UInt uiHeight, UInt uiBTSplitMode DEBUG_STRING_FN_DECLARE(sDebug_), UInt uiSplitConstrain )

#else
Void TEncCu::xCompressCU( TComDataCU*& rpcBestCU, TComDataCU*& rpcTempCU, const UInt uiDepth DEBUG_STRING_FN_DECLARE(sDebug_), PartSize eParentPartSize )
#endif
#else
Void TEncCu::xCompressCU( TComDataCU*& rpcBestCU, TComDataCU*& rpcTempCU, const UInt uiDepth )
#endif
{
//每个深度的预测用的都是temp,预测完后跟best比较并交换。best保留作为当前深度的预测数据,
//而temp再次初始化。在下一深度的子CU预测中用的是subtemp,每预测完一个子CU,就跟subbest比较交换,
//再把subbest的数据复制到已经初始化的temp的相应位置。当temp获取完子CU的subbest的数据后,
//就代表了整个下一深度的数据,这时再与代表当前深度数据的best比较交换;


#if JVET_C0024_BT_RMV_REDUNDANT
  rpcBestCU->setSplitConstrain( uiSplitConstrain );
  rpcTempCU->setSplitConstrain( uiSplitConstrain );


  Bool bQTreeValid = false;
#endif
  TComPic* pcPic = rpcBestCU->getPic();
  DEBUG_STRING_NEW(sDebug)
  const TComPPS &pps=*(rpcTempCU->getSlice()->getPPS());
  const TComSPS &sps=*(rpcTempCU->getSlice()->getSPS());


#if JVET_C0024_QTBT
  // These are only used if getFastDeltaQp() is true,32;
  const UInt fastDeltaQPCuMaxSize    = Clip3(sps.getMinQTSize(rpcBestCU->getSlice()->getSliceType(), rpcBestCU->getTextType())
    , sps.getCTUSize(), 32u);
#else
  // These are only used if getFastDeltaQp() is true
  const UInt fastDeltaQPCuMaxSize    = Clip3(sps.getMaxCUHeight()>>sps.getLog2DiffMaxMinCodingBlockSize(), sps.getMaxCUHeight(), 32u);
#endif


  // get Original YUV data from picture
#if JVET_C0024_QTBT
  UInt uiWidthIdx = g_aucConvertToBit[rpcTempCU->getWidth(0)];//=5;
  UInt uiHeightIdx = g_aucConvertToBit[rpcTempCU->getHeight(0)];//=5;
  //从图像中复制原始YUV数据;
  m_pppcOrigYuv[uiWidthIdx][uiHeightIdx]->copyFromPicYuv( pcPic->getPicYuvOrg(), rpcBestCU->getCtuRsAddr(), rpcBestCU->getZorderIdxInCtu() );


  UInt uiPelXInCTU = rpcBestCU->getCUPelX() - rpcBestCU->getPic()->getCtu(rpcBestCU->getCtuRsAddr())->getCUPelX();
  UInt uiPelYInCTU = rpcBestCU->getCUPelY() - rpcBestCU->getPic()->getCtu(rpcBestCU->getCtuRsAddr())->getCUPelY();
  rpcBestCU->getPic()->setCodedBlkInCTU(false, uiPelXInCTU>> MIN_CU_LOG2, uiPelYInCTU>> MIN_CU_LOG2, uiWidth>> MIN_CU_LOG2, uiHeight>> MIN_CU_LOG2 );  
#else
  m_ppcOrigYuv[uiDepth]->copyFromPicYuv( pcPic->getPicYuvOrg(), rpcBestCU->getCtuRsAddr(), rpcBestCU->getZorderIdxInCtu() );
#endif


  // variable for Cbf fast mode PU decision
#if !JVET_C0024_QTBT
  Bool    doNotBlockPu = true;
#endif
  Bool    earlyDetectionSkipMode = false;
  //获取当前最优CU的范围;
  const UInt uiLPelX   = rpcBestCU->getCUPelX();//左边的像素,0;
  const UInt uiRPelX   = uiLPelX + rpcBestCU->getWidth(0)  - 1;//最右边的像素,127;
  const UInt uiTPelY   = rpcBestCU->getCUPelY();//上边的像素,0;
  const UInt uiBPelY   = uiTPelY + rpcBestCU->getHeight(0) - 1;//最下边的像素,127;
#if !JVET_C0024_QTBT
  const UInt uiWidth   = rpcBestCU->getWidth(0);
#endif
#if JVET_C0024_DELTA_QP_FIX
  UInt uiQTWidth = sps.getCTUSize()>>uiDepth;//四叉树的宽度,128;
  UInt uiQTHeight = sps.getCTUSize()>>uiDepth;//四叉树的高度,128;
  UInt uiBTDepth = g_aucConvertToBit[uiQTWidth]-g_aucConvertToBit[uiWidth] + g_aucConvertToBit[uiQTHeight]-g_aucConvertToBit[uiHeight];//二叉树深度;
  const UInt uiQTBTDepth = (uiDepth<<1) + uiBTDepth;//QTBT的深度是四叉树的深度加二叉树的深度;
  const UInt uiMaxDQPDepthQTBT = pps.getMaxCuDQPDepth() << 1;
#endif


#if JVET_D0077_SAVE_LOAD_ENC_INFO
  Bool bUseSaveLoad = m_pcEncCfg->getUseSaveLoadEncInfo() && uiWidthIdx > 0 && uiHeightIdx > 0;
  Bool bUseSaveLoadSplitDecision = bUseSaveLoad && m_pcEncCfg->getUseSaveLoadSplitDecision();
#if COM16_C1046_PDPC_INTRA && !JVET_G0104_PLANAR_PDPC
  ChannelType eChannelType = rpcBestCU->getTextType();
#endif
  UInt uiZorderIdx = rpcBestCU->getZorderIdxInCtu();//当前最优CU在CTU中以Z扫描顺序的索引;
#endif

 Int iBaseQP = xComputeQP( rpcBestCU, uiDepth );//计算QP,量化步长;
  Int iMinQP;
  Int iMaxQP;
  Bool isAddLowestQP = false;

#if COM16_C806_EMT
  Double dBestInterCost = MAX_DOUBLE;
  Bool   bEarlySkipIntra = false;
#if !JVET_C0024_QTBT
  Bool   bAllIntra = (m_pcEncCfg->getIntraPeriod()==1);
  Double dIntra2Nx2NCost = MAX_DOUBLE;
#endif
#if !JVET_C0024_QTBT
  Double dIntraNxNCost = MAX_DOUBLE;
#endif
#endif

#if JVET_C0024_DELTA_QP_FIX
  const Char lastCodedQP = rpcBestCU->getCodedQP(); 
#endif

#if JVET_E0076_MULTI_PEL_MVD
  m_dBestMvDPelCost[0] = m_dBestMvDPelCost[1] = m_dBestMvDPelCost[2] = MAX_DOUBLE/2;
#endif
  const UInt numberValidComponents = rpcBestCU->getPic()->getNumberValidComponents();//3;
#if VCEG_AZ08_INTER_KLT
  g_bEnableCheck = false;
#endif
  /设置最大的QP和最小的QP/
#if JVET_C0024_DELTA_QP_FIX
  if( uiQTBTDepth <= uiMaxDQPDepthQTBT )
#else
  if( uiDepth <= pps.getMaxCuDQPDepth() )
#endif
  {
    Int idQP = m_pcEncCfg->getMaxDeltaQP();
    iMinQP = Clip3( -sps.getQpBDOffset(CHANNEL_TYPE_LUMA), MAX_QP, iBaseQP-idQP );
    iMaxQP = Clip3( -sps.getQpBDOffset(CHANNEL_TYPE_LUMA), MAX_QP, iBaseQP+idQP );
#if JVET_C0024_DELTA_QP_FIX
    if( pps.getUseDQP() )
    {
      UInt uiCurrPartIdxInCtu = rpcBestCU->getZorderIdxInCtu();
      rpcBestCU->setQuPartIdx( uiCurrPartIdxInCtu );
      rpcTempCU->setQuPartIdx( uiCurrPartIdxInCtu );
      rpcBestCU->setQuLastCodedQP( lastCodedQP );
      rpcTempCU->setQuLastCodedQP( lastCodedQP );
    }
#endif
  }
  else
  {
    iMinQP = rpcTempCU->getQP(0);
    iMaxQP = rpcTempCU->getQP(0);
  }
#if WCG_LUMA_DQP_CM_SCALE
  Int targetQP = iBaseQP;
  if (m_pcEncCfg->getUseLumaDeltaQp() )
  {
    if (uiQTBTDepth <= uiMaxDQPDepthQTBT)
    {
      m_LumaQPOffset = calculateLumaDQP(rpcTempCU, 0, m_pppcOrigYuv[uiWidthIdx][uiHeightIdx]);  // keep using the same m_QP_LUMA_OFFSET in the same LCU
    }
    targetQP = Clip3(-sps.getQpBDOffset(CHANNEL_TYPE_LUMA), MAX_QP, iBaseQP - m_LumaQPOffset);  // targetQP is used for control lambda,32;
    iMinQP = targetQP;
    iMaxQP = iMinQP;   // make it same as MinQP to force encode choose the modified QP
  }  

#endif
  if ( m_pcEncCfg->getUseRateCtrl() )
  {
    iMinQP = m_pcRateCtrl->getRCQP();
    iMaxQP = m_pcRateCtrl->getRCQP();
  }

  // transquant-bypass (TQB) processing loop variable initialisation ---
  
  const Int lowestQP = iMinQP; // For TQB, use this QP which is the lowest non TQB QP tested (rather than QP'=0) - that way delta QPs are smaller, and TQB can be tested at all CU levels.

  if ( (pps.getTransquantBypassEnableFlag()) )
  {
    isAddLowestQP = true; // mark that the first iteration is to cost TQB mode.
    iMinQP = iMinQP - 1;  // increase loop variable range by 1, to allow testing of TQB mode along with other QPs
    if ( m_pcEncCfg->getCUTransquantBypassFlagForceValue() )
    {
      iMaxQP = iMinQP;
    }
  }

#if VCEG_AZ06_IC
  Bool bICEnabled = rpcTempCU->getSlice()->getApplyIC();
#if JVET_C0024_QTBT
#if VCEG_AZ06_IC_SPEEDUP
 if (uiWidth * uiHeight <= 32 )
  {
    bICEnabled = false;
  }
#endif
#endif
#endif

  TComSlice * pcSlice = rpcTempCU->getPic()->getSlice(rpcTempCU->getPic()->getCurrSliceIdx());

#if COM16_C806_LARGE_CTU
#if JVET_C0024_QTBT//ucMaxDepth=4;
  UChar ucMinDepth = 0 , ucMaxDepth = g_aucConvertToBit[pcSlice->getSPS()->getCTUSize()] 
  - g_aucConvertToBit[pcSlice->getSPS()->getMinQTSize(pcSlice->getSliceType(), rpcTempCU->getTextType())];
#else
  UChar ucMinDepth = 0 , ucMaxDepth = ( UChar )pcSlice->getSPS()->getLog2DiffMaxMinCodingBlockSize();
#endif
  if( m_pcEncCfg->getUseFastLCTU() )//enable fast method for large CTU;
  {
    rpcTempCU->getMaxMinCUDepth( ucMinDepth , ucMaxDepth , rpcTempCU->getZorderIdxInCtu() );
  }
#endif

#if JVET_C0024_QTBT
  Bool bBoundary = !( uiRPelX < sps.getPicWidthInLumaSamples() && uiBPelY < sps.getPicHeightInLumaSamples() );//判断当前CU是否在图像边界;
#else
  const Bool bBoundary = !( uiRPelX < sps.getPicWidthInLumaSamples() && uiBPelY < sps.getPicHeightInLumaSamples() );
#endif
#if JVET_C0024_QTBT
  Bool bForceQT = uiWidth > MAX_TU_SIZE;
  if( bForceQT )
  {
    assert(uiWidth == uiHeight);
  }
#endif
#if JVET_D0077_SAVE_LOAD_ENC_INFO
  UChar saveLoadTag = m_pcPredSearch->getSaveLoadTag( uiZorderIdx, uiWidthIdx, uiHeightIdx );
  UChar saveLoadSplit = ( (bUseSaveLoadSplitDecision && saveLoadTag == LOAD_ENC_INFO) ? m_pcPredSearch->getSaveLoadSplit(uiWidthIdx, uiHeightIdx) : 0 );
  Double dCostTempBest = MAX_DOUBLE;//最优的临时代价;
  Double dNonSplitCost = MAX_DOUBLE;//不分割的代价;
  Double dHorSplitCost = MAX_DOUBLE;//水平分割的代价;
  Double dVerSplitCost = MAX_DOUBLE;//垂直分割的代价;
#endif
  if (!bBoundary
#if COM16_C806_LARGE_CTU
  && ucMinDepth <= uiDepth
#endif
#if JVET_C0024_QTBT
  && !bForceQT
#endif
#if JVET_D0077_SAVE_LOAD_ENC_INFO
  && !(saveLoadSplit & 0x01)
#endif
  )
  {
#if JVET_D0077_FAST_EXT
  Bool bPrevSameBlockIsIntra = rpcBestCU->getPic()->getIntra(rpcBestCU->getZorderIdxInCtu(), uiWidth, uiHeight);
  Bool bPrevSameBlockIsSkip = rpcBestCU->getPic()->getSkiped(rpcBestCU->getZorderIdxInCtu(), uiWidth, uiHeight);
#endif
  //从最小的QP到最大的QP遍历每一个QP,对每一个QP执行下面的操作(目的是选出最优的QP)/
  for (Int iQP = iMinQP; iQP <= iMaxQP; iQP++)
  {
  const Bool bIsLosslessMode = isAddLowestQP && (iQP == iMinQP);

  if (bIsLosslessMode)//判断是否为无损模式,若是无损,则QP设置为最低值;
  {
  iQP = lowestQP;
  }
#if WCG_LUMA_DQP_CM_SCALE
  if (m_pcEncCfg->getUseLumaDeltaQp() && (uiQTBTDepth <= uiMaxDQPDepthQTBT))
  {
  getSliceEncoder()->updateLambda(pcSlice, targetQP);
  }
#endif

  m_cuChromaQpOffsetIdxPlus1 = 0;
  if (pcSlice->getUseChromaQpAdj())
  {
  /* Pre-estimation of chroma QP based on input block activity may be performed
   * here, using for example m_ppcOrigYuv[uiDepth] */
   /* To exercise the current code, the index used for adjustment is based on
* block position
*/
#if JVET_C0024_QTBT
Int lgMinCuSize = g_aucConvertToBit[sps.getMinQTSize(pcSlice->getSliceType(), rpcBestCU->getTextType())] + MIN_CU_LOG2 +
  std::max<Int>(0, g_aucConvertToBit[sps.getCTUSize()] - g_aucConvertToBit[sps.getMinQTSize(pcSlice->getSliceType(), rpcBestCU->getTextType())] - Int(pps.getPpsRangeExtension().getDiffCuChromaQpOffsetDepth()));
#else
  Int lgMinCuSize = sps.getLog2MinCodingBlockSize() +
  std::max<Int>(0, sps.getLog2DiffMaxMinCodingBlockSize() - Int(pps.getPpsRangeExtension().getDiffCuChromaQpOffsetDepth()));
#endif
  m_cuChromaQpOffsetIdxPlus1 = ((uiLPelX >> lgMinCuSize) + (uiTPelY >> lgMinCuSize)) % (pps.getPpsRangeExtension().getChromaQpOffsetListLen() + 1);
  }
  //初始化当前CU的数据;
  rpcTempCU->initEstData(uiDepth, iQP, bIsLosslessMode);

#if VCEG_AZ07_IMV && !JVET_C0024_QTBT
  m_setInterCand.clear();
  for (Int n = 0; n < NUMBER_OF_PART_SIZES; n++)
  {
#if JVET_C0024_QTBT
  m_pppcTempCUIMVCache[n][uiWidthIdx][uiHeightIdx]->initEstData(uiDepth, iQP, bIsLosslessMode);
#else
  m_ppcTempCUIMVCache[n][uiDepth]->initEstData(uiDepth, iQP, bIsLosslessMode);
#endif
  }
#endif
  /帧间模式选择//
// do inter modes, SKIP and 2Nx2N
  if (rpcBestCU->getSlice()->getSliceType() != I_SLICE)//不是I_SLICE,即不进行帧内预测;
  {
#if JVET_D0077_SAVE_LOAD_ENC_INFO
#if VCEG_AZ07_FRUC_MERGE
  Bool bFastSkipFruc = (saveLoadTag == LOAD_ENC_INFO && 0 == m_pcPredSearch->getSaveLoadFrucMode(uiWidthIdx, uiHeightIdx));
#endif
#if VCEG_AZ07_IMV
  Bool bFastSkipIMV = (saveLoadTag == LOAD_ENC_INFO && (!m_pcPredSearch->getSaveLoadIMVFlag(uiWidthIdx, uiHeightIdx) || m_pcPredSearch->getSaveLoadMergeFlag(uiWidthIdx, uiHeightIdx)));
#endif
  Bool bFastSkipInter = (saveLoadTag == LOAD_ENC_INFO && m_pcPredSearch->getSaveLoadMergeFlag(uiWidthIdx, uiHeightIdx));
#if COM16_C1016_AFFINE
  Bool bFastSkipAffine = (saveLoadTag == LOAD_ENC_INFO && !m_pcPredSearch->getSaveLoadAffineFlag(uiWidthIdx, uiHeightIdx));
#endif
#endif
#if VCEG_AZ06_IC
  for (UInt uiICId = 0; uiICId < (bICEnabled ? 2 : 1); uiICId++)
  {
  Bool bICFlag = uiICId ? true : false;
#endif
  // 2Nx2N
  if (m_pcEncCfg->getUseEarlySkipDetection()) //使用earlyDetectionSkipMode;
  {
#if VCEG_AZ06_IC
  rpcTempCU->setICFlagSubParts(bICFlag, 0, uiDepth);
#endif    比较已有最佳模式与2N*2N Inter算出的TempRDcost的大小;
xCheckRDCostInter(rpcBestCU, rpcTempCU, SIZE_2Nx2N DEBUG_STRING_PASS_INTO(sDebug));
 rpcTempCU->initEstData(uiDepth, iQP, bIsLosslessMode);//by Competition for inter_2Nx2N
  }
  // SKIP
#if VCEG_AZ06_IC
  if (!bICFlag)
  {
#endif
#if COM16_C1016_AFFINE
#if JVET_D0077_FAST_EXT
  if (rpcTempCU->getSlice()->getSPS()->getUseAffine() && !bPrevSameBlockIsIntra
#if JVET_D0077_SAVE_LOAD_ENC_INFO
  && !bFastSkipAffine
#endif
  )
#else
  if (rpcTempCU->getSlice()->getSPS()->getUseAffine())
#endif
  {//比较已有最佳模式与AffineMerge2Nx2N算出的tempRDcost的大小;
  xCheckRDCostAffineMerge2Nx2N(rpcBestCU, rpcTempCU);//H.266新加的技术;
  rpcTempCU->initEstData(uiDepth, iQP, bIsLosslessMode);
  }
#endif
  //比较已有最佳模式与Merge2N*2N算出的TempRdcost大小;
  xCheckRDCostMerge2Nx2N(rpcBestCU, rpcTempCU DEBUG_STRING_PASS_INTO(sDebug), &earlyDetectionSkipMode);//by Merge for inter_2Nx2N
  rpcTempCU->initEstData(uiDepth, iQP, bIsLosslessMode);
#if VCEG_AZ06_IC
  }
#endif

#if VCEG_AZ07_FRUC_MERGE
#if JVET_D0077_FAST_EXT
  if (rpcTempCU->getSlice()->getSPS()->getUseFRUCMgrMode() && !bPrevSameBlockIsIntra
#if JVET_D0077_SAVE_LOAD_ENC_INFO
  && !bFastSkipFruc
#endif
  )
#else
  if (rpcTempCU->getSlice()->getSPS()->getUseFRUCMgrMode())
#endif
  {
#if VCEG_AZ06_IC
  rpcTempCU->setICFlagSubParts(bICFlag, 0, uiDepth);
#endif    //比较已有最佳模式与Merge2N*2NFRUC的TempRDcost的大小;
  xCheckRDCostMerge2Nx2NFRUC(rpcBestCU, rpcTempCU, &earlyDetectionSkipMode);//也是H.266里新加的;
  rpcTempCU->initEstData(uiDepth, iQP, bIsLosslessMode);
  }
#endif

#if JVET_C0024_QTBT
#if JVET_D0077_FAST_EXT
  if (!m_pcEncCfg->getUseEarlySkipDetection() && !bPrevSameBlockIsSkip && !bPrevSameBlockIsIntra
#if JVET_D0077_SAVE_LOAD_ENC_INFO
  && !bFastSkipInter
#if VCEG_AZ06_IC
  && !(saveLoadTag == LOAD_ENC_INFO && bICFlag != m_pcPredSearch->getSaveLoadICFlag(uiWidthIdx, uiHeightIdx))
#endif
#endif
#else
  if (!m_pcEncCfg->getUseEarlySkipDetection() && !rpcBestCU->getPic()->getSkiped(rpcBestCU->getZorderIdxInCtu(), uiWidth, uiHeight)
  && !rpcBestCU->getPic()->getIntra(rpcBestCU->getZorderIdxInCtu(), uiWidth, uiHeight)
#endif
  )
#else
  if (!m_pcEncCfg->getUseEarlySkipDetection())
#endif
  {
  // 2Nx2N, NxN
#if VCEG_AZ06_IC
  rpcTempCU->setICFlagSubParts(bICFlag, 0, uiDepth);
#endif    //比较已有最佳模式与2N*2N Inter的TempRDcost的大小;
  xCheckRDCostInter(rpcBestCU, rpcTempCU, SIZE_2Nx2N DEBUG_STRING_PASS_INTO(sDebug));
  rpcTempCU->initEstData(uiDepth, iQP, bIsLosslessMode);
#if !JVET_C0024_QTBT
  if (m_pcEncCfg->getUseCbfFastMode())
  {
  doNotBlockPu = rpcBestCU->getQtRootCbf(0) != 0;
  }
#endif
  }
#if VCEG_AZ06_IC
  }
#endif
#if VCEG_AZ07_IMV && JVET_D0077_SAVE_LOAD_ENC_INFO
#if JVET_D0077_FAST_EXT
  if (m_pcEncCfg->getIMV() && !rpcBestCU->getSlice()->isIntra() && !bPrevSameBlockIsIntra && !bPrevSameBlockIsSkip
#if JVET_D0077_SAVE_LOAD_ENC_INFO
  && !bFastSkipIMV
#endif
  )
#else
  if (m_pcEncCfg->getIMV() && !rpcBestCU->getSlice()->isIntra())
#endif
  {
#if JVET_E0076_MULTI_PEL_MVD
  for (UChar iMv = 1; iMv < 3; iMv++)
  {
  if (iMv == 2 && m_dBestMvDPelCost[0] * 1.06 < m_dBestMvDPelCost[1])
  {
  break;
  }
#if VCEG_AZ06_IC
  for (UInt uiICId = 0; uiICId < (bICEnabled ? 2 : 1); uiICId++)
  {
  Bool bICFlag = uiICId ? true : false;
#if JVET_D0077_SAVE_LOAD_ENC_INFO
  if (saveLoadTag == LOAD_ENC_INFO && bICFlag != m_pcPredSearch->getSaveLoadICFlag(uiWidthIdx, uiHeightIdx))
  {
  continue;
  }
#endif
  rpcTempCU->setICFlagSubParts(bICFlag, 0, uiDepth);
#endif
  xCheckRDCostInter(rpcBestCU, rpcTempCU, SIZE_2Nx2N, false, iMv);
  rpcTempCU->initEstData(uiDepth, iQP, bIsLosslessMode);
#if VCEG_AZ06_IC
  }
#endif
  }
#else
  // always check SIZE_2Nx2N
#if VCEG_AZ06_IC
  for (UInt uiICId = 0; uiICId < (bICEnabled ? 2 : 1); uiICId++)
  {
  Bool bICFlag = uiICId ? true : false;
#if JVET_D0077_SAVE_LOAD_ENC_INFO
  if (saveLoadTag == LOAD_ENC_INFO && bICFlag != m_pcPredSearch->getSaveLoadICFlag(uiWidthIdx, uiHeightIdx))
  {
  continue;
  }
#endif
  rpcTempCU->setICFlagSubParts(bICFlag, 0, uiDepth);
#endif
  xCheckRDCostInter(rpcBestCU, rpcTempCU, SIZE_2Nx2N, false, true);
  rpcTempCU->initEstData(uiDepth, iQP, bIsLosslessMode);
#if VCEG_AZ06_IC
  }
#endif
#endif
  }
#endif
  }


  if (bIsLosslessMode) // Restore loop variable if lossless mode was searched.
  {
  iQP = iMinQP;
  }
  }
  //QP循环结束
#if VCEG_AZ06_IC
#if !JVET_C0024_QTBT
  Bool bTestICNon2Nx2N = bICEnabled && rpcBestCU->getICFlag(0);
#if VCEG_AZ06_IC_SPEEDUP
  bTestICNon2Nx2N = false;
#endif
#endif
#endif

//=========================earlyDetectionSkipMode==========================

  if (!earlyDetectionSkipMode)
  {
  // 在实际的处理过程当中,对LCU的划分都是以4x4大小的块进行划分的,
  //这是为了处理方便,然后以Z扫描的方式进行扫描,这也是为了方便递归;
  从最小QP到最大QP遍历每一个QP,执行下面步骤,选出一个最优QP
  for (Int iQP = iMinQP; iQP <= iMaxQP; iQP++)
  {
  const Bool bIsLosslessMode = isAddLowestQP && (iQP == iMinQP); // If lossless, then iQP is irrelevant for subsequent modules.

  if (bIsLosslessMode)//判断是否为无损模式;
  {
  iQP = lowestQP;
  }
  //初始化当前CU的数据;
  rpcTempCU->initEstData(uiDepth, iQP, bIsLosslessMode);

//==============帧内模式选择==============================
// do normal intra modes
// speedup for inter frames
  Double intraCost = 0.0;

#if COM16_C806_EMT
  if (rpcBestCU->getSlice()->getSliceType() != I_SLICE && m_pcEncCfg->getUseFastInterEMT())
  {
  dBestInterCost = rpcBestCU->getTotalCost();
  }
#endif
  //如果帧内的类型是I_SLICE,则进行帧内模式选择;
  if ((rpcBestCU->getSlice()->getSliceType() == I_SLICE) ||
#if JVET_C0024_QTBT
  ((!m_pcEncCfg->getDisableIntraPUsInInterSlices()) && (!rpcBestCU->getPic()->getInter(rpcBestCU->getZorderIdxInCtu(), uiWidth, uiHeight)) && (
#else
  ((!m_pcEncCfg->getDisableIntraPUsInInterSlices()) && (
#endif
  (rpcBestCU->getCbf(0, COMPONENT_Y) != 0) ||
  ((rpcBestCU->getCbf(0, COMPONENT_Cb) != 0) && (numberValidComponents > COMPONENT_Cb)) ||
  ((rpcBestCU->getCbf(0, COMPONENT_Cr) != 0) && (numberValidComponents > COMPONENT_Cr))  // avoid very complex intra if it is unlikely
  )))
  {
#if VCEG_AZ05_ROT_TR  || VCEG_AZ05_INTRA_MPI || COM16_C1044_NSST || COM16_C1046_PDPC_INTRA
  Int bNonZeroCoeff = 0;
#endif
#if VCEG_AZ05_INTRA_MPI
  Char iMPIidx = 0;  Char iNumberOfPassesMPI = 2;
  if (rpcTempCU->getSlice()->getSliceType() != I_SLICE)  iNumberOfPassesMPI = 2;
  if (!rpcTempCU->getSlice()->getSPS()->getUseMPI()) iNumberOfPassesMPI = 1;
#if JVET_C0024_QTBT
  if (isChroma(rpcBestCU->getTextType()))
  {
  iNumberOfPassesMPI = 1;
  }
#endif
#endif
#if JVET_C0024_PBINTRA_FAST
  rpcTempCU->getInterHAD() = MAX_UINT;
  if (rpcBestCU->getPredictionMode(0) == MODE_INTER && !rpcBestCU->getSlice()->isIntra())
  {
  // redundant MC process to make sure that m_pppcPredYuvBest has the correct moiton compensation prediction data
#if JVET_E0052_DMVR
  m_pcPredSearch->motionCompensation(rpcBestCU, m_pppcPredYuvBest[uiWidthIdx][uiHeightIdx], false);
#if COM16_C806_OBMC
  m_pcPredSearch->subBlockOBMC(rpcBestCU, 0, m_pppcPredYuvBest[uiWidthIdx][uiHeightIdx], m_pppcTmpYuv1[uiWidthIdx][uiHeightIdx], m_pppcTmpYuv2[uiWidthIdx][uiHeightIdx], false);
#endif
#else
  m_pcPredSearch->motionCompensation(rpcBestCU, m_pppcPredYuvBest[uiWidthIdx][uiHeightIdx]);
#if COM16_C806_OBMC
  m_pcPredSearch->subBlockOBMC(rpcBestCU, 0, m_pppcPredYuvBest[uiWidthIdx][uiHeightIdx], m_pppcTmpYuv1[uiWidthIdx][uiHeightIdx], m_pppcTmpYuv2[uiWidthIdx][uiHeightIdx]);
#endif
#endif
  DistParam distParam;
  const Bool bUseHadamard = rpcTempCU->getCUTransquantBypass(0) == 0;
  m_pcRdCost->setDistParam(distParam, rpcTempCU->getSlice()->getSPS()->getBitDepth(CHANNEL_TYPE_LUMA), m_pppcOrigYuv[uiWidthIdx][uiHeightIdx]->getAddr(COMPONENT_Y)
  , m_pppcOrigYuv[uiWidthIdx][uiHeightIdx]->getStride(COMPONENT_Y)
  , m_pppcPredYuvBest[uiWidthIdx][uiHeightIdx]->getAddr(COMPONENT_Y), m_pppcPredYuvBest[uiWidthIdx][uiHeightIdx]->getStride(COMPONENT_Y)
  , rpcTempCU->getWidth(0), rpcTempCU->getHeight(0), bUseHadamard);
  distParam.bApplyWeight = false;
  UInt uiSad = distParam.DistFunc(&distParam);
  rpcTempCU->getInterHAD() = uiSad;
  }
#endif
#if COM16_C1046_PDPC_INTRA && !JVET_G0104_PLANAR_PDPC
  Char iPDPCidx = 0;  Char iNumberOfPassesPDPC = 2;
  if (rpcTempCU->getSlice()->getSliceType() != I_SLICE)  iNumberOfPassesPDPC = 2;
  if (!rpcTempCU->getSlice()->getSPS()->getUsePDPC()) iNumberOfPassesPDPC = 1;
#if JVET_C0024_QTBT
  if (isChroma(rpcBestCU->getTextType()))
  {
  iNumberOfPassesPDPC = 1;
  }
#endif
#endif

#if VCEG_AZ05_ROT_TR || COM16_C1044_NSST
  Char iROTidx = 0; Char iNumberOfPassesROT = 4;
#if JVET_C0024_QTBT
  if (isChroma(rpcBestCU->getTextType()) && !(uiWidth >= 8 && uiHeight >= 8))
  {
  iNumberOfPassesROT = 1;
  }
#endif
#if COM16_C1044_NSST
  if (!rpcTempCU->getSlice()->getSPS()->getUseNSST()) iNumberOfPassesROT = 1;
#else
  if (!rpcTempCU->getSlice()->getSPS()->getUseROT()) iNumberOfPassesROT = 1;
#endif
/此for循环由此开始,执行4次xCheckRDcostIntra循环
  for (iROTidx = 0; iROTidx < iNumberOfPassesROT; iROTidx++)
  {
#if JVET_D0077_SAVE_LOAD_ENC_INFO
  if (saveLoadTag == LOAD_ENC_INFO && iROTidx && iROTidx != m_pcPredSearch->getSaveLoadRotIdx(uiWidthIdx, uiHeightIdx))
  {
  continue;
  }
#endif
#endif
#if VCEG_AZ05_INTRA_MPI
#if VCEG_AZ05_ROT_TR || COM16_C1044_NSST
  if (iROTidx) iNumberOfPassesMPI = 1;
#endif
  for (iMPIidx = 0; iMPIidx < iNumberOfPassesMPI; iMPIidx++)
  {
#endif

#if COM16_C1046_PDPC_INTRA && !JVET_G0104_PLANAR_PDPC
#if VCEG_AZ05_ROT_TR || COM16_C1044_NSST
  if (iROTidx) iNumberOfPassesPDPC = 1;
#endif
  for (iPDPCidx = 0; iPDPCidx < iNumberOfPassesPDPC; iPDPCidx++)
  {
#if JVET_D0077_SAVE_LOAD_ENC_INFO
  if (CHANNEL_TYPE_LUMA == eChannelType && saveLoadTag == LOAD_ENC_INFO && iPDPCidx != m_pcPredSearch->getSaveLoadPdpcIdx(uiWidthIdx, uiHeightIdx))
  {
  continue;
  }
#endif
#endif
#if COM16_C806_EMT
#if JVET_C0024_QTBT
  UChar ucEmtUsage = (uiWidth > EMT_INTRA_MAX_CU || uiHeight > EMT_INTRA_MAX_CU || (rpcTempCU->getSlice()->getSPS()->getUseIntraEMT() == 0) || isChroma(rpcBestCU->getTextType())) ? 1 : 2;
#else
  UChar ucEmtUsage = ((rpcTempCU->getWidth(0) > EMT_INTRA_MAX_CU) || (rpcTempCU->getSlice()->getSPS()->getUseIntraEMT() == 0)) ? 1 : 2;
#endif
  //EMT使用次数//
  for (UChar ucCuFlag = 0; ucCuFlag < ucEmtUsage; ucCuFlag++)
  {
#if JVET_D0077_SAVE_LOAD_ENC_INFO
  if (saveLoadTag == LOAD_ENC_INFO && /*ucCuFlag && */ucCuFlag != m_pcPredSearch->getSaveLoadEmtFlag(uiWidthIdx, uiHeightIdx))
  {
  continue;
  }
#endif
  if (ucCuFlag && bEarlySkipIntra && m_pcEncCfg->getUseFastInterEMT())
  {
  continue;
  }
  rpcTempCU->setEmtCuFlagSubParts(ucCuFlag, 0, uiDepth);
#if VCEG_AZ05_INTRA_MPI
  rpcTempCU->setMPIIdxSubParts(iMPIidx, 0, uiDepth);
#endif
#if COM16_C1046_PDPC_INTRA && !JVET_G0104_PLANAR_PDPC
  rpcTempCU->setPDPCIdxSubParts(iPDPCidx, 0, uiDepth);
#endif

#if VCEG_AZ05_ROT_TR || COM16_C1044_NSST
#if JVET_C0024_QTBT
  rpcTempCU->setROTIdxSubParts(rpcTempCU->getTextType(), iROTidx, 0, uiDepth);
  if (!rpcTempCU->getSlice()->isIntra())
  {
  rpcTempCU->setROTIdxSubParts(CHANNEL_TYPE_CHROMA, iROTidx, 0, uiDepth);
  }
#else
  rpcTempCU->setROTIdxSubParts(iROTidx, 0, uiDepth);
#endif
#endif
#if JVET_C0024_PBINTRA_FAST
  if (rpcBestCU->getPredictionMode(0) == MODE_INTER && !rpcBestCU->getSlice()->isIntra())
  {
  if (rpcTempCU->getInterHAD() == 0)
  {
  continue;  //has calculated the best intra HAD much larger than that of inter; so skip intra mode RDO
  }
  }
#endif
  //比较已有最佳模式与2Nx2N Intra的TempRDcost的大小;
 xCheckRDCostIntra(rpcBestCU, rpcTempCU, intraCost, SIZE_2Nx2N DEBUG_STRING_PASS_INTO(sDebug)
#if VCEG_AZ05_ROT_TR || VCEG_AZ05_INTRA_MPI || COM16_C1044_NSST || COM16_C1046_PDPC_INTRA
  , bNonZeroCoeff
#endif
  );
  if (!ucCuFlag && !rpcBestCU->isIntra(0) && m_pcEncCfg->getUseFastInterEMT()
#if JVET_D0077_SAVE_LOAD_ENC_INFO
  && dBestInterCost < MAX_DOUBLE
#endif
  )
  {
  static const Double thEmtInterFastSkipIntra = 1.4; // Skip checking Intra if "2Nx2N using DCT2" is worse than best Inter mode
if (rpcTempCU->getTotalCost() > thEmtInterFastSkipIntra*dBestInterCost)
  {
  bEarlySkipIntra = true;
  }
  }
  if (!ucCuFlag && m_pcEncCfg->getUseFastIntraEMT())
  {
#if JVET_C0024_QTBT
  //dIntra2Nx2NCost = rpcBestCU->isIntra(0) ? rpcBestCU->getTotalCost() : rpcTempCU->getTotalCost();
#else
  dIntra2Nx2NCost = (rpcBestCU->isIntra(0) && rpcBestCU->getPartitionSize(0) == SIZE_2Nx2N) ? rpcBestCU->getTotalCost() : rpcTempCU->getTotalCost();
#endif
  }
  rpcTempCU->initEstData(uiDepth, iQP, bIsLosslessMode);
  }
 EMTUsage循环结束/

#if VCEG_AZ05_ROT_TR || COM16_C1044_NSST
  if (rpcBestCU->isIntra(0) && !bNonZeroCoeff) break;
  //if (bNonZeroCoeff>rpcTempCU->getWidth(0)*rpcTempCU->getHeight(0) && rpcTempCU->getSlice()->getSliceType() == I_SLICE) break;
  }
//iNumberOfPassesROT循环在这里结束

 // test PCM,尝试PCM模式;
  if (sps.getUsePCM()//PCM模式,在该模式下,编码器直接传输一个CU的像素值,而不经过预测,变换等其他操作;
  && rpcTempCU->getWidth(0) <= (1 << sps.getPCMLog2MaxSize())
  && rpcTempCU->getWidth(0) >= (1 << sps.getPCMLog2MinSize()))
  {
  UInt uiRawBits = getTotalBits(rpcBestCU->getWidth(0), rpcBestCU->getHeight(0), rpcBestCU->getPic()->getChromaFormat(), sps.getBitDepths().recon);
  UInt uiBestBits = rpcBestCU->getTotalBits();
  if ((uiBestBits > uiRawBits) || (rpcBestCU->getTotalCost() > m_pcRdCost->calcRdCost(uiRawBits, 0)))
  {//比较已有最佳模式与PCM算出的TempRDcost的大小;
  xCheckIntraPCM(rpcBestCU, rpcTempCU);
  rpcTempCU->initEstData(uiDepth, iQP, bIsLosslessMode);
  }
  }

  if (bIsLosslessMode) // Restore loop variable if lossless mode was searched.
  {
  iQP = iMinQP;
  }
  }
  /遍历QP结束//
  }
//===============earlyDetectionSkipMode条件判断结束=======================
#if VCEG_AZ08_INTER_KLT
#if VCEG_AZ08_USE_KLT
  if (sps.getUseInterKLT())//JEM中新加的;
  {
#endif
  if (!rpcBestCU->isIntra(0) && rpcBestCU->getQtRootCbf(0) != 0)
  {
  //Only check from the best modes for speeding up
  g_bEnableCheck = true;
  Int iQP = rpcBestCU->getQP(0);
#if JVET_C0024_QTBT
  xCheckRDCostInterKLT(rpcBestCU, rpcTempCU, SIZE_2Nx2N);//JEM里新加的技术;
#else
  PartSize eSize = rpcBestCU->getPartitionSize(0);
  xCheckRDCostInterKLT(rpcBestCU, rpcTempCU, eSize);
#endif
  rpcTempCU->initEstData(uiDepth, iQP, false);
  }
#if VCEG_AZ08_USE_KLT
  }
#endif
#endif
#if JVET_C0024_QTBT
  if (rpcBestCU->getTotalCost() < MAX_DOUBLE - 1)
#else
  if (rpcBestCU->getTotalCost() != MAX_DOUBLE)
#endif
  {
#if JVET_C0024_QTBT
  m_pcRDGoOnSbacCoder->load(m_ppppcRDSbacCoder[uiWidthIdx][uiHeightIdx][CI_NEXT_BEST]);
#else
  m_pcRDGoOnSbacCoder->load(m_pppcRDSbacCoder[uiDepth][CI_NEXT_BEST]);
#endif
  m_pcEntropyCoder->resetBits();//重置熵编码器的比特数;
#if JVET_C0024_QTBT
  if (uiBTSplitMode == 0)
  {
#endif
  m_pcEntropyCoder->encodeSplitFlag(rpcBestCU, 0, uiDepth, true);//编码split标志;
#if JVET_C0024_QTBT
  }
#if JVET_C0024_SPS_MAX_BT_DEPTH
  UInt uiMaxBTD = pcSlice->isIntra() ? (isLuma(rpcTempCU->getTextType()) ? sps.getMaxBTDepthISliceL() : sps.getMaxBTDepthISliceC()) : sps.getMaxBTDepth();
#else
  UInt uiMaxBTD = pcSlice->isIntra() ? (isLuma(rpcTempCU->getTextType()) ? MAX_BT_DEPTH : MAX_BT_DEPTH_C) : MAX_BT_DEPTH_INTER;
#endif
#if JVET_C0024_SPS_MAX_BT_SIZE
  UInt uiMaxBTSize = pcSlice->isIntra() ? (isLuma(rpcTempCU->getTextType()) ? sps.getMaxBTSizeISliceL() : sps.getMaxBTSizeISliceC()) : sps.getMaxBTSize();
#else
  UInt uiMaxBTSize = isLuma(rpcTempCU->getTextType()) ? pcSlice->getMaxBTSize() : MAX_BT_SIZE_C;
#endif
  UInt uiMinBTSize = pcSlice->isIntra() ? (isLuma(rpcTempCU->getTextType()) ? MIN_BT_SIZE : MIN_BT_SIZE_C) : MIN_BT_SIZE_INTER;

  if (rpcBestCU->getWidth(0) <= uiMaxBTSize && rpcBestCU->getHeight(0) <= uiMaxBTSize
  && (rpcBestCU->getWidth(0) > uiMinBTSize || rpcBestCU->getHeight(0) > uiMinBTSize)
  && rpcBestCU->getBTDepth(0) < uiMaxBTD)
  {
  m_pcEntropyCoder->encodeBTSplitMode(rpcBestCU, 0, rpcBestCU->getWidth(0), rpcBestCU->getHeight(0), true);
  }
#endif//统计总的比特数,二进制数和总的率失真代价;
  rpcBestCU->getTotalBits() += m_pcEntropyCoder->getNumberOfWrittenBits(); // split bits
  rpcBestCU->getTotalBins() += ((TEncBinCABAC *)((TEncSbac*)m_pcEntropyCoder->m_pcEntropyCoderIf)->getEncBinIf())->getBinsCoded();
  rpcBestCU->getTotalCost() = m_pcRdCost->calcRdCost(rpcBestCU->getTotalBits(), rpcBestCU->getTotalDistortion());
#if JVET_C0024_QTBT
  m_pcRDGoOnSbacCoder->store(m_ppppcRDSbacCoder[uiWidthIdx][uiHeightIdx][CI_NEXT_BEST]);
#else
  m_pcRDGoOnSbacCoder->store(m_pppcRDSbacCoder[uiDepth][CI_NEXT_BEST]);
#endif
#if JVET_D0077_SAVE_LOAD_ENC_INFO
  if (saveLoadTag == SAVE_ENC_INFO)
  {
#if COM16_C806_EMT
  m_pcPredSearch->setSaveLoadEmtFlag(uiWidthIdx, uiHeightIdx, rpcBestCU->getEmtCuFlag(0));
  m_pcPredSearch->setSaveLoadEmtIdx(uiWidthIdx, uiHeightIdx, rpcBestCU->getEmtTuIdx(0));
#endif
#if VCEG_AZ05_ROT_TR || COM16_C1044_NSST
  m_pcPredSearch->setSaveLoadRotIdx(uiWidthIdx, uiHeightIdx, rpcBestCU->getROTIdx(rpcBestCU->getTextType(), 0));
#endif
#if COM16_C1046_PDPC_INTRA && !JVET_G0104_PLANAR_PDPC
  m_pcPredSearch->setSaveLoadPdpcIdx(uiWidthIdx, uiHeightIdx, rpcBestCU->getPDPCIdx(0));
#endif
  if (!rpcBestCU->isIntra(0))
  {
#if VCEG_AZ07_FRUC_MERGE
  m_pcPredSearch->setSaveLoadFrucMode(uiWidthIdx, uiHeightIdx, rpcBestCU->getFRUCMgrMode(0));
#endif
#if VCEG_AZ07_IMV
  m_pcPredSearch->setSaveLoadIMVFlag(uiWidthIdx, uiHeightIdx, rpcBestCU->getiMVFlag(0));
#endif
#if VCEG_AZ06_IC
  m_pcPredSearch->setSaveLoadICFlag(uiWidthIdx, uiHeightIdx, rpcBestCU->getICFlag(0));
#endif
  m_pcPredSearch->setSaveLoadMergeFlag(uiWidthIdx, uiHeightIdx, rpcBestCU->getMergeFlag(0));
#if COM16_C1016_AFFINE
  m_pcPredSearch->setSaveLoadAffineFlag(uiWidthIdx, uiHeightIdx, rpcBestCU->getAffineFlag(0));
#endif
  m_pcPredSearch->setSaveLoadInterDir(uiWidthIdx, uiHeightIdx, rpcBestCU->getInterDir(0));
  }
  dNonSplitCost = dCostTempBest = rpcBestCU->getTotalCost();
  m_pcPredSearch->setSaveLoadTag(uiZorderIdx, uiWidthIdx, uiHeightIdx, LOAD_ENC_INFO);
  }
#endif
  }
#if JVET_C0024_DELTA_QP_FIX
  if (pps.getUseDQP())
  {
  rpcBestCU->setCodedQP(rpcBestCU->getQP(0));
  }
#endif
  }

#if JVET_C0024_QTBT && COM16_C806_LARGE_CTU
  if (ucMinDepth > uiDepth)
  {
      bBoundary = true; //to force not to try BT split. JCA
  }
#endif
  // copy original YUV samples to PCM buffer
  if( rpcBestCU->getTotalCost()!=MAX_DOUBLE && rpcBestCU->isLosslessCoded(0) && (rpcBestCU->getIPCMFlag(0) == false))
  {
#if JVET_C0024_QTBT
    xFillPCMBuffer(rpcBestCU, m_pppcOrigYuv[uiWidthIdx][uiHeightIdx]);
#else
    xFillPCMBuffer(rpcBestCU, m_ppcOrigYuv[uiDepth]);
#endif
  }

#if JVET_C0024_DELTA_QP_FIX
  if( uiQTBTDepth == uiMaxDQPDepthQTBT )
#else
  if( uiDepth == pps.getMaxCuDQPDepth() )
#endif
  {
    Int idQP = m_pcEncCfg->getMaxDeltaQP();
    iMinQP = Clip3( -sps.getQpBDOffset(CHANNEL_TYPE_LUMA), MAX_QP, iBaseQP-idQP );
    iMaxQP = Clip3( -sps.getQpBDOffset(CHANNEL_TYPE_LUMA), MAX_QP, iBaseQP+idQP );
  }
#if JVET_C0024_DELTA_QP_FIX
  else if( uiQTBTDepth < uiMaxDQPDepthQTBT )
#else
  else if( uiDepth < pps.getMaxCuDQPDepth() )
#endif
  {
    iMinQP = iBaseQP;
    iMaxQP = iBaseQP;
  }
  else
  {
    const Int iStartQP = rpcTempCU->getQP(0);
    iMinQP = iStartQP;
    iMaxQP = iStartQP;
  }

  if ( m_pcEncCfg->getUseRateCtrl() )
  {
    iMinQP = m_pcRateCtrl->getRCQP();
    iMaxQP = m_pcRateCtrl->getRCQP();
  }

  if ( m_pcEncCfg->getCUTransquantBypassFlagForceValue() )
  {
    iMaxQP = iMinQP; // If all TUs are forced into using transquant bypass, do not loop here.
  }

  const Bool bSubBranch = bBoundary || 
#if COM16_C806_LARGE_CTU
    ( !( m_pcEncCfg->getUseEarlyCU() && rpcBestCU->getTotalCost()!=MAX_DOUBLE && rpcBestCU->isSkipped(0) ) && ( !m_pcEncCfg->getUseFastLCTU() || uiDepth < ucMaxDepth ) );
#else
    !( m_pcEncCfg->getUseEarlyCU() && rpcBestCU->getTotalCost()!=MAX_DOUBLE && rpcBestCU->isSkipped(0) );
#endif

#if JVET_C0024_BT_RMV_REDUNDANT
  bQTreeValid = false;
  if( uiBTSplitMode == 0 )// 如果二叉树水平分割模式为0(水平分割);
  {
    UInt uiMinQTSize = sps.getMinQTSize(rpcBestCU->getSlice()->getSliceType(), rpcBestCU->getTextType());              
    bQTreeValid = ( uiWidth>=2*uiMinQTSize );
  }

  Bool bBTHorRmvEnable = false;
  Bool bBTVerRmvEnable = false;
  if (rpcBestCU->getSlice()->getSliceType() != I_SLICE)
  {
    bBTHorRmvEnable = true;
    bBTVerRmvEnable = bQTreeValid;
  }
#endif

#if JVET_C0024_QTBT
  Bool bQTSplit = bSubBranch && uiBTSplitMode==0 && (!getFastDeltaQp() || uiWidth > fastDeltaQPCuMaxSize || bBoundary);
  if (bQTSplit)//四叉树分割;
  {
      assert(uiWidth==uiHeight);
  }
  bQTSplit = bQTSplit && (uiWidth>sps.getMinQTSize(pcSlice->getSliceType(), rpcBestCU->getTextType()) || bBoundary);

  if (!bBoundary && rpcBestCU->isSkipped(0))
  {
    rpcBestCU->getPic()->setSkiped(rpcBestCU->getZorderIdxInCtu(), uiWidth, uiHeight, true);
  }
  if (!bBoundary && rpcBestCU->getPredictionMode(0)==MODE_INTER)
  {
    rpcBestCU->getPic()->setInter(rpcBestCU->getZorderIdxInCtu(), uiWidth, uiHeight, true);
  }
  else if (!bBoundary && rpcBestCU->getPredictionMode(0)==MODE_INTRA)
  {
    rpcBestCU->getPic()->setIntra(rpcBestCU->getZorderIdxInCtu(), uiWidth, uiHeight, true);
  }

#if !JVET_C0024_DELTA_QP_FIX
  UInt uiQTWidth = sps.getCTUSize()>>uiDepth;
  UInt uiQTHeight = sps.getCTUSize()>>uiDepth;
  UInt uiBTDepth = g_aucConvertToBit[uiQTWidth]-g_aucConvertToBit[uiWidth] + g_aucConvertToBit[uiQTHeight]-g_aucConvertToBit[uiHeight];
#endif

#if JVET_C0024_SPS_MAX_BT_DEPTH
  UInt uiMaxBTD = pcSlice->isIntra() ? (isLuma(rpcTempCU->getTextType())?sps.getMaxBTDepthISliceL():sps.getMaxBTDepthISliceC()): sps.getMaxBTDepth();
#else
  UInt uiMaxBTD = pcSlice->isIntra() ? (isLuma(rpcTempCU->getTextType())?MAX_BT_DEPTH:MAX_BT_DEPTH_C): MAX_BT_DEPTH_INTER;
#endif
#if JVET_C0024_SPS_MAX_BT_SIZE
  UInt uiMaxBTSize = pcSlice->isIntra() ? (isLuma(rpcTempCU->getTextType())?sps.getMaxBTSizeISliceL():sps.getMaxBTSizeISliceC()): sps.getMaxBTSize();
#else
  UInt uiMaxBTSize = isLuma(rpcTempCU->getTextType()) ? pcSlice->getMaxBTSize(): MAX_BT_SIZE_C;//32;
#endif
  UInt uiMinBTSize = pcSlice->isIntra() ? (isLuma(rpcTempCU->getTextType())?MIN_BT_SIZE:MIN_BT_SIZE_C): MIN_BT_SIZE_INTER;

  Bool bTestHorSplit = (!bBoundary && uiHeight>uiMinBTSize 
    && uiWidth<=uiMaxBTSize && uiHeight<=uiMaxBTSize && uiBTDepth<uiMaxBTD
#if JVET_C0024_QTBT
    && !bForceQT
#endif
    );//二叉树水平划分标记;

  Bool bTestVerSplit = (!bBoundary && uiWidth>uiMinBTSize 
    && uiWidth<=uiMaxBTSize && uiHeight<=uiMaxBTSize && uiBTDepth<uiMaxBTD
#if JVET_C0024_QTBT
    && !bForceQT
#endif
    );//二叉树垂直划分标记;

  //for encoder speedup
#if JVET_E0023_FAST_ENCODING_SETTING//满足这些条件,则不再进行二叉树和四叉树划分;
  if (rpcBestCU->getSkipFlag(0) && (bTestHorSplit || bTestVerSplit) && uiBTDepth >= ((pcSlice->getPictureDistance() <= PICTURE_DISTANCE_TH) ? FAST_SKIP_DEPTH : SKIP_DEPTH))
#else
  if (rpcBestCU->getSkipFlag(0) && (bTestHorSplit || bTestVerSplit) && uiBTDepth>=SKIP_DEPTH)
#endif
  { 
    bTestHorSplit = bTestVerSplit = bQTSplit = false;
  }

#if JVET_C0024_BT_RMV_REDUNDANT
  if( uiSplitConstrain == 1 )
  {
    bTestHorSplit = false;
  }
  if( uiSplitConstrain == 2 )
  {
    bTestVerSplit = false;
  }
#endif

#if JVET_D0077_SAVE_LOAD_ENC_INFO
  if( bUseSaveLoad )
  {
    m_pcPredSearch->setSaveLoadTag( uiZorderIdx, uiWidthIdx-1, uiHeightIdx-1, SAVE_ENC_INFO );
  }
#endif

#if JVET_D0077_SAVE_LOAD_ENC_INFO
  if( bUseSaveLoadSplitDecision && saveLoadTag == LOAD_ENC_INFO )
  {
    if( bTestHorSplit && (saveLoadSplit & 0x02) )
    {
      bTestHorSplit = false;
    }
    if( bTestVerSplit && (saveLoadSplit & 0x04) )
    {
      bTestVerSplit = false;
    }
  }
#endif

//水平二叉树划分//
  if (bTestHorSplit) //如果要进行二叉树水平划分;
  {
    // further split
 //================遍历每一个QP,执行下面步骤,选取最优的QP=====================
    for (Int iQP=iMinQP; iQP<=iMaxQP; iQP++)
    {
      const Bool bIsLosslessMode = false; // False at this level. Next level down may set it to true.
  //以4*4的方式初始化临时CU;
      rpcTempCU->initEstData( uiDepth, iQP, bIsLosslessMode );

      UChar       uhNextDepth         = uiDepth;
      UInt uiBTWidthIdx = g_aucConvertToBit[uiWidth];   
      UInt uiBTHeightIdx = g_aucConvertToBit[uiHeight>>1];
      TComDataCU* pcSubBestPartCU     = m_pppcBestCU[uiBTWidthIdx][uiBTHeightIdx];//对子最佳CU进行初始化;
      TComDataCU* pcSubTempPartCU     = m_pppcTempCU[uiBTWidthIdx][uiBTHeightIdx];//对子临时CU进行初始化;
      rpcTempCU->setBTSplitModeSubParts(1, 0, uiWidth, uiHeight);
#if JVET_C0024_BT_RMV_REDUNDANT
      uiSplitConstrain = 0;
#endif
#if JVET_C0024_DELTA_QP_FIX
      if( pps.getUseDQP() ) // inherit quantization group info. from parent CU.
      {
        pcSubBestPartCU->initSubBT( rpcTempCU, 0, uiDepth, uiWidth, uiHeight>>1, 1, iQP );           
        pcSubTempPartCU->initSubBT( rpcTempCU, 0, uiDepth, uiWidth, uiHeight>>1, 1, iQP );           // clear sub partition datas or init.
        pcSubBestPartCU->setCodedQP( lastCodedQP );
        pcSubTempPartCU->setCodedQP( lastCodedQP );
        pcSubBestPartCU->setQuPartIdx( rpcTempCU->getQuPartIdx() );
        pcSubTempPartCU->setQuPartIdx( rpcTempCU->getQuPartIdx() );
        pcSubBestPartCU->setQuLastCodedQP( rpcTempCU->getQuLastCodedQP() );
        pcSubTempPartCU->setQuLastCodedQP( rpcTempCU->getQuLastCodedQP() );
      }
#endif
  遍历子CU///
      for ( UInt uiPartUnitIdx = 0; uiPartUnitIdx < 2; uiPartUnitIdx++ )//等于2是因为进行了二叉树划分;
      {
//子CU的最佳CU,初始化,以4*4的方式初始化;
        pcSubBestPartCU->initSubBT( rpcTempCU, uiPartUnitIdx, uiDepth, uiWidth, uiHeight>>1, 1, iQP );           
        pcSubTempPartCU->initSubBT( rpcTempCU, uiPartUnitIdx, uiDepth, uiWidth, uiHeight>>1, 1, iQP );           // clear sub partition datas or init.

#if VCEG_AZ07_IMV && !JVET_C0024_QTBT
        for( Int size = 0 ; size < NUMBER_OF_PART_SIZES ; size++ )
        {
          m_pppcTempCUIMVCache[size][uiBTWidthIdx][uiBTHeightIdx]->initSubBT( rpcTempCU, uiPartUnitIdx, uiDepth, uiWidth, uiHeight>>1, 1, iQP ); 
        }
#endif
#if COM16_C806_OBMC
        m_pppcTempCUWoOBMC[uiBTWidthIdx][uiBTHeightIdx]->initSubBT( rpcTempCU, uiPartUnitIdx, uiDepth, uiWidth, uiHeight>>1, 1, iQP );  // clear sub partition datas or init.
#endif
#if VCEG_AZ07_FRUC_MERGE
        m_pppcFRUCBufferCU[uiBTWidthIdx][uiBTHeightIdx]->initSubBT( rpcTempCU, uiPartUnitIdx, uiDepth, uiWidth, uiHeight>>1, 1, iQP ); 
#endif
        if(( pcSubBestPartCU->getCUPelX() < pcSlice->getSPS()->getPicWidthInLumaSamples() ) && ( pcSubBestPartCU->getCUPelY() < pcSlice->getSPS()->getPicHeightInLumaSamples() ) )
        {
          if ( 0 == uiPartUnitIdx) //initialize RD with previous depth buffer
          {
            m_ppppcRDSbacCoder[uiWidthIdx][uiHeightIdx-1][CI_CURR_BEST]->load(m_ppppcRDSbacCoder[uiWidthIdx][uiHeightIdx][CI_CURR_BEST]);
          }
          else
          {
            m_ppppcRDSbacCoder[uiWidthIdx][uiHeightIdx-1][CI_CURR_BEST]->load(m_ppppcRDSbacCoder[uiWidthIdx][uiHeightIdx-1][CI_NEXT_BEST]);
          }
#if JVET_C0024_BT_RMV_REDUNDANT//对子CU递归调用xCompressCU;
          xCompressCU( pcSubBestPartCU, pcSubTempPartCU, uiDepth, uiWidth, uiHeight>>1, pcSubBestPartCU->getBTSplitMode(0), uiSplitConstrain );
          
          if( uiPartUnitIdx == 0 && pcSubBestPartCU->getBTSplitModeForBTDepth(0, uiBTDepth+1) == 2 && bBTHorRmvEnable )
          {
              uiSplitConstrain = 2;
          }
#else
xCompressCU( pcSubBestPartCU, pcSubTempPartCU, uiDepth, uiWidth, uiHeight>>1, pcSubBestPartCU->getBTSplitMode(0) );
#endif    //将子CU的最佳预测数据复制到TempCU中;
          rpcTempCU->copyPartFrom( pcSubBestPartCU, uiPartUnitIdx, uhNextDepth, uiWidth, uiHeight>>1 );         // Keep best part data to current temporary data.
#if JVET_C0024_DELTA_QP_FIX
          if( pps.getUseDQP() ) // update coded QP
          { 
            rpcTempCU->setCodedQP( pcSubBestPartCU->getCodedQP() ); 
            pcSubBestPartCU->setCodedQP( rpcTempCU->getCodedQP() );
            pcSubTempPartCU->setCodedQP( rpcTempCU->getCodedQP() );
          }
#endif
          xCopyYuv2Tmp( pcSubBestPartCU->getZorderIdxInCtu()-rpcTempCU->getZorderIdxInCtu(), uiWidth, uiHeight, 1 );
        }
      }
      m_pcRDGoOnSbacCoder->load(m_ppppcRDSbacCoder[uiWidthIdx][uiHeightIdx-1][CI_NEXT_BEST]);
      m_pcEntropyCoder->resetBits();//重置熵编码器的比特数;
      if (uiBTSplitMode==0 )
      {
        m_pcEntropyCoder->encodeSplitFlag( rpcTempCU, 0, uiDepth, true );
      }
      m_pcEntropyCoder->encodeBTSplitMode(rpcTempCU, 0, uiWidth, uiHeight, true);

  //统计当前CU的总的比特数,二进制数和率失真代价;
      rpcTempCU->getTotalBits() += m_pcEntropyCoder->getNumberOfWrittenBits(); // split bits
      rpcTempCU->getTotalBins() += ((TEncBinCABAC *)((TEncSbac*)m_pcEntropyCoder->m_pcEntropyCoderIf)->getEncBinIf())->getBinsCoded();

      rpcTempCU->getTotalCost()  = m_pcRdCost->calcRdCost( rpcTempCU->getTotalBits(), rpcTempCU->getTotalDistortion() );
#if JVET_D0077_SAVE_LOAD_ENC_INFO
      if( rpcTempCU->getTotalCost() < dHorSplitCost )
      {
        dHorSplitCost = rpcTempCU->getTotalCost();
      }
#endif
#if JVET_C0024_DELTA_QP_FIX
      if( uiQTBTDepth == uiMaxDQPDepthQTBT && pps.getUseDQP())
      {
        Bool foundNonZeroCbf = false;
        UInt uiFirstNonZeroPartIdx = 0;
        rpcTempCU->setQPSubCUs( rpcTempCU->getRefQP( 0 ), 0, uiDepth, uiWidth, uiHeight, uiFirstNonZeroPartIdx, foundNonZeroCbf );
        if ( foundNonZeroCbf )
        {
          m_pcEntropyCoder->resetBits();
          m_pcEntropyCoder->encodeQP( rpcTempCU, uiFirstNonZeroPartIdx, false );
          rpcTempCU->getTotalBits() += m_pcEntropyCoder->getNumberOfWrittenBits(); // dQP bits
          rpcTempCU->getTotalBins() += ((TEncBinCABAC *)((TEncSbac*)m_pcEntropyCoder->m_pcEntropyCoderIf)->getEncBinIf())->getBinsCoded();
          rpcTempCU->getTotalCost()  = m_pcRdCost->calcRdCost( rpcTempCU->getTotalBits(), rpcTempCU->getTotalDistortion() );
        }
        else
        {
          rpcTempCU->setQPSubParts( rpcTempCU->getRefQP( 0 ), 0, uiWidth, uiHeight ); // set QP to default QP
#if JVET_C0024_DELTA_QP_FIX
          if( pps.getUseDQP() ) // update coded QP
          { 
            rpcTempCU->setCodedQP( rpcTempCU->getQP( 0 ) ); 
          }
#endif
        }
      }
#endif
      m_pcRDGoOnSbacCoder->store(m_ppppcRDSbacCoder[uiWidthIdx][uiHeightIdx][CI_TEMP_BEST]);

      if (rpcBestCU->getTotalCost()!=MAX_DOUBLE)
      {
//是否是slice的末尾;
        const Bool isEndOfSlice        =    pcSlice->getSliceMode()==FIXED_NUMBER_OF_BYTES
          && ((pcSlice->getSliceBits()+rpcBestCU->getTotalBits())>pcSlice->getSliceArgument()<<3)
          && rpcBestCU->getCtuRsAddr() != pcPic->getPicSym()->getCtuTsToRsAddrMap(pcSlice->getSliceCurStartCtuTsAddr())
          && rpcBestCU->getCtuRsAddr() != pcPic->getPicSym()->getCtuTsToRsAddrMap(pcSlice->getSliceSegmentCurStartCtuTsAddr());
       //是否是slice  segment的末尾;
const Bool isEndOfSliceSegment =    pcSlice->getSliceSegmentMode()==FIXED_NUMBER_OF_BYTES
          && ((pcSlice->getSliceSegmentBits()+rpcBestCU->getTotalBits()) > pcSlice->getSliceSegmentArgument()<<3)
          && rpcBestCU->getCtuRsAddr() != pcPic->getPicSym()->getCtuTsToRsAddrMap(pcSlice->getSliceSegmentCurStartCtuTsAddr());
        // Do not need to check slice condition for slice-segment since a slice-segment is a subset of a slice.
        if(isEndOfSlice||isEndOfSliceSegment)//如果是slice或者是slice segment的末尾;
        {
          rpcBestCU->getTotalCost()=MAX_DOUBLE;
        }
      }
  //调用此函数选择最好的模式;
      xCheckBestMode( rpcBestCU, rpcTempCU, uiDepth, uiWidth, uiHeight);
      rpcTempCU->initEstData( uiDepth, iQP, bIsLosslessMode, uiWidth, uiHeight, uiBTSplitMode );

      rpcBestCU->getPic()->setCodedBlkInCTU(false, uiPelXInCTU>> MIN_CU_LOG2, uiPelYInCTU>> MIN_CU_LOG2, uiWidth>> MIN_CU_LOG2, uiHeight>> MIN_CU_LOG2 );  
      rpcBestCU->getPic()->addCodedAreaInCTU(-(Int)uiWidth*uiHeight);
    }
//===============QP遍历结束=================================
#if JVET_D0077_SAVE_LOAD_ENC_INFO
    if( dCostTempBest > dHorSplitCost )
    {
      dCostTempBest = dHorSplitCost;
  }
#endif
  }

/水平二叉树划分结束//
  //for encoder speedup,如果满足这些条件,则不需要再进行四叉树划分和二叉树垂直划分;
  if (bTestHorSplit && rpcBestCU->isSkipped(0) && rpcBestCU->getBTDepth(0)==uiBTDepth && uiBTDepth>=SKIPHORNOVERQT_DEPTH_TH)
  {
    bTestVerSplit = bQTSplit = false;
  }

  if (bTestVerSplit) //如果要进行二叉树垂直划分;
  {
    // further split
    //========从最小QP到最大QP遍历每一个QP,执行下面的步骤,选取最优QP=================
    for (Int iQP=iMinQP; iQP<=iMaxQP; iQP++)
    {
      const Bool bIsLosslessMode = false; // False at this level. Next level down may set it to true.
      rpcTempCU->initEstData( uiDepth, iQP, bIsLosslessMode );
      UChar       uhNextDepth         = uiDepth;
      UInt uiBTWidthIdx = g_aucConvertToBit[uiWidth>>1];   
      UInt uiBTHeightIdx = g_aucConvertToBit[uiHeight];
      TComDataCU* pcSubBestPartCU     = m_pppcBestCU[uiBTWidthIdx][uiBTHeightIdx];
      TComDataCU* pcSubTempPartCU     = m_pppcTempCU[uiBTWidthIdx][uiBTHeightIdx];
      rpcTempCU->setBTSplitModeSubParts(2, 0, uiWidth, uiHeight);
#if JVET_C0024_BT_RMV_REDUNDANT
      uiSplitConstrain = 0;
#endif
#if JVET_C0024_DELTA_QP_FIX // inherit quantization group info. from parent CU.
      if( pps.getUseDQP() )
      {
        pcSubBestPartCU->initSubBT( rpcTempCU, 0, uiDepth, uiWidth>>1, uiHeight, 2, iQP );           
        pcSubTempPartCU->initSubBT( rpcTempCU, 0, uiDepth, uiWidth>>1, uiHeight, 2, iQP );           // clear sub partition datas or init.
        pcSubBestPartCU->setCodedQP( lastCodedQP );
        pcSubTempPartCU->setCodedQP( lastCodedQP );
        pcSubBestPartCU->setQuPartIdx( rpcTempCU->getQuPartIdx() );
        pcSubTempPartCU->setQuPartIdx( rpcTempCU->getQuPartIdx() );
        pcSubBestPartCU->setQuLastCodedQP( rpcTempCU->getQuLastCodedQP() );
        pcSubTempPartCU->setQuLastCodedQP( rpcTempCU->getQuLastCodedQP() );
      }
#endif
      for ( UInt uiPartUnitIdx = 0; uiPartUnitIdx < 2; uiPartUnitIdx++ )//二叉树划分划分为两个子CU;
      {
        pcSubBestPartCU->initSubBT( rpcTempCU, uiPartUnitIdx, uiDepth, uiWidth>>1, uiHeight, 2, iQP );           
        pcSubTempPartCU->initSubBT( rpcTempCU, uiPartUnitIdx, uiDepth, uiWidth>>1, uiHeight, 2, iQP );           // clear sub partition datas or init.
#if VCEG_AZ07_IMV && !JVET_C0024_QTBT
        for( Int size = 0 ; size < NUMBER_OF_PART_SIZES ; size++ )
        {
          m_pppcTempCUIMVCache[size][uiBTWidthIdx][uiBTHeightIdx]->initSubBT( rpcTempCU, uiPartUnitIdx, uiDepth, uiWidth>>1, uiHeight, 2, iQP ); 
        }
#endif
#if COM16_C806_OBMC
        m_pppcTempCUWoOBMC[uiBTWidthIdx][uiBTHeightIdx]->initSubBT( rpcTempCU, uiPartUnitIdx, uiDepth, uiWidth>>1, uiHeight, 2, iQP );  // clear sub partition datas or init.
#endif
#if VCEG_AZ07_FRUC_MERGE
        m_pppcFRUCBufferCU[uiBTWidthIdx][uiBTHeightIdx]->initSubBT( rpcTempCU, uiPartUnitIdx, uiDepth, uiWidth>>1, uiHeight, 2, iQP ); 
#endif
        if(( pcSubBestPartCU->getCUPelX() < pcSlice->getSPS()->getPicWidthInLumaSamples() ) && ( pcSubBestPartCU->getCUPelY() < pcSlice->getSPS()->getPicHeightInLumaSamples() ) )
        {
          if ( 0 == uiPartUnitIdx) //initialize RD with previous depth buffer
          {
            m_ppppcRDSbacCoder[uiWidthIdx-1][uiHeightIdx][CI_CURR_BEST]->load(m_ppppcRDSbacCoder[uiWidthIdx][uiHeightIdx][CI_CURR_BEST]);
          }
          else
          {
            m_ppppcRDSbacCoder[uiWidthIdx-1][uiHeightIdx][CI_CURR_BEST]->load(m_ppppcRDSbacCoder[uiWidthIdx-1][uiHeightIdx][CI_NEXT_BEST]);
          }
#if JVET_C0024_BT_RMV_REDUNDANT
          xCompressCU( pcSubBestPartCU, pcSubTempPartCU, uiDepth, uiWidth>>1, uiHeight, pcSubBestPartCU->getBTSplitMode(0), uiSplitConstrain );
          
          if( uiPartUnitIdx == 0 && pcSubBestPartCU->getBTSplitModeForBTDepth(0, uiBTDepth+1) == 1 && bBTVerRmvEnable )
          {
              uiSplitConstrain = 1;
          }
#else
          xCompressCU( pcSubBestPartCU, pcSubTempPartCU, uiDepth, uiWidth>>1, uiHeight, pcSubBestPartCU->getBTSplitMode(0) );
#endif
          rpcTempCU->copyPartFrom( pcSubBestPartCU, uiPartUnitIdx, uhNextDepth, uiWidth>>1, uiHeight );         // Keep best part data to current temporary data.
#if JVET_C0024_DELTA_QP_FIX
          if( pps.getUseDQP() )  // update coded QP
          { 
            rpcTempCU->setCodedQP( pcSubBestPartCU->getCodedQP() ); 
            pcSubBestPartCU->setCodedQP( rpcTempCU->getCodedQP() );
            pcSubTempPartCU->setCodedQP( rpcTempCU->getCodedQP() );
          }
#endif
          xCopyYuv2Tmp( pcSubBestPartCU->getZorderIdxInCtu()-rpcTempCU->getZorderIdxInCtu(), uiWidth, uiHeight, 2 );
        }
      }
      m_pcRDGoOnSbacCoder->load(m_ppppcRDSbacCoder[uiWidthIdx-1][uiHeightIdx][CI_NEXT_BEST]);
      m_pcEntropyCoder->resetBits();
      if (uiBTSplitMode==0 )
      {
        m_pcEntropyCoder->encodeSplitFlag( rpcTempCU, 0, uiDepth, true );
      }
      m_pcEntropyCoder->encodeBTSplitMode(rpcTempCU, 0, uiWidth, uiHeight, true);

      rpcTempCU->getTotalBits() += m_pcEntropyCoder->getNumberOfWrittenBits(); // split bits
      rpcTempCU->getTotalBins() += ((TEncBinCABAC *)((TEncSbac*)m_pcEntropyCoder->m_pcEntropyCoderIf)->getEncBinIf())->getBinsCoded();
      rpcTempCU->getTotalCost()  = m_pcRdCost->calcRdCost( rpcTempCU->getTotalBits(), rpcTempCU->getTotalDistortion() );
#if JVET_D0077_SAVE_LOAD_ENC_INFO
      if( rpcTempCU->getTotalCost() < dVerSplitCost )
      {
        dVerSplitCost = rpcTempCU->getTotalCost();
      }
#endif
#if JVET_C0024_DELTA_QP_FIX
      if( uiQTBTDepth == uiMaxDQPDepthQTBT && pps.getUseDQP())
      {
        Bool foundNonZeroCbf = false;
        UInt uiFirstNonZeroPartIdx = 0;
        rpcTempCU->setQPSubCUs( rpcTempCU->getRefQP( 0 ), 0, uiDepth, uiWidth, uiHeight, uiFirstNonZeroPartIdx, foundNonZeroCbf );
        if ( foundNonZeroCbf )
        {
          m_pcEntropyCoder->resetBits();
          m_pcEntropyCoder->encodeQP( rpcTempCU, uiFirstNonZeroPartIdx, false );
          rpcTempCU->getTotalBits() += m_pcEntropyCoder->getNumberOfWrittenBits(); // dQP bits
          rpcTempCU->getTotalBins() += ((TEncBinCABAC *)((TEncSbac*)m_pcEntropyCoder->m_pcEntropyCoderIf)->getEncBinIf())->getBinsCoded();
          rpcTempCU->getTotalCost()  = m_pcRdCost->calcRdCost( rpcTempCU->getTotalBits(), rpcTempCU->getTotalDistortion() );
        }
        else
        {
          rpcTempCU->setQPSubParts( rpcTempCU->getRefQP( 0 ), 0, uiWidth, uiHeight ); // set QP to default QP
#if JVET_C0024_DELTA_QP_FIX
          if( pps.getUseDQP() ) // update coded QP
          { 
            rpcTempCU->setCodedQP( rpcTempCU->getQP( 0 ) ); 
          }
#endif
        }
      }
#endif
      m_pcRDGoOnSbacCoder->store(m_ppppcRDSbacCoder[uiWidthIdx][uiHeightIdx][CI_TEMP_BEST]);
      if (rpcBestCU->getTotalCost()!=MAX_DOUBLE)
      {
        const Bool isEndOfSlice        =    pcSlice->getSliceMode()==FIXED_NUMBER_OF_BYTES
          && ((pcSlice->getSliceBits()+rpcBestCU->getTotalBits())>pcSlice->getSliceArgument()<<3)
          && rpcBestCU->getCtuRsAddr() != pcPic->getPicSym()->getCtuTsToRsAddrMap(pcSlice->getSliceCurStartCtuTsAddr())
          && rpcBestCU->getCtuRsAddr() != pcPic->getPicSym()->getCtuTsToRsAddrMap(pcSlice->getSliceSegmentCurStartCtuTsAddr());
        const Bool isEndOfSliceSegment =    pcSlice->getSliceSegmentMode()==FIXED_NUMBER_OF_BYTES
          && ((pcSlice->getSliceSegmentBits()+rpcBestCU->getTotalBits()) > pcSlice->getSliceSegmentArgument()<<3)
          && rpcBestCU->getCtuRsAddr() != pcPic->getPicSym()->getCtuTsToRsAddrMap(pcSlice->getSliceSegmentCurStartCtuTsAddr());
        // Do not need to check slice condition for slice-segment since a slice-segment is a subset of a slice.
        if(isEndOfSlice||isEndOfSliceSegment)
        {
          rpcBestCU->getTotalCost()=MAX_DOUBLE;
        }
      }
      xCheckBestMode( rpcBestCU, rpcTempCU, uiDepth, uiWidth, uiHeight);
      rpcTempCU->initEstData( uiDepth, iQP, bIsLosslessMode, uiWidth, uiHeight, uiBTSplitMode );
     rpcBestCU->getPic()->setCodedBlkInCTU(false, uiPelXInCTU>> MIN_CU_LOG2, uiPelYInCTU>> MIN_CU_LOG2, uiWidth>> MIN_CU_LOG2, uiHeight>> MIN_CU_LOG2 );  
      rpcBestCU->getPic()->addCodedAreaInCTU(-(Int)uiWidth*uiHeight);
    }
//==================QP遍历结束===============================
#if JVET_D0077_SAVE_LOAD_ENC_INFO
    if( dCostTempBest > dVerSplitCost )
    {
      dCostTempBest = dVerSplitCost;
  }
#endif
  }
  //二叉树垂直划分结束
  UInt uiZorderBR = g_auiRasterToZscan[((uiHeight>> MIN_CU_LOG2)-1) * (sps.getCTUSize()>> MIN_CU_LOG2) + (uiWidth>> MIN_CU_LOG2)-1];  //bottom-right part.
  //如果满足这些条件,则不进行四叉树划分;
  if (bQTSplit && ((rpcBestCU->getBTDepth(0)==0 && uiMaxBTD>=(rpcBestCU->getSlice()->isIntra() ? 3: 2) )
    || (rpcBestCU->getBTDepth(0)==1 && rpcBestCU->getBTDepth(uiZorderBR)==1 && uiMaxBTD>=(rpcBestCU->getSlice()->isIntra()? 4: 3))) 
    && bTestHorSplit && bTestVerSplit ) 
  {
    bQTSplit = false;
  }
#endif

四叉树划分过程
#if JVET_C0024_QTBT
  if( bQTSplit)//如果要进行四叉树划分;
#else
  if( bSubBranch && uiDepth < sps.getLog2DiffMaxMinCodingBlockSize() && (!getFastDeltaQp() || uiWidth > fastDeltaQPCuMaxSize || bBoundary))
#endif
  {
    // further split
//=========从最小QP到最大QP遍历每一个QP,执行下面的步骤,选取最优QP================
    for (Int iQP=iMinQP; iQP<=iMaxQP; iQP++)
    {
      const Bool bIsLosslessMode = false; // False at this level. Next level down may set it to true.
      rpcTempCU->initEstData( uiDepth, iQP, bIsLosslessMode );
      UChar       uhNextDepth         = uiDepth+1;
#if JVET_C0024_QTBT
      UInt uiQTWidthIdx = g_aucConvertToBit[uiWidth>>1];  //4;
      UInt uiQTHeightIdx = g_aucConvertToBit[uiHeight>>1];//4;
      TComDataCU* pcSubBestPartCU     = m_pppcBestCU[uiQTWidthIdx][uiQTHeightIdx];
      TComDataCU* pcSubTempPartCU     = m_pppcTempCU[uiQTWidthIdx][uiQTHeightIdx];
#else
      TComDataCU* pcSubBestPartCU     = m_ppcBestCU[uhNextDepth];
      TComDataCU* pcSubTempPartCU     = m_ppcTempCU[uhNextDepth];
#endif
      DEBUG_STRING_NEW(sTempDebug)
#if JVET_C0024_DELTA_QP_FIX // inherit quantization group info. from parent CU.
      if( pps.getUseDQP() )
      {
        pcSubBestPartCU->initSubCU( rpcTempCU, 0, uhNextDepth, iQP );           // clear sub partition datas or init.
        pcSubTempPartCU->initSubCU( rpcTempCU, 0, uhNextDepth, iQP );           // clear sub partition datas or init.
        pcSubBestPartCU->setCodedQP( lastCodedQP );
        pcSubTempPartCU->setCodedQP( lastCodedQP );
        pcSubBestPartCU->setQuPartIdx( rpcTempCU->getQuPartIdx() );
        pcSubTempPartCU->setQuPartIdx( rpcTempCU->getQuPartIdx() );
        pcSubBestPartCU->setQuLastCodedQP( rpcTempCU->getQuLastCodedQP() );
        pcSubTempPartCU->setQuLastCodedQP( rpcTempCU->getQuLastCodedQP() );
      }
#endif
      for ( UInt uiPartUnitIdx = 0; uiPartUnitIdx < 4; uiPartUnitIdx++ )//四叉树划分划分为4个子CU;
      {//初始化最优划分的子CU;
        pcSubBestPartCU->initSubCU( rpcTempCU, uiPartUnitIdx, uhNextDepth, iQP );           // clear sub partition datas or init.
       //初始化当前的子CU;
pcSubTempPartCU->initSubCU( rpcTempCU, uiPartUnitIdx, uhNextDepth, iQP );           // clear sub partition datas or init.
#if VCEG_AZ07_IMV && !JVET_C0024_QTBT
        for( Int size = 0 ; size < NUMBER_OF_PART_SIZES ; size++ )
        {
#if JVET_C0024_QTBT
            m_pppcTempCUIMVCache[size][uiQTWidthIdx][uiQTHeightIdx]->initSubCU( rpcTempCU, uiPartUnitIdx, uhNextDepth, iQP );
#else
          m_ppcTempCUIMVCache[size][uhNextDepth]->initSubCU( rpcTempCU, uiPartUnitIdx, uhNextDepth, iQP );
#endif
        }
#endif
#if COM16_C806_OBMC
#if JVET_C0024_QTBT
          m_pppcTempCUWoOBMC[uiQTWidthIdx][uiQTHeightIdx]->initSubCU( rpcTempCU, uiPartUnitIdx, uhNextDepth, iQP ); // clear sub partition datas or init.
#else
        m_ppcTempCUWoOBMC[uhNextDepth]->initSubCU( rpcTempCU, uiPartUnitIdx, uhNextDepth, iQP ); // clear sub partition datas or init.
#endif
#endif
#if VCEG_AZ07_FRUC_MERGE
#if JVET_C0024_QTBT
          m_pppcFRUCBufferCU[uiQTWidthIdx][uiQTHeightIdx]->initSubCU( rpcTempCU, uiPartUnitIdx, uhNextDepth, iQP ); 
#else
        m_ppcFRUCBufferCU[uhNextDepth]->initSubCU( rpcTempCU, uiPartUnitIdx, uhNextDepth, iQP ); 
#endif
#endif
        if( ( pcSubBestPartCU->getCUPelX() < sps.getPicWidthInLumaSamples() ) && ( pcSubBestPartCU->getCUPelY() < sps.getPicHeightInLumaSamples() ) )
        {
#if JVET_C0024_QTBT
            if ( 0 == uiPartUnitIdx) //initialize RD with previous depth buffer
            {
              m_ppppcRDSbacCoder[uiQTWidthIdx][uiQTHeightIdx][CI_CURR_BEST]->load(m_ppppcRDSbacCoder[uiWidthIdx][uiHeightIdx][CI_CURR_BEST]);
            }
            else
            {
              m_ppppcRDSbacCoder[uiQTWidthIdx][uiQTHeightIdx][CI_CURR_BEST]->load(m_ppppcRDSbacCoder[uiQTWidthIdx][uiQTHeightIdx][CI_NEXT_BEST]);
            }
#else
          if ( 0 == uiPartUnitIdx) //initialize RD with previous depth buffer
          {
            m_pppcRDSbacCoder[uhNextDepth][CI_CURR_BEST]->load(m_pppcRDSbacCoder[uiDepth][CI_CURR_BEST]);
          }
          else
          {
            m_pppcRDSbacCoder[uhNextDepth][CI_CURR_BEST]->load(m_pppcRDSbacCoder[uhNextDepth][CI_NEXT_BEST]);
          }
#endif
#if AMP_ENC_SPEEDUP
          DEBUG_STRING_NEW(sChild)
#if JVET_C0024_QTBT//对每个子CU调用xCompressCU;
              xCompressCU( pcSubBestPartCU, pcSubTempPartCU, uhNextDepth, uiWidth>>1, uiHeight>>1 DEBUG_STRING_PASS_INTO(sChild), SIZE_2Nx2N );
#else
          if ( !(rpcBestCU->getTotalCost()!=MAX_DOUBLE && rpcBestCU->isInter(0)) )
          {
            xCompressCU( pcSubBestPartCU, pcSubTempPartCU, uhNextDepth DEBUG_STRING_PASS_INTO(sChild), NUMBER_OF_PART_SIZES );
          }
          else
          {
            xCompressCU( pcSubBestPartCU, pcSubTempPartCU, uhNextDepth DEBUG_STRING_PASS_INTO(sChild), rpcBestCU->getPartitionSize(0) );
          }
#endif
          DEBUG_STRING_APPEND(sTempDebug, sChild)
#else
          xCompressCU( pcSubBestPartCU, pcSubTempPartCU, uhNextDepth );
#endif
#if JVET_C0024_QTBT
            rpcTempCU->copyPartFrom( pcSubBestPartCU, uiPartUnitIdx, uhNextDepth, uiWidth>>1, uiHeight>>1 );         // Keep best part data to current temporary data.
#if JVET_C0024_DELTA_QP_FIX
            if( pps.getUseDQP() )  // update coded QP
            { 
              rpcTempCU->setCodedQP( pcSubBestPartCU->getCodedQP() ); 
              pcSubBestPartCU->setCodedQP( rpcTempCU->getCodedQP() );
              pcSubTempPartCU->setCodedQP( rpcTempCU->getCodedQP() );
            }
#endif
            assert(pcSubBestPartCU->getTotalNumPart()*uiPartUnitIdx == pcSubBestPartCU->getZorderIdxInCtu()-rpcTempCU->getZorderIdxInCtu());       
            xCopyYuv2Tmp( pcSubBestPartCU->getTotalNumPart()*uiPartUnitIdx, uiWidth, uiHeight );
#else
          rpcTempCU->copyPartFrom( pcSubBestPartCU, uiPartUnitIdx, uhNextDepth );         // Keep best part data to current temporary data.
          xCopyYuv2Tmp( pcSubBestPartCU->getTotalNumPart()*uiPartUnitIdx, uhNextDepth );
#endif
        }
        else
        {
#if JVET_C0024_QTBT
            pcSubBestPartCU->copyToPic( uhNextDepth, uiWidth>>1, uiHeight>>1 );
            rpcTempCU->copyPartFrom( pcSubBestPartCU, uiPartUnitIdx, uhNextDepth, uiWidth>>1, uiHeight>>1 );


            rpcBestCU->getPic()->addCodedAreaInCTU(uiWidth*uiHeight>>2);
#else
          pcSubBestPartCU->copyToPic( uhNextDepth );
          rpcTempCU->copyPartFrom( pcSubBestPartCU, uiPartUnitIdx, uhNextDepth );
#endif
        }
      }
#if JVET_C0024_QTBT
        m_pcRDGoOnSbacCoder->load(m_ppppcRDSbacCoder[uiQTWidthIdx][uiQTHeightIdx][CI_NEXT_BEST]);
#else
      m_pcRDGoOnSbacCoder->load(m_pppcRDSbacCoder[uhNextDepth][CI_NEXT_BEST]);
#endif
      if( !bBoundary )
      {
        m_pcEntropyCoder->resetBits();
#if JVET_C0024_QTBT
        if( !bForceQT )
#endif
        m_pcEntropyCoder->encodeSplitFlag( rpcTempCU, 0, uiDepth, true );
        rpcTempCU->getTotalBits() += m_pcEntropyCoder->getNumberOfWrittenBits(); // split bits
        rpcTempCU->getTotalBins() += ((TEncBinCABAC *)((TEncSbac*)m_pcEntropyCoder->m_pcEntropyCoderIf)->getEncBinIf())->getBinsCoded();
      }
      rpcTempCU->getTotalCost()  = m_pcRdCost->calcRdCost( rpcTempCU->getTotalBits(), rpcTempCU->getTotalDistortion() );
#if JVET_C0024_DELTA_QP_FIX
      if( uiQTBTDepth == uiMaxDQPDepthQTBT && pps.getUseDQP())
#else
      if( uiDepth == pps.getMaxCuDQPDepth() && pps.getUseDQP())
#endif
      {
        Bool hasResidual = false;
        for( UInt uiBlkIdx = 0; uiBlkIdx < rpcTempCU->getTotalNumPart(); uiBlkIdx ++)
        {
#if JVET_C0024_DELTA_QP_FIX
          if( rpcTempCU->getSlice()->isIntra() )
          {
            if( rpcTempCU->getTextType() == CHANNEL_TYPE_LUMA )
            {
              if( rpcTempCU->getCbf(uiBlkIdx, COMPONENT_Y) )
              {
                hasResidual = true;
              }
            }
            else
            {
              if(  (rpcTempCU->getCbf(uiBlkIdx, COMPONENT_Cb) && (numberValidComponents > COMPONENT_Cb)) ||
                   (rpcTempCU->getCbf(uiBlkIdx, COMPONENT_Cr) && (numberValidComponents > COMPONENT_Cr)) )
              {
                hasResidual = true;
              }
            }
          }
          else
#endif
          if( (     rpcTempCU->getCbf(uiBlkIdx, COMPONENT_Y)
                || (rpcTempCU->getCbf(uiBlkIdx, COMPONENT_Cb) && (numberValidComponents > COMPONENT_Cb))
                || (rpcTempCU->getCbf(uiBlkIdx, COMPONENT_Cr) && (numberValidComponents > COMPONENT_Cr)) ) )
          {
            hasResidual = true;
            break;
          }
        }
        if ( hasResidual )
        {
#if JVET_C0024_DELTA_QP_FIX
          Bool foundNonZeroCbf = false;
          UInt uiFirstNonZeroPartIdx = 0;
          rpcTempCU->setQPSubCUs( rpcTempCU->getRefQP( 0 ), 0, uiDepth, uiWidth, uiHeight, uiFirstNonZeroPartIdx, foundNonZeroCbf );
          
          m_pcEntropyCoder->resetBits();
          m_pcEntropyCoder->encodeQP( rpcTempCU, uiFirstNonZeroPartIdx, false );
          rpcTempCU->getTotalBits() += m_pcEntropyCoder->getNumberOfWrittenBits(); // dQP bits
          rpcTempCU->getTotalBins() += ((TEncBinCABAC *)((TEncSbac*)m_pcEntropyCoder->m_pcEntropyCoderIf)->getEncBinIf())->getBinsCoded();
          rpcTempCU->getTotalCost()  = m_pcRdCost->calcRdCost( rpcTempCU->getTotalBits(), rpcTempCU->getTotalDistortion() );
#else
          m_pcEntropyCoder->resetBits();
          m_pcEntropyCoder->encodeQP( rpcTempCU, 0, false );
          rpcTempCU->getTotalBits() += m_pcEntropyCoder->getNumberOfWrittenBits(); // dQP bits
          rpcTempCU->getTotalBins() += ((TEncBinCABAC *)((TEncSbac*)m_pcEntropyCoder->m_pcEntropyCoderIf)->getEncBinIf())->getBinsCoded();
          rpcTempCU->getTotalCost()  = m_pcRdCost->calcRdCost( rpcTempCU->getTotalBits(), rpcTempCU->getTotalDistortion() );
          Bool foundNonZeroCbf = false;
          rpcTempCU->setQPSubCUs( rpcTempCU->getRefQP( 0 ), 0, uiDepth, foundNonZeroCbf );
#endif
          assert( foundNonZeroCbf );
        }
        else
        {
#if JVET_C0024_DELTA_QP_FIX
          rpcTempCU->setQPSubParts( rpcTempCU->getRefQP( 0 ), 0, uiWidth, uiHeight ); // set QP to default QP
#else
          rpcTempCU->setQPSubParts( rpcTempCU->getRefQP( 0 ), 0, uiDepth ); // set QP to default QP
#endif
#if JVET_C0024_DELTA_QP_FIX
          if( pps.getUseDQP() ) // update coded QP
          { 
            rpcTempCU->setCodedQP( rpcTempCU->getQP( 0 ) ); 
          }
#endif
        }
      }
#if JVET_C0024_QTBT
        m_pcRDGoOnSbacCoder->store(m_ppppcRDSbacCoder[uiWidthIdx][uiHeightIdx][CI_TEMP_BEST]);
#else
      m_pcRDGoOnSbacCoder->store(m_pppcRDSbacCoder[uiDepth][CI_TEMP_BEST]);
#endif
      // If the configuration being tested exceeds the maximum number of bytes for a slice / slice-segment, then
      // a proper RD evaluation cannot be performed. Therefore, termination of the
      // slice/slice-segment must be made prior to this CTU.
      // This can be achieved by forcing the decision to be that of the rpcTempCU.
      // The exception is each slice / slice-segment must have at least one CTU.
  //如果正在测试的配置超过了片/片段的最大字节数,则无法执行正确的RD评估。 
  //因此,必须在该CTU之前终止切片/切片段。这可以通过强制该判决为rpcTempCU来实现。
  //例外是每个切片/切片段必须至少具有一个CTU。
      if (rpcBestCU->getTotalCost()!=MAX_DOUBLE)
      {
        const Bool isEndOfSlice        =    pcSlice->getSliceMode()==FIXED_NUMBER_OF_BYTES
                                         && ((pcSlice->getSliceBits()+rpcBestCU->getTotalBits())>pcSlice->getSliceArgument()<<3)
                                         && rpcBestCU->getCtuRsAddr() != pcPic->getPicSym()->getCtuTsToRsAddrMap(pcSlice->getSliceCurStartCtuTsAddr())
                                         && rpcBestCU->getCtuRsAddr() != pcPic->getPicSym()->getCtuTsToRsAddrMap(pcSlice->getSliceSegmentCurStartCtuTsAddr());
        const Bool isEndOfSliceSegment =    pcSlice->getSliceSegmentMode()==FIXED_NUMBER_OF_BYTES
                                         && ((pcSlice->getSliceSegmentBits()+rpcBestCU->getTotalBits()) > pcSlice->getSliceSegmentArgument()<<3)
                                         && rpcBestCU->getCtuRsAddr() != pcPic->getPicSym()->getCtuTsToRsAddrMap(pcSlice->getSliceSegmentCurStartCtuTsAddr());
                                             // Do not need to check slice condition for slice-segment since a slice-segment is a subset of a slice.
        if(isEndOfSlice||isEndOfSliceSegment)
        {
          rpcBestCU->getTotalCost()=MAX_DOUBLE;
        }
      }
#if JVET_C0024_QTBT
  //比较当前块的代价和划分成子块的总代价;
        xCheckBestMode( rpcBestCU, rpcTempCU, uiDepth, uiWidth, uiHeight DEBUG_STRING_PASS_INTO(sDebug) DEBUG_STRING_PASS_INTO(sTempDebug) DEBUG_STRING_PASS_INTO(false) ); // RD compare current larger prediction
        rpcBestCU->getPic()->setCodedBlkInCTU(false, uiPelXInCTU>>MIN_CU_LOG2, uiPelYInCTU>>MIN_CU_LOG2, uiWidth>>MIN_CU_LOG2, uiHeight>>MIN_CU_LOG2 );  
        rpcBestCU->getPic()->addCodedAreaInCTU(-(Int)uiWidth*uiHeight);
#else
      xCheckBestMode( rpcBestCU, rpcTempCU, uiDepth DEBUG_STRING_PASS_INTO(sDebug) DEBUG_STRING_PASS_INTO(sTempDebug) DEBUG_STRING_PASS_INTO(false) ); // RD compare current larger prediction
#endif
        // with sub partitioned prediction.
  }
//=================QP循环遍历结束===================================
  DEBUG_STRING_APPEND(sDebug_, sDebug);
#if JVET_C0024_QTBT
  rpcBestCU->copyToPic(uiDepth, uiWidth, uiHeight);                                                     // Copy Best data to Picture for next partition prediction.
  rpcBestCU->getPic()->setCodedBlkInCTU(true, uiPelXInCTU>>MIN_CU_LOG2, uiPelYInCTU>>MIN_CU_LOG2, uiWidth>>MIN_CU_LOG2, uiHeight>>MIN_CU_LOG2 );  
  rpcBestCU->getPic()->addCodedAreaInCTU(uiWidth*uiHeight);
  xCopyYuv2Pic( rpcBestCU->getPic(), rpcBestCU->getCtuRsAddr(), rpcBestCU->getZorderIdxInCtu(), uiDepth, uiDepth, uiWidth, uiHeight );   // Copy Yuv data to picture Yuv
#else
  rpcBestCU->copyToPic(uiDepth);                                                     // Copy Best data to Picture for next partition prediction.
  xCopyYuv2Pic( rpcBestCU->getPic(), rpcBestCU->getCtuRsAddr(), rpcBestCU->getZorderIdxInCtu(), uiDepth, uiDepth );   // Copy Yuv data to picture Yuv
#endif
#if JVET_D0077_SAVE_LOAD_ENC_INFO
  if( bUseSaveLoad )
  {
    m_pcPredSearch->setSaveLoadTag( MAX_UINT, uiWidthIdx - 1, uiHeightIdx - 1, SAVE_LOAD_INIT );
  }
  if( bUseSaveLoadSplitDecision && saveLoadTag == SAVE_ENC_INFO )
  {
    UChar c = 0;
    Double TH = JVET_D0077_SPLIT_DECISION_COST_SCALE * dCostTempBest;
    if( dNonSplitCost > TH )
    {
      c = c | 0x01;
    }
    if( dHorSplitCost > TH )
    {
      c = c | 0x02;
    }
    if( dVerSplitCost > TH )
    {
      c = c | 0x04;
    }
    m_pcPredSearch->setSaveLoadSplit(uiWidthIdx, uiHeightIdx, c);
  }
#endif
  if (bBoundary)
  {
    return;
  }
  // Assert if Best prediction mode is NONE
  // Selected mode's RD-cost must be not MAX_DOUBLE.
#if !JVET_C0024_QTBT
  assert( rpcBestCU->getPartitionSize ( 0 ) != NUMBER_OF_PART_SIZES       );
  assert( rpcBestCU->getPredictionMode( 0 ) != NUMBER_OF_PREDICTION_MODES );
  assert( rpcBestCU->getTotalCost     (   ) != MAX_DOUBLE                 );
#endif
 }
//四叉树划分结束//
}

  • 2
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 7
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值