目录
一、实验准备
本实验涉及到文件的位置和参数设置较多,所以我简要记录一下,方便我自己找问题,也方便后来人查看调试。忠告
:用尺寸小的264文件进行解码再编码,不然运行起来会很慢。
1. H.264编码过程
视频压缩编码的思想,我理解的是消除冗余,提高压缩程度。H.264采用的核心算法帧内压缩
和帧间压缩
就是为了解决视频数据主要的两种数据冗余:空间冗余和时间冗余。前者是生成I帧的算法,一般采用有损压缩算法,可以独立解码显示,压缩比不高,和JPEG差不多;后者是生成BP帧的算法,利用相邻数据帧相关性较大的特性,进一步提高压缩比,一般采用无损算法。除此之外,H.264较MPEG-2编码,使用了整数DCT
和CABAC
无损压缩算法,CABAC无损压缩给高频数据短码,低频数据长码,同时还会根据上下文相关性进行压缩,比VLC高效很多。
具体介绍可参考这篇博客,写得非常好!H.264基本原理与编码流程
2. 调试和编码(参考JM Reference Software Manual (JVT-AE010))
- 打开H.264-参考软件,
jm18.6
文件夹就是本次实验所用到的最主要的H.264编解码软件了,《JM Reference Software Manual (JVT-AE010)》为其使用手册。查看264文件的软件有H264Visa.exe
和eseye_u.exe
,前者可以查看运动矢量、宏块矩阵,后者可以在图形界面查看GOP条形图。查看yuv文件采用的是vooya.exe
,原来的yuvviewer没办法打开非16整倍数尺寸图像。 - 打开文件夹,其中包含一个名为“jm_vc7.sln“工作空间,适用于Visual Studio 2003(v7);一个名为“jm_vc8.sln”的工作空间,适用2005 (v8);一个名为“jm_vc9.sln”的工作空间,适用于2008 (v9)等等版本,用户根据自己的VS版本选择适当的解决方案。我自己版本是2019,没有对应的,但是我用vc10没有问题。
- 工作区包括以下三个项目:
lencod H.264/AVC参考编码器
、Idecod H.264/AVC参考解码器
、rtpdump RTP报文分析工具、rtp_loss模拟RTP丢包的工具。目前我们用到的只有第一个和第二个,选择所需的项目和适当的编译模式,比如“debug调试”或“release发布”,这里我们只需要编译。编译需要将在bin目录中创建二进制文件" lencode .exe “或” ldecode .exe ",印象里本来就有。(参考的是手册上第二节 installation and complaytion 下的Windows使用MS Visual Studio进行安装编译)
- 找到Iencod和Idecod文件夹中的decoder.cfg和encoder.cfg复制到bin中的。后面可以直接编辑cfg参数达到调试的目的(版本是否对应好像不会有影响)。
- 更改lencod解决方案和Idecod解决方案属性页面如下图所示:
3. 编码参数(参考JM Reference Software Manual (JVT-AE010))
3.1. 语法
我们在调试-命令参数里面填入的内容,就可以解释为读取<encoder.cfg>中的编码参数,一次性设置多个不同的参数(当然也可以学习语法,逐次调试参数)。
3.2. 编码器输入与输出
输入格式包括以下情况,实验中我们输入的是YUV420文件,这里提一句,解码器默认输出格式是YUV420。
另外,根据输入输出参数描述,我注意到:输入图像宽度如果该值不是16的倍数,则图像将自动扩展到下一个16的倍数,并在序列参数集中设置原始大小的裁剪参数。默认值是176。输入图像高度如果没有使用隔行工具,如果值不是16的倍数,图像将自动扩展到下一个16的倍数。否则,如果值不是32的倍数,图像将自动扩展到下一个32的倍数。如果图片被扩展,在序列参数集中设置原始大小的裁剪参数。默认值为144。我测试用到的demo.264文件图像尺寸是864×480,两个刚好是符合要求的,其提供的test.264文件和highway_qcif.264文件图像尺寸176×144,也刚好符合要求。
当运行编码器时,编码器将在屏幕上显示每帧的速率/失真统计以及其累积结果。根据详细输入参数的设置,生成的输出信息可以看到输入的yuv文件路径、输出h.264码率、输出的重建yuv文件、采样率、图像尺寸、总参考次数、序列类型、输出文件格式、总帧数、YUV各分量PSNR值、总比特数、比特率等等。示例图片就不放了,后面会有实际调试结果。
3.3 实验需要更改的参数及相关解释
序号 | 参数名称 | 作用 |
---|---|---|
1 | InputFile | 输入文件名称,如果是encoder.cfg,此处应为yuv文件,如果是decoder.cfg,此处应为264文件 |
2 | OutputFile | 输出文件名称 |
3 | stats.dat | 数据记录文件,里面有IBP码率、yuv的PSNR表格等等,方便后面作率失真曲线图 |
4 | SourceWidth\SourceHeight | 输入文件一帧画面宽\高 |
5 | OutputWidth\OutputHeight | 输出文件一帧画面宽\高 |
6 | FramesToBeEncoded | 编码帧数 |
7 | IntraPeriod | GOP中I帧数量,0表示只有第一帧为I帧,这里我们始终控制为0 |
8 | NumberBFrame | IP帧之间B帧的数量 |
9 | PrimaryGOPLength | 冗余分配的GOP长度 |
10 | IDRPeriod | PrimaryGOPLength一般设置为与IDRPeriod相同;即便不相同,也不对码流产生影响。IDRPeriod值决定GOP长度,0表示只有第一帧 |
11 | RateControlEnable | 是否控制比特率,1-允许 |
12 | Bitrate | 比特率,码率,单位bps |
13 | RCUpdateMode | 决定启用RateControlEnable码率控制时码率控制算法,设定为2 |
14 | HierarchicalCoding | 允许高级图像编码图像结构,可以控制分配优先级和分层算法,这里我不太懂,只有设定为0才能顺利输出结果 |
关于IDR和I帧的区别: 可以看这篇博客IBP、IDR帧的区别,我们需要知道IDR帧(Instantaneous Decoding Refresh)是用来即时解码刷新。IDRPeriod值决定GOP长度,而不是PrimaryGOPLength。
关于ProfileIDC:
配置文件idc语法元素的值。预测性配置文件和intra only配置文件之间的切换请参见intra profile参数。默认值为88。注意:配置文件限制了某些特性和编码模式的使用。请参阅H.264/AVC附录A,了解每个配置文件所支持的功能。参考软件可能会对概要文件一致性的某些特性进行测试,但是可能会缺少某些验证。
关于GOP开放还是闭合:
在搜索GOP相关的参数时,我有注意到EnableOpenGOP参数,查了一下GOPopen与否对实验的影响:
闭合GOP和开放GOP(closed GOP/open GOP)。闭合GOP是H.264中GOP的格式。在H.264的GOP中,所有的GOP都是独立解码的,与其他GOP无关,即它们都是“封闭”的。但是在HEVC中,GOP的结构发生了变化,采用了“开放”的结构,在解码过程过可能会参考其他GOP的数据。这时,一个GOP的起始帧命名为CRA,clean random access,同样采用帧内编码,但是这个GOP内的帧间编码帧可以越过CRA参考前一个GOP的数据,这便是GOP的open。
关于H.264码率控制算法:
H.264的码率控制算法建立在如下假设上:即编码图像有一个预先定义好的顺序,也即预先定义好了GOP的组成。该算法可以用来产生适合可用带宽的码流,同时考虑了HRD模型。在学习指南里有详细解释,暂不赘述。
二、实验过程
1. 264文件解码成YUV文件
对demo.264和highway_qcif.264进行解码,调整decoder.cfg文件中的输入输出文件名称,运行即可得到相应yuv文件,程序成功运行结果如下所示:
1. 注意到因为我们没有输入用来比较的文件demo_rec.yuv,所以无法计算SNR;
2. 输出的图像尺寸是854×480,我们用vooya.exe打开看确认是这样,之后进行编码就需要注意,如果以解码生成的YUV文件进行再编码,输入尺寸应为854×480,否则再编码结果会变成条纹斜拉乱七八糟。
3. 从逐帧解码可以看出,此文件一共60帧,第一帧是IDR帧。
4. highway_qcif.264解码输出页面类似,但是没有出现864变成854这种情况,尺寸依旧是176×144。
其他这些YUV文件应当是软件开发者提供给进行编解码调试的,我们暂时不看(看也可以,尺寸都是176×144)。
2. YUV文件编码成264文件
将上述两个视频序列编码为.264文件,以demo_dec.yuv编码,GOP=15,间隔2B帧,码率为1000000bps(1000kbps)为例,encoder.cfg文件中调整参数如下:
InputFile = "demo_dec.yuv"
FramesToBeEncoded = 30
SourceWidth = 854
SourceHeight = 480
OutputWidth = 864
OutputHeight = 480
TraceFile = "trace_demo15_2B_1000.txt"
ReconFile = "demo15_2B_1000_rec.yuv"
OutputFile = "demo15_2B_1000.264"
StatsFile = "stats_demo15_2B_1000.dat"
PrimaryGOPLength = 15
IDRPeriod = 15
NumberBFrames = 2
HierarchicalCoding = 0
FramesToBeEncoded = 30
RateControlEnable = 1
Bitrate = 1000000
RCUpdateMode = 2
运行结果如下图:
3. 更改码率&GOP长度&帧类型编码结果
- 固定码率,以不同的GOP长度及形状编码:GOP=15,2B帧;GOP=12,2B帧,GOP=9,2B帧
GOP=4,1B帧;GOP=12,无B帧;GOP=1,全I帧; - 相同的GOP长度及形状,不同的码率编码:1000kb/s, 800kb/s,400kb/s;
- 输出结果,统计实际码率,Y分量PSNR值,制表,并以实际码率为横坐标,以PSNR值为纵坐标,作率失真曲线如下图所示。
表格
由上表可以看出,当编码全I帧时,即便控制码率后,其输出实际码率基本不变,且都非常大,PSNR质量也基本不变,重建图像质量都很高;B帧越多,压缩比例越大,重建图像质量越差;固定B帧数量及码率,GOP越长,重建图像质量越差;固定GOP类型和帧类型,比如固定GOP=15,2B,随着码率增大,图像质量提高,实际运行时间也变长。
率失真曲线
可以通过筛选器进行筛选,这里就不单独截图了,仅作为作为一个证明实验结果示例图。具体结论见上一小节。
4. 分析运动矢量信息
编码模式分析
可参考上一次实验内容数据压缩11 | 实验7 | MP4及H.264码流分析
以GOP=12,2B帧,码率=1000kbps编码结果demo12_2B_1000.264
为例观察其运动矢量情况,图像较大,会使得运动矢量不清晰。故我选择以GOP=12,2B帧,码率=1000kbps编码结果highway.264
为观察对象,用eseye_u.exe打开,可以观察到:
P帧运动矢量只有红,对应前向预测I帧
B帧运动矢量有红有绿,对应双向预测。
查看宏块矩阵值,可以看到H.264帧间编码过程中,每预测一个宏块,则重建一个宏块,重建值=残差+预测值,最新重建的宏块作为下一宏块预测的参考块,是以宏块作为预测单位的,同时传输压缩的为残差。
三、总结反思
数据压缩确实是很磨人的课程,如果有后来人能看到这里,相信数据压缩的课程也差不多结束了,一定也像我一样感慨良多。说实话,我真不是会写代码的人,脑子转得慢,思考也不够深入,总是提不出那么多问题(每次都很羡慕一下课就可以围住老师请教的人),能坚持写到这,顶多算是性子沉稳一些,能坐得住,外加一点点(很微量)的完美主义。以前我也喜欢做编程相关的笔记,但是这是第一次把自己的笔记整理好发在公共平台,这种感觉很奇妙,有点害羞又有点骄傲,有点忐忑担忧又有点不管不顾。前人肩膀宽阔,却也不能长时间驻足,创新总是缺缺,DDL却时常提醒。写了大篇幅的文章不怎么能感动自己,就是让人腰酸背痛想睡觉。哈哈,不皮了,总之,很感谢老师让我拥有这次体验,让我在回忆往事的时候,还能高兴地说“我在CSDN上还有个连载专栏呢”这样的话,高山仰止,景行行止,虽不能至,然心向往之。