HM编码器代码阅读(22)——cabac的流程

熵编码初始化

cavlc(变长码)在HEVC中的实现比较简单,这里就主要说cabac在HEVC中的实现

初始化函数:TEncSbac::resetEntropy:

这个函数的实质就是初始化各种上下文

// 重置熵编码器
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;
	}

	// 初始化各个模型的缓存

	// split标志的上下文
	m_cCUSplitFlagSCModel.initBuffer       ( eSliceType, iQp, (UChar*)INIT_SPLIT_FLAG );

	// skip标志的上下文
	m_cCUSkipFlagSCModel.initBuffer        ( eSliceType, iQp, (UChar*)INIT_SKIP_FLAG );

	// merge标志上下文
	m_cCUMergeFlagExtSCModel.initBuffer    ( eSliceType, iQp, (UChar*)INIT_MERGE_FLAG_EXT);

	// merge索引上下文
	m_cCUMergeIdxExtSCModel.initBuffer     ( eSliceType, iQp, (UChar*)INIT_MERGE_IDX_EXT);

	// partsize上下文
	m_cCUPartSizeSCModel.initBuffer        ( eSliceType, iQp, (UChar*)INIT_PART_SIZE );

	// 预测上下文
	m_cCUPredModeSCModel.initBuffer        ( eSliceType, iQp, (UChar*)INIT_PRED_MODE );

	// 帧内预测上下文
	m_cCUIntraPredSCModel.initBuffer       ( eSliceType, iQp, (UChar*)INIT_INTRA_PRED_MODE );

	// 色度预测上下文
	m_cCUChromaPredSCModel.initBuffer      ( eSliceType, iQp, (UChar*)INIT_CHROMA_PRED_MODE );

	// 帧间预测角度上下文
	m_cCUInterDirSCModel.initBuffer        ( eSliceType, iQp, (UChar*)INIT_INTER_DIR );

	// MV残差上下文
	m_cCUMvdSCModel.initBuffer             ( eSliceType, iQp, (UChar*)INIT_MVD );

	// 参考帧上下文
	m_cCURefPicSCModel.initBuffer          ( eSliceType, iQp, (UChar*)INIT_REF_PIC );

	// 量化步长上下文
	m_cCUDeltaQpSCModel.initBuffer         ( eSliceType, iQp, (UChar*)INIT_DQP );

	// CBF上下文
	m_cCUQtCbfSCModel.initBuffer           ( eSliceType, iQp, (UChar*)INIT_QT_CBF );

	// 四叉树根的CBF上下文
	m_cCUQtRootCbfSCModel.initBuffer       ( eSliceType, iQp, (UChar*)INIT_QT_ROOT_CBF );

	// 系数的符号上下文
	m_cCUSigCoeffGroupSCModel.initBuffer   ( eSliceType, iQp, (UChar*)INIT_SIG_CG_FLAG );

	// 符号上下文
	m_cCUSigSCModel.initBuffer             ( eSliceType, iQp, (UChar*)INIT_SIG_FLAG );

	// 最后一个X上下文
	m_cCuCtxLastX.initBuffer               ( eSliceType, iQp, (UChar*)INIT_LAST );

	// 最后一个Y上下文
	m_cCuCtxLastY.initBuffer               ( eSliceType, iQp, (UChar*)INIT_LAST );
	m_cCUOneSCModel.initBuffer             ( eSliceType, iQp, (UChar*)INIT_ONE_FLAG );

	// CU绝对索引?上下文
	m_cCUAbsSCModel.initBuffer             ( eSliceType, iQp, (UChar*)INIT_ABS_FLAG );

	// MVP索引上下文
	m_cMVPIdxSCModel.initBuffer            ( eSliceType, iQp, (UChar*)INIT_MVP_IDX );

	// TU划分标志上下文
	m_cCUTransSubdivFlagSCModel.initBuffer ( eSliceType, iQp, (UChar*)INIT_TRANS_SUBDIV_FLAG );

	// SAO merge上下文
	m_cSaoMergeSCModel.initBuffer      ( eSliceType, iQp, (UChar*)INIT_SAO_MERGE_FLAG );

	// SAO类型索引上下文
	m_cSaoTypeIdxSCModel.initBuffer        ( eSliceType, iQp, (UChar*)INIT_SAO_TYPE_IDX );

	// 变换skip标志上下文
	m_cTransformSkipSCModel.initBuffer     ( eSliceType, iQp, (UChar*)INIT_TRANSFORMSKIP_FLAG );

	// 变换量化bypass标志上下文
	m_CUTransquantBypassFlagSCModel.initBuffer( eSliceType, iQp, (UChar*)INIT_CU_TRANSQUANT_BYPASS_FLAG );
	// new structure
	m_uiLastQp = iQp;

	// 二值化的一些操作
	m_pcBinIf->start();

	return;
}
Void TEncBinCABAC::start()
{
	m_uiLow            = 0;				// 下限(进行二值化的时候)
	m_uiRange          = 510;		// 范围(进行二值化的时候)
	m_bitsLeft         = 23;
	m_numBufferedBytes = 0;
	m_bufferedByte     = 0xff;
}
工程中预定义了一些初始的上下文模型,预定义的各个上下模型实际就是一些二维数组:

// 上下文模型的数量
#define MAX_NUM_CTX_MOD             512       ///< maximum number of supported contexts

// 上下文split标志的数量
#define NUM_SPLIT_FLAG_CTX            3       ///< number of context models for split flag
// 上下文skip标志的数量
#define NUM_SKIP_FLAG_CTX             3       ///< number of context models for skip flag

// 上下文merge扩展中merge标志的数量
#define NUM_MERGE_FLAG_EXT_CTX        1       ///< number of context models for merge flag of merge extended
// 上下文merge扩展中merge index的数量
#define NUM_MERGE_IDX_EXT_CTX         1       ///< number of context models for merge index of merge extended

// partition的类型
#define NUM_PART_SIZE_CTX             4       ///< number of context models for partition size
// 预测的类型
#define NUM_PRED_MODE_CTX             1       ///< number of context models for prediction mode

// 帧内预测的数量
#define NUM_ADI_CTX                   1       ///< number of context models for intra prediction

// 色度帧内预测的数量
#define NUM_CHROMA_PRED_CTX           2       ///< number of context models for intra prediction (chroma)
// 用于帧间预测的上下文模型的数量
#define NUM_INTER_DIR_CTX             5       ///< number of context models for inter prediction direction
// 用于MV的上下文模型的数量
#define NUM_MV_RES_CTX                2       ///< number of context models for motion vector difference
// 用于参考索引的上下文模型的数量
#define NUM_REF_NO_CTX                2       ///< number of context models for reference index
// 用于变换切分的的上下文模型的数量
#define NUM_TRANS_SUBDIV_FLAG_CTX     3       ///< number of context models for transform subdivision flags
// 用于量化树的CBF的上下文模型的数量
#define NUM_QT_CBF_CTX                4       ///< number of context models for QT CBF
// 用于量化树根的CBF的上下文模型的数量
#define NUM_QT_ROOT_CBF_CTX           1       ///< number of context models for QT ROOT CBF
// 用于dQP的上下文模型的数量
#define NUM_DELTA_QP_CTX              3       ///< number of context models for dQP

//
#define NUM_SIG_CG_FLAG_CTX           2       ///< number of context models for MULTI_LEVEL_SIGNIFICANCE
// 用于符号(正负号)标志的上下文模型的数量
#define NUM_SIG_FLAG_CTX              42      ///< number of context models for sig flag
// 用于亮度符号标志的上下文模型的数量
#define NUM_SIG_FLAG_CTX_LUMA         27      ///< number of context models for luma sig flag
// 用于色度符号标志的上下文模型的数量
#define NUM_SIG_FLAG_CTX_CHROMA       15      ///< number of context models for chroma sig flag

// 用于 最后一个系数 的上下文模型的数量
#define NUM_CTX_LAST_FLAG_XY          15      ///< number of context models for last coefficient position

#define NUM_ONE_FLAG_CTX              24      ///< number of context models for greater than 1 flag
#define NUM_ONE_FLAG_CTX_LUMA         16      ///< number of context models for greater than 1 flag of luma
#define NUM_ONE_FLAG_CTX_CHROMA        8      ///< number of context models for greater than 1 flag of chroma
#define NUM_ABS_FLAG_CTX               6      ///< number of context models for greater than 2 flag
#define NUM_ABS_FLAG_CTX_LUMA          4      ///< number of context models for greater than 2 flag of luma
#define NUM_ABS_FLAG_CTX_CHROMA        2      ///< number of context models for greater than 2 flag of chroma

// 用于MVP索引的上下文模型的数量
#define NUM_MVP_IDX_CTX               1       ///< number of context models for MVP index

// 用于SAO merge的上下文模型的数量
#define NUM_SAO_MERGE_FLAG_CTX        1       ///< number of context models for SAO merge flags
// 用于SAO 类型索引的上下文模型的数量
#define NUM_SAO_TYPE_IDX_CTX          1       ///< number of context models for SAO type index

// 用于变换skip的上下文模型的数量
#define NUM_TRANSFORMSKIP_FLAG_CTX    1       ///< number of context models for transform skipping 
#define NUM_CU_TRANSQUANT_BYPASS_FLAG_CTX  1 
#define CNU                          154      ///< dummy initialization value for unused context models 'Context model Not Used'

// ====================================================================================================================
// Tables
// ====================================================================================================================

// initial probability for cu_transquant_bypass flag
// cu_transquant_bypass标志的上下文模型
static const UChar
	INIT_CU_TRANSQUANT_BYPASS_FLAG[3][NUM_CU_TRANSQUANT_BYPASS_FLAG_CTX] =
{
	{ 154 }, 
	{ 154 }, 
	{ 154 }, 
};

// initial probability for split flag
// split标志的上下文模型
static const UChar 
	INIT_SPLIT_FLAG[3][NUM_SPLIT_FLAG_CTX] =  
{
	{ 107,  139,  126, },
	{ 107,  139,  126, }, 
	{ 139,  141,  157, }, 
};

// skip标志的上下文模型
static const UChar 
	INIT_SKIP_FLAG[3][NUM_SKIP_FLAG_CTX] =  
{
	{ 197,  185,  201, }, 
	{ 197,  185,  201, }, 
	{ CNU,  CNU,  CNU, }, 
};

// merge模式的标志的上下文
static const UChar
	INIT_MERGE_FLAG_EXT[3][NUM_MERGE_FLAG_EXT_CTX] = 
{
	{ 154, }, 
	{ 110, }, 
	{ CNU, }, 
};

// merge模式的索引的上下文
static const UChar 
	INIT_MERGE_IDX_EXT[3][NUM_MERGE_IDX_EXT_CTX] =  
{
	{ 137, }, 
	{ 122, }, 
	{ CNU, }, 
};

// part_size的上下文
static const UChar 
	INIT_PART_SIZE[3][NUM_PART_SIZE_CTX] =  
{
	{ 154,  139,  154,  154 },
	{ 154,  139,  154,  154 },
	{ 184,  CNU,  CNU,  CNU },
};

// 预测模式的上下文
static const UChar
	INIT_PRED_MODE[3][NUM_PRED_MODE_CTX] = 
{
	{ 134, }, 
	{ 149, }, 
	{ CNU, }, 
};

// 帧内预测的模式(亮度)的上下文
static const UChar 
	INIT_INTRA_PRED_MODE[3][NUM_ADI_CTX] = 
{
	{ 183, }, 
	{ 154, }, 
	{ 184, }, 
};

// 帧内预测的模式(色度)的上下文
static const UChar 
	INIT_CHROMA_PRED_MODE[3][NUM_CHROMA_PRED_CTX] = 
{
	{ 152,  139, }, 
	{ 152,  139, }, 
	{  63,  139, }, 
};

// 帧间预测方向(前后两个方向)
static const UChar 
	INIT_INTER_DIR[3][NUM_INTER_DIR_CTX] = 
{
	{  95,   79,   63,   31,  31, }, 
	{  95,   79,   63,   31,  31, }, 
	{ CNU,  CNU,  CNU,  CNU, CNU, }, 
};

// MV残差上下文
static const UChar 
	INIT_MVD[3][NUM_MV_RES_CTX] =  
{
	{ 169,  198, }, 
	{ 140,  198, }, 
	{ CNU,  CNU, }, 
};

// 参考帧上下文
static const UChar 
	INIT_REF_PIC[3][NUM_REF_NO_CTX] =  
{
	{ 153,  153 }, 
	{ 153,  153 }, 
	{ CNU,  CNU }, 
};

// dQP
// 量化步长上下文
static const UChar 
	INIT_DQP[3][NUM_DELTA_QP_CTX] = 
{
	{ 154,  154,  154, }, 
	{ 154,  154,  154, }, 
	{ 154,  154,  154, }, 
};

// CBF(编码块标志)上下文
static const UChar 
	INIT_QT_CBF[3][2*NUM_QT_CBF_CTX] =  
{
	{ 153,  111,  CNU,  CNU,   149,   92,  167,  154 },
	{ 153,  111,  CNU,  CNU,   149,  107,  167,  154 },
	{ 111,  141,  CNU,  CNU,    94,  138,  182,  154 },
};

static const UChar 
	INIT_QT_ROOT_CBF[3][NUM_QT_ROOT_CBF_CTX] = 
{
	{  79, }, 
	{  79, }, 
	{ CNU, }, 
};

// 最后一个系数的位置
static const UChar 
	INIT_LAST[3][2*NUM_CTX_LAST_FLAG_XY] =  
{
	{ 125,  110,  124,  110,   95,   94,  125,  111,  111,   79,  125,  126,  111,  111,   79,
	108,  123,   93,  CNU,  CNU,  CNU,  CNU,  CNU,  CNU,  CNU,  CNU,  CNU,  CNU,  CNU,  CNU, 
	}, 
	{ 125,  110,   94,  110,   95,   79,  125,  111,  110,   78,  110,  111,  111,   95,   94,
	108,  123,  108,  CNU,  CNU,  CNU,  CNU,  CNU,  CNU,  CNU,  CNU,  CNU,  CNU,  CNU,  CNU,
	}, 
	{ 110,  110,  124,  125,  140,  153,  125,  127,  140,  109,  111,  143,  127,  111,   79, 
	108,  123,   63,  CNU,  CNU,  CNU,  CNU,  CNU,  CNU,  CNU,  CNU,  CNU,  CNU,  CNU,  CNU, 
	}, 
};

static const UChar 
	INIT_SIG_CG_FLAG[3][2 * NUM_SIG_CG_FLAG_CTX] =  
{
	{ 121,  140,  
	61,  154, 
	}, 
	{ 121,  140, 
	61,  154, 
	}, 
	{  91,  171,  
	134,  141, 
	}, 
};

// 整数符号的标志
static const UChar 
	INIT_SIG_FLAG[3][NUM_SIG_FLAG_CTX] = 
{
	{ 170,  154,  139,  153,  139,  123,  123,   63,  124,  166,  183,  140,  136,  153,  154,  166,  183,  140,  136,  153,  154,  166,  183,  140,  136,  153,  154,  170,  153,  138,  138,  122,  121,  122,  121,  167,  151,  183,  140,  151,  183,  140,  }, 
	{ 155,  154,  139,  153,  139,  123,  123,   63,  153,  166,  183,  140,  136,  153,  154,  166,  183,  140,  136,  153,  154,  166,  183,  140,  136,  153,  154,  170,  153,  123,  123,  107,  121,  107,  121,  167,  151,  183,  140,  151,  183,  140,  }, 
	{ 111,  111,  125,  110,  110,   94,  124,  108,  124,  107,  125,  141,  179,  153,  125,  107,  125,  141,  179,  153,  125,  107,  125,  141,  179,  153,  125,  140,  139,  182,  182,  152,  136,  152,  136,  153,  136,  139,  111,  136,  139,  111,  }, 
};

// 1标志上下文
static const UChar 
	INIT_ONE_FLAG[3][NUM_ONE_FLAG_CTX] = 
{
	{ 154,  196,  167,  167,  154,  152,  167,  182,  182,  134,  149,  136,  153,  121,  136,  122,  169,  208,  166,  167,  154,  152,  167,  182, }, 
	{ 154,  196,  196,  167,  154,  152,  167,  182,  182,  134,  149,  136,  153,  121,  136,  137,  169,  194,  166,  167,  154,  167,  137,  182, }, 
	{ 140,   92,  137,  138,  140,  152,  138,  139,  153,   74,  149,   92,  139,  107,  122,  152,  140,  179,  166,  182,  140,  227,  122,  197, }, 
};

// 帧内预测索引
static const UChar 
	INIT_ABS_FLAG[3][NUM_ABS_FLAG_CTX] =  
{
	{ 107,  167,   91,  107,  107,  167, }, 
	{ 107,  167,   91,  122,  107,  167, }, 
	{ 138,  153,  136,  167,  152,  152, }, 
};

// MVP索引
static const UChar 
	INIT_MVP_IDX[3][NUM_MVP_IDX_CTX] =  
{
	{ 168 },
	{ 168 },
	{ CNU }, 
};

// SAO merge标志
static const UChar 
	INIT_SAO_MERGE_FLAG[3][NUM_SAO_MERGE_FLAG_CTX] = 
{
	{ 153,  }, 
	{ 153,  }, 
	{ 153,  }, 
};

// SAO 类型索引
static const UChar 
	INIT_SAO_TYPE_IDX[3][NUM_SAO_TYPE_IDX_CTX] = 
{
	{ 160, },
	{ 185, },
	{ 200, },
};

// 变换分割标志
static const UChar
	INIT_TRANS_SUBDIV_FLAG[3][NUM_TRANS_SUBDIV_FLAG_CTX] =
{
	{ 224,  167,  122, },
	{ 124,  138,   94, },
	{ 153,  138,  138, },
};

// 变换skip标志
static const UChar
	INIT_TRANSFORMSKIP_FLAG[3][2*NUM_TRANSFORMSKIP_FLAG_CTX] = 
{
	{ 139,  139}, 
	{ 139,  139}, 
	{ 139,  139}, 
};
//! \}
上下文模型在工程中是ContextModel3DBuffer类型,为了弄清楚这个结构,我们先看TEncSbac的构造函数:

TEncSbac::TEncSbac()
	// new structure here
	: m_pcBitIf                   ( NULL )
	, m_pcSlice                   ( NULL )
	, m_pcBinIf                   ( NULL )
	, m_uiCoeffCost               ( 0 )
	, m_numContextModels          ( 0 )		//context model的计数值,接下来的所有除了assert的语句都是对句法元素对应的context进行初始化 
	, m_cCUSplitFlagSCModel       ( 1,             1,               NUM_SPLIT_FLAG_CTX            , m_contextModels + m_numContextModels, m_numContextModels )
	, m_cCUSkipFlagSCModel        ( 1,             1,               NUM_SKIP_FLAG_CTX             , m_contextModels + m_numContextModels, m_numContextModels)
	, m_cCUMergeFlagExtSCModel    ( 1,             1,               NUM_MERGE_FLAG_EXT_CTX        , m_contextModels + m_numContextModels, m_numContextModels)
	, m_cCUMergeIdxExtSCModel     ( 1,             1,               NUM_MERGE_IDX_EXT_CTX         , m_contextModels + m_numContextModels, m_numContextModels)
	, m_cCUPartSizeSCModel        ( 1,             1,               NUM_PART_SIZE_CTX             , m_contextModels + m_numContextModels, m_numContextModels)
	, m_cCUPredModeSCModel        ( 1,             1,               NUM_PRED_MODE_CTX             , m_contextModels + m_numContextModels, m_numContextModels)
	, m_cCUIntraPredSCModel       ( 1,             1,               NUM_ADI_CTX                   , m_contextModels + m_numContextModels, m_numContextModels)
	, m_cCUChromaPredSCModel      ( 1,             1,               NUM_CHROMA_PRED_CTX           , m_contextModels + m_numContextModels, m_numContextModels)
	, m_cCUDeltaQpSCModel         ( 1,             1,               NUM_DELTA_QP_CTX              , m_contextModels + m_numContextModels, m_numContextModels)
	, m_cCUInterDirSCModel        ( 1,             1,               NUM_INTER_DIR_CTX             , m_contextModels + m_numContextModels, m_numContextModels)
	, m_cCURefPicSCModel          ( 1,             1,               NUM_REF_NO_CTX                , m_contextModels + m_numContextModels, m_numContextModels)
	, m_cCUMvdSCModel             ( 1,             1,               NUM_MV_RES_CTX                , m_contextModels + m_numContextModels, m_numContextModels)
	, m_cCUQtCbfSCModel           ( 1,             2,               NUM_QT_CBF_CTX                , m_contextModels + m_numContextModels, m_numContextModels)
	, m_cCUTransSubdivFlagSCModel ( 1,             1,               NUM_TRANS_SUBDIV_FLAG_CTX     , m_contextModels + m_numContextModels, m_numContextModels)
	, m_cCUQtRootCbfSCModel       ( 1,             1,               NUM_QT_ROOT_CBF_CTX           , m_contextModels + m_numContextModels, m_numContextModels)
	, m_cCUSigCoeffGroupSCModel   ( 1,             2,               NUM_SIG_CG_FLAG_CTX           , m_contextModels + m_numContextModels, m_numContextModels)
	, m_cCUSigSCModel             ( 1,             1,               NUM_SIG_FLAG_CTX              , m_contextModels + m_numContextModels, m_numContextModels)
	, m_cCuCtxLastX               ( 1,             2,               NUM_CTX_LAST_FLAG_XY          , m_contextModels + m_numContextModels, m_numContextModels)
	, m_cCuCtxLastY               ( 1,             2,               NUM_CTX_LAST_FLAG_XY          , m_contextModels + m_numContextModels, m_numContextModels)
	, m_cCUOneSCModel             ( 1,             1,               NUM_ONE_FLAG_CTX              , m_contextModels + m_numContextModels, m_numContextModels)
	, m_cCUAbsSCModel             ( 1,             1,               NUM_ABS_FLAG_CTX              , m_contextModels + m_numContextModels, m_numContextModels)
	, m_cMVPIdxSCModel            ( 1,             1,               NUM_MVP_IDX_CTX               , m_contextModels + m_numContextModels, m_numContextModels)
	, m_cSaoMergeSCModel          ( 1,             1,               NUM_SAO_MERGE_FLAG_CTX   , m_contextModels + m_numContextModels, m_numContextModels)
	, m_cSaoTypeIdxSCModel        ( 1,             1,               NUM_SAO_TYPE_IDX_CTX          , m_contextModels + m_numContextModels, m_numContextModels)
	, m_cTransformSkipSCModel     ( 1,             2,               NUM_TRANSFORMSKIP_FLAG_CTX    , m_contextModels + m_numContextModels, m_numContextModels)
	, m_CUTransquantBypassFlagSCModel( 1,          1,               NUM_CU_TRANSQUANT_BYPASS_FLAG_CTX, m_contextModels + m_numContextModels, m_numContextModels)
{
	assert( m_numContextModels <= MAX_NUM_CTX_MOD );
}
可以看到TEncSbac的构造函数调用的都是ContextModel3DBuffer的构造函数,ContextModel3DBuffer的构造函数定义如下:

ContextModel3DBuffer::ContextModel3DBuffer( UInt uiSizeZ, UInt uiSizeY, UInt uiSizeX, ContextModel *basePtr, Int &count )
	: m_sizeX  ( uiSizeX )
	, m_sizeXY ( uiSizeX * uiSizeY )
	, m_sizeXYZ( uiSizeX * uiSizeY * uiSizeZ )
{
	// allocate 3D buffer
	m_contextModel = basePtr;		//  m_contextModel由basePtr赋值,即指向指定的context的内存区
	count += m_sizeXYZ;				// count记录的是到目前为止所有context的尺寸
}
结合ContextModel3DBuffer和TEncSbac的构造函数可以看到,实际的上下文数据都存放在ContextModel中(或者ContextModel类型的指针指向的内存中),ContextModel3DBuffer只是一个便于访问的接口类。

上下文模型内容初始化的函数ContextModel3DBuffer::initBuffer定义如下:

Void ContextModel3DBuffer::initBuffer( SliceType sliceType, Int qp, UChar* ctxModel )
{ 
	ctxModel += sliceType * m_sizeXYZ;   // 根据当前slice的类型(I,P,B)选择对应的context,为什么这么做,下面会解释 
	// 根据sliceType计算initType并将context指针移动到正确的位置上,这个initType用于索引context model,且由slice_type来决定

	for ( Int n = 0; n < m_sizeXYZ; n++ )
	{
		m_contextModel[ n ].init( qp, ctxModel[ n ] );		// 完成context的各个状态变量的初始化工作
		m_contextModel[ n ].setBinsCoded( 0 );
	}
}
Void ContextModel::init( Int qp, Int initValue )
{
    // 选取中间值
	qp = Clip3(0, 51, qp);

	// 上下文模型初始化
	Int  slope      = (initValue>>4)*5 - 45;			// m
	Int  offset     = ((initValue&15)<<3)-16;		// n
	Int  initState  =  min( max( 1, ( ( ( slope * qp ) >> 4 ) + offset ) ), 126 );		// preCtxState  
	UInt mpState    = (initState >= 64 );				// MPS  
	m_ucState       = ( (mpState? (initState - 64):(63 - initState)) <<1) + mpState;		
}

熵编码以及上下文模型的更新

在HEVC中,熵编码分为常规编码和旁路编码,常规编码就是我们常见的自适应上下文模型算数编码,旁路编码是一种等概率的算数编码

常规编码

以预测模式(PredMode)这个语法元素的编码为例子:

/*
** 编码预测模式
*/
Void TEncSbac::codePredMode( TComDataCU* pcCU, UInt uiAbsPartIdx )
{
	// get context function is here
	// 得到预测的模式
	Int iPredMode = pcCU->getPredictionMode( uiAbsPartIdx );
	// 进行熵编码,然后上下文更新
	m_pcBinIf->encodeBin( iPredMode == MODE_INTER ? 0 : 1, m_cCUPredModeSCModel.get( 0, 0, 0 ) );
}
核心函数只有一个:

/*
** cabac熵编码的核心,编码一个比特位!
** 1、把该比特对应的上下文模型设置为已经编码
** 2、计算LPS
** 3、计算新的范围
** 4、根据比特值和MPS是否相等,来更新上下文模式
*/
Void TEncBinCABAC::encodeBin( UInt binValue, ContextModel &rcCtxModel )
{
	// 调试的打印信息
	{
		DTRACE_CABAC_VL( g_nSymbolCounter++ )
			DTRACE_CABAC_T( "\tstate=" )
			DTRACE_CABAC_V( ( rcCtxModel.getState() << 1 ) + rcCtxModel.getMps() )
			DTRACE_CABAC_T( "\tsymbol=" )
			DTRACE_CABAC_V( binValue )
			DTRACE_CABAC_T( "\n" )
	}
	m_uiBinsCoded += m_binCountIncrement;

	// 设置已经编码的标志
	rcCtxModel.setBinsCoded( 1 );

	// LPS
	UInt  uiLPS   = TComCABACTables::sm_aucLPSTable[ rcCtxModel.getState() ][ ( m_uiRange >> 6 ) & 3 ];

	// range
	m_uiRange    -= uiLPS;

	// 判断binValue是否等于MPS
	if( binValue != rcCtxModel.getMps() )		// binVal != valMPS,概率索引值将减小,即LPS的概率增大
	{
		Int numBits = TComCABACTables::sm_aucRenormTable[ uiLPS >> 3 ];		// RenormE 
		m_uiLow     = ( m_uiLow + m_uiRange ) << numBits;		// codILow = codILow + codIRange
		m_uiRange   = uiLPS << numBits;									// codIRange = codIRangeLPS

		// 更新LPS
		rcCtxModel.updateLPS();													// pStateIdx = transIdxLPS[pStateIdx] 
			
		// 这是存放剩余比特的地方还是存放编码后数据的地方?????
		m_bitsLeft -= numBits;  
	}
	else// binVal == valMPS,概率索引值将增大,即LPS的概率减小
	{
		// 更新MPS
		rcCtxModel.updateMPS();			// pStateIdx = transIdxLPS[pStateIdx] 
		if ( m_uiRange >= 256 )
		{
			return;
		}

		m_uiLow <<= 1;
		m_uiRange <<= 1;
		m_bitsLeft--;
	}

	// 尝试写到比特流中,先判断当前缓冲区中的空闲空间是否足够,不足的话就写到比特流中,腾出空间
	testAndWriteOut();
}

旁路编码

盘路编码无需对概率进行自适应更新,而是采用0和1概率各占1/2的固定概率进行编码。以SAO的边带信息编码为例:

Void TEncSbac::codeSaoUflc       ( UInt uiLength, UInt uiCode )
{
	m_pcBinIf->encodeBinsEP ( uiCode, uiLength );
}
核心函数有两个:

/*
** 等概率熵编码(不是cabac编码)
** 某些特殊的地方会用到它
** EP即equiprobable,表示等概率
*/
Void TEncBinCABAC::encodeBinEP( UInt binValue )
{
	{
		DTRACE_CABAC_VL( g_nSymbolCounter++ )
			DTRACE_CABAC_T( "\tEPsymbol=" )
			DTRACE_CABAC_V( binValue )
			DTRACE_CABAC_T( "\n" )
	}
	m_uiBinsCoded += m_binCountIncrement;
	m_uiLow <<= 1;
	if( binValue )
	{
		m_uiLow += m_uiRange;
	}
	m_bitsLeft--;

	testAndWriteOut();
}

/*
** 等概率熵编码
*/
Void TEncBinCABAC::encodeBinsEP( UInt binValues, Int numBins )
{
	m_uiBinsCoded += numBins & -m_binCountIncrement;

	for ( Int i = 0; i < numBins; i++ )
	{
		DTRACE_CABAC_VL( g_nSymbolCounter++ )
			DTRACE_CABAC_T( "\tEPsymbol=" )
			DTRACE_CABAC_V( ( binValues >> ( numBins - 1 - i ) ) & 1 )
			DTRACE_CABAC_T( "\n" )
	}

	while ( numBins > 8 )
	{
		numBins -= 8;
		UInt pattern = binValues >> numBins; 
		m_uiLow <<= 8;
		m_uiLow += m_uiRange * pattern;
		binValues -= pattern << numBins;
		m_bitsLeft -= 8;

		testAndWriteOut();
	}

	m_uiLow <<= numBins;
	m_uiLow += m_uiRange * binValues;
	m_bitsLeft -= numBins;

	testAndWriteOut();
}

你可能感兴趣的:(HEVC编码器HM源码阅读)