这里主要有一下几个过程:
1. 初始化h->stat.frame,即全部清零。
2. 写条带头:x264_slice_header_write,即把刚才x264_slice_header_init设置的一些参数写入。
3. 如果是CABAC编码,则初始化CABAC。有关CABAC在后续相关章节讨论。
4. 遍历一帧中的所有宏块,这是编码的主要部分:
for( mb_xy = h->sh.i_first_mb, i_skip = 0; mb_xy < h->sh.i_last_mb; )
其中sh.i_first_mb和sh.i_last_mb在x264_slice_header_init中赋值,分别是0和宏块行列数乘积。
5. 最后输出码流尾部。
其间穿插一些必要的初始化和配置。
本章着重分析编码的主要部分,包括一下过程:
需要注意的是,这里讨论的宏块是固定尺寸的,即Y分量计为16x16。(而运动宏块的尺寸则是多变的)
1. 首先根据宏块的序号得出宏块的坐标。然后统计当前宏块的码流位置:
int mb_spos = bs_pos(&h->out.bs) + x264_cabac_pos(&h->cabac);
2. 然后出现一句:
if( i_mb_x == 0 )
x264_fdec_filter_row( h, i_mb_y );
这是对行进行去块过程。详细情况专门论述。
3. 随后是x264_macroblock_cache_load,这里主要进行当前宏块和相关信息的提取。这个函数比较大,也在专题中论述。
4. 接下去进行解码分析操作
x264_macroblock_analyse
5. 以及解码实体:
x264_macroblock_encode
6. 而后处理码流输出,也分CABAC和CAVLC两种情况。
7. 接着出现x264_macroblock_cache_save,和x264_macroblock_cache_load对应,保存处理完的宏块。
8. 更新宏块统计
下面,首先看编码主体x264_macroblock_encode的结构。
该函数按不同宏块类型情况进行不同的处理。包括如下类型:
P_SKIP
B_SKIP
I_16x16 - 一次完成一个块h->mb.pic.p_fdec[0]的编码。
用函数指针h->predict_16x16[i_mode]进行帧内预测
I_8x8 - 分4次完成。h->mb.pic.p_fdec[0][8 * (i&1) + 8 * (i>>1) * FDEC_STRIDE]指定了当前位置。即:
[0][1]
[2][3]
用函数指针完成4个宏块的帧内预测
I_4x4 - 分16次完成。h->mb.pic.p_fdec[0][4 * block_idx_x[i] + 4 * block_idx_y[i] * FDEC_STRIDE]指定当前位置。
根据block_idx_x和block_idx_y的定义,其顺序是:
[0][1][4][5]
[2][3][6][7]
[8][9][c][d]
[a][b][e][f]
用函数指针完成4个宏块的帧内预测
Inter - 首先进行运动补偿。见后续讨论。
然后分多种情形:
1. 无损压缩情况:h->mb.b_lossless == TRUE(必须采用4x4DCT)
根据上述I_4x4中描述的顺序遍历16个4x4块。
这里调用的函数是zigzag_sub_4x4_field,完成残差。(无损情况直接发送残差)
2. 指定采用8x8DCT情况:h->mb.b_transform_8x8 == TRUE
首先是作残差并DCT的函数:sub16x16_dct8。
然后对4个8x8的DCT系数块进行处理:包括可能的去噪x264_denoise_dct,量化(标量/矢量)。有关量化也在专题中论述。量化完成后进行系数扫描(对角平衡的普通扫描)。
3. 一般情况
接着处理色差分量,如果是Intra的则进行预测。
最后写Coded Block Pattern。