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();
}