发布时间:2025-06-24 19:29:50  作者:北方职教升学中心  阅读量:348


执行逻辑
首先用COM_BSW_GET_SINK_BYTE这个函数计算出当前buffer中有几个字节(8 bit),假设为bytes个字节。

概述

首先,在AVS3的代码中,编码器和解码器用的不同的比特流结构

  • 编码器比特流结构体: COM_BSW=_COM_BSW(BitStream Writer)
  • 解码器比特流结构体: COM_BSR=_COM_BSR(BitStream Reader)

AVS3中编码器比特流结构体的定义

struct_COM_BSW{/* buffer */u32                code;/* bits left in buffer */intleftbits;/*! address of current writing position */u8               *cur;/*! address of bitstream buffer end */u8               *end;/*! address of bitstream buffer begin */u8               *beg;/*! address of temporal buffer for demulation begin */u8               *buftmp;/*! size of bitstream buffer in byte */intsize;/*! address of function for flush */COM_BSW_FN_FLUSH  fn_flush;/*! arbitrary data, if needs */intndata[4];/*! arbitrary address, if needs */void*pdata[4];};

对于这个结构体,其理解方式如下:
Function: 编码器的比特流结构体, Bitstream structure for encoder
理解: 比特流用3个u8类型的指针来表示,分别是: beg, cur, end. 其中beg表示比特流的起始地址,end表示比特流的终止地址, cur表示比特流当前的“位流指针”所指向的地址(i.e. 下一次要写入的地址);
size表示比特流总共的字节大小(因此,end=beg+size-1)
除了比特流以外,还需要维护一个总共空间为32位的buffer, buffer的内容用u32类型的code来表示, leftbits表示buffer中剩余可写入的比特位数, code中的高leftbits位是buffer中的有效内容,且buffer中的最高有效位是比特流中的低位(i.e. 优先向比特流中写入buffer中的高位)
e.g. code=0xFFFF FFF0, leftbits=4, 则buffer=[1111 1111 1111 1111 1111 1111 1111], 其中code的高28(=32-4)位是有效buffer位.
使用方法: 你想要写比特流,就先要写入buffer, 然后等时机合适,再用fn_flush将buffer的内容写入到比特流中(i.e 更新位流指针cur的位置)

比特流结构体的初始化

voidcom_bsw_init(COM_BSW *bs,u8 *buf,u8 *buftmp,intsize,COM_BSW_FN_FLUSH fn_flush){bs->size      =size;bs->beg       =buf;bs->cur       =buf;bs->buftmp    =buftmp;bs->end       =buf +size -1;bs->code      =0;bs->leftbits  =32;bs->fn_flush  =(fn_flush ==NULL?com_bsw_flush :fn_flush);//*  bs->fn_flush = com_bsw_flush}

Function: 初始化比特流对象bs,用参数buf,size,fn_flush初始化bs,将fn_flush赋值为com_bsw_flush这个函数,bitstream reader initialization
Logic: 将bs中的size、
用bs->code |= val 来更新buffer.
以上就是主要的执行逻辑。
额外处理: 首先用fn_flush将buffer中的所有内容全都写入到比特流中,然后将多出来的(len - leftbits) 位, 写入到buffer中, 令bs->leftbits= 32- (len - leftbits).

beg、
接下来再考虑一些边界情况,i.e. 如果写入数据后,超出buffer的大小怎么办

  • 如果len< bs->leftbits, 此时写入数据后并没有超出buffer的空间,因此此时无需额外处理
  • 如果len>= bs->leftbits, 此时写入数据后超出buffer的空间,多出来(len - leftbits) 位,此时需要额外处理。end、
    然后循环bytes次,依次将每一个字节的内容写到比特流中(优先写入code中的高字节数据)
    e.g. code=0x1111 1110, leftbits = 4, 则buffer=[1111 1111 1111 1111 1111 1111 1111 0000],则bytes=4
    循环执行一次,(bs->code>>24 & 0xFF)等价于 取出 bs->code中的高8位
    ∗ * (bs->cur++) = bs->code中的高8位(0XFF)
    然后bs->code<<=8, 此时bs->code = 0xFF FFF000.
    循环执行第二次,让 ∗ * (bs->cur++) = bs->code中的高8位(0XFF)
    然后bs->code<<=8, 此时bs->code = 0xFFF00000.
    循环执行第三次,让 ∗ * (bs->cur++) = bs->code中的高8位(0XFF)
    然后bs->code<<=8, 此时bs->code = 0xF0000000.
    循环执行第四次,让 ∗ * (bs->cur++) = bs->code中的高8位(0XF0)
    然后bs->code<<=8, 此时bs->code = 0x00000000.
    结束这个循环,这个函数向比特流中写入了: FF FF FF F0

注意: 执行fn_flush 并不会将buffer中的内容清空!

向比特流写入数据

首先,向比特流写入数据有以下几个常用的函数:

  • com_bsw_write1: 向比特流写入1位数据
  • com_bsw_write: 向比特流写入一个长度为len位的数据

com_bsw_write1函数

com_bsw_write1函数是用于向比特流写入1位数据

intcom_bsw_write1(COM_BSW *bs,intval){com_assert(bs);bs->leftbits--;bs->code |=((val &0x1)<<bs->leftbits);if(bs->leftbits ==0){com_assert_rv(bs->cur <=bs->end,-1);bs->fn_flush(bs);bs->code =0;bs->leftbits =32;}return0;}

参数解读: bs 比特流结构体对象,val表示你要向比特流写入的1位数据(理论上val应该是0或者1,但是如果你传入大于1的数字,也只会向比特流写入最低位的那个数据)
因此,以下我们不妨假设val是一位数据(0或者1)
code中有效的位数是(32-bs->leftbits),i.e. code的高(32-bs->leftbits)是有效的,其余的低bs->leftbits位是无效的.
现在要向buffer里面写入val,那么应该写入的位置就是第(bs->leftbits-1)位(下标从0开始计数)
首先将bs->leftbits 减一,因为你向buffer里面写入了一位数据,buffer的剩余空闲位置自然就减少1位, 然后让 code|= (val << bs->leftbits) 更新buffer.
如果此时buffer满了(bs->leftbits == 0), 那么就调用bs->fn_flush(bs), 将buffer的内容写到bs的比特流中, 然后再清空buffer(bs->code = 0; bs->leftbits = 32;)

com_bsw_write函数

com_bsw_write函数是用于向比特流写入一个长度为len位的数字val

intcom_bsw_write(COM_BSW *bs,u32 val,intlen)/* len(1 ~ 32) */{intleftbits;com_assert(bs);leftbits =bs->leftbits;val <<=(32-len);bs->code |=(val >>(32-leftbits));if(len <leftbits){bs->leftbits -=len;}else{com_assert_rv(bs->cur +4<=bs->end,-1);bs->leftbits =0;bs->fn_flush(bs);#ifdefined(X86F)/* on X86 machine, shift operation works properly when the value of the           right operand is less than the number of bits of the left operand. */bs->code =(leftbits <32?val <<leftbits :0);#elsebs->code =(val <<leftbits);#endifbs->leftbits =32-(len -leftbits);}return0;}

参数解读: bs 比特流结构体对象,val表示你要向比特流写入的len位数据, len表示写入数据的位数
code中有效的位数是(32-bs->leftbits),i.e. code的高(32-bs->leftbits)是有效的,其余的低bs->leftbits位是无效的.
执行逻辑:
现在要向buffer里面写入val,那么应该写入的位置就是第(bs->leftbits-1)~(bs->leftbits-len)位
代码中val <<= (32 - len), (val >> (32 - leftbits)) 就相当于令val左移 (leftbits - len)位(并且把bs->leftbits位以及更高的位给直接“去掉”/“置零”了), 因此,此时val有效的位数就是第(bs->leftbits-1)~(bs->leftbits-len)位。code等信息都赋值为传入的参数值(e.g. buf, size, fn_flush)
并将bs中的缓冲区buffer置成0(空), leftbits置成32(当前buffer中没有内容,剩余可写入的内容有32位)

com_bsw_flush函数

com_bsw_flush函数(fn_flush函数)的定义如下:

/* number of bytes to be sunk */#defineCOM_BSW_GET_SINK_BYTE(bs)((32-(bs)->leftbits +7)>>3)staticintcom_bsw_flush(COM_BSW *bs){intbytes =COM_BSW_GET_SINK_BYTE(bs);while(bytes--){*bs->cur++=(bs->code >>24)&0xFF;bs->code <<=8;}return0;}

Function: 将比特流结构体对象bs中的buffer内容写入到bs中的比特流中。cur、