H.266/VVC-VTM代码学习-帧内预测15-解码端解压缩decompressCtu函数及xReconIntraQT调用xIntraRecQT函数完成帧内预测重建

H.266/VVC专栏传送

上一篇:H.266/VVC-VTM代码学习-帧内预测14-ISP模式在estIntraPredLumaQT中的设定(2)
下一篇:H.266/VVC-VTM代码学习-帧内预测16-解码端xIntraRecBlk完成TU指定分量帧内重建(附ISP变换和预测尺寸不同、JCCR、LMCS简述)

前言

VTM是H.266/VVC视频编码标准的参考软件,研究VTM代码给研究人员解释了VVC编码标准的详细标准规范与细节。

本文是笔者对VTM代码的一点学习记录,成文于笔者刚开始接触VVC期间,期间很多概念和理论框架还很不成熟,若文中存在错误欢迎批评指正,也欢迎广大视频编码学习者沟通交流、共同进步。

VTM代码的下载及编译请参考博文:
【视频编码学习】H.266/VVC参考软件VTM配置运行(VTM-6.0版本)

本文涉及的代码主要存在于工程下的Lib\DecoderLib\DecCu.cpp文件中。

一、decompressCtu函数作为帧内重建的入口函数

void DecCu::decompressCtu( CodingStructure& cs, const UnitArea& ctuArea )
{
  //DualITree时maxNumChannelType=2
  //即I帧且亮度色度双重树时,CTU对亮度域和色度域有两套划分树,有两套CU,所以分开处理
  //不是400色彩采样率,且是双重树时,maxNumChannelType=2
  const int maxNumChannelType = cs.pcv->chrFormat != CHROMA_400 && CS::isDualITree( cs ) ? 2 : 1;
  //若需要重置IBCBuffer
  if (cs.resetIBCBuffer)
  {
    //重置IBC的Buffer(用-1填充)
    m_pcInterPred->resetIBCBuffer(cs.pcv->chrFormat, cs.slice->getSPS()->getMaxCUHeight());
    cs.resetIBCBuffer = false;
  }
  //DualITree时亮度和色度分开处理,非DualITree时这个循环只执行一次
  //DualITree需要严格区分luma和chroma,而非DualITree无需区分luma和chroma的,因为此时的cu同时包含了Y/Cb/Cr域
  for( int ch = 0; ch < maxNumChannelType; ch++ )
  {
    const ChannelType chType = ChannelType( ch );
    Position prevTmpPos;
    prevTmpPos.x = -1; prevTmpPos.y = -1;

    //遍历当前CTU的CU,逐个进行解压缩
    for( auto &currCU : cs.traverseCUs( CS::getArea( cs, ctuArea, chType ), chType ) )
    {
      //如果当前Y分量有效(当前色彩采样类型有效、当前分量有效、当前块尺寸大于0)
      if(currCU.Y().valid())
      {
        //为IBC重置VPDU
        //VSize是VPDU的尺寸,设置为CU的尺寸和64中的较小值
        const int vSize = cs.slice->getSPS()->getMaxCUHeight() > 64 ? 64 : cs.slice->getSPS()->getMaxCUHeight();
        if((currCU.Y().x % vSize) == 0 && (currCU.Y().y % vSize) == 0)
        {
          for(int x = currCU.Y().x; x < currCU.Y().x + currCU.Y().width; x += vSize)
          {
            for(int y = currCU.Y().y; y < currCU.Y().y + currCU.Y().height; y += vSize)
            {
              m_pcInterPred->resetVPDUforIBC(cs.pcv->chrFormat, cs.slice->getSPS()->getMaxCUHeight(), vSize, x + g_IBCBufferSize / cs.slice->getSPS()->getMaxCUHeight() / 2, y);
            }
          }
        }
      }
      //当前模式不为intra和PLT,且当前CU的Y分量有效(当前色彩采样类型有效、当前分量有效、当前块尺寸大于0)
      if (currCU.predMode != MODE_INTRA && currCU.predMode != MODE_PLT && currCU.Y().valid())
      {
        //根据解码的运动信息,得到mv
        xDeriveCUMV(currCU);
#if K0149_BLOCK_STATISTICS
        if(currCU.geoFlag)
        {
          storeGeoMergeCtx(m_geoMrgCtx);
        }
#endif
      }
      //对当前CU预测模式判断,作相应重建
      switch( currCU.predMode )
      {
      case MODE_INTER:
      case MODE_IBC:
        //帧间模式的重建
        xReconInter( currCU );
        break;
      case MODE_PLT:
      case MODE_INTRA:
        //帧内模式的重建
        xReconIntraQT( currCU );
        break;
      default:
        THROW( "Invalid prediction mode" );
        break;
      }

      //用解码后的采样点填充 IBC Buffer
      m_pcInterPred->xFillIBCBuffer(currCU);

      DTRACE_BLOCK_REC( cs.picture->getRecoBuf( currCU ), currCU, currCU.predMode );
    }
  }
#if K0149_BLOCK_STATISTICS
  getAndStoreBlockStatistics(cs, ctuArea);
#endif
}

二、xReconIntraQT函数调用函数实现PLT模式和INTRA模式的重建(入口在一中)

void DecCu::xReconIntraQT( CodingUnit &cu )
{

  //若当前CU是PLT模式
  if (CU::isPLT(cu))
  {
    //当前划分树是separate tree(分离树)
    //当前树的状态不是TREE_D(TREE_D对于单树表示联合树,对于二重树表示TREE_L和TREE_C),或当前CS是二重树
    if (cu.isSepTree())
    {
      //当前CU是Luma CU
      if (cu.chType == CHANNEL_TYPE_LUMA)
      {
        //对Luma进行重建
        xReconPLT(cu, COMPONENT_Y, 1);
      }
      //色彩采样率不为400 且 当前CU是Chroma CU
      if (cu.chromaFormat != CHROMA_400 && (cu.chType == CHANNEL_TYPE_CHROMA))
      {
        //对Chroma两通道进行重建
        xReconPLT(cu, COMPONENT_Cb, 2);
      }
    }
    //当前划分树不是separate tree
    //当前树状态是TREE_D,且当前CS不是二重树
    else
    {
      //色彩采样率不为400
      if( cu.chromaFormat != CHROMA_400 )
      {
        //对三个通道进行重建
        xReconPLT(cu, COMPONENT_Y, 3);
      }
      //色彩采样率为400
      else
      {
        xReconPLT(cu, COMPONENT_Y, 1);//只对Luma一个通道重建
      }
    }
    return;
  }
  
  /******* 以下是对帧内模式的重建 *******/
  //若采用ACT变换
  if (cu.colorTransform)
  {
    //进行ACT变换的帧内模式重建
    xIntraRecACTQT(cu);
  }
  //若不采用ACT变换
  else
  {
  //获取通道数量
  const uint32_t numChType = ::getNumberValidChannels( cu.chromaFormat );

  for( uint32_t chType = CHANNEL_TYPE_LUMA; chType < numChType; chType++ )
  {
    if( cu.blocks[chType].valid() )
    {
      //cu分别对luma和chroma,实现帧内像素的重建
      xIntraRecQT( cu, ChannelType( chType ) );
    }
  }
  }
}

三、xIntraRecQT函数调用函数实现不使用ACT变换时的帧内预测模式重建(入口在二中)

void DecCu::xIntraRecQT(CodingUnit &cu, const ChannelType chType)
{
  //对CU的每个TU分别进行帧内像素重建
  for( auto &currTU : CU::traverseTUs( cu ) )
  {
    if( isLuma( chType ) )
    {
      //Luma TB 的重建
      xIntraRecBlk( currTU, COMPONENT_Y );
    }
    else
    {
      const uint32_t numValidComp = getNumberValidComponents( cu.chromaFormat );

      for( uint32_t compID = COMPONENT_Cb; compID < numValidComp; compID++ )
      {
        //色度Cb、Cr的像素重建
        xIntraRecBlk( currTU, ComponentID( compID ) );
      }
    }
  }
}

上一篇:H.266/VVC-VTM代码学习-帧内预测14-ISP模式在estIntraPredLumaQT中的设定(2)
下一篇:H.266/VVC-VTM代码学习-帧内预测16-解码端xIntraRecBlk完成TU指定分量帧内重建(附ISP变换和预测尺寸不同、JCCR、LMCS简述)

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值