H.266/VVC代码学习:MPM列表建立(getIntraMPMs函数)

VVC具有67种角度模式,如果分别对每个PU的预测模式进行编码,则对于67种模式需要7比特来编码,因此VVC中也采用了构建最可能模式列表(most probable mode ,MPM)的方法。在图像和视频编码中,相邻块通常具有较强的相关性,因此相邻块的帧内预测模式相同或者相似的概率较大,因此MPM列表基于左相邻PU和上相邻PU的帧内预测模式构建的,在VVC中,其MPM列表的长度为6。在帧内编码中,MPM列表的主要在以下两个过程

  1. 进行多参考行模式的SATD粗选中(mrl_idx = 1、2),仅使用MPM列表中的6种帧内预测模式
  2. 在对MIP模式粗选结束后,遍历MPM列表中的预测模式是否在率失真候选列表中

MPM列表是基于左边相邻块和上方相邻块的帧内模式构造的,如上图所示,构造方法如下:

  • 当左边块和上边块不可参考时,其帧内模式默认设置为Planar模式
  • 如果左边块和上边块都是非角度模式时
    • MPM list -> {Planar,DC,V,H,V--4,V+4}
  • 如果左边块和上边块其中一个是角度模式,另一个不是角度模式时
    • 设Max是左边块和上边块较大的模式
    • MPM list ->{Planar, Max, Max − 1, Max + 1, Max − 2, Max + 2}
  • 如果左边块和上边块都是角度模式且它们不同时
    • 设Max是左边块和上边块较大的模式
    • 设Min是左边块和上边块较小的模式
    • 如果Max - Min 的等于 1
      • 则 MPM list -> {Planar, Left, Above, Min – 1, Max + 1, Min – 2}
    • 如果如果Max - Min 的大于等于62
      • 则MPM list ->{Planar, Left, Above, Min + 1, Max – 1, Min + 2}
    • 如果如果Max - Min 的等于2
      • 则MPM list -> {Planar, Left, Above, Min + 1, Min – 1, Max + 1}
    • 否则,MPM list ->{Planar, Left, Above, Min – 1, –Min + 1, Max – 1}
  • 如果左边块和上边块时相同的角度模式时
    • MPM list –>{Planar, Left, Left − 1, Left + 1, Left − 2, Left + 2}}

具体构建步骤如下:

1、获得左下和右上相邻参考像素,分别记为A和B,如下图所示

在这里插入图片描述

2、获取相邻像素A和B所在PU的帧内预测模式,获取方法如下:

  • 如果以下条件之一成立,则相邻PU的帧内预测模式设置为Planar模式 
    • 其相邻PU不可用
    • 相邻PU的编码模式不是帧内编码模式
    • 相邻PU是MIP模式
    • 相邻PU和当前PU不是位于同一个CTU
  • 否则,获取其相邻PU的帧内预测模式

3、将相邻像素A、B所处PU的预测模式分别记为A、B,则MPM列表构建如下:

(1)A = B且A > B

MPM[0]Planar
MPM[1]

A

MPM[2]

 2 + ( ( A + 61 ) % 64 )

MPM[3]2 + ( ( A − 1 ) % 64 )
MPM[4]2 + ( ( A + 60 ) % 64 )
MPM[5]2 + ( A  % 64 )

(2)A ≠ B,A > DC且B > DC

记MinAB = Min(A,B), MaxAB = max(A,B)

MPM[0]Planar
MPM[1]

A

MPM[2]B

  ①若maxAB - minAB = 1,则

MPM[3]

2 + ( ( minAB + 61 ) % 64 )

MPM[4]2 + ( ( maxAB − 1 ) % 64 )
MPM[5]2 + ( ( minAB + 60 ) % 64 )

  ②若maxAB - minAB >= 62,则

MPM[3]

2 + ( ( minAB − 1 ) % 64 )

MPM[4]2 + ( ( maxAB + 61 ) % 64 )
MPM[5]2 + ( minAB % 64 )

   ③若maxAB - minAB = 2,则

MPM[3]

2 + ( ( minAB − 1 ) % 64 )

MPM[4]2 + ( ( minAB + 61 ) % 64 )
MPM[5]2 + ( ( maxAB - 1 ) % 64 )

  ④否则

MPM[3]

2 + ( ( minAB + 61 ) % 64 )

MPM[4]2 + ( ( minAB - 1 ) % 64 )
MPM[5]2 + ( ( maxAB + 61 ) % 64 )

(3)A ≠ B,A > DC 或 B > DC

MPM[0]Planar
MPM[1]

maxAB

MPM[2]2 + ( ( maxAB + 61 ) % 64 )
MPM[3]2 + ( ( maxAB − 1 ) % 64 )
MPM[4]2 + ( ( maxAB + 60 ) % 64 )
MPM[5]2 + ( maxAB % 64 )

(4)否则,

MPM[0]Planar
MPM[1]

DC

MPM[2]VER
MPM[3]HOR
MPM[4]VER-4
MPM[5]VER+4

具体代码实现及注释如下:

int PU::getIntraMPMs( const PredictionUnit &pu, unsigned* mpm, const ChannelType &channelType /*= CHANNEL_TYPE_LUMA*/ )
{
  const int numMPMs = NUM_MOST_PROBABLE_MODES;
  {
    CHECK(channelType != CHANNEL_TYPE_LUMA, "Not harmonized yet");
    int numCand      = -1;
    int leftIntraDir = PLANAR_IDX, aboveIntraDir = PLANAR_IDX;//将左相邻块和上相邻块预测模式设置为Planar模式

    const CompArea &area = pu.block(getFirstComponentOfChannel(channelType));
    const Position posRT = area.topRight();//当前块的左上角
    const Position posLB = area.bottomLeft();//当前块的右下角

    // Get intra direction of left PU
    // 获得左相邻PU
    const PredictionUnit *puLeft = pu.cs->getPURestricted(posLB.offset(-1, 0), pu, channelType);
    if (puLeft && CU::isIntra(*puLeft->cu))
    {
      leftIntraDir = PU::getIntraDirLuma( *puLeft );//获得左相邻PU的预测模式
    }

    // Get intra direction of above PU
    // 获得上相邻PU
    const PredictionUnit *puAbove = pu.cs->getPURestricted(posRT.offset(0, -1), pu, channelType);
    if (puAbove && CU::isIntra(*puAbove->cu) && CU::isSameCtu(*pu.cu, *puAbove->cu))
    {
      aboveIntraDir = PU::getIntraDirLuma( *puAbove );//获得左相邻PU的预测模式
    }

    CHECK(2 >= numMPMs, "Invalid number of most probable modes");

    const int offset = (int)NUM_LUMA_MODE - 6;//61
    const int mod = offset + 3;//64

    {
      mpm[0] = PLANAR_IDX;//Planar
      mpm[1] = DC_IDX;//DC
      mpm[2] = VER_IDX;//50
      mpm[3] = HOR_IDX;//18
      mpm[4] = VER_IDX - 4;//46
      mpm[5] = VER_IDX + 4;//54

      if (leftIntraDir == aboveIntraDir)
      {
        numCand = 1;
        if (leftIntraDir > DC_IDX)
        {
          mpm[0] = PLANAR_IDX;
          mpm[1] = leftIntraDir;
          mpm[2] = ((leftIntraDir + offset) % mod) + 2;
          mpm[3] = ((leftIntraDir - 1) % mod) + 2;
          mpm[4] = ((leftIntraDir + offset - 1) % mod) + 2;
          mpm[5] = ( leftIntraDir               % mod) + 2;
        }
      }
      else //L!=A
      {
        numCand = 2;
        int  maxCandModeIdx = mpm[0] > mpm[1] ? 0 : 1;

        if ((leftIntraDir > DC_IDX) && (aboveIntraDir > DC_IDX))
        {
          mpm[0] = PLANAR_IDX;
          mpm[1] = leftIntraDir;
          mpm[2] = aboveIntraDir;
          maxCandModeIdx = mpm[1] > mpm[2] ? 1 : 2;
          int minCandModeIdx = mpm[1] > mpm[2] ? 2 : 1;
          if (mpm[maxCandModeIdx] - mpm[minCandModeIdx] == 1)
          {
            mpm[3] = ((mpm[minCandModeIdx] + offset)     % mod) + 2;
            mpm[4] = ((mpm[maxCandModeIdx] - 1)          % mod) + 2;
            mpm[5] = ((mpm[minCandModeIdx] + offset - 1) % mod) + 2;
          }
          else if (mpm[maxCandModeIdx] - mpm[minCandModeIdx] >= 62)
          {
            mpm[3] = ((mpm[minCandModeIdx] - 1)      % mod) + 2;
            mpm[4] = ((mpm[maxCandModeIdx] + offset) % mod) + 2;
            mpm[5] = ( mpm[minCandModeIdx]           % mod) + 2;
          }
          else if (mpm[maxCandModeIdx] - mpm[minCandModeIdx] == 2)
          {
            mpm[3] = ((mpm[minCandModeIdx] - 1)      % mod) + 2;
            mpm[4] = ((mpm[minCandModeIdx] + offset) % mod) + 2;
            mpm[5] = ((mpm[maxCandModeIdx] - 1)      % mod) + 2;
          }
          else
          {
            mpm[3] = ((mpm[minCandModeIdx] + offset) % mod) + 2;
            mpm[4] = ((mpm[minCandModeIdx] - 1)      % mod) + 2;
            mpm[5] = ((mpm[maxCandModeIdx] + offset) % mod) + 2;
          }
        }
        else if (leftIntraDir + aboveIntraDir >= 2)
        {
          mpm[0] = PLANAR_IDX;
          mpm[1] = (leftIntraDir < aboveIntraDir) ? aboveIntraDir : leftIntraDir;
          maxCandModeIdx = 1;
          mpm[2] = ((mpm[maxCandModeIdx] + offset)     % mod) + 2;
          mpm[3] = ((mpm[maxCandModeIdx] - 1)          % mod) + 2;
          mpm[4] = ((mpm[maxCandModeIdx] + offset - 1) % mod) + 2;
          mpm[5] = ( mpm[maxCandModeIdx]               % mod) + 2;
        }
      }
    }
    for (int i = 0; i < numMPMs; i++)
    {
      CHECK(mpm[i] >= NUM_LUMA_MODE, "Invalid MPM");
    }
    CHECK(numCand == 0, "No candidates found");
    return numCand;
  }
}

getPURestricted函数主要是根据位置获取PU

const PredictionUnit* CodingStructure::getPURestricted( const Position &pos, const PredictionUnit& curPu, const ChannelType _chType ) const
{
  const PredictionUnit* pu = getPU( pos, _chType );
  // exists       same slice and tile                  pu precedes curPu in encoding order
  //                                                  (thus, is either from parent CS in RD-search or its index is lower)
  //存在 相同slice和Tile    PU在编码顺序中先于当前PU
  //(因此,在RD搜索中是来自父CS的,或者其索引较低)
  const bool wavefrontsEnabled = curPu.cu->slice->getSPS()->getEntropyCodingSyncEnabledFlag();
  int ctuSizeBit = floorLog2(curPu.cs->sps->getMaxCUWidth());
  int xNbY  = pos.x << getChannelTypeScaleX( _chType, curPu.chromaFormat );//相邻PU的左上角位置x
  int xCurr = curPu.blocks[_chType].x << getChannelTypeScaleX( _chType, curPu.chromaFormat );//当前PU的左上角位置x
  //判断相邻PU和当前PU是否在同一CTU中
  bool addCheck = (wavefrontsEnabled && (xNbY >> ctuSizeBit) >= (xCurr >> ctuSizeBit) + 1 ) ? false : true;
  if( pu && CU::isSameSliceAndTile( *pu->cu, *curPu.cu ) && ( pu->cs != curPu.cs || pu->idx <= curPu.idx ) && addCheck )
  {
    return pu;
  }
  else
  {
    return nullptr;
  }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值