reduceHadCandList函数由estIntraPredLumaQT函数调用,主要是用来缩减后续进行全RD Cost细选的模式列表。
基本过程:
- 缩减传统候选模式数,仅加入Cost较小的前三种传统的模式
- 缩减MIP候选模式数,删除Cost较大的最后一种MIP模式
- 对于尺寸大于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());
}