感觉在视频编码中熵编码是个很神奇的存在,现在 对这方面还不太懂,先记录一下H266中关于上下文模型的函数。
CABAC中上下文模型中的上下文关系大概可以分为4种情况。
第一种上下文模型根据它相邻的一编码块的语法元素构成,一般是用其左边和上边块的对应语法元素来建立相应的概率模型,对当前语法元素进行模型预测。
第二种上下文模型仅局限于对块类型和子块类型的应用,其中第 n比特的概率模型的选定要参考前面已经编码的n-1 bit所采用的模型;
第三种和第四种上下文模型仅用于残差数据的编码,有依赖于块的类型。其中第三种模型依赖的是带编码系数在扫描路径中的位置。第四种模型则是根据前面已编码系数幅度中某个特定幅度值出现的总次数,来为当前变换系数中的二进制值确定上下文模型。
下面是第一种上下文模型。
UInt TComDataCU::getCtxAffineFlag( UInt uiAbsPartIdx )//得到Affine flag的上下文模型;
{
TComDataCU* pcTempCU;
UInt uiTempPartIdx;
UInt uiCtx = 0;
//得到左相邻CU的affine 标记;
pcTempCU = getPULeft( uiTempPartIdx, m_absZIdxInCtu + uiAbsPartIdx );
uiCtx = ( pcTempCU ) ? pcTempCU->isAffine( uiTempPartIdx ) : 0;
//得到上相邻CU的affine 标记;
pcTempCU = getPUAbove( uiTempPartIdx, m_absZIdxInCtu + uiAbsPartIdx );
uiCtx += ( pcTempCU ) ? pcTempCU->isAffine( uiTempPartIdx ) : 0;
return uiCtx;
}
#if ALF_HM3_REFACTOR
UInt TComDataCU::getCtxAlfCtrlFlag( UInt uiAbsPartIdx )//得到ALF控制 flag的上下文模型
{
TComDataCU* pcTempCU;
UInt uiTempPartIdx;
UInt uiCtx = 0;
// Get BCBP of left PU
pcTempCU = getPULeft( uiTempPartIdx, getZorderIdxInCtu() + uiAbsPartIdx );
uiCtx = ( pcTempCU ) ? pcTempCU->getAlfCtrlFlag( uiTempPartIdx ) : 0;
// Get BCBP of above PU
pcTempCU = getPUAbove( uiTempPartIdx, getZorderIdxInCtu() + uiAbsPartIdx );
uiCtx += ( pcTempCU ) ? pcTempCU->getAlfCtrlFlag( uiTempPartIdx ) : 0;
return uiCtx;
}
#if JVET_C0024_QTBT
UInt TComDataCU::getCtxBTSplitFlag( UInt uiAbsPartIdx, UInt uiWidth, UInt uiHeight )//得到二叉树划分的上下文模型
{
TComDataCU* pcTempCU;
UInt uiTempPartIdx;
UInt uiCtx;
UInt uiTempDepth;
UInt uiCurrDepth = getDepth(uiAbsPartIdx)*2 + getBTDepth(uiAbsPartIdx, uiWidth, uiHeight);
// Get left split flag
pcTempCU = getPULeft( uiTempPartIdx, m_absZIdxInCtu + uiAbsPartIdx );
uiTempDepth = ( pcTempCU ) ? (pcTempCU->getDepth(uiTempPartIdx)*2 + pcTempCU->getBTDepth(uiTempPartIdx)) : 0;
uiCtx = ( pcTempCU ) ? ( uiTempDepth > uiCurrDepth ? 1 : 0 ) : 0;
// Get above split flag
pcTempCU = getPUAbove( uiTempPartIdx, m_absZIdxInCtu + uiAbsPartIdx );
uiTempDepth = ( pcTempCU ) ? (pcTempCU->getDepth(uiTempPartIdx)*2 + pcTempCU->getBTDepth(uiTempPartIdx)) : 0;
uiCtx += ( pcTempCU ) ? ( uiTempDepth > uiCurrDepth ? 1 : 0 ) : 0;
return uiCtx;
}
#endif
UInt TComDataCU::getCtxFRUCME( UInt uiAbsPartIdx )//得到FRUC 运动估计的上下文模型
{
TComDataCU* pcTempCU;
UInt uiTempPartIdx;
UInt uiCtx = 0;
// Get BCBP of left PU
pcTempCU = getPULeft( uiTempPartIdx, m_absZIdxInCtu + uiAbsPartIdx );
uiCtx = ( pcTempCU ) ? pcTempCU->getFRUCMgrMode( uiTempPartIdx ) == FRUC_MERGE_BILATERALMV : 0;
// Get BCBP of above PU
pcTempCU = getPUAbove( uiTempPartIdx, m_absZIdxInCtu + uiAbsPartIdx );
uiCtx += ( pcTempCU ) ? pcTempCU->getFRUCMgrMode( uiTempPartIdx ) == FRUC_MERGE_BILATERALMV : 0;
return( uiCtx );
}
#if VCEG_AZ07_FRUC_MERGE
UInt TComDataCU::getCtxFRUCMgrMode( UInt uiAbsPartIdx )//得到 FRUC merge的上下文模型
{
TComDataCU* pcTempCU;
UInt uiTempPartIdx;
UInt uiCtx = 0;
// Get BCBP of left PU
pcTempCU = getPULeft( uiTempPartIdx, m_absZIdxInCtu+ uiAbsPartIdx );
uiCtx = ( pcTempCU ) ? pcTempCU->getFRUCMgrMode( uiTempPartIdx ) > 0 : 0;
// Get BCBP of above PU
pcTempCU = getPUAbove( uiTempPartIdx, m_absZIdxInCtu + uiAbsPartIdx );
uiCtx += ( pcTempCU ) ? pcTempCU->getFRUCMgrMode( uiTempPartIdx ) > 0 : 0;
return( uiCtx );
}
#if VCEG_AZ07_IMV
UInt TComDataCU::getCtxiMVFlag( UInt uiAbsPartIdx )//得到运动矢量分辨率 flag的上下文模型
{
TComDataCU* pcTempCU;
UInt uiTempPartIdx;
UInt uiCtx = 0;
// Get BCBP of left PU
pcTempCU = getPULeft( uiTempPartIdx, m_absZIdxInCtu + uiAbsPartIdx );
#if JVET_E0076_MULTI_PEL_MVD
uiCtx = ( pcTempCU ) ? (pcTempCU->getiMVFlag( uiTempPartIdx ) ? 1 : 0 ) : 0;
#else
uiCtx = ( pcTempCU ) ? pcTempCU->getiMVFlag( uiTempPartIdx ) : 0;
#endif
// Get BCBP of above PU
pcTempCU = getPUAbove( uiTempPartIdx, m_absZIdxInCtu + uiAbsPartIdx );
#if JVET_E0076_MULTI_PEL_MVD
uiCtx += ( pcTempCU ) ? (pcTempCU->getiMVFlag( uiTempPartIdx ) ? 1 : 0 ) : 0;
#else
uiCtx += ( pcTempCU ) ? pcTempCU->getiMVFlag( uiTempPartIdx ) : 0;
#endif
return uiCtx;
}
UInt TComDataCU::getCtxSkipFlag( UInt uiAbsPartIdx )//得到skip flag的上下文模型
{
TComDataCU* pcTempCU;
UInt uiTempPartIdx;
UInt uiCtx = 0;
// Get BCBP of left PU
pcTempCU = getPULeft( uiTempPartIdx, m_absZIdxInCtu + uiAbsPartIdx );
uiCtx = ( pcTempCU ) ? pcTempCU->isSkipped( uiTempPartIdx ) : 0;
// Get BCBP of above PU
pcTempCU = getPUAbove( uiTempPartIdx, m_absZIdxInCtu + uiAbsPartIdx );
uiCtx += ( pcTempCU ) ? pcTempCU->isSkipped( uiTempPartIdx ) : 0;
return uiCtx;
}
UInt TComDataCU::getCtxSplitFlag( UInt uiAbsPartIdx, UInt uiDepth )//得到四叉树划分 flag的上下文模型
{
TComDataCU* pcTempCU;
UInt uiTempPartIdx;
UInt uiCtx;
// Get left split flag
pcTempCU = getPULeft( uiTempPartIdx, m_absZIdxInCtu + uiAbsPartIdx );
uiCtx = ( pcTempCU ) ? ( ( pcTempCU->getDepth( uiTempPartIdx ) > uiDepth ) ? 1 : 0 ) : 0;
// Get above split flag
pcTempCU = getPUAbove( uiTempPartIdx, m_absZIdxInCtu + uiAbsPartIdx );
uiCtx += ( pcTempCU ) ? ( ( pcTempCU->getDepth( uiTempPartIdx ) > uiDepth ) ? 1 : 0 ) : 0;
#if COM16_C806_LARGE_CTU
UChar ucMinDepth = 0;
#if JVET_C0024_QTBT
UChar ucMaxDepth = g_aucConvertToBit[getSlice()->getSPS()->getCTUSize()]
- g_aucConvertToBit[getSlice()->getSPS()->getMinQTSize(getSlice()->getSliceType(), getTextType())];
#else
UChar ucMaxDepth = ( UChar )( getSlice()->getSPS()->getLog2DiffMaxMinCodingBlockSize() );
#endif
getMaxMinCUDepth( ucMinDepth , ucMaxDepth , uiAbsPartIdx + getZorderIdxInCtu() );
if( uiDepth < ucMinDepth )
{
uiCtx = 3;
}
else if( uiDepth >= ucMaxDepth + 1 )
{
uiCtx = 4;
}
#endif
return uiCtx;
}
还有两种上下文模型暂时还不知道属于哪一种上下文模型:
UInt TComDataCU::getCtxInterDir( UInt uiAbsPartIdx )//帧间模式的上下文模型
{
#if COM16_C806_LARGE_CTU
#if JVET_C0024_QTBT
return( Clip3( 0 , 3 , 5 - ((g_aucConvertToBit[getWidth( uiAbsPartIdx )]+g_aucConvertToBit[getHeight(uiAbsPartIdx)]+1)>>1) ) ); //和普通的得到上下文模型的函数不一样
#else
return( Clip3( 0 , 3 , 4 - g_aucConvertToBit[getWidth( uiAbsPartIdx )] ) );
#endif
#else
return getDepth( uiAbsPartIdx );
#endif
}
UInt TComDataCU::getCtxQtCbf( TComTU &rTu, const ChannelType chType )//变换量化 cbf的上下文模型
{
const UInt transformDepth = rTu.GetTransformDepthRel();
if (isChroma(chType))
{
return transformDepth;
}
else
{
const UInt uiCtx = ( transformDepth == 0 ? 1 : 0 );
return uiCtx;
}
}