实验内容
- 调试JM18.6 H264编解码器,将输入的Annex B格式码流解码至YUV文件
- 调整编码器参数,将解码后的YUV文件编码至不同格式的H.264文件
- 用码流分析软件检查所生成的码流中各种编码模式和运动矢量等信息
- 用播放器观看所生成码流的质量
- 生成率失真曲线
实验过程及结果
解码.264文件(Annex B码流)至YUV 420文件
在H.264中,编码后的比特流将被NAL( Network Abstraction Layer)打包形成NAL Unity:
NAL Unity由一个字节的头部和有效载荷组成,可以被单独的解析和处理,包含1字节的头部和有效载荷:
H.264码流的Annex B格式由NAL Unity数据加开始前缀组成。其开始前缀为2个或者3个0x00,后面再加一个0x01。此外,为了防止NALU载荷中出现开始前缀,需要对其进行防竞争处理,通过在0x01前插入防竞争字节0x03实现,将0x000001变成0x00000301。
更为详细的Annex B码流格式可参考:字节流格式(Annex B)和RTP格式流浅析
使用ffmpeg将.mp4文件转换至.264格式的Annex B Byte Stream Format,命令:
ffmpeg -i test1.mp4 -codec copy -bsf:v h264_mp4toannexb test1.264
转换结果:
使用JM H264编解码器中的解码器部分将两段文件解码至YUV文件,使用解码器时,需要修改解码器配置文件中以下两项以指定输入输出文件:
InputFile = "test2.264" # H.264/AVC coded bitstream
OutputFile = "test2_dec.yuv" # Output file, YUV/RGB
解码结果:
将解码后的YUV文件编码至不同格式的H.264文件
视频编码帧主要分为三种:
I(Intra frame)帧:帧内编码帧,仅利用该帧图象本身信息进行编码,数据率最大。
P(Predictive-coded frame )帧:前向预测编码帧,根据前面最靠近的I帧或者另一个P帧进行预测,属于前向预测,数据率小于I帧
B(Bidirectionally predictive-coded frame)帧:双向预测编码帧,它既用过去的帧作基准,也用未来的帧作基准,即前向和后向预测都有,数据率最小。
图像组GOP(group of pictures)
图像组是将一个图像序列中连续的几个不同编码帧种类的图像组成一个小组,简称为GOP。一个GOP中通常只包含1个I帧。
在相同码率的情况下,GOP越长,图像质量越高(P、B帧可分配到更多比特);在相同图像质量的情况下,GOP越长,码率越低(高码率的I帧少)。
在JM H264编解码器中,调整GOP需要设置cfg文件中的如下参数:
IntraPeriod = 0 # Period of I-pictures (0=only first) I帧周期,实验中不调整
IDRPeriod = 1 # Period of IDR pictures (0=only first) IDR帧周期
EnableIDRGOP = 1 # Support for IDR closed GOPs (0: disabled, 1: enabled) 使用IDR帧的GOP
NumberBFrames = 0 # Number of B coded frames inserted (0=not used) GOP中I、P帧之间B帧数量
PrimaryGOPLength = 1 # GOP length for redundant allocation (1-16) GOP长度
关于IDR帧和I帧:都是帧内编码帧,IDR帧之后的所有帧都不能引用任何IDR帧之前的帧的内容,与此相反,对于普通的I-帧来说,位于其之后的B-和P-帧可以引用位于普通I-帧之前的I-帧。实验中通过设置IDRPeriod,令所有I帧都为IDR帧。
调整码率控制需要设置cfg文件中的如下参数:
RateControlEnable = 1 # 0 Disable, 1 Enable 启用码率控制
Bitrate = 1000000 # Bitrate(bps) 目标比特率
RCUpdateMode = 1 # Rate Control type. Modes supported : 码率控制算法选择
# 0 = original JM rate control,
# 1 = rate control that is applied to all frames regardless of the slice type,
# 2 = original plus intelligent QP selection for I and B slices (including Hierarchical),
# 3 = original + hybrid quadratic rate control for I and B slice using bit rate statistics
对于全I帧编码视频,码率控制算法设置为1时码率控制效果较好,对于IP、IBP帧视频设置为2即可。
此外,还需调整编码器的输入、输出文件设置:
InputFile = "test2_yuv.yuv" # Input sequence
StartFrame = 0 # Start frame for encoding. (0-N)
FramesToBeEncoded = 90 # Number of frames to be coded
FrameRate = 24.0 # Frame Rate per second (0.1-100.0)
SourceWidth = 640 # Source frame width
SourceHeight = 360 # Source frame height
SourceResize = 0 # Resize source size for output
OutputWidth = 640 # Output frame width
OutputHeight = 360 # Output frame height
PixelFormat = 0 # Pixel Format for 422 packed inputs
# 0: UYVY
# 1: YUY2/YUYV
# 2: YVYU
# 3: BGR (Unsupported)
# 4: V210 (Video Clarity)
StandardRange = 0 # 0: Standard range 1: Full range (RGB input)
VideoCode = 1 # Video codes for RGB ==> YUV conversions
# 0 = NULL,
# 1 = ITU_REC709,
# 2 = CCIR_601,
# 3 = FCC,
# 4 = ITU_REC624BG,
# 5 = SMPTE_170M,
# 6 = SMPTE_240M,
# 7 = SMPTE_260M,
# 8 = ITU_REC709_EXACT
TraceFile = "trace_enc2_gop12_2b.txt" # Trace file
ReconFile = "test_rec2_gop12_2b.yuv" # Reconstruction YUV file
OutputFile = "test2_enc_gop12_2b.264" # Bitstream
StatsFile = "stats2_gop12_2b.dat" # Coding statistics file
通过调整cfg文件,将以上YUV文件编码为如下格式的Annex B码流。
固定码率(1000Kbps),以不同的GOP长度及形状编码:GOP=15,2B帧;GOP=12,2B帧;GOP=9,2B帧;GOP=4,1B帧;GOP=12,无B帧;GOP=1,全I帧
相同的GOP长度及形状(GOP=12,2B帧),不同的码率:2000Kbps;1500Kbps;1000Kbps;750Kbps;500Kbps;250Kbps;
观看编码后的视频,并分析编码模式和运动矢量等信息
使用Elecard StreamEye (StreamEye)码流分析软件对编码后的内容进行分析。
观察Test1文件在不同编码方式下宏块类型和运动矢量
观察的Test1文件分辨率为640*480,画面中有一条黑线绕中心旋转且整体画面细节较少,主要用于观察运动矢量的情况。
Test1文件,全I帧编码,设定1000kbps码率
画面中的某一I宏块:
从文件信息可知文件平均码率为1212kbps,与设定值有一定误差,全I帧编码。
图像中红色标记的宏块为I宏块,网格指示宏块的大小。网格越密集代表该处宏块切分的越细。在视频中黑线扫过的部分运动估计/运动补偿所用的块大小为88和44,而几乎无内容变化的区域为16*16。由于采用全I帧编码,因此无运动矢量。
图中软件展示的柱状图为图像帧的码率和帧类型,红色为I帧,蓝色为P帧,绿色为B帧。
Test1文件,GOP=4,1B帧,设定1000kbps码率,平均码率926Kbps,GOP结构为I-P-B-P,图中绿色、红色线为运动矢量:
图中带有黄色标记的宏块为帧间编码宏块,由于该位置相较于参考帧无变化,所以跳过不编码:
在B帧中,带有蓝色标记的为B宏块,由参考帧中的参考宏块加上残差数据得到。在P帧中,带有蓝色标记的为P宏块:
图像中大部分没有变化的宏块跳过不予编码,仅针对存在运动、变化的宏块进行编码,从而使数据量大幅下降。
Test1文件,GOP=9,2B帧,设定1000kbps码率,平均码率413kbps,GOP结构为I-B-B-P-B-B-P-B-P:
Test1文件,GOP=12,2B帧,设定1000kbps码率,平均码率368kbps,GOP结构为I-B-B-P-B-B-P-B-B-P-B-P,P帧中有部分区域使用了帧内编码的I宏块:
Test1文件,GOP=12,只包含I、P帧,设定1000kbps码率,平均码率809kbps,GOP结构为I-P-P-P-P-P-P-P-P-P-P-P:
Test1文件,GOP=15,2B帧,设定1000kbps码率,平均码率398kbps,GOP结构为I-B-B-P-B-B-P-B-B-P-B-B-P-B-B:
通过对Test1文件的分析,对于图像中内容变化较少的图像,使用较长的GOP可以显著降低码率。通过观察,H.264在编码P、B时不全使用帧间编码的P、B宏块,对于部分区域也会使用帧内编码的I宏块。
观察Test2文件在相同码率不同编码方式下的画质
Test2文件分辨率为640*360,画面包含丰富的细节但运动很细微,主要用于观察不同编码模式对画质的影响。
使用编码前的YUV文件作为画质的参考:
全I帧编码,设定1000kbps码率,平均码率为1210kbps,可以明显观察出画质较差,图像中草地的细节几乎不可见:
GOP=4,1B帧,设定1000kbps码率,平均码率为1274kbps,画质明显好于全I帧编码:
该编码模式下即使图像整体有细微的运动,但变化不明显的区域跳过不予编码,造成了画质的下降。图中蓝色标记代表使用帧间编码的B宏块,黄色标记代表跳过不予编码的B宏块:
GOP=9,2B帧,设定1000kbps码率,平均码率为1296kbps:
GOP=12,2B帧,设定1000kbps码率,平均码率1367kbps:
该编码模式下,GOP较长因此P帧可以分配到较多的比特,视频的P帧中使用了帧间估计的P宏块,图像质量相较于前几种编码方式有所提升。图中红色标记为宏块的运动矢量:
图像的B帧中仍然有较多的B宏块没有进行编码:
GOP=12,只包含I、P帧,设定1000kbps码率,平均码率为1278kbps,只包含I帧、P帧的编码方式情况下视频画质与包含IBP帧的情况相差不大:
GOP=15,2B帧,设定1000kbps码率,实际码率为1341kbps。在该编码方式下,视频的画质与GOP=12的编码方式差别不大:
观察Test2文件在不同码率相同编码方式下的画质
GOP=12,2B帧,设定250kbps码率,实际平均码率364kbps,画质较差:
GOP=12,2B帧,设定500kbps码率,实际平均码率668kbps,画质有所提升:
GOP=12,2B帧,设定750kbps码率,实际平均码率995kbps:
GOP=12,2B帧,设定1000kbps码率,实际平均码率1367kbps:
GOP=12,2B帧,设定1500kbps码率,实际码率1935kbps:
GOP=12,2B帧,设定2000kbps码率,实际码率2663kbps:
生成率失真曲线
使用编码前视频的YUV文件与JM编码前编码后的YUV文件进行计算视频的平均PSNR:
由于实验选用的Test1视频文件中细节较少,画面简单,所以不同GOP编码方式与PSNR没有较强的相关性。
在Test2的视频中,由于画面由较为丰富的细节且有一定的运动,此时不同GOP长度、不同码率下的PSNR说明了如下结论:
相同码率下GOP越长、包含B帧越多图像质量越好;相同GOP时码率越高图像质量越好;与理论相符。