本文的代码均是TEncSearch::estIntraPredLumaQT函数或被它调用的函数中的代码。在TEncSearch::estIntraPredLumaQT函数中,首先确定RMD(Rough Mode Decision)候选。RMD的候选模式的个数由以下两个数组确定:
const UChar g_aucIntraModeNumFast_UseMPM[MAX_CU_DEPTH] =
{
3, // 2x2
8, // 4x4
8, // 8x8
3, // 16x16
3, // 32x32
3 // 64x64
};
const UChar g_aucIntraModeNumFast_NotUseMPM[MAX_CU_DEPTH] =
{
3, // 2x2
9, // 4x4
9, // 8x8
4, // 16x16 33
4, // 32x32 33
5 // 64x64 33
};
从上面两个数组可以看出,RMD模式的个数与PU的大小有关。PU较小(4x4或8x8)时,RMD个数为8;PU较大(16x16或32x32或64x64)时,RMD个数为3。选择RMD时,uiMode按代价uiCost在CandCostList中从小到大排列在CandModeList中。
UInt TEncSearch::xUpdateCandList( UInt uiMode, Double uiCost, UInt uiFastCandNum, UInt * CandModeList, Double * CandCostList )
{
UInt i;
UInt shift=0;
// 确定插入位置shift(从右至左)
while ( shift1-shift ] )
{
shift++;
}
if( shift!=0 )
{
// 插入点及之后的模式号外后挪
for(i=1; i<shift; i++)
{
CandModeList[ uiFastCandNum-i ] = CandModeList[ uiFastCandNum-1-i ];
CandCostList[ uiFastCandNum-i ] = CandCostList[ uiFastCandNum-1-i ];
}
// 在插入点插入相应的模式号
CandModeList[ uiFastCandNum-shift ] = uiMode;
CandCostList[ uiFastCandNum-shift ] = uiCost;
return 1;
}
return 0;
}
上面函数的返回值用作TEncSearch::estIntraPredLumaQT中定义的变量CandNum的增量,然而CandNum的值没有被使用,因此上面函数的返回值是没有用处的。CandCostList以从小到大的顺序,往后挪时,会把cost最大的模式覆盖掉,这样做是合理。
RMO后,再加入MPM(most probable mode)模式。如果MPM模式不在RMO产生的集合里,则加入MPM模式。
if (m_pcEncCfg->getFastUDIUseMPMEnabled())
{
Int uiPreds[NUM_MOST_PROBABLE_MODES] = {-1, -1, -1};
Int iMode = -1;
pcCU->getIntraDirPredictor( uiPartOffset, uiPreds, COMPONENT_Y, &iMode ); // 获取MPM模式
// MPM模式的个数
const Int numCand = ( iMode >= 0 ) ? iMode : Int(NUM_MOST_PROBABLE_MODES);
for( Int j=0; j < numCand; j++)
{
Bool mostProbableModeIncluded = false;
Int mostProbableMode = uiPreds[j];
for( Int i=0; i < numModesForFullRD; i++)
{
mostProbableModeIncluded |= (mostProbableMode == uiRdModeList[i]);
}
if (!mostProbableModeIncluded)
{
uiRdModeList[numModesForFullRD++] = mostProbableMode;
}
}
}
获取MPM模式的代码如下(在指针piMode指向的变量中赋MPM的个数):
/** Get most probable intra modes
*\param uiAbsPartIdx partition index
*\param uiIntraDirPred pointer to the array for MPM storage
*\param compID colour component ID
*\param piMode it is set with MPM mode in case both MPM are equal. It is used to restrict RD search at encode side.
*\returns Number of MPM
*/
Void TComDataCU::getIntraDirPredictor( UInt uiAbsPartIdx, Int uiIntraDirPred[NUM_MOST_PROBABLE_MODES], const ComponentID compID, Int* piMode ) const
{
UInt LeftPartIdx = MAX_UINT;
UInt AbovePartIdx = MAX_UINT;
Int iLeftIntraDir, iAboveIntraDir;
const TComSPS *sps=getSlice()->getSPS();
const UInt partsPerMinCU = 1<<(2*(sps->getMaxTotalCUDepth() - sps->getLog2DiffMaxMinCodingBlockSize()));
const ChannelType chType = toChannelType(compID);
const ChromaFormat chForm = getPic()->getChromaFormat();
// Get intra direction of left PU
const TComDataCU *pcCULeft = getPULeft( LeftPartIdx, m_absZIdxInCtu + uiAbsPartIdx );
if (isChroma(compID))
{
LeftPartIdx = getChromasCorrespondingPULumaIdx(LeftPartIdx, chForm, partsPerMinCU);
}
// 若左边PU不是Intra块,则赋为DC模式:Any unavailable prediction mode is considered to be Intra_DC.
iLeftIntraDir = pcCULeft ? ( pcCULeft->isIntra( LeftPartIdx ) ? pcCULeft->getIntraDir( chType, LeftPartIdx ) : DC_IDX ) : DC_IDX;
// Get intra direction of above PU
const TComDataCU *pcCUAbove = getPUAbove( AbovePartIdx, m_absZIdxInCtu + uiAbsPartIdx, true, true );
if (isChroma(compID))
{
AbovePartIdx = getChromasCorrespondingPULumaIdx(AbovePartIdx, chForm, partsPerMinCU);
}
// 若上边PU不是Intra块,则赋为DC模式:Any unavailable prediction mode is considered to be Intra_DC.
iAboveIntraDir = pcCUAbove ? ( pcCUAbove->isIntra( AbovePartIdx ) ? pcCUAbove->getIntraDir( chType, AbovePartIdx ) : DC_IDX ) : DC_IDX;
if (isChroma(chType))
{
if (iLeftIntraDir == DM_CHROMA_IDX)
{
iLeftIntraDir = pcCULeft-> getIntraDir( CHANNEL_TYPE_LUMA, LeftPartIdx );
}
if (iAboveIntraDir == DM_CHROMA_IDX)
{
iAboveIntraDir = pcCUAbove->getIntraDir( CHANNEL_TYPE_LUMA, AbovePartIdx );
}
}
assert (2if(iLeftIntraDir == iAboveIntraDir) // 若左边和上边PU的模式相同,MPM数量为1。
{
if( piMode )
{
*piMode = 1;
}
if (iLeftIntraDir > 1) // angular modes
{
uiIntraDirPred[0] = iLeftIntraDir;
uiIntraDirPred[1] = ((iLeftIntraDir + 29) % 32) + 2;
uiIntraDirPred[2] = ((iLeftIntraDir - 1 ) % 32) + 2;
}
else //non-angular
{
uiIntraDirPred[0] = PLANAR_IDX;
uiIntraDirPred[1] = DC_IDX;
uiIntraDirPred[2] = VER_IDX;
}
}
else // 若左边和上边PU的模式不同,MPM数量为2。
{
if( piMode )
{
*piMode = 2;
}
uiIntraDirPred[0] = iLeftIntraDir; // 左边PU的模式作为MPM模式
uiIntraDirPred[1] = iAboveIntraDir; // 上边PU的模式作为MPM模式
if (iLeftIntraDir && iAboveIntraDir ) //both modes are non-planar
{
uiIntraDirPred[2] = PLANAR_IDX;
}
else
{
uiIntraDirPred[2] = (iLeftIntraDir+iAboveIntraDir)<2? VER_IDX : DC_IDX;
}
}
for (UInt i=0; iassert(uiIntraDirPred[i] < 35);
}
}
上面的代码中条件if (isChroma(chType))均不会满足,调用时给的chType均是COMPONENT_Y。