xCheckModeSplit()中的useSubStructure()函数,releaseIntermediateData()函数解析,add()函数解析(getBuf()函数没看)

 可参考这两篇博客

VVC学习之四:VTM中的数据结构——描述_Aidoneus_y的博客-CSDN博客

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

主要作用:将子cu的最优模式信息copy到tempCS中

void CodingStructure::useSubStructure( const CodingStructure& subStruct, const ChannelType chType, const UnitArea &subArea, const bool cpyPred /*= true*/, const bool cpyReco /*= true*/, const bool cpyOrgResi /*= true*/, const bool cpyResi /*= true*/, const bool updateCost /*= true*/ )
{
  //获取正在压缩的区域信息
  UnitArea clippedArea = clipArea( subArea, *picture );

  setDecomp( clippedArea );

  CPelUnitBuf subPredBuf = cpyPred ? subStruct.getPredBuf( clippedArea ) : CPelUnitBuf();
  CPelUnitBuf subResiBuf = cpyResi ? subStruct.getResiBuf( clippedArea ) : CPelUnitBuf();
  CPelUnitBuf subRecoBuf = cpyReco ? subStruct.getRecoBuf( clippedArea ) : CPelUnitBuf();
  // 如果父CU存在
  if( parent )
  {
    // copy data to picture
    if (cpyPred)
    {
      getPredBuf(clippedArea).copyFrom(subPredBuf);
    }
    if (cpyResi)
    {
      getResiBuf(clippedArea).copyFrom(subResiBuf);
    }
    if (cpyReco)
    {
      getRecoBuf(clippedArea).copyFrom(subRecoBuf);
    }
    if (cpyOrgResi)
    {
      getOrgResiBuf(clippedArea).copyFrom(subStruct.getOrgResiBuf(clippedArea));
    }
  }

  if (cpyPred)
  {
    picture->getPredBuf(clippedArea).copyFrom(subPredBuf);
  }
  if (cpyResi)
  {
    picture->getResiBuf(clippedArea).copyFrom(subResiBuf);
  }
  if (cpyReco)
  {
    picture->getRecoBuf(clippedArea).copyFrom(subRecoBuf);
  }

  if (!subStruct.m_isTuEnc && ((!slice->isIntra() || slice->getSPS()->getIBCFlag()) && chType != CHANNEL_TYPE_CHROMA))
  {
    // copy motion buffer
    MotionBuf ownMB  = getMotionBuf          ( clippedArea );
    CMotionBuf subMB = subStruct.getMotionBuf( clippedArea );

    ownMB.copyFrom( subMB );

    motionLut = subStruct.motionLut;
  }
  prevPLT = subStruct.prevPLT;


  if ( updateCost )
  {
    fracBits += subStruct.fracBits;
    dist     += subStruct.dist;
    cost     += subStruct.cost;
    costDbOffset += subStruct.costDbOffset;
  }
  if( parent )
  {
    // allow this to be false at the top level
    CHECKD( !area.contains( subArea ), "Trying to use a sub-structure not contained in self" );
  }

  // copy the CUs over
  if( subStruct.m_isTuEnc )
  {
    // don't copy if the substruct was created for encoding of the TUs
  }
  else
  {
    for( const auto &pcu : subStruct.cus )
    {
      // add an analogue CU into own CU store
      const UnitArea &cuPatch = *pcu;
      CodingUnit &cu = addCU( cuPatch, pcu->chType );

      // copy the CU info from subPatch
      cu = *pcu;
    }
  }

  // copy the PUs over
  if( subStruct.m_isTuEnc )
  {
    // don't copy if the substruct was created for encoding of the TUs
  }
  else
  {
    for( const auto &ppu : subStruct.pus )
    {
      // add an analogue PU into own PU store
      const UnitArea &puPatch = *ppu;
      PredictionUnit &pu = addPU( puPatch, ppu->chType );

      // copy the PU info from subPatch
      pu = *ppu;
    }
  }
  // copy the TUs over
  for( const auto &ptu : subStruct.tus )
  {
    // add an analogue TU into own TU store
    const UnitArea &tuPatch = *ptu;
    TransformUnit &tu = addTU( tuPatch, ptu->chType );

    // copy the TU info from subPatch
    tu = *ptu;
  }
}

CU整个区域的setDecomp()函数

void CodingStructure::setDecomp(const UnitArea &_area, const bool _isCoded /*= true*/)
{
  //三个分量
  for( uint32_t i = 0; i < _area.blocks.size(); i++ )
  {
    //如果当前CU正常
    if (_area.blocks[i].valid())
    {
      setDecomp(_area.blocks[i], _isCoded);
    }
  }
}

 1.1  CU单独YCbCr分量的setDecomp()函数

void CodingStructure::setDecomp(const CompArea &_area, const bool _isCoded /*= true*/)
{
  //根据当前区域分量的类别设置scale
  const UnitScale& scale = unitScale[_area.compID];

  AreaBuf<bool> isCodedBlk( m_isDecomp[toChannelType( _area.compID )] + rsAddr( _area, area.blocks[_area.compID].pos(), area.blocks[_area.compID].width, scale ),
                            area.blocks[_area.compID].width >> scale.posx,
                            _area.width                     >> scale.posx,
                            _area.height                    >> scale.posy);
  isCodedBlk.fill( _isCoded );
}

 这里出现一个stride,注意:这里area表示当前CU的父CU区域,_area才表示当前CU区域。所以此处stride表示父CU区域的宽度

最终以{(Y) x = 0, y = 0, width = 8, height = 4}为例,当前

名称类型
isCodedBlk{width = 2, heigth = 1, stride = 4}AreaBuf<bool>

且isDecomp设为false。并把这些数值存入AreaBuf<>这个容器

inline size_t rsAddr(const Position &pos, const Position &origin, const uint32_t stride, const UnitScale &unitScale )
{
  return (stride >> unitScale.posx) * ((pos.y - origin.y) >> unitScale.posy) + ((pos.x - origin.x) >> unitScale.posx);
}

这里返回的rsAddr应为光栅扫描模式下当前CU在父CU中的地址顺序

Y分量的stride缩小4倍。CbCr分量好像不执行,invalid

1.2

三个CPelUnitBuf:猜测是CUpixel 的意思,将CU的三个分量的值都存进这个缓冲区内这里的

getRecoBuf()是,与下面直接getRecoBuf()调用的函数不同,推测这里是subStruct调用getRecoBuf()函数,得到的CPelUnitBuf赋给subRecoBuf。等于是将当前子CU的信息赋给了subRecoBuf

const CPelUnitBuf CodingStructure::getRecoBuf(const UnitArea &unit)    const { return getBuf(unit, PIC_RECONSTRUCTION); 

const CPelUnitBuf CodingStructure::getBuf( const UnitArea &unit, const PictureType &type ) const
{
  // no parent fetching for buffers
  if( area.chromaFormat == CHROMA_400 )
  {
    return CPelUnitBuf( area.chromaFormat, getBuf( unit.Y(), type ) );
  }
  else
  {
    return CPelUnitBuf( area.chromaFormat, getBuf( unit.Y(), type ), getBuf( unit.Cb(), type ), getBuf( unit.Cr(), type ) );
  }
}

if语句:如果存在父结点,根据cpyPred,cpyResi,cpyReco,cpyOrgResi的值,确定是否将当前子CU的不同类型的BUF里的值,如subRecoBuf存到PelUnitBuf

PelUnitBuf CodingStructure::getRecoBuf(const UnitArea &unit)          { return getBuf(unit, PIC_RECONSTRUCTION); 

PelUnitBuf CodingStructure::getBuf( const UnitArea &unit, const PictureType &type )
{
  // no parent fetching for buffers
  if( area.chromaFormat == CHROMA_400 )
  {
    return PelUnitBuf( area.chromaFormat, getBuf( unit.Y(), type ) );
  }
  else
  {
    return PelUnitBuf( area.chromaFormat, getBuf( unit.Y(), type ), getBuf( unit.Cb(), type ), getBuf( unit.Cr(), type ) );
  }
}

 第二个if语句:将前面PelUnitBuf的值存进picture所调用的PelUnitBuf里,注意这几个getBuf()函数的不同

PelUnitBuf Picture::getRecoBuf(const UnitArea &unit, bool wrap)           { return getBuf(unit,                      wrap ? PIC_RECON_WRAP : PIC_RECONSTRUCTION); }

PelUnitBuf Picture::getBuf( const UnitArea &unit, const PictureType &type )
{
  if( chromaFormat == CHROMA_400 )
  {
    return PelUnitBuf( chromaFormat, getBuf( unit.Y(), type ) );
  }
  else
  {
    return PelUnitBuf( chromaFormat, getBuf( unit.Y(), type ), getBuf( unit.Cb(), type ), getBuf( unit.Cr(), type ) );
  }
}

注意看得到的数据:buffer里存储了亮度分量的一些数据,有stride

第三个if语句:

else
  {
    for( const auto &pcu : subStruct.cus )
    {
      // add an analogue CU into own CU store
      const UnitArea &cuPatch = *pcu;
      CodingUnit &cu = addCU( cuPatch, pcu->chType );

      // copy the CU info from subPatch
      cu = *pcu;
    }
  }

 遍历subStruct.cus,用pcu给每一个cus赋值。pcu有当前子CU的信息

CodingUnit& CodingStructure::addCU( const UnitArea &unit, const ChannelType chType )
{
  CodingUnit *cu = m_cuCache.get();
  //将cu一些信息初始化
  cu->UnitArea::operator=( unit );
  cu->initData();
  cu->cs        = this;
  cu->slice     = nullptr;
  cu->next      = nullptr;
  cu->firstPU   = nullptr;
  cu->lastPU    = nullptr;
  cu->firstTU   = nullptr;
  cu->lastTU    = nullptr;
  cu->chType    = chType;
  cu->treeType = treeType;
  cu->modeType = modeType;
  //前面的CU?
  CodingUnit *prevCU = m_numCUs > 0 ? cus.back() : nullptr;

  if( prevCU )
  {
    prevCU->next = cu;
  }

  cus.push_back( cu );

  uint32_t idx = ++m_numCUs;
  cu->idx  = idx;

  uint32_t numCh = ::getNumberValidChannels( area.chromaFormat );

  for( uint32_t i = 0; i < numCh; i++ )
  {
    if( !cu->blocks[i].valid() )
    {
      continue;
    }
    //当前CU的父CU  area
    const CompArea &_selfBlk = area.blocks[i];
    //当前CU的 area
    const CompArea     &_blk = cu-> blocks[i];
    //当前CU的缩放比例
    const UnitScale& scale = unitScale[_blk.compID];
    //缩放后的父CU  area
    const Area scaledSelf  = scale.scale( _selfBlk );
    //缩放后的CU  area
    const Area scaledBlk   = scale.scale(     _blk );
    //一个地址信息
    unsigned *idxPtr       = m_cuIdx[i] + rsAddr( scaledBlk.pos(), scaledSelf.pos(), scaledSelf.width );
    CHECK( *idxPtr, "Overwriting a pre-existing value, should be '0'!" );
    //将数据存进AreaBuf
    AreaBuf<uint32_t>( idxPtr, scaledSelf.width, scaledBlk.size() ).fill( idx );
  }

  return *cu;
}

这个addCU()函数作用好像是初始化 pcu的一些数据,然后据此推测出缩放后的CU,父CU的size,和idxptr,将这些数据存入AreaBuf

最后返回*cu=*pcu,再赋给cus。

VVC中图块划分结果在图像上显示(中间有一段没写完)_青椒鸡汤的博客-CSDN博客

也有一部分解释

主要目的:推测应该是得到AreaBuf的那几个数据

2.  releaseIntermediateData()函数:

void CodingStructure::clearTUs()
{
  //查看色彩格式并得到通道数
  int numCh = ::getNumberValidChannels( area.chromaFormat );
  for( int i = 0; i < numCh; i++ )
  {
    //等于当前TU所属分量的大小向右移动所属的刻度位数
    size_t _area = ( area.blocks[i].area() >> unitScale[i].area );

    memset( m_isDecomp[i], false, sizeof( *m_isDecomp[0] ) * _area );
    memset( m_tuIdx   [i],     0, sizeof( *m_tuIdx   [0] ) * _area );
  }

  numCh = getNumberValidComponents( area.chromaFormat );
  //各分量清零
  for( int i = 0; i < numCh; i++ )
  {
    m_offsets[i] = 0;
  }
  //清零
  for( auto &pcu : cus )
  {
    pcu->firstTU = pcu->lastTU = nullptr;
  }

  m_tuCache.cache( tus );
  m_numTUs = 0;
}

void CodingStructure::clearPUs()
{
  int numCh = ::getNumberValidChannels( area.chromaFormat );
  for( int i = 0; i < numCh; i++ )
  {
    memset( m_puIdx[i], 0, sizeof( *m_puIdx[0] ) * unitScale[i].scaleArea( area.blocks[i].area() ) );
  }

  m_puCache.cache( pus );
  m_numPUs = 0;

  for( auto &pcu : cus )
  {
    pcu->firstPU = pcu->lastPU = nullptr;
  }
}

void CodingStructure::clearCUs()
{
  int numCh = ::getNumberValidChannels( area.chromaFormat );
  for( int i = 0; i < numCh; i++ )
  {
    memset( m_cuIdx[i], 0, sizeof( *m_cuIdx[0] ) * unitScale[i].scaleArea( area.blocks[i].area() ) );
  }

  m_cuCache.cache( cus );
  m_numCUs = 0;
}

unitScale[i].area:这个unitScale应该是当前单位缩放比例数(看上面setDecomp()函数,设置)

UnitScale( int sx, int sy ) : posx(sx), posy(sy), area(posx+posy) {}

 此时{x = 8, y = 0, width = 8, height = 4},推测posx根据Y或Cb分量不同已经定好了

 

 m_isDecomp:推测为Decompose的意思,默认设置为false。

后面都是初始化清零一些参数

推测这个函数作用是:当前CU已测试完,所以清理一些参数,以方便下一个CU测试。注意这里这个函数是被tempSubCS和bestSubCS分别调用的,所以应该就是方便之后CU写入数据。这块之后再看一遍

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值