从本篇开始,接下来的若干篇会逐步分析HM 9.1中有关熵编码的过程。在此以及以后的几篇,我都默认大家对熵编码(针对CABAC,因为HEVC只有这一种编码方式,而H.264有CAVLC和CABAC两种)的基本概念和流程有了一定的基础,同时,由于HEVC中的CABAC基本流程与H.264中的基本一致,因此,这里暂时不会介绍熵编码框架和流程,有兴趣的可以参考H.264中的相关资料。我会按照编码的执行顺序逐步地分析代码,到最后会再给出总结。
本文首先介绍编码器的初始化过程,即draft 9.3.4.1的部分。
在Void TEncSlice::compressSlice( TComPic*& rpcPic )有这么一段:
// set entropy coder
if( m_pcCfg->getUseSBACRD() ) //!< 默认条件下m_bUseSBACRD为true //!< draft 9.3.4.1
{
m_pcSbacCoder->init( m_pcBinCABAC );
m_pcEntropyCoder->setEntropyCoder ( m_pcSbacCoder, pcSlice );
m_pcEntropyCoder->resetEntropy (); //!< 主要进行上下文模型的初始化,codILow和codIRange的初始化等
m_pppcRDSbacCoder[0][CI_CURR_BEST]->load(m_pcSbacCoder);
pppcRDSbacCoder = (TEncBinCABAC *) m_pppcRDSbacCoder[0][CI_CURR_BEST]->getEncBinIf();
pppcRDSbacCoder->setBinCountingEnableFlag( false );
pppcRDSbacCoder->setBinsCoded( 0 );
}
重点看m_pcEntropyCoder->resetEntropy ();
该函数中调用的initBuffer功能即是对相应的context变量进行初始化,这个可参考draft 9.3.1.1的相关内容。
Void TEncSbac::resetEntropy ()
{
Int iQp = m_pcSlice->getSliceQp();
SliceType eSliceType = m_pcSlice->getSliceType();
Int encCABACTableIdx = m_pcSlice->getPPS()->getEncCABACTableIdx();
if (!m_pcSlice->isIntra() && (encCABACTableIdx==B_SLICE || encCABACTableIdx==P_SLICE) && m_pcSlice->getPPS()->getCabacInitPresentFlag())
{
eSliceType = (SliceType) encCABACTableIdx;
}
//! draft 9.3.1.1 Initialization process for context variables
m_cCUSplitFlagSCModel.initBuffer ( eSliceType, iQp, (UChar*)INIT_SPLIT_FLAG );
m_cCUSkipFlagSCModel.initBuffer ( eSliceType, iQp, (UChar*)INIT_SKIP_FLAG );
m_cCUMergeFlagExtSCModel.initBuffer ( eSliceType,