VTM10.0帧内之ISP技术
Posted 神遁克里苏
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了VTM10.0帧内之ISP技术相关的知识,希望对你有一定的参考价值。
ISP(Intra Sub-Partitions,帧内子区域划分)
依据CU的亮度块尺寸,将其沿水平或垂直方向划分成2个或者4个尺寸相同的子块,然后逐个子区域进行预测和重建。
进行帧内ISP的最小CU尺寸为4 x 8或8 x 4(即4 x 4的CU不使用ISP),4 x 8或8 x 4的CU会被分成2个子区域,其他尺寸则被分成4个子区域,即每个子区域最少需要有16个像素。
代码意思见注释
void IntraPrediction::initIntraPatternChTypeISP(const CodingUnit& cu, const CompArea& area, PelBuf& recBuf, const bool forceRefFilterFlag)
{
const CodingStructure& cs = *cu.cs;
if (!forceRefFilterFlag)
{//帧内预测参数初始化
initPredIntraParams(*cu.firstPU, area, *cs.sps);
}
const Position posLT = area;
//左侧CU可用,且已解码
bool isLeftAvail = (cs.getCURestricted(posLT.offset(-1, 0), cu, CHANNEL_TYPE_LUMA) != NULL) && cs.isDecomp(posLT.offset(-1, 0), CHANNEL_TYPE_LUMA);
//上侧CU可用,且已解码
bool isAboveAvail = (cs.getCURestricted(posLT.offset(0, -1), cu, CHANNEL_TYPE_LUMA) != NULL) && cs.isDecomp(posLT.offset(0, -1), CHANNEL_TYPE_LUMA);
// ----- Step 1: unfiltered reference samples -----
if (cu.blocks[area.compID].x == area.x && cu.blocks[area.compID].y == area.y)
{//如果当前cu的起始位置与area的起始位置相同,也就是该子块是CU中的第一个块
Pel *refBufUnfiltered = m_refBuffer[area.compID][PRED_BUF_UNFILTERED];//当前块的未滤波参考缓存
// With the first subpartition all the CU reference samples are fetched at once in a single call to xFillReferenceSamples
if (cu.ispMode == HOR_INTRA_SUBPARTITIONS)
{//如果是水平划分的,那左边的参考像素长度就是cu长度乘2,上边参考像素的长度就是当前Cu的宽然后加上这个area的宽
m_leftRefLength = cu.Y().height << 1;
m_topRefLength = cu.Y().width + area.width;//在ISP水平划分模式下,area子块的跨百度好像就是cu的宽,所以这里是2倍的cu宽
}
else //if (cu.ispMode == VER_INTRA_SUBPARTITIONS)
{//垂直划分
m_leftRefLength = cu.Y().height + area.height;
m_topRefLength = cu.Y().width << 1;
}
//调用xFillReferenceSamples,得到参考像素,该CU中其他的子块就不用再调用了。
xFillReferenceSamples(cs.picture->getRecoBuf(cu.Y()), refBufUnfiltered, cu.Y(), cu);
//xFillReferenceSamples函数结束时,已经把所有的参考像素放进了refBufUnfiltered中。
// After having retrieved all the CU reference samples, the number of reference samples is now adjusted for the current subpartition
//检索完所有的CU参考采样点后,现在针对当前子块调整参考采样点的数量
//划分侧参考长度为 CU在对应侧尺寸 + 预测区域对应侧尺寸
//不划分测参考长度为 2*CU在对应侧尺寸
m_topRefLength = cu.blocks[area.compID].width + area.width;
m_leftRefLength = cu.blocks[area.compID].height + area.height;
}
else
{//如果当前cu的其实位置与area的起始位置不同
//左侧和上侧的参考长度都为CUsize + areasize
m_topRefLength = cu.blocks[area.compID].width + area.width;
m_leftRefLength = cu.blocks[area.compID].height + area.height;
const int predSizeHor = m_topRefLength;
const int predSizeVer = m_leftRefLength;
if (cu.ispMode == HOR_INTRA_SUBPARTITIONS)
{
//src中存放当前area上一行的第一个像素
Pel* src = recBuf.bufAt(0, -1);
//水平方向分割,不是第一次调用时,参考像素要加上m_refBufferStride[area.compID]
//m_refBufferStride[area.compID]在xFillReferenceSamples中赋值,m_refBufferStride[area.compID] = predStride;
//const int predStride = predSize + 1 + multiRefIdx;
//const int predSize = m_topRefLength;
Pel *ref = m_refBuffer[area.compID][PRED_BUF_UNFILTERED] + m_refBufferStride[area.compID];
if (isLeftAvail)
{
for (int i = 0; i <= 2 * cu.blocks[area.compID].height - area.height; i++)
{//因为之前已经得到了所有的参考像素,所以这里就只加上area的高,就可以得到它的左侧第一个参考像素
ref[i] = ref[i + area.height];
}
}
else
{//如果左侧不可用,则参考像素等于上方子块(这个块上一行的第一个点)的重建值,recBuf.bufAt(0, -1)
for (int i = 0; i <= predSizeVer; i++)
{
ref[i] = src[0];
}
}
//上方参考
Pel *dst = m_refBuffer[area.compID][PRED_BUF_UNFILTERED] + 1;
dst[-1] = ref[0];
for (int i = 0; i < area.width; i++)
{//使用上面一个子块的重建填充area的宽度的参考像素
dst[i] = src[i];
}
Pel sample = src[area.width - 1];
dst += area.width;
for (int i = 0; i < predSizeHor - area.width; i++)
{//上方右侧的参考像素由上方最后一个点填充
dst[i] = sample;
}
}
else//垂直分割
{
Pel* src = recBuf.bufAt(-1, 0);
Pel *ref = m_refBuffer[area.compID][PRED_BUF_UNFILTERED];
if (isAboveAvail)
{
for (int i = 0; i <= 2 * cu.blocks[area.compID].width - area.width; i++)
{
ref[i] = ref[i + area.width];
}
}
else
{
for (int i = 0; i <= predSizeHor; i++)
{
ref[i] = src[0];
}
}
Pel *dst = m_refBuffer[area.compID][PRED_BUF_UNFILTERED] + m_refBufferStride[area.compID] + 1;
dst[-1] = ref[0];
for (int i = 0; i < area.height; i++)
{
*dst = *src;
src += recBuf.stride;
dst++;
}
Pel sample = src[-recBuf.stride];
for (int i = 0; i < predSizeVer - area.height; i++)
{
*dst = sample;
dst++;
}
}
}
// ----- Step 2: filtered reference samples -----进行参考像素的滤波
if (m_ipaParam.refFilterFlag || forceRefFilterFlag)
{
Pel *refBufUnfiltered = m_refBuffer[area.compID][PRED_BUF_UNFILTERED];
Pel *refBufFiltered = m_refBuffer[area.compID][PRED_BUF_FILTERED];
xFilterReferenceSamples(refBufUnfiltered, refBufFiltered, area, *cs.sps, cu.firstPU->multiRefIdx);
}
}
以上是关于VTM10.0帧内之ISP技术的主要内容,如果未能解决你的问题,请参考以下文章