HEVC编码时,根据MPM和pu的预测模式来选择使用一个bin还是5个bin编码预测模式索引,若pu的预测模式和mpm中某一模式相同,则编码mpm中的索引,用一个bin。如果pu的预测模式不属于mpm列表中的预测模式,则用5个bin编码该pu的预测模式,这个过程属于熵编码阶段,以HM为例,该过程发生在函数codeIntraDirLumaAng中。
Void TEncSbac::codeIntraDirLumaAng( TComDataCU* pcCU, UInt absPartIdx, Bool isMultiple)
{
UInt dir[4],j;
Int preds[4][NUM_MOST_PROBABLE_MODES] = {{-1, -1, -1},{-1, -1, -1},{-1, -1, -1},{-1, -1, -1}};
Int predIdx[4] ={ -1,-1,-1,-1};
PartSize mode = pcCU->getPartitionSize( absPartIdx ); // PU的划分方式 [wzq 8/24/2020 ]
UInt partNum = isMultiple?(mode==SIZE_NxN?4:1):1;
UInt partOffset = ( pcCU->getPic()->getNumPartitionsInCtu() >> ( pcCU->getDepth(absPartIdx) << 1 ) ) >> 2;
for (j=0;j<partNum;j++)
{
dir[j] = pcCU->getIntraDir( CHANNEL_TYPE_LUMA, absPartIdx+partOffset*j );
pcCU->getIntraDirPredictor(absPartIdx+partOffset*j, preds[j], COMPONENT_Y); // 构造MPM列表 [wzq 8/24/2020 ]
for(UInt i = 0; i < NUM_MOST_PROBABLE_MODES; i++)
{
if(dir[j] == preds[j][i]) // preds[]是构造的3个mpms [wzq 8/24/2020 ]
{
predIdx[j] = i; // predIdx[j]存储预测模式在mpm中的indx, [wzq 9/25/2020 ]
}
}
m_pcBinIf->encodeBin((predIdx[j] != -1)? 1 : 0, m_cCUIntraPredSCModel.get( 0, 0, 0 ) );
}
for (j=0;j<partNum;j++)
{
if(predIdx[j] != -1)
{
m_pcBinIf->encodeBinEP( predIdx[j] ? 1 : 0 );
if (predIdx[j])
{
m_pcBinIf->encodeBinEP( predIdx[j]-1 ); // 编码预测模式在mpm中的indx,用一个bin [wzq 9/25/2020 ]
}
}
else // 预测模式不属于mpm中的任一个 [wzq 9/25/2020 ]
{
if (preds[j][0] > preds[j][1])
{
std::swap(preds[j][0], preds[j][1]);
}
if (preds[j][0] > preds[j][2])
{
std::swap(preds[j][0], preds[j][2]);
}
if (preds[j][1] > preds[j][2])
{
std::swap(preds[j][1], preds[j][2]);
}
for(Int i = (Int(NUM_MOST_PROBABLE_MODES) - 1); i >= 0; i--)
{
dir[j] = dir[j] > preds[j][i] ? dir[j] - 1 : dir[j];
}
m_pcBinIf->encodeBinsEP( dir[j], 5 ); // 用5bin编码预测模式的indx [wzq 9/25/2020 ]
}
}
return;
}
在SVT-HEVC中,该过程发生在函数EncodeIntraLumaModeSecondStage中
static void EncodeIntraLumaModeSecondStage(
CabacEncodeContext_t *cabacEncodeCtxPtr,
EB_U8 leftNeighborMode,
EB_U8 topNeighborMode,
EB_U32 lumaMode)
{
EB_S32 predictionIndex;
EB_U32 lumaPredictionArray[3];
if (leftNeighborMode == topNeighborMode) {
if (leftNeighborMode > 1) { // For angular modes
lumaPredictionArray[0] = leftNeighborMode;
lumaPredictionArray[1] = ((leftNeighborMode + 29) & 0x1F) + 2;
lumaPredictionArray[2] = ((leftNeighborMode - 1) & 0x1F) + 2;
}
else { // Non Angular modes
lumaPredictionArray[0] = EB_INTRA_PLANAR;
lumaPredictionArray[1] = EB_INTRA_DC;
lumaPredictionArray[2] = EB_INTRA_VERTICAL;
}
}
else {
lumaPredictionArray[0] = leftNeighborMode;
lumaPredictionArray[1] = topNeighborMode;
if (leftNeighborMode && topNeighborMode) {
lumaPredictionArray[2] = EB_INTRA_PLANAR; // when both modes are non planar
}
else {
lumaPredictionArray[2] = (leftNeighborMode + topNeighborMode) < 2 ? EB_INTRA_VERTICAL : EB_INTRA_DC;
}
}
predictionIndex = (lumaMode == lumaPredictionArray[0]) ? 0 :
(lumaMode == lumaPredictionArray[1]) ? 1 :
(lumaMode == lumaPredictionArray[2]) ? 2 :
-1; // luma mode is not equal to any of the predictors
if (predictionIndex != -1)
{
EncodeBypassOneBin(&(cabacEncodeCtxPtr->bacEncContext),predictionIndex ? 1 : 0);
if (predictionIndex)
{
EncodeBypassOneBin(&(cabacEncodeCtxPtr->bacEncContext),predictionIndex - 1);
}
}
else
{
if (lumaPredictionArray[0] > lumaPredictionArray[1])
{
SWAP(lumaPredictionArray[0], lumaPredictionArray[1]);
}
if (lumaPredictionArray[0] > lumaPredictionArray[2])
{
SWAP(lumaPredictionArray[0], lumaPredictionArray[2]);
}
if (lumaPredictionArray[1] > lumaPredictionArray[2])
{
SWAP(lumaPredictionArray[1], lumaPredictionArray[2]);
}
lumaMode =
(lumaMode > lumaPredictionArray[2]) ? lumaMode - 1 :
lumaMode;
lumaMode =
(lumaMode > lumaPredictionArray[1]) ? lumaMode - 1 :
lumaMode;
lumaMode =
(lumaMode > lumaPredictionArray[0]) ? lumaMode - 1 :
lumaMode;
EncodeBypassBins( &(cabacEncodeCtxPtr->bacEncContext),lumaMode,5);
}
}