死亡岛激流全流程:x264源码阅读笔记2

来源:百度文库 编辑:偶看新闻 时间:2024/04/30 00:24:29

写参数集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_writestatic 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<I_left-1)=0111 1111,1100 1101&0111 1111 = 0100 1101,这样就把0写入了存储空间,得到码流0100 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)0100 0000 0100 1101 |0100 0000 = 0100 1101 ,这样就把1写入了存储空间,得到码流0100 1101,然后I_left=6.   函数bs_write1static 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 01001101 77 M 0 7 0x00890058 00001101 13 □ 0 6 0x00890058 00101101 45 - 1 5  可以看到,存储单元的初值为11011101,也就是0xCD,这是VC默认的初始化值。 我们首先要写入的是0,那么只需要把0放入11001101的最第一位(从左向右数),替换原来的1即可,变为01001101,它的十进制值就是77;下一次仍要写入0,则把0放到01001101的第二位,变为00001101;最后要写入1,则把1放到00001101的第三位,变为00101101。就这样依次逐位写入码流,直到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 … …