H.266/VVC-VTM代码学习-帧内预测12-编码端获取MPM列表getIntraMPMs函数

H.266/VVC专栏传送

上一篇:H.266/VVC-VTM代码学习-帧内预测11-编码端亮度块模式选择estIntraPredLumaQT函数
下一篇:H.266/VVC-VTM代码学习-帧内预测13-ISP模式在estIntraPredLumaQT中的设定(1)

前言

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

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

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

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

一、函数代码

int PU::getIntraMPMs( const PredictionUnit &pu, unsigned* mpm, const ChannelType &channelType /*= CHANNEL_TYPE_LUMA*/ )
{
  //MPM中最大模式数量设置为6
  const int numMPMs = NUM_MOST_PROBABLE_MODES;
  {
    //只支持LUMA块
    CHECK(channelType != CHANNEL_TYPE_LUMA, "Not harmonized yet");
    //候选数量
    int numCand      = -1;
    //左侧模式和上方模式初始化为PLANAR
    int leftIntraDir = PLANAR_IDX, aboveIntraDir = PLANAR_IDX;

    //当前区域
    const CompArea &area = pu.block(getFirstComponentOfChannel(channelType));
    //右上方位置(最后一列的-1行)
    const Position posRT = area.topRight();
    //左下方位置(最后一行的-1列)
    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))
    {
      //以左下位置所在PU的预测模式设置为左侧预测模式
      leftIntraDir = PU::getIntraDirLuma( *puLeft );
    }

    // 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))
    {
      //以右上位置所在PU的预测模式设置为上方预测模式
      aboveIntraDir = PU::getIntraDirLuma( *puAbove );
    }

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

    //67 - 6 = 61
    const int offset = (int)NUM_LUMA_MODE - 6;
    //61 + 3 = 64
    const int mod = offset + 3;
    /******* 初始化MPM列表 *******/
    //0
    mpm[0] = PLANAR_IDX;
    //1
    mpm[1] = DC_IDX;
    //50
    mpm[2] = VER_IDX;
    //18
    mpm[3] = HOR_IDX;
    //46
    mpm[4] = VER_IDX - 4;
    //54
    mpm[5] = VER_IDX + 4;

    //若左侧预测模式与上方相同
    if (leftIntraDir == aboveIntraDir)
    {
      //候选数量为1
      numCand = 1;
      //若相同且为角度模式
      if (leftIntraDir > DC_IDX)
      {
        //0
        mpm[0] = PLANAR_IDX;
        //相同的角度模式
        mpm[1] = leftIntraDir;
        //((相同模式 + 61)% 64)+ 2
        mpm[2] = ((leftIntraDir + offset) % mod) + 2;
        //((相同模式 - 1)% 64)+ 2
        mpm[3] = ((leftIntraDir - 1) % mod) + 2;
        //((相同模式 +  60)% 64)+ 2
        mpm[4] = ((leftIntraDir + offset - 1) % mod) + 2;
        //(相同模式 % 64)+ 2
        mpm[5] = (leftIntraDir % mod) + 2;
      }
    }
    // L!=A 左侧与上方预测模式不同
    else   
    {
      //候选数量为2
      numCand            = 2;
      //最大候选模式索引
      int maxCandModeIdx = mpm[0] > mpm[1] ? 0 : 1;
      
      //若不同但都为角度模式
      if ((leftIntraDir > DC_IDX) && (aboveIntraDir > DC_IDX))
      {
        //0
        mpm[0]             = PLANAR_IDX;
        //左侧模式
        mpm[1]             = leftIntraDir;
        //上侧模式
        mpm[2]             = aboveIntraDir;
        //更大模式的MPM索引
        maxCandModeIdx     = mpm[1] > mpm[2] ? 1 : 2;
        //更小模式的MPM索引
        int minCandModeIdx = mpm[1] > mpm[2] ? 2 : 1;
        //若两模式差距为1
        if (mpm[maxCandModeIdx] - mpm[minCandModeIdx] == 1)
        {
          //((较小模式 + 61)% 64)+ 2
          mpm[3] = ((mpm[minCandModeIdx] + offset) % mod) + 2;
          //((较大模式 - 1)% 64)+ 2
          mpm[4] = ((mpm[maxCandModeIdx] - 1) % mod) + 2;
          //((较小模式 + 60)% 64)+ 2
          mpm[5] = ((mpm[minCandModeIdx] + offset - 1) % mod) + 2;
        }
        //若两模式差距大于61
        else if (mpm[maxCandModeIdx] - mpm[minCandModeIdx] >= 62)
        {
          //((较小模式 - 1)% 64)+ 2
          mpm[3] = ((mpm[minCandModeIdx] - 1) % mod) + 2;
          //((较大模式 + 61)% 64)+ 2
          mpm[4] = ((mpm[maxCandModeIdx] + offset) % mod) + 2;
          //(较小模式 % 64)+ 2
          mpm[5] = (mpm[minCandModeIdx] % mod) + 2;
        }
        //若两模式差距为2
        else if (mpm[maxCandModeIdx] - mpm[minCandModeIdx] == 2)
        {
          //((较小模式 - 1)% 64)+ 2
          mpm[3] = ((mpm[minCandModeIdx] - 1) % mod) + 2;
          //((较小模式 + 61)% 64)+ 2
          mpm[4] = ((mpm[minCandModeIdx] + offset) % mod) + 2;
          //((较大模式 - 1)% 64)+ 2
          mpm[5] = ((mpm[maxCandModeIdx] - 1) % mod) + 2;
        }
        //若两模式差距在3~61
        else
        {
          //((较小模式 + 61)% 64)+ 2
          mpm[3] = ((mpm[minCandModeIdx] + offset) % mod) + 2;
          //((较小模式 - 1)% 64)+ 2
          mpm[4] = ((mpm[minCandModeIdx] - 1) % mod) + 2;
          //((较大模式 + 61)% 64)+ 2
          mpm[5] = ((mpm[maxCandModeIdx] + offset) % mod) + 2;
        }
      }//if ((leftIntraDir > DC_IDX) && (aboveIntraDir > DC_IDX)) 不同但都为角度模式
      
      //不同且至少一个角度模式
      else if (leftIntraDir + aboveIntraDir >= 2)
      {
        //0
        mpm[0]         = PLANAR_IDX;
        //两者中较大的模式
        mpm[1]         = (leftIntraDir < aboveIntraDir) ? aboveIntraDir : leftIntraDir;
        maxCandModeIdx = 1;
        //((较大模式 + 61)% 64)+ 2
        mpm[2]         = ((mpm[maxCandModeIdx] + offset) % mod) + 2;
        //((较大模式 - 1)% 64)+ 2
        mpm[3]         = ((mpm[maxCandModeIdx] - 1) % mod) + 2;
        //((较大模式 + 60)% 64)+ 2
        mpm[4]         = ((mpm[maxCandModeIdx] + offset - 1) % mod) + 2;
        //(较大模式 % 64)+ 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;
  }
}

二、逻辑结构

当前函数是根据当前亮度块的左侧和上方PU预测模式,形成当前块的最可能模式(MPM)列表。这一函数的主要作用是在编码端确定当前块的预测模式和预测参数时(estIntraPredLumaQT),对多参考行进行SATD粗选需要遍历MPM列表进行多参考行选择。还有在获取fastUDI的MPM检查候选模式列表,只需要筛选MPM中最可能的几种模式(只需筛选MPM的前numCand个模式)。

该函数获取MPM列表只支持对亮度块进行操作,MPM长度为6。MPM列表是按照当前块的左下角块(下图A)和右上角块(下图B)进行当前块的最可能模式预测。

在这里插入图片描述

根据左下侧块(A)和右上侧块(B)的帧内预测模式共分为以下几种情况分别对MPM列表进行设定:

1.初始化
MPM模式
MPM[0]0 (PLANAR)
MPM[1]1 (DC)
MPM[2]50 (VER)
MPM[3]18 (HOR)
MPM[4]46 (VER-4)
MPM[5]54 (VER+4)
2.A、B模式相同时

numCand = 1
A、B模式相同且为角度模式时:

MPM模式
MPM[0]0 (PLANAR)
MPM[1]相同的角度模式
MPM[2]((相同模式 + 61)% 64)+ 2
MPM[3]((相同模式 - 1)% 64)+ 2
MPM[4]((相同模式 + 60)% 64)+ 2
MPM[5](相同模式 % 64)+ 2

若A、B模式相同但不同为角度模式(同为PLANAR或DC),则MPM保持为初始化状态。

3.A、B模式不同时

numCand = 2

(1) A、B不同但都为角度模式
MPM模式
MPM[0]0 (PLANAR)
MPM[1]A模式
MPM[2]B模式

后三个模式通过A、B模式进一步关系确定:

① 两模式差距为1

MPM模式
MPM[3]((较小模式 + 61)% 64)+ 2
MPM[4]((较大模式 - 1)% 64)+ 2
MPM[5]((较小模式 + 60)% 64)+ 2

② 两模式差距大于61

MPM模式
MPM[3]((较小模式 - 1)% 64)+ 2
MPM[4]((较大模式 + 61)% 64)+ 2
MPM[5](较小模式 % 64)+ 2

③ 两模式差距为2

MPM模式
MPM[3]((较小模式 - 1)% 64)+ 2
MPM[4]((较小模式 + 61)% 64)+ 2
MPM[5]((较大模式 - 1)% 64)+ 2

④ 两模式差距在3~61(包括边界)

MPM模式
MPM[3]((较小模式 + 61)% 64)+ 2
MPM[4]((较小模式 - 1)% 64)+ 2
MPM[5]((较大模式 + 61)% 64)+ 2
(2) A、B不同且至少一个角度模式
MPM模式
MPM[0]0 (PLANAR)
MPM[1]A、B中较大模式
MPM[2]((较大模式 + 61)% 64)+ 2
MPM[3]((较大模式 - 1)% 64)+ 2
MPM[4]((较大模式 + 60)% 64)+ 2
MPM[5](较大模式 % 64)+ 2

若A、B不同且均不为角度模式,则MPM保持为初始化状态。

上一篇:H.266/VVC-VTM代码学习-帧内预测11-编码端亮度块模式选择estIntraPredLumaQT函数
下一篇:H.266/VVC-VTM代码学习-帧内预测13-ISP模式在estIntraPredLumaQT中的设定(1)

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值