xGetLMParameters在predIntraChromaLM函数中被调用,来获取MMLM和MDLM模式的线性模型参数。
函数搜寻参考像素中亮度像素的最大最小点,保存两个点的luma和chroma值。
由保存的亮度像素最大最小点的值即可确定线性模型参数a、b、shift。
void IntraPrediction::xGetLMParameters(const PredictionUnit &pu, const ComponentID compID,
const CompArea &chromaArea,
int &a, int &b, int &iShift)
{
CHECK(compID == COMPONENT_Y, "");
const SizeType cWidth = chromaArea.width;
const SizeType cHeight = chromaArea.height;
const Position posLT = chromaArea;
CodingStructure & cs = *(pu.cs);
const CodingUnit &cu = *(pu.cu);
const SPS & sps = *cs.sps;
const uint32_t tuWidth = chromaArea.width;
const uint32_t tuHeight = chromaArea.height;
const ChromaFormat nChromaFormat = sps.getChromaFormatIdc();
const int baseUnitSize = 1 << MIN_CU_LOG2; //亮度4x4,色度2x2
const int unitWidth = baseUnitSize >> getComponentScaleX(chromaArea.compID, nChromaFormat);
const int unitHeight = baseUnitSize >> getComponentScaleX(chromaArea.compID, nChromaFormat);
const int tuWidthInUnits = tuWidth / unitWidth;
const int tuHeightInUnits = tuHeight / unitHeight;
const int aboveUnits = tuWidthInUnits;
const int leftUnits = tuHeightInUnits; //长和宽包含的2x2基本块的数目
#if JVET_L0338_MDLM
int topTemplateSampNum = 2 * cWidth; // for MDLM, the template sample number is 2W or 2H;
int leftTemplateSampNum = 2 * cHeight; //MDLM模式的参考像素模板的宽长分别为2W、2H
assert(m_topRefLength >= topTemplateSampNum);
assert(m_leftRefLength >= leftTemplateSampNum);
int totalAboveUnits = (topTemplateSampNum + (unitWidth - 1)) / unitWidth;
int totalLeftUnits = (leftTemplateSampNum + (unitHeight - 1)) / unitHeight;
int totalUnits = totalLeftUnits + totalAboveUnits + 1; //左下、左、左上、上、右上 五个区域包含的base块数目
int aboveRightUnits = totalAboveUnits - aboveUnits;
int leftBelowUnits = totalLeftUnits - leftUnits; //右上和左下包含的2x2基本块的数目
int avaiAboveRightUnits = 0;
int avaiLeftBelowUnits = 0;
int avaiAboveUnits = 0;
int avaiLeftUnits = 0; //4个区域可用参考小块的数目
int curChromaMode = pu.intraDir[1]; //色度帧内模式
#endif
bool neighborFlags[4 * MAX_NUM_PART_IDXS_IN_CTU_WIDTH + 1];
#if JVET_L0338_MDLM
memset(neighborFlags, 0, totalUnits);
#else
memset(neighborFlags, 0, 1 + leftUnits + aboveUnits);
#endif
bool aboveAvailable, leftAvailable; //上侧和左侧块是否可用
int availableUnit =
isAboveAvailable(cu, CHANNEL_TYPE_CHROMA, posLT, aboveUnits, unitWidth,
#if JVET_L0338_MDLM
(neighborFlags + leftUnits + leftBelowUnits + 1));
#else
(neighborFlags + leftUnits + 1));
#endif
aboveAvailable = availableUnit == tuWidthInUnits; //上侧2x2小块均可用时,才标记上侧块可用
availableUnit =
isLeftAvailable(cu, CHANNEL_TYPE_CHROMA, posLT, leftUnits, unitHeight,
#if JVET_L0338_MDLM
(neighborFlags + leftUnits + leftBelowUnits - 1));
#else
(neighborFlags + leftUnits - 1));
#endif
leftAvailable = availableUnit == tuHeightInUnits; //左侧2x2小块均可用时,才标记上侧块可用
#if JVET_L0338_MDLM
if (leftAvailable) // if left is not available, then the below left is not available
{ //如果左侧块不可用,那么左下块也就不可用
avaiLeftUnits = tuHeightInUnits;
avaiLeftBelowUnits = isBelowLeftAvailable(cu, CHANNEL_TYPE_CHROMA, chromaArea.bottomLeftComp(chromaArea.compID), leftBelowUnits, unitHeight, (neighborFlags + leftBelowUnits - 1));
}
if (aboveAvailable) // if above is not available, then the above right is not available.
{ //如果上侧块不可用,那么右上块也就不可用
avaiAboveUnits = tuWidthInUnits;
avaiAboveRightUnits = isAboveRightAvailable(cu, CHANNEL_TYPE_CHROMA, chromaArea.topRightComp(chromaArea.compID), aboveRightUnits, unitWidth, (neighborFlags + leftUnits + leftBelowUnits + aboveUnits + 1));
} //这里记录左下、左、上、右上4个区域的分别可用2x2小块的数目
#endif
Pel *srcColor0, *curChroma0;
int srcStride, curStride;
PelBuf temp;
#if JVET_L0338_MDLM
if ((curChromaMode == MDLM_L_IDX) || (curChromaMode == MDLM_T_IDX))
{ // LM_L、LM_T
srcStride = 2 * MAX_CU_SIZE + 1;
temp = PelBuf(m_pMdlmTemp + srcStride + 1, srcStride, Size(chromaArea));
}
else // MMLM
{
#endif
srcStride = MAX_CU_SIZE + 1;
temp = PelBuf(m_piTemp + srcStride + 1, srcStride, Size(chromaArea));
#if JVET_L0338_MDLM
} //m_pMdlmTemp和m_piTemp存储参考像素和pu中luma像素的采样值,temp指针指向pu中的第一个采样像素
#endif
///以上的代码和xGetLumaRecPixels()函数中一样
srcColor0 = temp.bufAt(0, 0); //亮度重建采样像素
curChroma0 = getPredictorPtr(compID); //compID的未滤波pu参考像素(色度像素)
curStride = m_topRefLength + 1;
curChroma0 += curStride + 1; //指向pu最开始像素点
unsigned internalBitDepth = sps.getBitDepth(CHANNEL_TYPE_CHROMA);
int minLuma[2] = { MAX_INT, 0 };
int maxLuma[2] = { -MAX_INT, 0 }; //找到亮度最大和最小的像素点,用来构造线性模型
Pel *src = srcColor0 - srcStride; //都指向Above的第一个像素点
Pel *cur = curChroma0 - curStride; //因为亮度2:1采样过,所以两者长度大小相等
#if JVET_L0338_MDLM
int minDim = 1;
int actualTopTemplateSampNum = 0;
int actualLeftTemplateSampNum = 0;
if (curChromaMode == MDLM_T_IDX) //LM_T
{
leftAvailable = 0;
actualTopTemplateSampNum = unitWidth*(avaiAboveUnits + avaiAboveRightUnits);
minDim = actualTopTemplateSampNum; //上 右上侧可用像素数
}
else if (curChromaMode == MDLM_L_IDX) //LM_L
{
aboveAvailable = 0;
actualLeftTemplateSampNum = unitHeight*(avaiLeftUnits + avaiLeftBelowUnits);
minDim = actualLeftTemplateSampNum; //左 左下侧可用像素数
}
else if (curChromaMode == LM_CHROMA_IDX) //LM
{
actualTopTemplateSampNum = cWidth;
actualLeftTemplateSampNum = cHeight; //4区域可用像素数
minDim = leftAvailable && aboveAvailable ? 1 << g_aucPrevLog2[std::min(actualLeftTemplateSampNum, actualTopTemplateSampNum)]
: 1 << g_aucPrevLog2[leftAvailable ? actualLeftTemplateSampNum : actualTopTemplateSampNum];
}
#endif
int numSteps = minDim;
if (aboveAvailable) //上
{
for (int j = 0; j < numSteps; j++)
{
#if JVET_L0338_MDLM
int idx = (j * actualTopTemplateSampNum) / minDim;
#else
int idx = (j * cWidth) / minDim;
#endif
if (minLuma[0] > src[idx]) //找亮度最小最大点,存储对应的luma和chroma像素值
{
minLuma[0] = src[idx];
minLuma[1] = cur[idx];
}
if (maxLuma[0] < src[idx])
{
maxLuma[0] = src[idx];
maxLuma[1] = cur[idx];
}
}
}
if (leftAvailable) //左
{
src = srcColor0 - 1; //指向左上
cur = curChroma0 - 1;
for (int i = 0; i < numSteps; i++)
{
#if JVET_L0338_MDLM
int idx = (i * actualLeftTemplateSampNum) / minDim;
#else
int idx = (i * cHeight) / minDim;
#endif
if (minLuma[0] > src[srcStride * idx]) //找亮度最小最大点,存储对应的luma和chroma像素值
{
minLuma[0] = src[srcStride * idx];
minLuma[1] = cur[curStride * idx];
}
if (maxLuma[0] < src[srcStride * idx])
{
maxLuma[0] = src[srcStride * idx];
maxLuma[1] = cur[curStride * idx];
}
}
}
if ((leftAvailable || aboveAvailable)) //确定线性参数a、b、shift
{
a = 0;
iShift = 16;
int shift = (internalBitDepth > 8) ? internalBitDepth - 9 : 0;
int add = shift ? 1 << (shift - 1) : 0;
int diff = (maxLuma[0] - minLuma[0] + add) >> shift;
if (diff > 0)
{
int div = ((maxLuma[1] - minLuma[1]) * g_aiLMDivTableLow[diff - 1] + 32768) >> 16;
a = (((maxLuma[1] - minLuma[1]) * g_aiLMDivTableHigh[diff - 1] + div + add) >> shift);
}
b = minLuma[1] - ((a * minLuma[0]) >> iShift);
}
else
{
a = 0;
b = 1 << (internalBitDepth - 1);
iShift = 0;
}
}