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
 }
//////////////////////////////四叉樹劃分結束//////////////////////////////////////////////////
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章