static uint8_t cabac_contexts[4][QP_MAX_SPEC+1][1024]; //分别使用不同的上下文,IPB帧,QP,最大1024个状态
void x264_cabac_init( s264_t *h )
{
int ctx_count = CHROMA444 ? 1024 : 460;
for( int i = 0; i < 4; i++ )
{
const int8_t (*cabac_context_init)[1024][2] = i == 0 ? &x264_cabac_context_init_I
: &x264_cabac_context_init_PB[i-1]; //被模式0,1,2影响
for( int qp = 0; qp <= QP_MAX_SPEC; qp++ )
for( int j = 0; j < ctx_count; j++ )
{ //根据QP,帧类型,以及初始化的数组LPS,MPS得到一个新的state值,然后clip到 64 ~ 127,作为初始化值
int state = x264_clip3( (((*cabac_context_init)[j][0] * qp) >> 4) + (*cabac_context_init)[j][1], 1, 126 );
//state clip到最小的,state 或者127 - states, 然后最高位第7bits存放到低位。
cabac_contexts[i][qp][j] = (S264_MIN( state, 127-state ) << 1) | (state >> 6); //高bit存放到最低bit中,不太理解这样做的用意
}
}
}
void x264_cabac_context_init( x264_t *h, x264_cabac_t *cb, int i_slice_type, int i_qp, int i_model )
{ //i_model 一般为0, i_qp 不同的qp值,用的上下文不同。 slice type也有区分,
memcpy( cb->state, cabac_contexts[i_slice_type == SLICE_TYPE_I ? 0 : i_model + 1][i_qp], CHROMA444 ? 1024 : 460 );
}
void x264_cabac_encode_init_core( x264_cabac_t *cb )
{
cb->i_low = 0; //初始为0 - 502 代表着区间 0, 1
cb->i_range = 0x01FE; //502, 在这个范围内编码
cb->i_queue = -9; // the first bit will be shifted away and not written, 9个bit空出来,不写。
cb->i_bytes_outstanding = 0; //未输出字节数量
}
void x264_cabac_encode_init( x264_cabac_t *cb, uint8_t *p_data, uint8_t *p_end )
{
x264_cabac_encode_init_core( cb );
cb->p_start = p_data; //设置编码缓冲区
cb->p = p_data; //编码缓冲区
cb->p_end = p_end; //结束编码 数据位置
}
static inline void cabac_putbyte( x264_cabac_t *cb )
{
if( cb->i_queue >= 0 ) //9bits
{
int out = cb->i_low >> (cb->i_queue+10); //保留 i_queue + 10位 0 ~ 1024表示cabac 精度
cb->i_low &= (0x400<i_queue)-1; //保留 i_queue + 10位 0 ~ 1024表示cabac 精度
cb->i_queue -= 8; //已经输出 8bits
if( (out & 0xff) == 0xff ) //全ff换种编码方式
cb->i_bytes_outstanding++; //出现过ff,
else
{ //一般不会大于2字节
int carry = out >> 8;
int bytes_outstanding = cb->i_bytes_outstanding;
// this can't modify before the beginning of the stream because
// that would correspond to a probability > 1.
// it will write before the beginning of the stream, which is ok
// because a slice header always comes before cabac data.
// this can't carry beyond the one byte, because any 0xff bytes
// are in bytes_outstanding and thus not written yet.
cb->p[-1] += carry;
while( bytes_outstanding > 0 ) //如果有进位
{
*(cb->p++) = carry-1; //编码记录有几个0xff
bytes_outstanding--;
}
*(cb->p++) = out;
cb->i_bytes_outstanding = 0;
}
}
}
static inline void cabac_encode_renorm( x264_cabac_t *cb ) //重新归一化 输出bits
{
int shift = x264_cabac_renorm_shift[cb->i_range>>3]; //越小,需要放大的倍数越多. 先右移3bits,寻址6bits的移动数组
cb->i_range <<= shift; //需要跟随i_range一起放大
cb->i_low <<= shift; //放大low值,以免损失精度,高bits先编码,
cb->i_queue += shift; //编码shift bits
cabac_putbyte( cb ); //输出字节序列
}
/* Making custom versions of this function, even in asm, for the cases where
- b is known to be 0 or 1, proved to be somewhat useful on x86_32 with GCC 3.4
- but nearly useless with GCC 4.3 and worse than useless on x86_64. */
void x264_cabac_encode_decision_c( x264_cabac_t *cb, int i_ctx, int b )
{
int i_state = cb->state[i_ctx]; //获取当前上下文
int i_range_lps = x264_cabac_range_lps[i_state>>1][(cb->i_range>>6)-4]; //获取当前lps range调整值
cb->i_range -= i_range_lps; //range调整
if( b != (i_state & 1) ) //发生bits翻转
{
cb->i_low += cb->i_range; //mps 的range 负值给 lps = low
cb->i_range = i_range_lps;
}
cb->state[i_ctx] = x264_cabac_transition[i_state][b]; //状态切换到新的bin的state
cabac_encode_renorm( cb );
}