H264简介和原理

Posted by alonealice on 2020-10-13

什么是H264

H264其实就是一种视频压缩的算法,它是目前所有的视频压缩技术中运用最广泛,最流行的,普遍运用在各种视频播放的应用和服务中。对比其他的压缩标准,它主要有两大优势,一是网络亲和性,它可以适用于各种传输网络;二是更高的视频压缩比,对比H.263和MPEG-4,约为它们的 2 倍。

H264主要采用了几下几种方法对视频数据进行的压缩:帧内预测压缩、帧间预测压缩、整数离散余弦变换和CABAC压缩。

基础概念

I帧、P帧和B帧

视频经过上述一系列的压缩后,里面的视频帧会分为3种,I帧、P帧和B帧。

I帧:帧内编码帧 又称intra picture,即为关键帧。I帧是将全帧图像信息经过帧内压缩技术后的产物。你可以理解为这一帧画面的完整保留;解码时只需要本帧数据就可以完成,不需要参考其他帧数据。 I帧描述了图像背景和运动主体的详情,因此不需要考虑运动矢量,它的数据信息占比也比较大也。I帧是P帧和B帧的参考帧,P帧和B帧需要参考I帧还原画面,因此I帧直接影响依赖它的后面各帧的画面质量。

P帧:前向预测编码帧 又称predictive-frame,它是I帧后面相隔1~2帧的编码帧。它是通过压缩当前帧与前面已编码的帧的时间冗余信息来压缩传输数据量的编码图像的,因此也叫预测帧。即它采用运动补偿的方法,传送它与前面的I或P帧的差值及运动矢量(预测误差)。因此解码时,需要用之前缓存的画面(I帧)叠加上本帧定义的差别,生成最终画面。P帧是前向预测的帧间编码,因此它只参考前面最靠近它的I帧或P帧,但它同样可以是其后面P帧的参考帧,也可以是其前后的B帧的参考帧。由于是差值传送,P帧的压缩比较高。

B帧: 双向预测内插编码帧(双向差别帧、双向预测帧) 又称bi-directional interpolated prediction frame,既考虑与源图像序列前面的已编码帧(I帧),也参考源图像序列后面已编码帧(P帧)。也就是说,B帧记录的是本帧与前后帧的差别,换言之,要解码B帧,不仅要取得之前的缓存画面,还要解码之后的画面,通过前后画面的与本帧数据的叠加取得最终的画面。B帧压缩率最高。

GOP:两个I帧之间是一个图像序列,也就是一个GOP,在一个图像序列中只有一个I帧。GOP主要用作形容一个 i 帧到下一个 i 帧之间的间隔了多少个帧,增大一个GOP帧数能够有效的减少编码后的视频体积,但是也会降低视频质量。
I帧是完整的视频帧,换句话说,客户端只有在获得I帧后才会有完整的视频。如果直接发送,不等I帧,客户端得到的画面会残缺,但是延迟较低。如果等I帧,客户端缓冲时间较长,得到画面会完整,但是延迟至少是一个gop。

H264数据结构

H264的码流是有一个接一个的 NALU 组成的,而它的功能分为两层:视频编码层(VCL)和网络提取层(NAL)。其中,前者负责有效表示视频数据的内容,而后者则负责格式化数据并提供头信息,以保证数据适合各种信道和存储介质上的传输。因此我们平时的每帧数据就是一个NAL单元(NALU)。

VCL 数据即编码处理的输出,它表示被压缩编码后的视频数据 序列。在 VCL 数据传输或存储之前,这些编码的 VCL 数据,先被映射或封装进 NAL 单元中。每个 NALU 包括一个原始字节序列负荷(RBSP,)、一组对应于视频编码的 NALU 头部信息。RBSP 的基本结构是:在原始编码数据的后面填加了结尾比特。

NALU和切片

视频里面的每一帧图片,在经过H264编码之后,都会成为一个或多个片(slice),而NALU就是用来装载片的载体,但是NALU内部不一定都是切片,也有可能装载其他描述视频的信息。

片的主要作用是用作宏块的载体,同时也是为限制误码的扩散和传输,每个片都应该是互相独立被传输的,某片的预测(片内预测和片间预测)不能以其它片中的宏块为参考图像。

宏块

宏块是视频信息的主要承载者,因为它包含着每一个像素的亮度和色度信息。视频解码最主要的工作则是提供高效的方式从码流中获得宏块中的像素阵列。

H264默认是使用 16X16 大小的区域作为一个宏块,也可以划分成 8X8 大小。一个宏块由一个16×16亮度像素和附加的一个8×8 Cb和一个 8×8 Cr 彩色像素块组成。每个图象中,若干宏块被排列成片的形式。

宏块中包含了宏块类型、预测类型、Coded Block Pattern、Quantization Parameter、像素的亮度和色度数据集等等信息。

子宏块

切片类型和宏块类型的关系:

I片:只包 I宏块,I 宏块利用从当前片中已解码的像素作为参考进行帧内预测(不能取其它片中的已解码像素作为参考进行帧内预测)。

P片:可包 P和I宏块,P 宏块利用前面已编码图象作为参考图象进行帧内预测,一个帧内编码的宏块可进一步作宏块的分割:即 16×16、16×8、8×16 或 8×8 亮度像素块(以及附带的彩色像素);如果选了 8×8 的子宏块,则可再分成各种子宏块的分割,其尺寸为 8×8、8×4、4×8 或 4×4 亮度像素块(以及附带的彩色像素)。

B片:可包 B和I宏块,B 宏块则利用双向的参考图象(当前和 来的已编码图象帧)进行帧内预测。

SP片(切换P):用于不同编码流之间的切换,包含 P 或 I 宏块

SI片:扩展档次中必须具有的切换,它包 了一种特殊类型的编码宏块,叫做 SI 宏块,SI 也是扩展档次中的必备功能。

I、P、B压缩分别为I、P、B帧。

整个H264的数据结构如下:

H264编码后视频的每一组图像(GOP)都给予了传输中的序列(PPS)和本身这个帧的图像参数(SPS)。

压缩技术

帧内压缩

人眼对图象都有一个识别度,对低频的亮度很敏感,对高频的亮度不太敏感。所以可以将一幅图像中人眼不敏感的数据去除掉。这样就提出了帧内预测技术。

帧内压缩就是将一幅图像被划分好宏块后,对每个宏块可以进行 9 种模式的预测。找出与原图最接近的一种预测模式。然后将将原始图像与帧内预测后的图像相减得残差值,在将之前得到的预测模式信息一起保存起来,这样我们就可以在解码时恢复原图了。

帧间压缩

利用连续帧中的时间冗余来进行运动估计和补偿。码流中增加SP帧,方便在不同码率的码流间切换,同时支持随机接入和快速回放。

帧分组

视频数据主要有两类数据冗余,一类是时间上的数据冗余,另一类是空间上的数据冗余。其中时间上的数据冗余是最大的。视频里有很多特别密切的帧,其实我们只需要保存一帧的数据,其它帧都可以通过这一帧再按某种规则预测出来。

H264编码器会按顺序,每次取出两幅相邻的帧进行宏块比较,计算两帧的相似度,在相邻几幅图像画面中,一般有差别的像素只有10%以内的点,亮度差值变化不超过2%,而色度差值的变化只有1%以内,我们认为这样的图可以分到一组。在这样一组帧中,经过编码后,我们只保留第一帖的完整数据,其它帧都通过参考上一帧计算出来。我们称第一帧为IDR/I帧,其它帧我们称为P/B帧,这样编码后的数据帧组我们称为GOP。

运动估计与补偿

H264编码器中将帧分组后,就要计算帧组内物体的运动矢量。编码器首先按顺序从缓冲区头部取出两帧视频数据,然后进行宏块扫描,找到运动物体后计算相邻两帧间物体运动的方向和距离。运动矢量计算出来后,将相同部分(也就是绿色部分)减去,就得到了补偿数据。我们最终只需要将补偿数据进行压缩保存,以后在解码时就可以恢复原图。

运动矢量与补偿称为帧间压缩技术,它解决的是视频帧在时间上的数据冗余。

对残差数据做DCT

将残差数据做整数离散余弦变换,去掉数据的相关性,进一步压缩数据。

熵编码(CABAC)

熵编码压缩是一种无损压缩,其实现原理是使用新的编码来表示输入的数据,从而达到压缩的效果。常用的熵编码有游程编码,哈夫曼编码和CAVLC编码等。

CABAC也是 H.264/MPEG-4AVC中使用的熵编码算法。CABAC在不同的上下文环境中使用不同的概率模型来编码。其编码过程大致是这样:首先,将欲编码的符号用二进制bit表示;然后对于每个bit,编码器选择一个合适的概率模型,并通过相邻元素的信息来优化这个概率模型;最后,使用算术编码压缩数据。