H.266/VVC代码学习:reduceHadCandList函数

reduceHadCandList函数由estIntraPredLumaQT函数调用,主要是用来缩减后续进行全RD Cost细选的模式列表。

基本过程:

  1. 缩减传统候选模式数,仅加入Cost较小的前三种传统的模式
  2. 缩减MIP候选模式数,删除Cost较大的最后一种MIP模式
  3. 对于尺寸大于8x8的PU,判断前三种MIP模式矩阵是否在临时的候选模式列表中,如果不在,则将其加入进去

代码如下:

// candModeList 候选模式数
// candCostList 候选模式代价列表
// numModesForFullRD 全RD测试的模式数
// mipHadCost MIP SATD Cost列表(索引是MIP模式号)
// thresholdHadCost HAD阈值:1.0 + 1.4 / sqrt((double) (pu.lwidth() * pu.lheight()));
template<typename T, size_t N>
void IntraSearch::reduceHadCandList(static_vector<T, N>& candModeList, static_vector<double, N>& candCostList, int& numModesForFullRD, const double thresholdHadCost, const double* mipHadCost, const PredictionUnit &pu, const bool fastMip)
{
  const int maxCandPerType = numModesForFullRD >> 1; // 每种类型的模式,最多的候选数目 mip/traditional
  static_vector<ModeInfo, FAST_UDI_MAX_RDMODE_NUM> tempRdModeList;
  static_vector<double, FAST_UDI_MAX_RDMODE_NUM> tempCandCostList; // 临时的候选模式列表和Cost列表
  const double minCost = candCostList[0]; // 最小的Cost
  bool keepOneMip = candModeList.size() > numModesForFullRD; // 保留一个MIP模式

  int numConv = 0; // 传统模式数目
  int numMip = 0; // MIP模式数目

  // 缩减传统候选模式数和MIP候选模式数
  // keepOneMip(无论之前TRUE or FALSE,最终都会删除最后一种MIP模式)
  for (int idx = 0; idx < candModeList.size() - (keepOneMip?0:1); idx++)
  {
    bool addMode = false;
    const ModeInfo& orgMode = candModeList[idx];

    if (!orgMode.mipFlg) // 传统模式
    {
      addMode = (numConv < 3); // 如果传统模式数目小于 3,则将其加入临时候选模式列表中,否则,不加入候选模式列表中
      numConv += addMode ? 1:0;
    }
    else
    {
      // 如果MIP模式的候选数目小于maxCandPerType 或者 MIP模式的Cost小于thresholdHadCost * minCost或者保留第一个MIP模式
      // 将MIP模式加入到临时候选模式列表中
      addMode = ( numMip < maxCandPerType || (candCostList[idx] < thresholdHadCost * minCost) || keepOneMip );
      keepOneMip = false;
      numMip += addMode ? 1:0;
    }
    if( addMode )
    {
      tempRdModeList.push_back(orgMode);
      tempCandCostList.push_back(candCostList[idx]);
    }
  }

  // 如果PU大于 8x8,判断前三种MIP模式是否在临时的候选模式列表中,如果不在,则将其加入进去
  if ((pu.lwidth() > 8 && pu.lheight() > 8)) 
  {
    // Sort MIP candidates by Hadamard cost 使用HAD排序MIP候选模式
    const int transpOff = getNumModesMip( pu.Y() ); // 不同尺寸对应的MIP模式数
    static_vector<uint8_t, FAST_UDI_MAX_RDMODE_NUM> sortedMipModes(0);
    static_vector<double, FAST_UDI_MAX_RDMODE_NUM> sortedMipCost(0);
    // 将前三种MIP模式矩阵排序
    for( uint8_t mode : { 0, 1, 2 } ) 
    {
      // 判断转置后的MIP模式的HAD和转置前的MIP模式的HAD,将HAD较小的MIP模式加入到sortedMipModes中
      uint8_t candMode = mode + uint8_t((mipHadCost[mode + transpOff] < mipHadCost[mode]) ? transpOff : 0);
      updateCandList(candMode, mipHadCost[candMode], sortedMipModes, sortedMipCost, 3);
    }

    // Append MIP mode to RD mode list 将MIP模式加入到RD模式列表
    const int modeListSize = int(tempRdModeList.size()); // 临时模式列表的尺寸
    for (int idx = 0; idx < 3; idx++)
    {
      const bool     isTransposed = (sortedMipModes[idx] >= transpOff ? true : false); // 是否转置
      const uint32_t mipIdx       = (isTransposed ? sortedMipModes[idx] - transpOff : sortedMipModes[idx]); // MIP模式号
      const ModeInfo mipMode( true, isTransposed, 0, NOT_INTRA_SUBPARTITIONS, mipIdx ); // MIP模式
      bool alreadyIncluded = false; // 是否在模式列表中
      for (int modeListIdx = 0; modeListIdx < modeListSize; modeListIdx++)
      {
        if (tempRdModeList[modeListIdx] == mipMode)
        {
          alreadyIncluded = true;
          break;
        }
      }

      if (!alreadyIncluded) // 如果没有在候选列表中,则将其加入
      {
        tempRdModeList.push_back(mipMode);
        tempCandCostList.push_back(0);
        if( fastMip ) break; // 如果使用fastMIP,则仅加入一种模式
      }
    }
  }
  // 更新模式列表和代价列表
  candModeList = tempRdModeList;
  candCostList = tempCandCostList;
  numModesForFullRD = int(candModeList.size());
}

Guess you like

Origin blog.csdn.net/BigDream123/article/details/123788516