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
#i
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值