H.266/VVC专栏传送
上一篇:无
下一篇:H.266/VVC-VTM代码学习-帧内预测02-获取参考像素并对其滤波xFillReferenceSamples、xFilterReferenceSamples
前言
VTM是H.266/VVC视频编码标准的参考软件,研究VTM代码给研究人员解释了VVC编码标准的详细标准规范与细节。
本文是笔者对VTM代码的一点学习记录,成文于笔者刚开始接触VVC期间,期间很多概念和理论框架还很不成熟,若文中存在错误欢迎批评指正,也欢迎广大视频编码学习者沟通交流、共同进步。
VTM代码的下载及编译请参考博文:
【视频编码学习】H.266/VVC参考软件VTM配置运行(VTM-6.0版本)
本文涉及的代码存在于工程下的/lib/CommonLib/SourceFiles/IntraPrediction.cpp文件中。
一、主要函数
1.函数代码
// Function for initialization of intra prediction parameters
void IntraPrediction::initPredIntraParams(const PredictionUnit & pu, const CompArea area, const SPS& sps)
{
const ComponentID compId = area.compID;
const ChannelType chType = toChannelType(compId);
//是否使用ISP(多划分预测)
const bool useISP = NOT_INTRA_SUBPARTITIONS != pu.cu->ispMode && isLuma( chType );
//CU大小
const Size cuSize = Size( pu.cu->blocks[compId].width, pu.cu->blocks[compId].height );
//PU大小
const Size puSize = Size( area.width, area.height );
const Size& blockSize = useISP ? cuSize : puSize;
//预测模式
const int dirMode = PU::getFinalIntraMode(pu, chType);
//将预测模式转换为宽角度模式
const int predMode = getModifiedWideAngle( blockSize.width, blockSize.height, dirMode );
//模式标号大于34视作垂直类模式
m_ipaParam.isModeVer = predMode >= DIA_IDX;
//获得参考行索引
m_ipaParam.multiRefIndex = isLuma (chType) ? pu.multiRefIdx : 0 ;
//参考像素滤波初始化为否
m_ipaParam.refFilterFlag = false;
//插值初始化为否
m_ipaParam.interpolationFlag = false;
//是否提供PDPC技术(若PU边长均≥4且使用0号参考行则提供PDPC)
m_ipaParam.applyPDPC = (puSize.width >= MIN_TB_SIZEY && puSize.height >= MIN_TB_SIZEY) && m_ipaParam.multiRefIndex == 0;
//记录角度模式关于垂直或水平的偏移量
//若predMode>=34,则intraPredAngLeMode=predMode-VER_IDX(50)
//若predMode<34,则intraPredAngLeMode=predMode-HOR_IDX(18)
//宽角度模式是-14~80,故该值范围为-32~30
const int intraPredAngleMode = (m_ipaParam.isModeVer) ? predMode - VER_IDX : -(predMode - HOR_IDX);
int absAng = 0;
//预测模式是角度模式(即模式号大于DC)且模式号小于LUMA模式总数67
if (dirMode > DC_IDX && dirMode < NUM_LUMA_MODE) // intraPredAngle for directional modes
{
//偏离水平或垂直不同程度的不同模式对应的模式偏移值offset
static const int angTable[32] = { 0, 1, 2, 3, 4, 6, 8, 10, 12, 14, 16, 18, 20, 23, 26, 29, 32, 35, 39, 45, 51, 57, 64, 73, 86, 102, 128, 171, 256, 341, 512, 1024 };
// (512 * 32) / offset
static const int invAngTable[32] = {
0, 16384, 8192, 5461, 4096, 2731, 2048, 1638, 1365, 1170, 1024, 910, 819, 712, 630, 565,
512, 468, 420, 364, 321, 287, 256, 224, 191, 161, 128, 96, 64, 48, 32, 16
};
//模式偏离水平或垂直的值(取绝对值),值范围为0~32
const int absAngMode = abs(intraPredAngleMode);
//模式19~49(模式号大于水平,小于垂直)为-1,其他为1
const int signAng = intraPredAngleMode < 0 ? -1 : 1;
//角度模式对应偏移值offset
absAng = angTable [absAngMode];
//角度偏移值的倒数*512*32,后续便于除法运算
m_ipaParam.absInvAngle = invAngTable[absAngMode];
//预测角度(带正负号的偏移值)
m_ipaParam.intraPredAngle = signAng * absAng;
if (intraPredAngleMode < 0)
{
//模式19~49不用PDPC
m_ipaParam.applyPDPC = false;
}
else if (intraPredAngleMode > 0)
{
//预测模式对应侧的长度
//类垂直模式为PU高,类水平模式为PU宽
const int sideSize = m_ipaParam.isModeVer ? puSize.height : puSize.width;
const int maxScale = 2;
m_ipaParam.angularScale = std::min(maxScale, floorLog2(sideSize) - (floorLog2(3 * m_ipaParam.absInvAngle - 2) - 8));
m_ipaParam.applyPDPC &= m_ipaParam.angularScale >= 0;
}
}
/********************判断是否对参考像素进行滤波**********************/
//high level conditions and DC intra prediction
//若SPS标识参考像素滤波不可用
//或当前块不是Luma块
//或使用ISP(多划分预测)
//或使用MIP(矩阵加权帧内预测)
//或使用非第0行参考像素
//或使用DC模式时
//不进行之后的判断并且保持不滤波的初始设置
if( sps.getSpsRangeExtension().getIntraSmoothingDisabledFlag()
|| !isLuma( chType )
|| useISP
|| PU::isMIP( pu, chType )
|| m_ipaParam.multiRefIndex
|| DC_IDX == dirMode
)
{
}
//LumaBDPCM模式或者chromaBDPCM模式不滤波
else if ((isLuma(chType) && pu.cu->bdpcmMode) || (!isLuma(chType) && pu.cu->bdpcmModeChroma))
{
m_ipaParam.refFilterFlag = false;
}
else if (dirMode == PLANAR_IDX)//Planar模式若PU w*h > 32 就参考像素滤波
{
m_ipaParam.refFilterFlag = puSize.width * puSize.height > 32 ? true : false;
}
//不用多划分预测(ISP)时
else if (!useISP)
{
bool filterFlag = false;
{
//与水平模式或垂直模式的模式标号差
const int diff = std::min<int>( abs( predMode - HOR_IDX ), abs( predMode - VER_IDX ) );
//log2(width)和log2(height)的均值
const int log2Size = ((floorLog2(puSize.width) + floorLog2(puSize.height)) >> 1);
CHECK( log2Size >= MAX_INTRA_FILTER_DEPTHS, "Size not supported" );
//与水平模式或垂直模式的模式标号差是否大于log2(width)和log2(height)的均值对应的值
//log2(width)和log2(height)的均值 对应值
// 0 24
// 1 24
// 2 24
// 3 14
// 4 2
// 5 0
// 6 0
// 7 0
filterFlag = (diff > m_aucIntraFilter[log2Size]);
}
// Selelection of either ([1 2 1] / 4 ) refrence filter OR Gaussian 4-tap interpolation filter
if (filterFlag)
{
//return ((absAng & 31) == 0) 即是否为32的整数倍
const bool isRefFilter = isIntegerSlope(absAng);
CHECK( puSize.width * puSize.height <= 32, "DCT-IF interpolation filter is always used for 4x4, 4x8, and 8x4 luma CB" );
m_ipaParam.refFilterFlag = isRefFilter;//角度偏移值为32整数倍时启用参考像素滤波
m_ipaParam.interpolationFlag = !isRefFilter;//插值标志与参考像素滤波标志相反
}
}
}
2.逻辑结构
1.基础参数初始化:确定预测模式标号、CU大小、PU大小、将预测模式转换为宽角度下的预测模式、确定预测角度模式是垂直类还是水平类。
2.通过预测模式标号确定预测角度偏移值offset,并准备offset的倒数便于后续除法运算。
3.判断是否使用PDPC。
4.判断是否对参考像素进行滤波。
二、部分代码涉及知识
1.VVC中的预测模式中加入了宽角度模式,如图所示。
2.VVC中使用了PDPC技术,使最终预测值结合了滤波前和滤波后的参考像素值。从代码上看,PDPC技术的使用范围是:
(1) (puSize.width >= 4) && (puSize.height >= 4) && (m_ipaParam.multiRefIndex == 0),即PU尺寸两个维度都不小于4且使用0号参考行。
(2)模式19~49不使用PDPC。
(3)使用PDPC时,angularScale必须不小于0。
3.判断是否对参考像素进行滤波时,以下情况使用参考像素滤波:
(1)Planar模式若PU尺寸 > 32 就进行参考像素滤波。
(2)当前模式与水平模式或垂直模式的模式标号差大于log2(width)和log2(height)的均值对应的值(对应值见下表),且角度偏移值是否为32的整数倍,进行参考像素滤波。
log2(width)和log2(height)的均值 | 对应值 |
---|---|
0 | 24 |
1 | 24 |
2 | 24 |
3 | 14 |
4 | 2 |
5 | 0 |
6 | 0 |
7 | 0 |
上一篇:无
下一篇:H.266/VVC-VTM代码学习-帧内预测02-获取参考像素并对其滤波xFillReferenceSamples、xFilterReferenceSamples