H.266/VVC代码学习笔记7:VTM5.0中Mip模式的MPM列表构造函数——getMipMPMs()

在最新的VVC的参考软件VTM5.0中新加入的技术Mip亮度预测模式有其独立于传统的68种预测模式的MPM列表,而其MPM列表的构造也不同于传统的MPM列表构造。今天来详细讲一下关于Mip模式的MPM列表的构造函数。

传统亮度预测模式的MPM列表的构造函数的代码之前我已经讲过啦,这里直接给出链接:
H.266/VVC代码学习笔记6:传统的MPM列表构造函数——getIntraMPMs()

Mip模式的技术全称是ALWIP技术,关于ALWIP技术的具体技术细节我在之前的博客也深入讲过啦,这里直接给出链接:
H.266/VVC代码学习笔记4:带你深入解析VTM5.0中的最新技术ALWIP

接下来就是关于Mip模式的MPM列表构造函数的代码详解,我都加了非常详细的注释,方便大家学习

//构造MIp模式的MPM列表
int PU::getMipMPMs(const PredictionUnit &pu, unsigned *mpm)
{
  const CompArea &area = pu.block( getFirstComponentOfChannel( CHANNEL_TYPE_LUMA ) );//获取当前亮度PU区域
  const Position &pos = area.pos();//获取当前亮度PU区域的位置

  bool realMode = false;

  // Get intra mode of left PU
  //获取左边PU块的帧内模式
  int leftIntraMode = -1;


  //获取指向左块的指针
  const PredictionUnit *puLeft = pu.cs->getPURestricted( pos.offset( -1, 0 ), pu, CHANNEL_TYPE_LUMA );


  //如果左块存在且左块的CU的模式是帧内预测模式
  if( puLeft && CU::isIntra( *puLeft->cu ) )
  {
    //如果左块是Mip模式
    if( PU::isMIP( *puLeft ) )
    {

      //如果左块的Mip尺寸等级和当前PU的MIp的尺寸等级相同,否则leftIntraMode默认为-1
      if (getMipSizeId(*puLeft) == getMipSizeId(pu))
      {
        leftIntraMode = puLeft->intraDir[CHANNEL_TYPE_LUMA];//leftIntraMode就保存左块的帧内亮度Mip模式
        realMode = true;
      }
    }
    else//如果左块的模式不是Mip模式,则将左块的传统角度模式通过转换列表转换到Mip模式再赋给leftIntraMode
    {
      leftIntraMode = g_mapAngular33ToMip[getMipSizeId(pu)][g_intraMode65to33AngMapping[puLeft->intraDir[CHANNEL_TYPE_LUMA]]];
    }
  }

  // Get intra mode of above PU
  //获取上PU的帧内模式
  int aboveIntraMode = -1;

  //获取指向上PU的指针
  const PredictionUnit *puAbove = pu.cs->getPURestricted( pos.offset( 0, -1 ), pu, CHANNEL_TYPE_LUMA );

  //如果上块存在且上块的CU的模式是帧内预测模式且上部CU和当前CU属于同一个CTU
  if( puAbove && CU::isIntra( *puAbove->cu ) && CU::isSameCtu(*pu.cu, *puAbove->cu) )
  {
    //如果上块是Mip模式
    if( PU::isMIP( *puAbove ) )
    {
      //如果上块的Mip尺寸等级和当前PU的MIp的尺寸等级相同,否则aboveIntraMode默认为-1
      if (getMipSizeId(*puAbove) == getMipSizeId(pu))
      {
        aboveIntraMode = puAbove->intraDir[CHANNEL_TYPE_LUMA];//aboveIntraMode就保存上块的帧内亮度Mip模式
        realMode = true;
      }
    }
    else//如果上块的模式不是Mip模式,则将上块的传统角度模式通过转换列表转换到Mip模式再赋给aboveIntraMode
    {
      aboveIntraMode = g_mapAngular33ToMip[getMipSizeId(pu)][g_intraMode65to33AngMapping[puAbove->intraDir[CHANNEL_TYPE_LUMA]]];
    }
  }

  // derive MPMs
  //开始推导Mip模式的MPM列表,并检查是否MPM列表的数目相等
  CHECKD(NUM_MPM_MIP != 3, "Error: wrong number of MPMs for MIP");


  //根据当前的块大小构造一个默认的初始MPM列表
  const int* modeList = g_sortedMipMpms[getMipSizeId(pu)];

  int numCand = 0;//候选的模式数量

  //如果左和上的模式相等
  if( leftIntraMode == aboveIntraMode )
  {
    //如果左块和当前块的等级相同
    if( leftIntraMode > -1 )
    {
      mpm[0] = leftIntraMode;//MPM的第一个放入左块中的模式
      numCand = 1;//候选的模式数量为1

      if( leftIntraMode != modeList[0] )//如果左块的模式不等于默认列表中的第一个模式
      {
        mpm[1] = modeList[0];//将默认列表中的第一个模式放入MPM的第二个模式
        mpm[2] = (leftIntraMode != modeList[1]) ? modeList[1] : modeList[2];
        //如果左块的模式不等于默认列表中的第二个模式,则将默认列表中的第二个模式放入MPM的第三个模式
        //否则,将默认列表中的第三个模式放入MPM的第三个模式
      }
      else//如果左块的模式等于默认列表中的第一个模式,则默认的MPM列表就是当前的MPM列表
      {
        mpm[1] = modeList[1];
        mpm[2] = modeList[2];
      }
    }
    else//如果左块和当前块的等级不相同,则默认的MPM列表就是当前的MPM列表
    {
      mpm[0] = modeList[0];
      mpm[1] = modeList[1];
      mpm[2] = modeList[2];
    }
  }
  else//如果左和上的模式不相等
  {
    if( leftIntraMode > -1 && aboveIntraMode > -1 )//如果左和上的块尺寸等级都和当前CU相等
    {
      mpm[0] = leftIntraMode;//左模式放入第一个
      mpm[1] = aboveIntraMode;//左模式放入第二个
      numCand = 2;//候选的模式数量为2
      //为MPM列表的最后一个元素定义索引
      int index = 0;

      //循环三次
      for( int i = 0; i < 3; i++ )
      {
        //如果左和上的模式都不和默认的MPM列表中的模式不相等
        if( (leftIntraMode != modeList[i]) && (aboveIntraMode != modeList[i]) )
        {
          index = i;//默认的列表索引给index
          break;
        }
      }
      CHECK( index > 2, "Error" );
      mpm[2] = modeList[index];//MPM列表的最后一个模式放入选中的index模式
    }
    else//如果左和上的块尺寸等级至少有一个和当前CU不相等
    {
      mpm[0] = leftIntraMode > -1 ? leftIntraMode : aboveIntraMode;//如果左和当前等级相同,MPM第一个放入左模式;否则放入右模式
      numCand = 1;

      if( mpm[0] != modeList[0] )//如果当前MPM的第一个和默认MPM列表的第一个模式不相等
      {
        mpm[1] = modeList[0];//将默认MPM列表的第一个模式放入当前MPM的第二个中
        mpm[2] = (mpm[0] != modeList[1]) ? modeList[1] : modeList[2];
        //如果mpm[0]不等于默认列表中的第二个模式,则将默认列表中的第二个模式放入当前MPM的第三个模式
        //否则,将默认列表中的第三个模式放入当前MPM的第三个模式
      }
      else//如果当前MPM的第一个和默认MPM列表的第一个模式相等,则默认的MPM列表就是当前的MPM列表
      {
        mpm[1] = modeList[1];
        mpm[2] = modeList[2];
      }
    }
  }

  return (realMode ? numCand : 0);//返回MPM中最优的模式候选个数
}
  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值