H.264官方软件JM源代码简单分析-解码器ldecod

前一阵子看了一下H.264官方参考软件JM的源代码,在这里总结一下它的结构。JM编解码H.264的速度相对于FFmpeg来说是非常慢的,但是它的代码写得清晰易懂,更适合做学术方面的研究。JM包含了视频解码器ldecod和视频编码器lencod。本文记录视频解码器ldecod的结构。

函数调用关系图

JM中的H.264视频解码器ldecod的函数调用关系图如下所示。

 

单击查看更清晰的大图

下面解释一下图中关键标记的含义。

函数背景色
函数在图中以方框的形式表现出来。不同的背景色标志了该函数不同的作用:
白色背景的函数:普通内部函数。
粉红色背景函数:解析函数(Parser)。这些函数用于解析SPS、PPS等信息。
紫色背景的函数:熵解码函数(Entropy Decoding)。这些函数读取码流数据并且进行CABAC或者CAVLC熵解码。
绿色背景的函数:解码函数(Decode)。这些函数通过帧内预测、帧间预测、DCT反变换等方法解码压缩数据。

黄色背景的函数:环路滤波函数(Loop Filter)。这些函数对解码后的数据进行滤波,去除方块效应。

箭头线
箭头线标志了函数的调用关系:
黑色箭头线:不加区别的调用关系。
粉红色的箭头线:解析函数(Parser)之间的调用关系。
紫色箭头线:熵解码函数(Entropy Decoding)之间的调用关系。
绿色箭头线:解码函数(Decode)之间的调用关系。
黄色箭头线:环路滤波函数(Loop Filter)之间的调用关系。
 
函数所在的文件
每个函数标识了它所在的文件路径。

下文记录结构图中的几个关键部分。

普通内部函数

普通内部函数指的是ldecod中还没有进行分类的函数。例如:
解码器的main()函数中调用的参数配置函数Configure()、打开解码器函数OpenDecoder()、解码函数DecodeOneFrame()、输出函数WriteOneFrame()、关闭解码器函数CloseDecoder()等。
解码器主要解码函数DecodeOneFrame()逐层调用的函数decode_one_frame()、decode_slice()、decode_one_slice()等。

解析函数(Parser)

解析函数(Parser)用于解析H.264码流中的一些信息(例如SPS、PPS、Slice Header等)。在read_new_slice()中都调用这些解析函数完成了解析。下面举几个解析函数的例子。

read_next_nalu():解析NALU。这个函数是后几个解析函数的前提。
ProcessPPS():解析Slice Header。其中调用了InterpretPPS()用于解析PPS。
ProcessSPS():解析SEI。其中调用了InterpretSPS()用于解析SPS。

其中read_next_nalu()调用了下面几个函数:

get_annex_b_NALU():读取annexb格式的NALU。
GetRTPNALU():读取RTP格式的NALU。
NALUtoRBSP():将NALU处理为RBSP格式。
(PS:annexb和RTP是H.264码流的2种格式)

熵解码函数(Entropy Decoding)

熵解码函数(Entropy Decoding)读取码流数据并且进行CABAC或者CAVLC熵解码。熵解码工作是在Slice结构体的read_one_macroblock()函数中完成的。该函数根据宏块类型的不同,会调用不同的熵解码函数。CAVLC对应的解码函数是:

read_one_macroblock_p_slice_cavlc():解码P宏块。
read_one_macroblock_b_slice_cavlc():解码B宏块。
read_one_macroblock_i_slice_cavlc():解码I宏块。

CABAC对应的解码函数是:

read_one_macroblock_p_slice_cabac():解码P宏块。
read_one_macroblock_b_slice_cabac():解码B宏块。
read_one_macroblock_i_slice_cabac():解码I宏块。

解码函数(Decode)

解码函数(Decode)通过帧内预测、帧间预测等方法解码宏块压缩数据。解码工作都是在decode_one_macroblock()中完成的。decode_one_macroblock()调用了Slice结构体中的decode_one_component()解码一个亮度分量。decode_one_component()根据宏块所在的Slice的不同,会调用不同的处理函数:

decode_one_component_i_slice():解码I Slice中的宏块。
decode_one_component_p_slice():解码P Slice中的宏块。
decode_one_component_b_slice():解码B Slice中的宏块。

I Slice中只包含Intra类型的宏块。因此decode_one_component_i_slice()调用下面函数对Intra类型宏块进行解码:

mb_pred_intra16x16():帧内预测16x16宏块
mb_pred_intra4x4():帧内预测4x4宏块
mb_pred_intra8x8():帧内预测8x8宏块

P Slice中包含Intra类型和Inter类型(单向)的宏块。因此decode_one_component_p_slice()调用下面函数对Intra类型宏块进行解码:

mb_pred_intra16x16():同上
mb_pred_intra4x4():同上
mb_pred_intra8x8():同上
mb_pred_p_inter16x16():单向帧间预测16x16宏块
mb_pred_p_inter16x8():单向帧间预测16x8宏块
mb_pred_p_inter8x16():单向帧间预测8x16宏块
mb_pred_p_inter8x8():单向帧间预测8x8宏块

B Slice中包含Intra类型和Inter类型(双向)的宏块。因此decode_one_component_b_slice()调用的函数和P Slice中的宏块是类似的,唯一的不同在于它增加了对B宏块的处理。
对于逐行扫描的Intra16x16宏块,具体的预测函数是intra_pred_16x16_normal(),其中根据帧内预测类型的不同,调用不同的函数进行处理:

intra16x16_vert_pred():垂直模式
intra16x16_hor_pred():水平模式
intra16x16_dc_pred():DC模式
intra16x16_plane_pred():Plane模式

对于逐行扫描的Inter16x16的P类型宏块,具体的预测函数是mb_pred_p_inter16x16(),其中会调用perform_mc()完成运动补偿。对于单向运动补偿,perform_mc()会调用perform_mc_single();对于双向运动补偿,perform_mc()会调用perform_mc_bi()。运动补偿的过程中,会调用get_block_luma()完成四分之一像素的插值工作。
无论Inter类型宏块还是Intra类型的宏块,最后都会调用iMBtrans4x4()完成DCT反变换和残差叠加的工作。其中DCT反变换在inverse4x4()中完成,而残差叠加在sample_reconstruct()中完成。

环路滤波函数(Loop Filter)

环路滤波函数(Loop Filter)对解码后的数据进行滤波,去除方块效应。去块效应滤波是在DeblockPicture()中完成的。DeblockPicture()调用了DeblockMb()。而DeblockMb()中调用GetStrengthVer()、GetStrengthHor()函数获取滤波强度;调用EdgeLoopLumaVer()、EdgeLoopLumaHor()进行滤波。

雷霄骅
[email protected]
http://blog.csdn.net/leixiaohua1020

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-10-11 14:03:53

H.264官方软件JM源代码简单分析-解码器ldecod的相关文章

HEVC官方软件HM源代码简单分析-解码器TAppDecoder

本文记录HEVC官方参考软件HM的源代码结构.HM相比于JM来说,采用了面向对象的编程方法,因而结构相对更加清晰.HM包含了视频解码器TAppDecoder和视频编码器TAppEncoder.本文记录视频解码器TAppDecoder的结构. 函数调用关系图 HM中的HEVC视频解码器TAppDecoder的函数调用关系图如下所示. 单击查看更清晰的大图 下面解释一下图中关键标记的含义. 函数背景色 函数在图中以方框的形式表现出来.不同的背景色标志了该函数不同的作用:白色背景的函数:普通内部函数.

FFmpeg的H.264解码器源代码简单分析:解析器(Parser)部分

本文继续分析FFmpeg中libavcodec的H.264解码器(H.264 Decoder).上篇文章概述了FFmpeg中H.264解码器的结构:从这篇文章开始,具体研究H.264解码器的源代码.本文分析H.264解码器中解析器(Parser)部分的源代码.这部分的代码用于分割H.264的NALU,并且解析SPS.PPS.SEI等信息.解析H.264码流(对应AVCodecParser结构体中的函数)和解码H.264码流(对应AVCodec结构体中的函数)的时候都会调用该部分的代码完成相应的功

FFmpeg的H.264解码器源代码简单分析:概述

本文简单记录FFmpeg中libavcodec的H.264解码器(H.264 Decoder)的源代码.这个H.264解码器十分重要,可以说FFmpeg项目今天可以几乎"垄断"视音频编解码技术,很大一部分贡献就来自于这个H.264解码器.这个H.264解码器一方面功能强大,性能稳定:另一方面源代码也比较复杂,难以深入研究.本文打算梳理一下这个H.264解码器的源代码结构,以方便以后深入学习H.264使用.PS:这部分代码挺复杂的,还有不少地方还比较模糊,还需要慢慢学习...... 函数

FFmpeg的H.264解码器源代码简单分析:解码器主干部分

本文分析FFmpeg的H.264解码器的主干部分."主干部分"是相对于"熵解码"."宏块解码"."环路滤波"这些细节部分而言的.它包含了H.264解码器直到decode_slice()前面的函数调用关系(decode_slice()后面就是H.264解码器的细节部分,主要包含了"熵解码"."宏块解码"."环路滤波"3个部分). 函数调用关系图 解码器主干部分的源代码在

x264源代码简单分析:宏块分析(Analysis)部分-帧间宏块(Inter)

本文记录x264的 x264_slice_write()函数中调用的x264_macroblock_analyse()的源代码.x264_macroblock_analyse()对应着x264中的分析模块.分析模块主要完成了下面2个方面的功能: (1)对于帧内宏块,分析帧内预测模式(2)对于帧间宏块,进行运动估计,分析帧间预测模式 上一篇文章记录了帧内宏块预测模式的分析,本文继续记录帧间宏块预测模式的分析. 函数调用关系图 宏块分析(Analysis)部分的源代码在整个x264中的位置如下图所示

x264源代码简单分析:熵编码(Entropy Encoding)部分

本文记录x264的 x264_slice_write()函数中调用的x264_macroblock_write_cavlc()的源代码.x264_macroblock_write_cavlc()对应着x264中的熵编码模块.熵编码模块主要完成了编码数据输出的功能. 函数调用关系图 熵编码(Entropy Encoding)部分的源代码在整个x264中的位置如下图所示. 单击查看更清晰的图片 熵编码(Entropy Encoding)部分的函数调用关系如下图所示.   单击查看更清晰的图片 从图中

FFmpeg的HEVC解码器源代码简单分析:环路滤波(Loop Filter)

===================================================== HEVC源代码分析文章列表: [解码 -libavcodec HEVC 解码器] FFmpeg的HEVC解码器源代码简单分析:概述 FFmpeg的HEVC解码器源代码简单分析:解析器(Parser)部分 FFmpeg的HEVC解码器源代码简单分析:解码器主干部分 FFmpeg的HEVC解码器源代码简单分析:CTU解码(CTU Decode)部分-PU FFmpeg的HEVC解码器源代码简单

x264源代码简单分析:滤波(Filter)

本文记录x264的x264_slice_write()函数中调用的x264_fdec_filter_row()的源代码.x264_fdec_filter_row()对应着x264中的滤波模块.滤波模块主要完成了下面3个方面的功能: (1)环路滤波(去块效应滤波)(2)半像素内插(3)视频质量指标PSNR和SSIM的计算 本文分别记录上述3个方面的源代码. 函数调用关系图 滤波(Filter)部分的源代码在整个x264中的位置如下图所示. 单击查看更清晰的图片 滤波(Filter)部分的函数调用关

FFmpeg与libx264接口源代码简单分析

===================================================== H.264源代码分析文章列表: [编码 - x264] x264源代码简单分析:概述 x264源代码简单分析:x264命令行工具(x264.exe) x264源代码简单分析:编码器主干部分-1 x264源代码简单分析:编码器主干部分-2 x264源代码简单分析:x264_slice_write() x264源代码简单分析:滤波(Filter)部分 x264源代码简单分析:宏块分析(Anal