VTM10.0xPredIntraAng函数解析
Posted 神遁克里苏
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了VTM10.0xPredIntraAng函数解析相关的知识,希望对你有一定的参考价值。
xPredIntraAng函数内进行角度模式的解析,获取块内的预测值。
void IntraPrediction::xPredIntraAng( const CPelBuf &pSrc, PelBuf &pDst, const ChannelType channelType, const ClpRng& clpRng)
{
int width =int(pDst.width);
int height=int(pDst.height);
const bool bIsModeVer = m_ipaParam.isModeVer;
const int multiRefIdx = m_ipaParam.multiRefIndex;
const int intraPredAngle = m_ipaParam.intraPredAngle;
const int absInvAngle = m_ipaParam.absInvAngle;
Pel* refMain;
Pel* refSide;
Pel refAbove[2 * MAX_CU_SIZE + 3 + 33 * MAX_REF_LINE_IDX];
Pel refLeft [2 * MAX_CU_SIZE + 3 + 33 * MAX_REF_LINE_IDX];
// Initialize the Main and Left reference array.
//先初始化先初始化主要的和左边的参考
//predModeIntra与intraPredAngle不同,前者才是指模式号,后者是角度
//小于0是指18到49的角度
if (intraPredAngle < 0)
{//+ multiRefIdx是因为第1参考行比第0参考行多出一个,第2参考行比第0参考行多出2个像素
for (int x = 0; x <= width + 1 + multiRefIdx; x++)
{//buf[y * stride + x];,这里就是at(x, 0)=0*stride+x
refAbove[x + height] = pSrc.at(x, 0);//x+height是为了预留主参考像素向左扩展的位置
}
for (int y = 0; y <= height + 1 + multiRefIdx; y++)
{//buf[y * stride + x];,这里就是1*stride+y
refLeft[y + width] = pSrc.at(y, 1);
}//怀疑是因为pstr中存放的是两行,一行上边的一行左边的?
//因为对于19到49 的角度只用refAbove + height或是refLeft + width即可预测
//bIsModeVer表示是否是偏向垂直的预测模式,如果是则主参考行为上边,副参考行为左边。
//如果是偏向水平的预测模式,则主参考行为左边,副参考行为上边
//本函数后面把主参考行当成上参考行进行预测,那么偏向水平的预测模式生成的预测图像会转置,预测结束后要转置回来
refMain = bIsModeVer ? refAbove + height : refLeft + width;
refSide = bIsModeVer ? refLeft + width : refAbove + height;
// Extend the Main reference to the left.
//向左边扩展主参考行
int sizeSide = bIsModeVer ? height : width;
for (int k = -sizeSide; k <= -1; k++)
{
refMain[k] = refSide[std::min((-k * absInvAngle + 256) >> 9, sizeSide)];
}
}
else//intraPredAngle>=0
{
for (int x = 0; x <= m_topRefLength + multiRefIdx; x++)
{
refAbove[x] = pSrc.at(x, 0);
}
for (int y = 0; y <= m_leftRefLength + multiRefIdx; y++)
{
refLeft[y] = pSrc.at(y, 1);
}
refMain = bIsModeVer ? refAbove : refLeft;
refSide = bIsModeVer ? refLeft : refAbove;
// Extend main reference to right using replication
//用复制的方式,向右边扩展主参考行
const int log2Ratio = floorLog2(width) - floorLog2(height);
const int s = std::max<int>(0, bIsModeVer ? log2Ratio : -log2Ratio);
const int maxIndex = (multiRefIdx << s) + 2;
const int refLength = bIsModeVer ? m_topRefLength : m_leftRefLength;
const Pel val = refMain[refLength + multiRefIdx];
for (int z = 1; z <= maxIndex; z++)
{
refMain[refLength + multiRefIdx + z] = val;
}
}
// swap width/height if we are doing a horizontal mode:
//当做偏向水平的预测模式时,把宽和长交换
if (!bIsModeVer)
{
std::swap(width, height);
}
Pel tempArray[MAX_CU_SIZE * MAX_CU_SIZE];
const int dstStride = bIsModeVer ? pDst.stride : width;
Pel * pDstBuf = bIsModeVer ? pDst.buf : tempArray;
// compensate for line offset in reference line buffers
refMain += multiRefIdx;
refSide += multiRefIdx;
Pel *pDsty = pDstBuf;
if( intraPredAngle == 0 ) // pure vertical or pure horizontal, intraPredAngle等于0 表示水平或垂直模式
{
for( int y = 0; y < height; y++ )
{
for( int x = 0; x < width; x++ )
{
pDsty[x] = refMain[x + 1];
}
//PDPC,对预测值进行修正
if (m_ipaParam.applyPDPC)
{
const int scale = (floorLog2(width) + floorLog2(height) - 2) >> 2;
const Pel topLeft = refMain[0];
const Pel left = refSide[1 + y];
for (int x = 0; x < std::min(3 << scale, width); x++)
{
const int wL = 32 >> (2 * x >> scale);
const Pel val = pDsty[x];
pDsty[x] = ClipPel(val + ((wL * (left - topLeft) + 32) >> 6), clpRng);
}
}
pDsty += dstStride;
}
}
else//intraPredAngle != 0 ,其他的角度模式
{
for (int y = 0, deltaPos = intraPredAngle * (1 + multiRefIdx); y<height; y++, deltaPos += intraPredAngle, pDsty += dstStride)
{
const int deltaInt = deltaPos >> 5;//获得整数部分
const int deltaFract = deltaPos & 31;//获得小数部分
if ( !isIntegerSlope( abs(intraPredAngle) ) )//如果不是整数角度
{
if( isLuma(channelType) )//亮度
{
const bool useCubicFilter = !m_ipaParam.interpolationFlag;
//定义f,加权的权值
const TFilterCoeff intraSmoothingFilter[4] = {TFilterCoeff(16 - (deltaFract >> 1)), TFilterCoeff(32 - (deltaFract >> 1)), TFilterCoeff(16 + (deltaFract >> 1)), TFilterCoeff(deltaFract >> 1)};
const TFilterCoeff* const f = (useCubicFilter) ? InterpolationFilter::getChromaFilterTable(deltaFract) : intraSmoothingFilter;
for (int x = 0; x < width; x++)
{
Pel p[4];
p[0] = refMain[deltaInt + x];
p[1] = refMain[deltaInt + x + 1];
p[2] = refMain[deltaInt + x + 2];
p[3] = refMain[deltaInt + x + 3];
//对这4个点进行加权
Pel val = (f[0] * p[0] + f[1] * p[1] + f[2] * p[2] + f[3] * p[3] + 32) >> 6;
pDsty[x] = ClipPel(val, clpRng); // always clip even though not always needed
}
}
else//色度
{
// Do linear filtering
for (int x = 0; x < width; x++)
{
Pel p[2];
p[0] = refMain[deltaInt + x + 1];
p[1] = refMain[deltaInt + x + 2];
pDsty[x] = p[0] + ((deltaFract * (p[1] - p[0]) + 16) >> 5);
}
}
}
else//如果是整数
{
// Just copy the integer samples
for( int x = 0; x < width; x++ )
{
pDsty[x] = refMain[x + deltaInt + 1];
}
}
if (m_ipaParam.applyPDPC)
{
const int scale = m_ipaParam.angularScale;
int invAngleSum = 256;
for (int x = 0; x < std::min(3 << scale, width); x++)
{
invAngleSum += absInvAngle;
int wL = 32 >> (2 * x >> scale);
Pel left = refSide[y + (invAngleSum >> 9) + 1];
pDsty[x] = pDsty[x] + ((wL * (left - pDsty[x]) + 32) >> 6);
}
}
}
}
以上是关于VTM10.0xPredIntraAng函数解析的主要内容,如果未能解决你的问题,请参考以下文章