x264 cabac代码注释

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 );
    }
  • 19
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值