x264源码阅读笔记2

写参数集x264_sps_write()和x264_pps_write()以及其中基本的bs_write()的过程。

挺有意思,挺巧妙的。他们就是负责码流写入的过程,这个不同于写字节,直接COPY内存,用C语言实现对位的操作真的显得比较笨拙,但是这里代码还是很巧妙的。

说基本的,static inline void bs_write( bs_t *s, int i_count, uint32_t i_bits )这个函数的作用就是,向s里写入i_bits流的前i_count位,s当然是以字节为单位了,所以够8个位就写下个,哎呀太麻烦了,引别人写的把,不知道他这个是什么时候版本,但是大概意思差不多。酬和看。

 

函数bs_write
static inline void bs_write( bs_t *s, int i_count, uint32_t i_bits )
{
    while( i_count > 0 )
    {
        if( s->p >= s->p_end )
        {
            break;
        }
        i_count--;
        if( ( i_bits >> i_count )&0x01 )
        {
            *s->p |= 1 << ( s->i_left - 1 );
        }
        else
        {
            *s->p &= ~( 1 << ( s->i_left - 1 ) );
        }
        s->i_left--;
        if( s->i_left == 0 )
        {
            s->p++;
            s->i_left = 8;
        }
    }
}
函数功能:
i_count 是循环的次数,i_bits是要编码的数,i_left是当前空闲码流的位数。
i_bits 编为 i_count 位的码流 ,每次循环,I_count和I_left都会减1,I_count和I_left并不一定相等。 当i_left==0时,s->p指针指向下一个码流单元,i_left更新为8。
 
函数流程
首先判断I_count是否大于0,如果是,则判断s->p是否大于s->p_end,若是则终止,否则,可以写入码流。这个条件是在判断是否有空闲的存储空间供新的码流写入。
若可以写码流,则I_count--,表明可以进行写一位的操作。注意,写I_bits是逐位写入的。
if ( ( i_bits >> i_count )&0x01 ) 是用来判断当前要写入的I_bits位是0还是1,从而选择不同的算法来写入这个码流。如果当前要写入的是0,则选择*s->p &= ~( 1 << ( s->i_left - 1 ) )来把这个0写入码流;如果当前要写入的是1,则选择*s->p |= 1 << ( s->i_left - 1 )来把这个1写入码流。
  
写完一位码流后,初始的i_left被新写入的bit占了一位,所以i_left的值-1.
   这时判断I_left是否等于0,如果I_left还大于0,表示当前的存储单元中还有剩余的空间供码流写入,则直接进入下一次循环。如果I_left==0时,表示当前存储单元已被写满,所以s->p指针指向下一个存储单元,I_left更新为8。这时再进入下一循环。
  
在进入下一循环的时候,先判断I_count的值,如果非零,程序继续;如果为0,表示码流已经全部写入,程序终止。
 
关键语句分析
if ( ( i_bits >> i_count )&0x01 )
 
定位要写入的I_bits的位,比如I_bits=d(66)=b(0100 0010),I_count=8,首先I_count--,那么I_bits右移7位后就是0,而它与0x01(也就是0000 0001)位与后的值是0,这就确定了要写入的码流是0。再比如I_count=6,则I_bits右移6位后是01,而01和0x01位与后得到的是1,这就表明要写入的码流是1。
 
*s->p &= ~( 1 << ( s->i_left-1) )
此算式可以将0写入码流。比如*s->p=1100 1101,I_bits=d(66)=b(0100 0010),I_count=7,I_left=8。
~(1<<s->I_left-1)= 0 111 1111,
1 100 1101&
0 111 1111 = 0 100 1101 ,这样就把0写入了存储空间,得到码流 0 100 1101 。然后I_left=7
 
*s->p |= 1 << ( s->i_left - 1 );
此算式可以将1写入码流。比如*s->p=1100 1101,I_bits=d(66)=b(0100 0010),I_count=6,I_left=7。
1<<(s->I_left-1)0 1 00 0000 
0 1 00 1101 |
0 1 00 0000 = 0 1 00 1101 , 这样就把1写入了存储空间,得到码流0100 1101,然后I_left=6.
 
 
 
函数bs_write1
static inline void bs_write1( bs_t *s, uint32_t i_bits )
{
    if( s->p < s->p_end )
    {   
        if( i_bits&0x01 )
        {
            *s->p |= 1 <<( s->i_left-1);
        }
        else
        {
            *s->p &= ~( 1 << (s->i_left-1) );
        }
         s->i_left--;
        if( s->i_left == 0 )
        {
            s->p++;
            s->i_left = 8;
        }
    }
}
 
bs_write1 ()相当于bs_write(bs_t *s,1, uint32_t i_bits)
就是只写入1 bit码流。
 

地址
码流值
十进制值
ASCII 码值
i_bits
i_left
0x00890058
11001101
205
 
 
8
0x00890058
0 1001101
77
M
0
7
0x00890058
0 0 001101
13
0
6
0x00890058
00 1 01101
45
-
1
5

 
可以看到,存储单元的初值为 11011101 , 也就是0xCD,这是VC默认的初始化值。 我们首先要写入的是 0 ,那么只需要把0放入 1 1001101 的最第一位(从左向右数),替换原来的1即可,变为 0 1001101 ,它的十进制值就是77;下一次仍要写入 0 ,则把0放到0 1 001101 的第二位,变为 00 001101 ;最后要写入 1 ,则把1放到00 0 01101 的第三位,变为 001 01101 。就这样依次逐位写入码流,直到I_left=0为止。
下面是哥伦布编码流
 
bs_write_ue( s, sps->i_id );
这里ue,是在语法中定义为指数哥伦布码的编码方法,其具体方法见规范第9章。应是一种变长的编码!简举例,0阶指数哥化布编码:
Bit string form
Range of codeNum
1
0
0 1 x0
1-2
0 0 1 x1 x0
3-6
0 0 0 1 x2 x1 x0
7-14
0 0 0 0 1 x3 x2 x1 x0
15-30
0 0 0 0 0 1 x4 x3 x2 x1 x0
31-62
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值