一.帧内预测的亮度模式的熵编码过程
将67种预测模式分为3部分:
a.6种MPM模式;
对于使用6 MPMs选择的模式的熵编码,使用一个截断的一元码。前三个bins用上下文进行编码,上下文取决于与当前正在被发送的bin相关的MPM模式。MPM模式可以被分成3类:(a)水平主导的模式,即MPM模式的编号小于或等于对角方向的模式编号(b)垂直主导的模式,即MPM模式的编号大于对角方向的模式编号,(c)非角度模式。因此,基于此分类使用三种上下文发送MPM索引.
b.选择模式:{0,4,8,12,,,,,,60};
61个non-MPM首先被分成两个集合:一个选择模式集合,一个非选择模式集合。选择模式的集合包含16个模式,剩下的45个模式被分到非选择模式集合。当前模式所属的模式集合用一个flag在比特流中指明。如果要指示的模式是在选择模式集合内,则用4比特的定长码来发送。如果要指示的模式来自非选择模式集合,则用一个截断二元码来发送。
c.非选择模式{1,2,3,5,6,7,,,,,,66};
Void TEncSbac::codeIntraDirLumaAng( TComDataCU* pcCU, UInt absPartIdx, Bool isMultiple
#if VCEG_AZ07_INTRA_65ANG_MODES
, Int* piModes, Int iAboveLeftCase
#endif
)//估计帧内的亮度预测模式
{
UInt dir[4],j;
#if VCEG_AZ07_INTRA_65ANG_MODES
Int preds[4][NUM_MOST_PROBABLE_MODES] = {
{-1, -1, -1, -1, -1, -1},{-1, -1, -1, -1, -1, -1},{-1, -1, -1, -1, -1, -1},{-1, -1, -1, -1, -1, -1}};//为什么有4组
#else
Int preds[4][NUM_MOST_PROBABLE_MODES] = {
{-1, -1, -1},{-1, -1, -1},{-1, -1, -1},{-1, -1, -1}};
#endif
Int predIdx[4] ={ -1,-1,-1,-1};
#if JVET_C0024_QTBT
UInt partNum = 1;
#else
PartSize mode = pcCU->getPartitionSize( absPartIdx );
UInt partNum = isMultiple?(mode==SIZE_NxN?4:1):1;
#endif
UInt partOffset = ( pcCU->getPic()->getNumPartitionsInCtu() >> ( pcCU->getDepth(absPartIdx) << 1 ) ) >> 2;
#if JVET_C0055_INTRA_MPM
static const UInt mpmContext[NUM_INTRA_MODE] = { 1, 1, //DC,planar
#if VCEG_AZ07_INTRA_65ANG_MODES
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // 2-34
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 // 35-66
#else
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // 2-18
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 // 19-35
#endif
};
#elif VCEG_AZ07_INTRA_65ANG_MODES
const UInt uiContextMPM0[4] = { 2, 3, 1, 2 };
const UInt uiContextMPM1[4] = { 4, 5, 5, 6 };
const UInt uiContextMPM2[4] = { 7, 7, 8, 7 };
Int aiCase[4]={0,0,0,0};
#endif
for (j=0;j<partNum;j++)//partNum等于1
{
dir[j] = pcCU->getIntraDir( CHANNEL_TYPE_LUMA, absPartIdx+partOffset*j );//得到帧内亮度分量的预测模式
#if VCEG_AZ07_INTRA_65ANG_MODES
if( piModes )// piModes指向6个MPM
{
assert( !isMultiple );
memcpy( preds[j], piModes, 6*sizeof(Int) );//把piModes指向的MPM复制给preds[0];
#if !JVET_C0055_INTRA_MPM
aiCase[j] = iAboveLeftCase;
#endif
}
else// piModes为空
#endif
pcCU->getIntraDirPredictor(absPartIdx+partOffset*j, preds[j], COMPONENT_Y
#if VCEG_AZ07_INTRA_65ANG_MODES && !JVET_C0055_INTRA_MPM
, aiCase[j]
#endif
);//得到MPMs
for(UInt i = 0; i < NUM_MOST_PROBABLE_MODES; i++)//NUM_MOST_PROBABLE_MODES=6,那就是MPM;
{
if(dir[j] == preds[j][i])//如果预测模式是在MPM中
{
predIdx[j] = i;// predIdx标识为在MPM中的索引
}
}
m_pcBinIf->encodeBin((predIdx[j] != -1)? 1 : 0, m_cCUIntraPredSCModel.get( 0, 0, 0 ) );//编码一个bin表示predIdx[j]!=-1,如果是不等于,则bin为1
}
for (j=0;j<partNum;j++)//partNum
{
if(predIdx[j] != -1)//不等于-1,表明预测模式在MPM候选模式中
{
#if JVET_C0055_INTRA_MPM
m_pcBinIf->encodeBin( predIdx[j] ? 1 : 0, m_cCUIntraPredSCModel.get( 0, 0, mpmContext[preds[j][0]] ) );//编码一个bin指示predIdx是否为0
#elif VCEG_AZ07_INTRA_65ANG_MODES
m_pcBinIf->encodeBin( predIdx[j] ? 1 : 0, m_cCUIntraPredSCModel.get( 0, 0, uiContextMPM0[aiCase[j]] ) );
#else
m_pcBinIf->encodeBinEP( predIdx[j] ? 1 : 0 );
#endif
if (predIdx[j])//如果predIdx>0
{
#if VCEG_AZ07_INTRA_65ANG_MODES
#if JVET_C0055_INTRA_MPM
m_pcBinIf->encodeBin( (predIdx[j]-1) ? 1 : 0, m_cCUIntraPredSCModel.get( 0, 0, mpmContext[preds[j][1]] ) );//编码一个bin指示predIdx是否为1
if ( (predIdx[j]-1) )//predIdx>1
{
m_pcBinIf->encodeBin( (predIdx[j]-2) ? 1 : 0, m_cCUIntraPredSCModel.get( 0, 0, mpmContext[preds[j][2]] ) );//编码一个bin指示predIdx是否为2
#else
m_pcBinIf->encodeBin( (predIdx[j]-1) ? 1 : 0, m_cCUIntraPredSCModel.get( 0, 0, uiContextMPM1[aiCase[j]] ) );
if ( (predIdx[j]-1) )
{
m_pcBinIf->encodeBin( (predIdx[j]-2) ? 1 : 0, m_cCUIntraPredSCModel.get( 0, 0, uiContextMPM2[aiCase[j]] ) );
#endif
if (predIdx[j]-2)//predIdx>2
{
m