发布时间:2025-06-24 19:29:50 作者:北方职教升学中心 阅读量:348
执行逻辑
首先用COM_BSW_GET_SINK_BYTE这个函数计算出当前buffer中有几个字节(8 bit),假设为bytes个字节。beg、概述
首先,在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).
接下来再考虑一些边界情况,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、