本帖最后由 墨燃 于 6-19 14:00 编辑
3. X264 开源编码器分析
3.1 三大开源编码器: 目前 H.264的开源编码器主要有三类:JM,T264和 X264。JM 作为 H.264 的官方测试源码,由德国 hhi 研究所负责开发。它实现了 264 所有的特性,但其程序结构冗长,只考虑引入各种新特性以提高编码性能,忽视了编码复杂度,其编码复杂度极高,不宜实用。T264是中国视频编码自由组织联合开发的H.264编解码器, 编码器能编码输出标准的H.264码流,但解码器只能解 T264 编码器生成的码流,目前已经停止更新。X264 是网上自由组织联合开发的兼容 264 标准码流的编码器,它注重实用,和 JM 相比,在不明显降低编码性能的前提下,努力降低编码的计算复杂度,编码效率很高。 3.2 X264流程 因为 X264 编码器的高效率和高性能,应用之中较多使用,下面对 X264 进行源码分析,进一步分析 H.264 的编码器原理。 在 X264 编码器的调度中最重要的是 Encode 函数,是对整个视频序列的 H.264 编码。在函数中,首先进行了函数的初始化操作,然后判断是否已经编码完毕,如果没有则继续读取一帧数据到缓冲区,然后进行帧解码;如果编码完毕则退出编码流程。详细函数关系如下图所示:
其中,x264_encoder_open()这个函数是对不正确的参数进行修改,并对各结构体参数和cabac 编码,预测等需要的参数进行初始化。x264_picture_alloc()这个函数分配能容纳一帧sizeof(x264_picture_t)字节数的空间,然后进行初始化。p_read_frame()这个函数就是一次读入一帧到刚分配的空间,这里的数据都是原始的视频图像数据。Encode_frame()这个函数对视频序列其中一帧进行 264 编码。 x264_picture_clean()和 x264_encoder_close()两个函数主要是编码后的处理工作,如将帧数据全置零等。 在 Encode_frame() 函数中开始上文提到的 VCL 编码和 NAL 编码,其中x264_encoder_encode()函数为 VCL 层编码, 其详细流程如下图所示。 其中, Setup new frame from picture 主要是将图片的原始数据赋值给一个未使用的帧,用于编码。Get frame to be encoded 主要是帧管理的操作,从编码帧的缓存中取出一帧来对他进行编码。Setup frame context 主要是对即将编码帧进行帧类型的预设定。 Init ,Write the bitstream主要是对参考列表的初始化,片头的初始化,以及对将编码后数据写入比特流进行传输。Update encoder state这部分是一帧编码后的编码器的更新处理部分,主要有参考帧的管理,去块滤波,象素内插等工作。Compute/Print statistics这部分并不属于编码的工作,只是对其中编码性能的统计计算和显示工作。
x264_slice_write()函数是编码中最重要的函数,以上所介绍的预测编码等都在这个函数中实现的。 Init()函数主要是初始化的一些操作。x264_macroblock_cache_load()函数主要是把当前宏块的 up 宏块和 left 宏块的预测模式,非零系数值等数据加载进来,放到一个数组里面,供当前模块参考使用。 x264_macroblock_analyse()函数主要是模式选择的问题,通过对SAD 值或者其他 COST 值的分析,确定当前宏块的编码类型。以 I 帧模块为例,我们可以将它分割成16个4*4的块,如果这16个块的sad加起来小于按16*16的方式计算出来的sad值,我们就将这个 16*16 的块分成 16 个 4*4 的块进行编码,否则采用 16*16 的方式编码。x264_macroblock_encode()函数即是依据上面所确定的编码模式对当前宏块进行 264 编码。CABAC/CAVLC 部分为熵编码部分。
 |