宏块编码函数x264_macroblock_encode()是完成变换与量化的主要函数,而x264_macroblock_encode()调用了x264_macroblock_encode_internal()函数,在x264_macroblock_encode_internal()函数中,主要完成了如下功能:
x264_macroblock_encode_skip():编码skip类型宏块。
x264_mb_encode_i16x16():编码intra16x16类型的宏块。该函数除了进行dct变换之外,还对16个小块的dc系数进行了hadamard变换。
x264_mb_encode_i4x4():编码intra4x4类型的宏块。
帧间宏块编码:这一部分代码直接写在了函数体里面。
x264_mb_encode_chroma():编码色度块。
x264_macroblock_encode()函数与x264_macroblock_encode_internal()函数都处于encoder文件夹内的macroblock.c中,其调用关系图如下所示:
x264_macroblock_encode()函数处于encoder文件夹内的macroblock.c中,x264_macroblock_encode()封装了x264_macroblock_encode_internal()。如果色度模式是yuv444的话,传递的参数plane_count=3而chroma=0;如果不是yuv444的话,传递的参数plane_count=1而chroma=1。
对应的代码如下:
x264_macroblock_encode_internal()函数也处于encoder文件夹内的macroblock.c中,具体的代码分析如下:
从源代码可以看出,x264_macroblock_encode_internal()的流程大致如下:
(1)、如果是skip类型,调用x264_macroblock_encode_skip()编码宏块。
(2)、如果是intra16x16类型,调用x264_mb_encode_i16x16()编码宏块。
(3)、如果是intra4x4类型,循环16次调用x264_mb_encode_i4x4()编码宏块。
(4)、如果是inter类型,则不再调用子函数,而是直接进行编码:
a)、对16x16块调用x264_dct_function_t的sub16x16_dct()汇编函数,求得编码宏块数据p_fenc与重建宏块数据p_fdec之间的残差(“sub”),并对残差进行dct变换。
b)、分成4个8x8的块,对每个8x8块分别调用x264_quant_function_t的quant_4x4x4()汇编函数进行量化。
c)、分成16个4x4的块,对每个4x4块分别调用x264_quant_function_t的dequant_4x4()汇编函数进行反量化(用于重建帧)。
d)、分成4个8x8的块,对每个8x8块分别调用x264_dct_function_t的add8x8_idct()汇编函数,对残差进行dct反变换,并将反变换后的数据叠加(“add”)至预测数据上(用于重建帧)。
(5)、如果对色度编码,调用x264_mb_encode_chroma()。
从inter宏块编码的步骤可以看出,编码就是“dct变换+量化”两步的组合。在接下来的文章中将依次分析变换、量化的具体代码。