熵编码与码流buffer操作
bitstream buffer的操作
bitstream buffer操作的流程(version20171114)
其操作流程图(活动图)如下。
在x264码流操作中,主要涉及到两个内存空间:h->nal_buffer,h->thread[i]->out.p_bitstream。其中p_bitstream用于编码过程的码流写入操作;nal_buffer,为编码数据的nal和bytestream封装后的目标地址。
在每个单元(比如sps、pps、nal等)的码流写入后,都要调用bs_flush()。将当前字内已经写入的bit从低位bit移动到高位bit,同时确定下一个字节的位置,可能位于当前字内。
码流写入方式(version20100611)
写入码流的核心函数为bs_write()。
大小端模式
所谓的大端模式,是指数据的低位(就是权值较小的后面那几位)保存在内存的高地址中,而数据的高位,保存在内存的低地址中,这样的存储模式有点儿类似于把数据当作字符串顺序处理:地址由小向大增加,而数据从高位往低位放。
所谓的小端模式,是指数据的低位保存在内存的低地址中,而数 据的高位保存在内存的高地址中,这种存储模式将地址的高低和数据位权有效地结合起来,高地址部分权值高,低地址部分权值低,和我们的逻辑方法一致。
以小端模式,假设数据为0x12345678,内存和int数据的示意图如下。
码流在内存中的顺序
码流在内存中的顺序中为从低地址高位bit到高地址低位bit。在小端模式下,其在内存中顺序和寄存器中的次序如下。
码流写入流程
将语法元素写入码流的方式。不管是大端还是小端,写入方式是:从低位字节的低位bit写入语法元素。而实际需要从高地址字的高位bit写入,所以写完一个字后,需要字内字节交换。
建议的优化策略
码流由bytestream格式修改为netstream格式
这样就可以省去包头(0x00 00 01/0x00 00 00 01)封装和插入起始码0x03。
修改bit的写入过程
修改bit写入字内存的过程,避免字内字节交换。
CAVLC编码(version20100611)
CAVLC编码的总体流程
x264中CAVLC的总体实现流程
宏块级编码的初始化流程位于函数x264_init_vlc_tables()实现,其主要用于初始化CAVLC表格x264_level_token。
宏块级的CAVLC编码位于函数x264_macroblock_write_cavlc(),其具体流程如下。
block_residual_write_cavlc()的总体实现流程
block_residual_write_cavlc()概况如下。
/**
*@brief 对4x4量化后的数据CAVLC编码并输出
*@param[in] h指向当前编码器
*@param[in] i_ctxBlockCat i_ctxBlockCat:编码4x4块的类型,其定义具体如下。
enum cabac_ctx_block_cat_e
{
DCT_LUMA_DC = 0,//亮度DC系数编码
DCT_LUMA_AC = 1,//亮度AC系数编码
DCT_LUMA_4x4 = 2,//亮度x4块编码,包括DC和AC系数
DCT_CHROMA_DC = 3,//色度块的DC系数编码
DCT_CHROMA_AC = 4,//色度块的AC系数编码
DCT_LUMA_8x8 = 5,//亮度x8块编码
};
*@param[in] nC表示相邻块非0系数的情况
*@param[in] 指向需要熵编码的量化数据
*@return 非0系数的个数
*/
block_residual_write_cavlc( x264_t *h, int i_ctxBlockCat, dctcoef *l, int nC )
在x264中,block_residual_write_cavlc()分两层实现,第一层实现以宏的方式进行,具体代码如下。
![block_residual_write_cavlc()外层编码流程图](F:/block_residual_write_cavlc()外层编码流程图.svg)#define block_residual_write_cavlc(h,cat,idx,l)\
{\
int nC = cat == DCT_CHROMA_DC ? 4 : ct_index[x264_mb_predict_non_zero_code( h, cat == DCT_LUMA_DC ? 0 : idx )];\
uint8_t *nnz = &h->mb.cache.non_zero_count[x264_scan8[idx]];\
if( !*nnz )\
bs_write_vlc( &h->out.bs, x264_coeff0_token[nC] );\
else\
*nnz = block_residual_write_cavlc(h,cat,l,nC);\
}
在第一层中,具体实现流程如下。