VVC/JEM代码学习10:xEncodeCU

26 篇文章 2 订阅
#if JVET_C0024_QTBT
Void TEncCu::xEncodeCU( TComDataCU* pcCU, UInt uiAbsPartIdx, UInt uiDepth, UInt uiWidth, UInt uiHeight, UInt uiSplitConstrain )
#else
Void TEncCu::xEncodeCU( TComDataCU* pcCU, UInt uiAbsPartIdx, UInt uiDepth )
#endif
{
#if JVET_C0024_BT_RMV_REDUNDANT
  pcCU->setSplitConstrain( uiSplitConstrain );
  Bool bQTreeValid = false;//bQTreeValid不用于知道四叉树的划分,而只用于赋值给bBTVerRmvEnable用于帧间二叉树划分的限制;
#endif

        TComPic   *const pcPic   = pcCU->getPic();
        TComSlice *const pcSlice = pcCU->getSlice();
  const TComSPS   &sps =*(pcSlice->getSPS());
  const TComPPS   &pps =*(pcSlice->getPPS());

#if !JVET_C0024_QTBT
  const UInt maxCUWidth  = sps.getMaxCUWidth();
  const UInt maxCUHeight = sps.getMaxCUHeight();

        Bool bBoundary = false;
#endif//当前CU的左上角和右下角的坐标;
        UInt uiLPelX   = pcCU->getCUPelX() + g_auiRasterToPelX[ g_auiZscanToRaster[uiAbsPartIdx] ];
#if JVET_C0024_QTBT
  const UInt uiRPelX   = uiLPelX + uiWidth  - 1;
#else
  const UInt uiRPelX   = uiLPelX + (maxCUWidth>>uiDepth)  - 1;
#endif
        UInt uiTPelY   = pcCU->getCUPelY() + g_auiRasterToPelY[ g_auiZscanToRaster[uiAbsPartIdx] ];
#if JVET_C0024_QTBT
  const UInt uiBPelY   = uiTPelY + uiHeight - 1;
#else
  const UInt uiBPelY   = uiTPelY + (maxCUHeight>>uiDepth) - 1;
#endif


#if JVET_C0024_QTBT
  Bool bForceQT = uiWidth > MAX_TU_SIZE;
  if( bForceQT )
  {
    assert(uiWidth == uiHeight);
  }
  UInt uiCTUSize = pcCU->getSlice()->getSPS()->getCTUSize();
#if JVET_C0024_DELTA_QP_FIX
  UInt uiQTWidth = uiCTUSize>>uiDepth;
  UInt uiQTHeight = uiCTUSize>>uiDepth;
  const UInt uiQTBTDepth = (uiDepth<<1) + (g_aucConvertToBit[uiQTWidth]-g_aucConvertToBit[uiWidth] + g_aucConvertToBit[uiQTHeight]-g_aucConvertToBit[uiHeight]);
  const UInt uiMaxDQPDepthQTBT = pps.getMaxCuDQPDepth() << 1;
#endif
  if (uiCTUSize>>uiDepth == uiWidth && uiWidth==uiHeight)//判断是否是正方形;
  {
#endif
  if( ( uiRPelX < sps.getPicWidthInLumaSamples() ) && ( uiBPelY < sps.getPicHeightInLumaSamples() ) )//没到达边缘
  {
#if JVET_C0024_QTBT
    if( bForceQT )//强迫四叉树划分
    {
      assert(uiDepth < pcCU->getDepth( uiAbsPartIdx ) ); 
    }
    else//不强迫四叉树划分
#endif
    m_pcEntropyCoder->encodeSplitFlag( pcCU, uiAbsPartIdx, uiDepth );//编码四叉树的划分标记;
  }
  else//是边缘,则不编码四叉树划分标记
  {
#if JVET_C0024_QTBT
    assert(uiDepth < pcCU->getDepth( uiAbsPartIdx ) );
#else
    bBoundary = true;
#endif
  }

#if JVET_C0024_BT_RMV_REDUNDANT
  bQTreeValid = true;
  UInt uiMinQTSize = sps.getMinQTSize(pcCU->getSlice()->getSliceType(), pcCU->getTextType());
  if ((uiCTUSize>>uiDepth) <= uiMinQTSize)//如果此时方块大小小于等于最小的四叉树大小,则不进行四叉树划分;
  {
    bQTreeValid = false;
  }
#endif

#if JVET_C0024_QTBT
  if( uiDepth < pcCU->getDepth( uiAbsPartIdx ) )//如果还没达到最大深度,用深度来判断是否进行了划分;
#else
  if( ( ( uiDepth < pcCU->getDepth( uiAbsPartIdx ) ) && ( uiDepth < sps.getLog2DiffMaxMinCodingBlockSize() ) ) || bBoundary )
#endif
  {//getNumPartitionsInCtu()函数返回一个CTU中包含4*4小块的个数;
    UInt uiQNumParts = ( pcPic->getNumPartitionsInCtu() >> (uiDepth<<1) )>>2;//最小的分区是4x4大小的块,这里计算出以该4x4块为单位的分割数,这么做便于计算当前CU的Zorder坐标
#if JVET_C0024_DELTA_QP_FIX
    if( uiQTBTDepth == uiMaxDQPDepthQTBT && pps.getUseDQP())
#else
    if( uiDepth == pps.getMaxCuDQPDepth() && pps.getUseDQP())
#endif
    {
      setdQPFlag(true);
#if JVET_C0024_DELTA_QP_FIX
      pcCU->setQuPartIdx( uiAbsPartIdx );
      pcCU->setQuLastCodedQP( pcCU->getCodedQP() );
#endif
    }

    if( uiDepth == pps.getPpsRangeExtension().getDiffCuChromaQpOffsetDepth() && pcSlice->getUseChromaQpAdj())
    {
      setCodeChromaQpAdjFlag(true);
    }

    for ( UInt uiPartUnitIdx = 0; uiPartUnitIdx < 4; uiPartUnitIdx++, uiAbsPartIdx+=uiQNumParts )//如果进行了四叉树划分,则递归调用4次xEncodeCU;
    {
      uiLPelX   = pcCU->getCUPelX() + g_auiRasterToPelX[ g_auiZscanToRaster[uiAbsPartIdx] ];
      uiTPelY   = pcCU->getCUPelY() + g_auiRasterToPelY[ g_auiZscanToRaster[uiAbsPartIdx] ];
      if( ( uiLPelX < sps.getPicWidthInLumaSamples() ) && ( uiTPelY < sps.getPicHeightInLumaSamples() ) )//没达到图像边界
      {
#if JVET_C0024_QTBT
        xEncodeCU( pcCU, uiAbsPartIdx, uiDepth+1, uiWidth>>1, uiHeight>>1 );//深度加1,宽和高减半
#else
        xEncodeCU( pcCU, uiAbsPartIdx, uiDepth+1 );
#endif
      }
#if JVET_C0024_QTBT
      else//到达边界,则累加编码面积;
      {
        pcCU->getPic()->addCodedAreaInCTU(uiWidth*uiHeight>>2);
      }
#endif
    }
    return;
  }

#if JVET_C0024_QTBT
  }
#if JVET_C0024_BT_RMV_REDUNDANT
  Bool bBTHorRmvEnable = false;
  Bool bBTVerRmvEnable = false;
  if (pcCU->getSlice()->getSliceType() != I_SLICE)//不是I SLICE才能进行remove  redundant???
  {
    bBTHorRmvEnable = true;
    bBTVerRmvEnable = bQTreeValid;
  }
#endif
#if JVET_C0024_SPS_MAX_BT_DEPTH
  UInt uiMaxBTD = pcSlice->isIntra() ? (isLuma(pcCU->getTextType())?sps.getMaxBTDepthISliceL():sps.getMaxBTDepthISliceC()): sps.getMaxBTDepth();
#else
  UInt uiMaxBTD = pcCU->getSlice()->isIntra() ? (isLuma(pcCU->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(pcCU->getTextType())?sps.getMaxBTSizeISliceL():sps.getMaxBTSizeISliceC()): sps.getMaxBTSize();
#else
  UInt uiMaxBTSize = isLuma(pcCU->getTextType()) ? pcCU->getSlice()->getMaxBTSize(): MAX_BT_SIZE_C;
#endif
  UInt uiMinBTSize = pcCU->getSlice()->isIntra() ? (isLuma(pcCU->getTextType())?MIN_BT_SIZE:MIN_BT_SIZE_C): MIN_BT_SIZE_INTER;
  UInt uiBTDepth = pcCU->getBTDepth(uiAbsPartIdx, uiWidth, uiHeight);//二叉树的深度是从四叉树叶节点开始算的

  if ( (uiHeight>uiMinBTSize || uiWidth>uiMinBTSize) 
    && uiWidth<=uiMaxBTSize && uiHeight<=uiMaxBTSize && uiBTDepth<uiMaxBTD) //判断是否进行了二叉树划分
  {
#if JVET_C0024_BT_RMV_REDUNDANT
    uiSplitConstrain = 0;
#endif
    m_pcEntropyCoder->encodeBTSplitMode(pcCU, uiAbsPartIdx, uiWidth, uiHeight);//编码二叉树划分标记;
    if (pcCU->getBTSplitModeForBTDepth(uiAbsPartIdx, uiBTDepth)==1)//水平二叉树划分;
    {
#if JVET_C0024_DELTA_QP_FIX
      if( uiQTBTDepth == uiMaxDQPDepthQTBT && pps.getUseDQP())
      {
        setdQPFlag(true);
#if JVET_C0024_DELTA_QP_FIX
        pcCU->setQuPartIdx( uiAbsPartIdx );
        pcCU->setQuLastCodedQP( pcCU->getCodedQP() );
#endif
      }
#endif
      for ( UInt uiPartUnitIdx = 0; uiPartUnitIdx < 2; uiPartUnitIdx++ )//递归调用两次xEncodeCU;
      {
        if (uiPartUnitIdx==1)
        {
          uiAbsPartIdx = g_auiRasterToZscan[g_auiZscanToRaster[uiAbsPartIdx] 
          + (uiHeight>>1)/pcCU->getPic()->getMinCUHeight()*pcCU->getPic()->getNumPartInCtuWidth()];
        }
#if JVET_C0024_BT_RMV_REDUNDANT
        xEncodeCU( pcCU, uiAbsPartIdx, uiDepth, uiWidth, uiHeight>>1, uiSplitConstrain );//高度减半,uiDepth不变,应该这个指的是四叉树的深度
        if (pcCU->getBTSplitModeForBTDepth(uiAbsPartIdx, uiBTDepth+1) == 2 && bBTHorRmvEnable && uiPartUnitIdx==0)//如果当前层是水平划分,下一层是上边垂直个划分
        {
          uiSplitConstrain = 2;//则限制下一层进行垂直划分(即防止通过二叉树划分出来一个四叉树)
        }
#else
        xEncodeCU( pcCU, uiAbsPartIdx, uiDepth, uiWidth, uiHeight>>1 );
#endif
      }
      return;
    }
    else if (pcCU->getBTSplitModeForBTDepth(uiAbsPartIdx, uiBTDepth)==2)//垂直二叉树划分;
    {
#if JVET_C0024_DELTA_QP_FIX
      if( uiQTBTDepth == uiMaxDQPDepthQTBT && pps.getUseDQP())
      {
        setdQPFlag(true);
#if JVET_C0024_DELTA_QP_FIX
        pcCU->setQuPartIdx( uiAbsPartIdx );
        pcCU->setQuLastCodedQP( pcCU->getCodedQP() );
#endif
      }
#endif
      for ( UInt uiPartUnitIdx = 0; uiPartUnitIdx < 2; uiPartUnitIdx++ )//递归调用两次xEncodeCU;
      {
        if (uiPartUnitIdx==1)
        {
          uiAbsPartIdx = g_auiRasterToZscan[g_auiZscanToRaster[uiAbsPartIdx] 
          + (uiWidth>>1)/pcCU->getPic()->getMinCUWidth()];
        }
#if JVET_C0024_BT_RMV_REDUNDANT
        xEncodeCU( pcCU, uiAbsPartIdx, uiDepth, uiWidth>>1, uiHeight, uiSplitConstrain );//宽度减半,uiDepth也不变
        if (pcCU->getBTSplitModeForBTDepth(uiAbsPartIdx, uiBTDepth+1) == 1 && bBTVerRmvEnable && uiPartUnitIdx==0)//如果当前层是垂直划分,且下一层的左边是水平划分,
        {
          uiSplitConstrain = 1;//则限制右边水平划分(即防止通过二叉树划分出来一个四叉树);
        }
#else
        xEncodeCU( pcCU, uiAbsPartIdx, uiDepth, uiWidth>>1, uiHeight );
#endif
      }
      return;
    }
  }

  pcCU->getPic()->addCodedAreaInCTU(uiWidth*uiHeight);
  UInt uiBlkX = g_auiRasterToPelX[ g_auiZscanToRaster[uiAbsPartIdx] ] >> MIN_CU_LOG2;
  UInt uiBlkY = g_auiRasterToPelY[ g_auiZscanToRaster[uiAbsPartIdx] ] >> MIN_CU_LOG2;
  pcCU->getPic()->setCodedBlkInCTU(true, uiBlkX, uiBlkY, uiWidth>> MIN_CU_LOG2, uiHeight>> MIN_CU_LOG2);

#endif

#if JVET_C0024_AMAX_BT
  if (!pcCU->getSlice()->isIntra())//不是I帧
  {
    g_uiBlkSize[pcCU->getSlice()->getDepth()] += uiWidth*uiHeight;
    g_uiNumBlk[pcCU->getSlice()->getDepth()]++;
  }
#endif
#if JVET_C0024_DELTA_QP_FIX
  if( uiQTBTDepth <= uiMaxDQPDepthQTBT && pps.getUseDQP())
#else
  if( uiDepth <= pps.getMaxCuDQPDepth() && pps.getUseDQP())
#endif
  {
    setdQPFlag(true);
#if JVET_C0024_DELTA_QP_FIX
    pcCU->setQuPartIdx( uiAbsPartIdx );
    pcCU->setQuLastCodedQP( pcCU->getCodedQP() );
#endif
  }

  if( uiDepth <= pps.getPpsRangeExtension().getDiffCuChromaQpOffsetDepth() && pcSlice->getUseChromaQpAdj())
  {
    setCodeChromaQpAdjFlag(true);
  }

  if (pps.getTransquantBypassEnableFlag())
  {
    m_pcEntropyCoder->encodeCUTransquantBypassFlag( pcCU, uiAbsPartIdx );//编码CU的变换量化旁路标记;
  }

  if( !pcSlice->isIntra() )//不是I帧;
  {
    m_pcEntropyCoder->encodeSkipFlag( pcCU, uiAbsPartIdx );//编码skip标记,只有帧间有skip;
  }

  if( pcCU->isSkipped( uiAbsPartIdx ) )//如果是skip模式;
  {
#if VCEG_AZ07_FRUC_MERGE
    m_pcEntropyCoder->encodeFRUCMgrMode( pcCU , uiAbsPartIdx , 0 );//编码FRUCmerge模式;
    if( !pcCU->getFRUCMgrMode( uiAbsPartIdx ) )//如果不是FRUC merge模式,因为FRUC merge,Affine merge和merge是竞争关系;
#endif
#if COM16_C1016_AFFINE
    {
      if ( pcCU->isAffineMrgFlagCoded(uiAbsPartIdx, 0) )
      {
        m_pcEntropyCoder->encodeAffineFlag( pcCU, uiAbsPartIdx, 0 );//编码仿射标记;
      }

      if ( !pcCU->isAffine(uiAbsPartIdx) )//如果不是仿射;
      {
        m_pcEntropyCoder->encodeMergeIndex( pcCU, uiAbsPartIdx );//编码MERGE索引;
      }
    }
#else
    m_pcEntropyCoder->encodeMergeIndex( pcCU, uiAbsPartIdx );
#endif
#if VCEG_AZ06_IC
    m_pcEntropyCoder->encodeICFlag  ( pcCU, uiAbsPartIdx );//编码局部亮度补偿标记;
#endif
#if !JVET_C0024_QTBT
    finishCU(pcCU,uiAbsPartIdx);
#endif
#if JVET_C0024_DELTA_QP_FIX
    if( pps.getUseDQP() )
    { 
      pcCU->setCodedQP( pcCU->getQP(uiAbsPartIdx) );
    }
#endif
    return;
  }

  m_pcEntropyCoder->encodePredMode( pcCU, uiAbsPartIdx );//编码预测模式
#if JVET_C0024_QTBT
  if (isLuma(pcCU->getTextType()))
  {
#endif
#if VCEG_AZ05_INTRA_MPI
  m_pcEntropyCoder->encodeMPIIdx(pcCU, uiAbsPartIdx);
#endif   
#if COM16_C1046_PDPC_INTRA && !JVET_G0104_PLANAR_PDPC
  m_pcEntropyCoder->encodePDPCIdx(pcCU, uiAbsPartIdx);
#endif  
#if JVET_C0024_QTBT
  }
#else
  m_pcEntropyCoder->encodePartSize( pcCU, uiAbsPartIdx, uiDepth );
#endif

#if JVET_C0024_QTBT
  if (pcCU->isIntra( uiAbsPartIdx ) )//如果是帧内预测
#else
  if (pcCU->isIntra( uiAbsPartIdx ) && pcCU->getPartitionSize( uiAbsPartIdx ) == SIZE_2Nx2N )
#endif
  {
    m_pcEntropyCoder->encodeIPCMInfo( pcCU, uiAbsPartIdx );//编码PCM信息,所以PCM属于帧内;

    if(pcCU->getIPCMFlag(uiAbsPartIdx))
    {
#if !JVET_C0024_QTBT
      // Encode slice finish
      finishCU(pcCU,uiAbsPartIdx);
#endif
#if JVET_C0024_DELTA_QP_FIX
      if( pps.getUseDQP() )
      { 
        pcCU->setCodedQP( pcCU->getQP(uiAbsPartIdx) );
      }
#endif
      return;
    }
  }

  // prediction Info ( Intra : direction mode, Inter : Mv, reference idx )
  m_pcEntropyCoder->encodePredInfo( pcCU, uiAbsPartIdx );//编码预测信息(帧内:预测方向,帧间:MV和参考帧索引);
#if COM16_C806_OBMC
  m_pcEntropyCoder->encodeOBMCFlag( pcCU, uiAbsPartIdx );//编码重叠块运动补偿标记;
#endif
#if VCEG_AZ06_IC
  m_pcEntropyCoder->encodeICFlag  ( pcCU, uiAbsPartIdx );//编码局部光照补偿标记;
#endif
  // Encode Coefficients
  Bool bCodeDQP = getdQPFlag();
  Bool codeChromaQpAdj = getCodeChromaQpAdjFlag();
#if  VCEG_AZ05_ROT_TR  || VCEG_AZ05_INTRA_MPI || COM16_C1044_NSST || COM16_C1046_PDPC_INTRA
  Int bNonZeroCoeff = false;
#endif
#if JVET_C0045_C0053_NO_NSST_FOR_TS
  Int iNonZeroCoeffNonTs;
#endif
  m_pcEntropyCoder->encodeCoeff( pcCU, uiAbsPartIdx, uiDepth, bCodeDQP, codeChromaQpAdj
#if VCEG_AZ05_ROT_TR  || VCEG_AZ05_INTRA_MPI || COM16_C1044_NSST || COM16_C1046_PDPC_INTRA
    , bNonZeroCoeff
#endif
#if JVET_C0045_C0053_NO_NSST_FOR_TS
    , iNonZeroCoeffNonTs
#endif
    );//编码残差系数;
  setCodeChromaQpAdjFlag( codeChromaQpAdj );
  setdQPFlag( bCodeDQP );
#if JVET_C0024_DELTA_QP_FIX
  if( pps.getUseDQP() )
  { 
    pcCU->setCodedQP( pcCU->getQP(uiAbsPartIdx) );
  }
#endif

#if !JVET_C0024_QTBT
  // --- write terminating bit ---
  finishCU(pcCU,uiAbsPartIdx);
#endif
}


评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值