以下内容源于网络资源的学习与整理,如有侵权请告知删除。
参考博客
(1)H264 编码基本原理_ByteSaid的博客-CSDN博客_h264编码原理
(2)H264 编码简介_mydear_11000的博客-CSDN博客
(3)什么是I帧,P帧,B帧_Rachel-Zhang的博客-CSDN博客_i帧
(4)H264数据格式解析_qq_34613314的博客-CSDN博客_h264格式
(5)H264(NAL简介与I帧判断)_jefry_xdz的博客-CSDN博客_h264 nal
一、H264的简介
H.264同时也是 MPEG-4 第十部分,是由 ITU-T 视频编码专家组(VCEG)和 ISO/IEC 动态图像专家组(MPEG)联合组成的联合视频组(JVT,Joint Video Team)提出的高度压缩数字视频编解码器标准。这个标准通常被称之为 H.264/AVC(或者 AVC/H.264 或者 H.264/MPEG-4 AVC 或 MPEG-4/H.264 AVC)。H.264是一种面向块,基于运动补偿的视频编码标准。
二、相关的概念
1、帧、片、宏块
可以简单理解:帧(frame)就是一幅图像,一幅图像由一个或多个片(slice)组成,一个片由一个或多个宏块(MB)组成,一个宏块一般由16*16像素的YUV数据组成。
2、I帧、P帧、B帧
H264协议定义了三种帧:完整编码的帧叫I帧;参考之前的I帧生成的、只对差异部分进行编码的帧叫P帧;参考前后帧进行编码的帧叫B帧。
I帧、B帧和P帧,是根据压缩算法的需要,人为定义出来的概念。它们本质上都是实实在在的物理帧。一般来说,I帧的压缩率是7,P帧是20,B帧可以达到50。可见使用B帧能节省大量的空间,节省出来的空间可以用来保存多一些I帧,这样在相同的码率下,可以提供更好的画质。
(1)I帧
I帧,又被称为内部画面(intra picture),可以理解为一帧完整的画面,因此解码时不需要参考其他帧的数据,只需要本帧数据就可以完成。
I帧具有以下特点:
-
它是一个全帧压缩编码帧,即它将全帧图像信息进行JPEG压缩编码及传输。
-
解码时仅用I帧的数据就可重构完整图像。
-
I帧描述了图像背景和运动主体的详情。
-
I帧不需要参考其他画面而生成。
-
I帧是P帧和B帧的参考帧(其质量直接影响到同组中以后各帧的质量)。
-
I帧是帧组GOP的基础帧(第一帧),在一组中只有一个I帧。
-
I帧不需要考虑运动矢量。
-
I帧所占数据的信息量比较大。
(2)P帧
P帧,又称为“前向预测编码帧”。P帧表示的是这一帧跟之前的一个I帧(或P帧)的差别,P帧没有完整的画面数据,解码时需要用前一帧的画面叠加上本帧定义的差别,生成最终画面。
P帧的预测与重构:在发送端,P帧以I帧为参考帧,在I帧中找出P帧“某点”的预测值和运动矢量,取预测差值和运动矢量一起传送。在接收端,根据运动矢量从I帧中找出P帧“某点”的预测值并与差值相加以得到P帧“某点”样值,从而可得到完整的P帧。
P帧具有以下特点:
-
P帧是I帧后面相隔1~2帧的编码帧。
-
P帧采用运动补偿的方法传送它与前面的I或P帧的差值及运动矢量(预测误差)。
-
解码时必须将I帧中的预测值与预测误差求和后才能重构完整的P帧图像。
-
P帧属于前向预测的帧间编码,它只参考前面最靠近它的I帧或P帧。
-
P帧可以作为其后面P帧的参考帧,也可以作为其前后的B帧的参考帧。
-
由于P帧是参考帧,它可能造成解码错误的扩散。
-
由于是差值传送,P帧的压缩比较高。
(3)B帧
值得一提的是,对图像进行编码时,每帧的原始数据其实已经存在,所以B帧可以参考后面的帧。
B帧,又称为“双向预测内插编码帧”。B帧是双向差别帧,也就是B帧记录的是本帧与前后帧的差别。要解码B帧,不仅要取得之前的缓存画面,还要解码之后的画面,通过前后画面与本帧数据的叠加取得最终的画面。B帧压缩率高,但是解码时CPU会比较累。
B帧的预测与重构:在发送端,B帧以前面的I或P帧和后面的P帧为参考帧,找出B帧“某点”的预测值和两个运动矢量,并取预测差值和运动矢量传送。在接收端,根据运动矢量在两个参考帧中找出预测值并与差值求和,得到B帧“某点”的样值,从而可得到完整的B帧。
B帧具有以下特点:
-
B帧是由前面的I或P帧和后面的P帧来进行预测的。
-
B帧传送的是它与前面的I或P帧和后面的P帧之间的预测误差及运动矢量。
-
B帧是双向预测编码帧。
-
B帧压缩比最高,因为它只反映与参考帧间运动主体的变化情况,预测比较准确。
-
B帧不是参考帧,不会造成解码错误的扩散。
如下图所示,因为有 B 帧这样的双向预测帧的存在,某一帧的解码序列和实际的显示序列是不一样的。其中DTS(Decode Time Stamp)表示用于视频的解码序列;PTS:(Presentation Time Stamp)表示用于视频的显示序列。
3、序列、IDR图像
(1)序列
在H264协议中,图像是以序列为单位进行组织的,或者说一段图像是由许多序列组成的。序列是由一段内容差异不大的图像编码后生成的一串数据流,以I帧开始,到下一个I帧结束。(这说明一个序列包含许多帧。)
当运动变化比较少时,一个序列可以很长,因为图像的内容变化很少,因此可以编一个I帧,然后一直P帧、B帧。当运动变化大时,一个序列就会比较短,比如就包含一个I帧和3、4个P帧。
(2)IDR图像
某个序列的第一幅图像叫做IDR图像(立即刷新图像),IDR图像都是I帧图像。
H264协议引入IDR图像是为了解码的重同步,当解码器解码到 IDR 图像时,会立即将参考帧队列清空,将已解码的数据全部输出或抛弃,重新查找参数集,开始一个新的序列。这样,如果前一个序列出现重大错误,在这里可以获得重新同步的机会。
IDR图像一定是 I 帧,但I帧不一定是IDR图像。一个序列中可以有很多的I帧,如果某个I帧不用来当做IDR图像,则这个I帧之后的图像可以引用这个I帧之前的图像做运动参考,而IDR图像之后的图像永远不会使用这个IDR图像之前的图像数据来解码。因此播放器可以从任意一个IDR帧开始播放,因为在它之后没有任何帧引用这个IDR 帧之前的帧。
三、H264编码的依据与算法
1、H264编码的依据
根据一段时间内图像的统计结果,在相邻的几幅图像画面中,有差别的像素少于10%,亮度的差值不超过2%,色度的差值不超过1%。因此对于一段变化不大的图像画面,我们可以先编码出一个完整的图像帧A,随后的B帧不需要全部编码,而只是写入与A帧的差别,这样B帧的大小就只有完整帧的1/10或更小!B帧之后的C帧如果变化不大,我们在C帧中写入与B帧的差别……如此循环。
这一段类似的图像画面的数据就组成了一个序列。当某个图像与之前的图像变化很大,无法参考前面的帧来生成时,我们就结束上一个序列,开始下一段序列。
2、H264编码的算法
H264采用的核心算法是帧内压缩和帧间压缩,帧内压缩是生成I帧的算法,帧间压缩是生成B帧和P帧的算法。
帧内压缩也称为空间压缩。当压缩一帧图像时,仅考虑本帧的数据而不考虑相邻帧之间的冗余信息,这实际上与静态图像压缩类似。帧内一般采用有损压缩算法,由于帧内压缩是编码一个完整的图像,所以可以独立的解码、显示。帧内压缩一般达不到很高的压缩,跟编码 JPEG 差不多。
帧间压缩也称为时间压缩。它通过比较时间轴上不同帧之间的数据进行压缩。帧间压缩一般是无损的。帧差值算法是一种典型的时间压缩法,相邻几帧的数据有很大的相关性,它通过比较本帧与相邻帧之间的差异,仅记录本帧与其相邻帧的差值,这样可以大大减少数据量。
具体过程见H264 编码基本原理_ByteSaid的博客-CSDN博客_h264编码原理,很形象与生动。
四、H264的功能结构
在H264协议中,整个系统框架可以划分为两个层面:视频编码层(VCL,Video Coding Layer)和网络抽象层(NAL,Network Abstraction Layer)。
VCL层只关心视频编码部分,重点在于编码算法以及在特定硬件平台的实现。这层输出的数据是被压缩编码后的纯视频流信息,包括帧内预测,帧间预测、变换量化、熵编码等内容,没有任何冗余头信息。一般做编码器的人会重点研究VCL部分。
NAL层关心的是VCL输出的纯视频流信息如何被表达和封包以利于网络传输。换句话说,NAL负责将VCL输出的数据封装到NAL单元里,并提供头信息,以保证数据适合各种信道和存储介质上的传输。这层输出的数据就是H264的码流。一般做视频传输和解码播放的人会重点研究NAL部分。
我们并不用研究视频如何编解码,因为这部分海思已经写好,我们要做的是视频的传输与解码播放工作,因此要重点研究NAL层。
这里继续介绍几个重要概念:
(1)SODB:String Of Data Bits ,VCL层输出的纯视频流。
(2)RBSP:Raw Byte Sequence Payload,原始字节序列负荷。
(3)NALU:Network Abstraction Layer Units,NAL单元。
它们的关系是:
(1)SODB + RBSP trailing bits = RBSP
(2)NAL header(1 byte) + RBSP = NALU
五、H.264视频流分析工具
(1)播放器:vlc
(2)二进制工具:winhex
(3)网络抓包工具:wireshark
(4)雷神作品:SpecialVH264.exe
p帧举例:
I帧举例:
(5)国外工具:Elecard StreamEye Tools
六、H264的NAL单元(NALU)详解
这里以一个h264码流文件stream_chn0.h264为例进行说明。
1、整体分析
利用雷神的SpecialVH264.exe软件打开这个文件,如下所示。
由上图可知:一个H264码流由许多序列组成,每个序列都由“ 1个SPS帧+1个PPS帧+1个SEI帧+1个I帧+29个P帧 ”组成,每个序列都是一组二进制数字。其中SPS、PPS、SEI帧有利于网络传输或解码。每个序列中都没有B帧,这可能是海思平台编码方案的特点,其他平台可能不是这样的。
2、分隔符
这里的每帧数据就是一个NALU(SPS、PPS和SEI帧除外)。
利用winhex软件打开stream_chn0.h264这个文件,内容如下。
其中红框的内容是分隔符,一般是“00 00 00 01”,主要用来区分与隔开两个帧。上图的第一个红框和第二个红框之间有14个字节,表示SPS;第二个红框和第三个红框之间有4个字节,表示PPS;第三个红框和第四个红框之间有5个字节,表示的内容是SEI。这与利用SpecialVH264.exe软件打开文件时显示的信息一致,如下所示。
3、SPS、PPS和SEI帧
上面提到了SPS、PPS、SEI帧。
- SPS,Sequence Paramater Set,序列参数集。
- PPS,Picture Paramater Set,图像参数集。
- SEI,Supplemental Enhancement Information,补充增强信息。
因为编程中这部分内容不是很重要,这里不作介绍。关于它们的具体介绍,参见以下博客:
H264码流中SPS PPS详解 - 瓦楞球 - 博客园
从零开始写H264解码器(7) SEI解析_taotao830的博客-CSDN博客
4、profile和level
上面的描述中涉及到profile和level,它们的介绍见以下博客:
h264中profile和level的含义_xiaojun11-的博客-CSDN博客
5、NALU类型
这里每帧数据就是一个NALU,因此NALU类型也可以叫做帧类型,则NALU类型包括SPS、PPS、SEI、I、P和B类型。
分隔符之后的第一个字节提供了帧类型、参考级别等信息。将之转为二进制数字,则从右到左:
- 第7位表示禁止位,值为1表示语法出错,所以一般都为0。
- 第5~6位表示参考级别。
- 第0~4为表示NALU类型,即帧类型。
我们可以根据这个字节0~4位的数值,来判断一个帧的类型。
比如上面分隔符之后的第一个字节分别为0x67、0x68、0x06、0x65,则:
0x67的二进制是0110 0111,0~4位是00111,转为十进制是7,对应上表是序列参数集,即SPS。
0x68的二进制是0110 1000,0~4位是01000,转为十进制是8,对应上表是图像参数集,即PPS。
0x06的二进制是0000 0110,0~4位是00110,转为十进制是6,对应着补充增强信息,即SEI。
0x65的二进制是0110 0101,0~4位是00101,转为十进制是5,对应上表是IDR,即I帧。
可知判断I帧的算法是:(分隔符之后的第一个字节) &(0001 1111)= 5? yes:no
6、参考级别( nal_ref_idc)
上面提到, 分隔符之后的第一个字节的第5~6位提供了参考级别信息。
什么是参考级别?参考级别是衡量一帧图像内容重要性的指标。比如网络视频传输时,可能因为网络而存在丢包的情况,RTSP 为了保持实时性,可能选择性丢弃一些不是非常重要的帧。这时候某一帧是否可以被丢弃,就要看这一帧的参考级别。
I帧作为IDR图像,对于解码很重要,肯定不能被丢弃,则I帧的参考级别的数值应该很大。由雷神的SpecialVH264.exe软件可知I帧对应的参考级别是HIGHEST(也就是3)。或者由winhex软件得知分隔符后I帧的第一个字节是0x65,二进制是0110 0101,第5~6位是11,转为十进制是3,也就是说参考级别为3。P帧、SPS帧和PPS帧也不能被丢弃,因为它们参考级别也是3。可以被丢弃的帧只有 SEI 帧,SEI帧对应的参考级别是DISPOS,也就是0。
7、内容总结
(1)一段H264的码流由多个序列组成。
(2)每个序列都是这样固定结构:1个SPS帧+1个PPS帧+1个SEI帧+1个I帧+29个P帧 。
(3)其中SPS、PPS和SEI帧,描述了该序列的图像信息,这些信息有利于网络传输或解码。
(4)每个序列有且只有1个I帧,I帧是关键,丢失I帧则整个序列就没有意义了。
(5)P帧的个数等于fps-1。
(6)I帧越大则P帧可以越小,反之I帧越小则P帧会越大。
(7)I帧的大小取决于图像本身的复杂度,以及压缩算法的空间压缩部分。
(8)P帧的大小取决于图像变化的剧烈程度。
(9)CBR(固定码率)和VBR(可变码率)下P帧的大小策略会不同,CBR时P帧大小基本恒定(图像剧烈变化时,清晰度会降低;图像保持不动时,清晰度提高),VBR时变化会比较剧烈(就算图像剧烈变化,清晰度也保持一致,但码率会明显增加,导致网速吃紧。H264是VBR?yes)。