xCompressCU(1)(PLT未写)

,VTM代码学习(1)CU划分_jwgroot的博客-CSDN博客
H.266/VVC-VTM代码学习20-CU层进行RDO函数xCompressCU_liaojq2020的博客-CSDN博客
VVC代码学习1:xCompressCU函数_Everglow_zbz的博客-CSDN博客
H.266/VVC代码学习:xCompressCU函数_涵小呆的博客-CSDN博客
VTM3.0代码阅读:xCompressCU函数_矛盾统一的博客-CSDN博客

VTM1.0代码阅读:xCompressCU函数_矛盾统一的博客-CSDN博客

H.266/VVC代码学习13:VTM4.0中的CU层操作(compressCtu 、 xCompressCU)_海洋之心。的博客-CSDN博客

一个CTU分割细节过程—— VTM (13.0)源码阅读_chvfily的博客-CSDN博客

VTM10.0代码学习11:from_EncSlice_compressSlice()_to_EncCu_xCompressCU()_柴门风雪夜的博客-CSDN博客

注意:看xCompressCU函数时不要在这个函数开头打断点,因为后面函数调用时会有干扰

void EncCu::xCompressCU( CodingStructure*& tempCS, CodingStructure*& bestCS, Partitioner& partitioner, double maxCostAllowed )
{

这里传输过来的参数tempCS,bestCS应该是待处理的CTU级别的CS结构。这里推测tempCS存储的根据CTU宽高度得到的默认最优cs,bestCS存储的也是默认最优cs。后面tempCS随时会变化,然后做比较后,在看是否传给beseCs

 CHECK(maxCostAllowed < 0, "Wrong value of maxCostAllowed!");

  uint32_t compBegin; //亮色度成员分量属性
  uint32_t numComp; //亮色度分量数目
  bool jointPLT = false;
  if (partitioner.isSepTree( *tempCS ))
  {
    if( !CS::isDualITree(*tempCS) && partitioner.treeType != TREE_D )// TREE_L或者TREE_C情况下
    {
      compBegin = COMPONENT_Y;
      numComp = (tempCS->area.chromaFormat != CHROMA_400)?3: 1;
      jointPLT = true;
    }
    else //dual tree,当前为tree-D情况下
    {
      if (isLuma(partitioner.chType)) //亮度分量tree _L
      {
        compBegin = COMPONENT_Y;
        numComp   = 1;
      }
      else  //色度分量tree _C
      {
        compBegin = COMPONENT_Cb;
        numComp   = 2;///起始分量为 Cb,总分量数为2
      }
    }
  }
  else  //若当前不是dualtree,且为tree-D时,则当前CS为joint tree,亮度和色度共同划分
  {
    compBegin = COMPONENT_Y;
    numComp = (tempCS->area.chromaFormat != CHROMA_400) ? 3 : 1;
    jointPLT = true;
  }

isSepTree():如果当前CS属于Dual tree或不是tree_D(对single tree,tree_D = joint tree;对dual tree,tree_D = tree _C),则返回值为true

isDualITree():如果当前帧为I 帧且当前待处理的CTU不是single tree,则返回值为true

第一个if语句:在CS结构为TREE_L或者TREE_C情况下,起始分量为Y分量,若亮色度采样格式不为4:0:0,则亮色度总分量数为3,否则为1。使用jointPLT

SplitSeries splitmode = -1;
// 以下是用于存储 PLT mode 的相关变量
  uint8_t   bestLastPLTSize[MAX_NUM_CHANNEL_TYPE];
  Pel       bestLastPLT[MAX_NUM_COMPONENT][MAXPLTPREDSIZE]; // store LastPLT for
  uint8_t   curLastPLTSize[MAX_NUM_CHANNEL_TYPE];
  Pel       curLastPLT[MAX_NUM_COMPONENT][MAXPLTPREDSIZE]; // store LastPLT if no partition
// 遍历所有分量,为 PLT mode 的存储变量赋值
  for (int i = compBegin; i < (compBegin + numComp); i++)
  {
    ComponentID comID = jointPLT ? (ComponentID)compBegin : ((i > 0) ? COMPONENT_Cb : COMPONENT_Y);
    bestLastPLTSize[comID] = 0;
    curLastPLTSize[comID] = tempCS->prevPLT.curPLTSize[comID];
    memcpy(curLastPLT[i], tempCS->prevPLT.curPLT[i], tempCS->prevPLT.curPLTSize[comID] * sizeof(Pel));
  }

  Slice&   slice      = *tempCS->slice;// 当前 slice
  const PPS &pps      = *tempCS->pps;
  const SPS &sps      = *tempCS->sps;
  const uint32_t uiLPelX  = tempCS->area.Y().lumaPos().x;// 当前块的左上角x
  const uint32_t uiTPelY  = tempCS->area.Y().lumaPos().y;// 当前块的左上角y
  
// 父结点的模式类型(MODE_TYPE_ALL / MODE_TYPE_INTER / MODE_TYPE_INTRA)
  const ModeType modeTypeParent  = partitioner.modeType;
// 父结点的划分树类型(TREE_D / TREE_L / TREE_C)
  const TreeType treeTypeParent  = partitioner.treeType;
// 父结点的通道类型(CHANNEL_TYPE_LUMA / CHANNEL_TYPE_CHROMA)
  const ChannelType chTypeParent = partitioner.chType;
  const UnitArea currCsArea = clipArea( CS::getArea( *bestCS, bestCS->area, partitioner.chType ), *tempCS->picture );

  m_modeCtrl->initCULevel( partitioner, *tempCS );

注意:PLT的变量之后再看

currCsArea参数具体意思_青椒鸡汤的博客-CSDN博客

currCsArea:当前待划分CTU的区域信息,YCbCr的区域信息和限制信息

initCULevel():获取当前CU可能的预测和编码模式,并且按照顺序推入栈中。

这里传输了tempCS和partitioner,所以函数中对CU的操作,其中的CU是现在系统算出来的临时CS结构中的CU

很重要这个之后再看

H.266/VVC-VTM代码学习19-CU层确定测试模式函数initCULevel_liaojq2020的博客-CSDN博客

 

#if GDR_ENABLED
  if (m_pcEncCfg->getGdrEnabled())
  {
    bool isInGdrInterval = slice.getPicHeader()->getInGdrInterval();

    // 1.0 applicable to inter picture only
    if (isInGdrInterval)
    {
      int gdrPocStart = m_pcEncCfg->getGdrPocStart();
      int gdrInterval = m_pcEncCfg->getGdrInterval();

      int picWidth = slice.getPPS()->getPicWidthInLumaSamples();
      int m1, m2, n1;

      int curPoc = slice.getPOC();
      int gdrPoc = (curPoc - gdrPocStart) % gdrInterval;

      int begGdrX = 0;
      int endGdrX = 0;

      double dd = (picWidth / (double)gdrInterval);
      int mm = (int)((picWidth / (double)gdrInterval) + 0.49999);
      m1 = ((mm + 7) >> 3) << 3;
      m2 = ((mm + 0) >> 3) << 3;

      if (dd > mm && m1 == m2)
      {
        m1 = m1 + 8;
      }

      n1 = (picWidth - m2 * gdrInterval) / 8;

      if (gdrPoc < n1)
      {
        begGdrX = m1 * gdrPoc;
        endGdrX = begGdrX + m1;
      }
      else
      {
        begGdrX = m1 * n1 + m2 * (gdrPoc - n1);
        endGdrX = begGdrX + m2;
        if (picWidth <= endGdrX)
        {
          begGdrX = picWidth;
          endGdrX = picWidth;
        }
      }

      bool isInRefreshArea = tempCS->withinRefresh(begGdrX, endGdrX);

      if (isInRefreshArea)
      {
        m_modeCtrl->forceIntraMode();
      }
      else if (tempCS->containRefresh(begGdrX, endGdrX) || tempCS->overlapRefresh(begGdrX, endGdrX))
      {
        // 1.3.1 enable only vertical splits (QT, BT_V, TT_V)
        m_modeCtrl->forceVerSplitOnly();

        // 1.3.2 remove TT_V if it does not satisfy the condition
        if (tempCS->refreshCrossTTV(begGdrX, endGdrX))
        {
          m_modeCtrl->forceRemoveTTV();
        }
      }

      if (tempCS->area.lwidth() != tempCS->area.lheight())
      {
        m_modeCtrl->forceRemoveQT();
      }

      if (!m_modeCtrl->anyPredModeLeft())
      {
        m_modeCtrl->forceRemoveDontSplit();
      }

      if (isInRefreshArea && !m_modeCtrl->anyIntraIBCMode() && (tempCS->area.lwidth() == 4 || tempCS->area.lheight() == 4))
      {
        m_modeCtrl->finishCULevel(partitioner);
        return;
      }
    }
  }
#endif

与GDR的设置有关,跳过

  if( partitioner.currQtDepth == 0 && partitioner.currMtDepth == 0 && !tempCS->slice->isIntra() && ( sps.getUseSBT() || sps.getUseInterMTS() ) )
  {
    auto slsSbt = dynamic_cast<SaveLoadEncInfoSbt*>( m_modeCtrl );
    int maxSLSize = sps.getUseSBT() ? tempCS->slice->getSPS()->getMaxTbSize() : MTS_INTER_MAX_CU_SIZE;
    slsSbt->resetSaveloadSbt( maxSLSize );
  }
  m_sbtCostSave[0] = m_sbtCostSave[1] = MAX_DOUBLE;// 用于存储子块变换(sub-block transform,SBT)模式的 cost

if语句:如果当前QT深度和Mt深度为0,不为I帧且SBT或MTS开启,则运行。因为SBT默认false,所以跳过

SBT:子块变换(sub-block transform,SBT)

 m_CurrCtx->start = m_CABACEstimator->getCtx();

  if( slice.getUseChromaQpAdj() )
  {
    // TODO M0133 : double check encoder decisions with respect to chroma QG detection and actual encode
    int lgMinCuSize = sps.getLog2MinCodingBlockSize() +
      std::max<int>(0, floorLog2(sps.getCTUSize()) - sps.getLog2MinCodingBlockSize() - int((slice.getCuChromaQpOffsetSubdiv()+1) / 2));
    if( partitioner.currQgChromaEnable() )
    {
      m_cuChromaQpOffsetIdxPlus1 = ( ( uiLPelX >> lgMinCuSize ) + ( uiTPelY >> lgMinCuSize ) ) % ( pps.getChromaQpOffsetListLen() + 1 );
    }
  }
  else
  {
    m_cuChromaQpOffsetIdxPlus1 = 0;
  }

  if( !m_modeCtrl->anyMode() )
  {
    m_modeCtrl->finishCULevel( partitioner );
    return;
  }


  // 以下是 RDO 前的初始化
  // 记录当前的位置、尺寸信息
  DTRACE_UPDATE( g_trace_ctx, std::make_pair( "cux", uiLPelX ) );
  DTRACE_UPDATE( g_trace_ctx, std::make_pair( "cuy", uiTPelY ) );
  DTRACE_UPDATE( g_trace_ctx, std::make_pair( "cuw", tempCS->area.lwidth() ) );
  DTRACE_UPDATE( g_trace_ctx, std::make_pair( "cuh", tempCS->area.lheight() ) );
  DTRACE( g_trace_ctx, D_COMMON, "@(%4d,%4d) [%2dx%2d]\n", tempCS->area.lx(), tempCS->area.ly(), tempCS->area.lwidth(), tempCS->area.lheight() );

  // 初始化 Affine(仿射运动补偿预测)模式的相关变量
  m_pcInterSearch->resetSavedAffineMotion();

  double bestIntPelCost = MAX_DOUBLE;//最佳的整像素帧间预测的cost

m_CurrCtx->start:上下文模型起点

getUseChromaQpAdj():是否使用色度QP调整。默认为false

 第二个if分支:如果没有要测试的模式则结束此函数

  // 若使用色彩变换
  // 当前CS与最佳CS的 cost 均初始化为最大值,且选中第一色彩空间
if (tempCS->slice->getSPS()->getUseColorTrans())
  {
    tempCS->tmpColorSpaceCost = MAX_DOUBLE;
    bestCS->tmpColorSpaceCost = MAX_DOUBLE;
    tempCS->firstColorSpaceSelected = true;
    bestCS->firstColorSpaceSelected = true;
  }

  // 若使用色彩变换,且不是双重intra树时
  // 当前CS与最佳CS均设置不止测试第一色彩空间,且两色彩空间的 Intra cost 初始化为最大值
  if (tempCS->slice->getSPS()->getUseColorTrans() && !CS::isDualITree(*tempCS))
  {
    tempCS->firstColorSpaceTestOnly = false;
    bestCS->firstColorSpaceTestOnly = false;
    tempCS->tmpColorSpaceIntraCost[0] = MAX_DOUBLE;
    tempCS->tmpColorSpaceIntraCost[1] = MAX_DOUBLE;
    bestCS->tmpColorSpaceIntraCost[0] = MAX_DOUBLE;
    bestCS->tmpColorSpaceIntraCost[1] = MAX_DOUBLE;
    // 若当前 CS 的最佳父结点存在,且最佳父结点只测试第一色彩空间、
    // 则当前 CS 与最佳 CS 均只测试第一色彩空间
    if (tempCS->bestParent && tempCS->bestParent->firstColorSpaceTestOnly)
    {
      tempCS->firstColorSpaceTestOnly = bestCS->firstColorSpaceTestOnly = true;
    }
  }
    

色彩转换ACT(adaptive color transform ) :默认为false

 bestParent:代表当前CS结构的最佳父节点

 if (tempCS->slice->getCheckLDC())
  {
    m_bestBcwCost[0] = m_bestBcwCost[1] = std::numeric_limits<double>::max();
    m_bestBcwIdx[0] = m_bestBcwIdx[1] = -1;
  }

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值