音视频学习(二)-- H.264编码原理

4,753 阅读11分钟

一、前言

上一篇文章《音视频学习(一)-- 基础知识准备》我们对音视频的基础知识有了一个大概的了解,这篇我们来深入了解一下视频的编码技术。

1、为什么要对视频编码

假设一个 1 小时的未压缩的电影(1920 * 1080),像素数据格式为 RGB24,按照每秒 25 帧来计算: 3600 * 25 * 1920 * 1080 * 3 = 559.872GByte 500G 的电影显然太大了,下载耗时也占地方,在线看也很慢,毕竟我们平时看的一般也就几个 G 而已。所以我们要对视频进行 压缩,而 编码 就是 压缩 的过程。

2、如何编码

帧率(FPS)代表每秒显示的帧数(显示的画面数),也可以用频率的单位 Hz 来衡量。由于人眼的视觉暂留现象,当帧率到达一定数值后,人眼就会感觉画面是连续运动的了。一秒钟达到 16 帧以上,大脑就会认为是连贯的了,动画片和电影一般是 25 帧。

上面的翻页动画可以看出有很多高度重复的画面,比如背景,这时候我们就可以对其进行压缩。压缩的过程其实就是去除冗余信息的过程。

  • 视频信息中的冗余

视频信息中通常包含的冗余有三种:空间冗余时间冗余统计冗余。处理这三种冗余信息通常采用不同的方式:

(1)空间冗余: 采用帧内预测编码压缩;

(2)时间冗余: 采用运动搜索和运动补偿压缩;

(3)统计冗余: 采用熵编码压缩。

编码又分为 软编码 和 硬编码

  • 软编码:使用CPU进行编码 特点:实现直接、简单,参数调整方便,升级易,但 CPU 负载重,性能较硬编码低,低码率下质量通常比硬编码要好一点。

  • 硬编码:使用非 CPU 进行编码,如显卡GPU特点:性能高,低码率下通常质量低于硬编码器,但部分产品在 GPU 硬件平台移植了优秀的软编码算法,质量基本等同于软编码。

对视频进行编码有很多种技术手段,H.264 视频压缩算法目前是所有视频压缩技术中使用最广泛的。下面我们认识一下 H.264

二、H.264

1、简介

国际上制定视频编解码技术的组织有两个,一个是“国际电联(ITU-T)”,它制定的标准有 H.261、H.263、H.263+ 等,另一个是“国际标准化组织(ISO)”它制定的标准有 MPEG-1、MPEG-2、MPEG-4 等。而 H.264 则是由两个组织联合组建的联合视频组(JVT)共同制定的新数字视频编码标准,所以它既是 ITU-TH.264,又是 ISO/IECMPEG-4 高级视频编码(Advanced Video Coding,AVC)的第 10 部分。

  • 优势: H.264 最大的优势是具有很高的数据压缩比率,在同等图像质量的条件下,H.264 的压缩比是 MPEG-22 倍以上,是 MPEG-41.5~2 倍。

2、VCL 与 NAL 分层

H.264 原始码流(裸流)是由一个接一个 NALU 组成,它的功能分为两层,VCL(视频编码层)和 NAL(网络提取层)。

  • VCL: 视像编码层(Video Coding Layer, 简称VCL),包括核心压缩引擎和块,宏块和片的语法级别定义,设计目标是尽可能地独立于网络进行高效的编码,对视频原始数据进行压缩。
  • NAL: 网络抽象层(Network Abstraction Layer,简称NAL)。在以太网每个包大小是 1500 字节,而一帧往往会大于这个值,所以就需要用于按照一定格式,对 VCL 视像编码层输出的数据拆成多个包传输,并提供包头(header)等信息,以在不同速率的网络上传输或进行存储,所有的拆包和组包都是 NAL 层去处理的。覆盖了所有片级以上的语法级别。

VCL 数据传输或者存储之前,会被映射到一个 NALU 中,H264 数据包含一个个 NALU。如下图:

一个NALU = 一组对应于视频编码的NALU头部信息 + 一个原始字节序列负荷(RBSP,Raw Byte Sequence Payload)

H.264 码流第一个 NALUSPS,第二个 NALUPPS,第三个 NALUIDR(即时解码器刷新)

  • SPS: 序列参数集 SPS(Sequence Parameter Sets),存储的是一个序列的信息,包括有多少帧等
  • PPS: 图像参数集 PPS(Picture Parameter Sets ),存储的一帧的信息。 解码的时候必须获取到 SPSPPS 的信息,才能对后面的数据进行解码。

image

3、帧、片 与 宏块

(1)帧

I帧(关键帧)

I 帧也叫关键帧,采用的是 帧内压缩技术

  • I 帧概念理解: 我们拍摄视频时,1 秒内拍摄的内容很少会有大幅度的变化,但是摄像头一秒钟会抓取几十帧,比如电影就是 125 帧,这样一组帧内的变化很小,为了压缩数据,没必要都存下来,我们只把第一帧完整的保存下来作为关键帧即可。 I 帧很关键,后面解码数据都要依赖于这个 I 帧。

P帧(向前参考帧)

P 帧也叫向前参考帧,采用的是 帧间压缩技术P帧只会保存跟前一帧不一样的数据, 压缩时只参考前一个帧。 视频的第一帧会被作为关键帧完整保存下来,后面的帧会向前依赖,也就是第二帧依赖于第一个帧,后面所有的帧只存储于前一帧的差异,这样就能将数据大大的减少,从而达到一个高压缩率的效果。

B帧(双向参考帧)

B 帧也叫双向参考帧,采用的是 帧间压缩技术。 压缩时既参考前一帧也参考后一帧,这样就使得它的压缩率更高,存储的数据量更小。如果B帧的数量越多,你的压缩率就越高.这是B帧的优点,但是B帧最大的缺点是,如果是实时互动的直播,那时与B帧就要参考后面的帧才能解码,那在网络中就要等待后面的帧传输过来.这就与网络有关了.如果网络状态很好的话,解码会比较快,如果网络不好时解码会稍微慢一些.丢包时还需要重传.对实时互动的直播,一般不会使用B帧. 如果在泛娱乐的直播中,可以接受一定度的延时,需要比较高的压缩比就可以使用B帧. 如果我们在实时互动的直播,我们需要提高时效性,这时就不能使用B帧了.

(2)GOF(Group of Frame)或 GOP(Group of Picture)

我们管一组帧叫做 GOF 或者 GOP。一组帧就是一个 I 帧到下一个 I 帧之间的数据。下面这张图清楚地展示了一组 GOP 内三种帧的解码顺序和显示顺序,可以发现不管是解码还是显示都是先从 I 帧开始的。

帧顺序.jpeg

(3)片(slice)

片的主要作用是用作宏块的载体。设置片的目的是为了限制误码的扩散和传输,编码片是项目独立的,一个片的预测不能以其他片中的宏块为参考图像。保证了某一片的预测误差不会传播到别的片。 我们可以理解为一张图片可以包含一个或多个片,而每一个片包含整数个宏块,即每片至少一个宏块,最多时每片包整个图像的宏块。 切片可以细分为“切片头+切片数据”,因为一帧数据一次有可能传不完,所以需要记录头信息。

(4)宏块(Macroblock)

宏块是视频信息的主要承载者,因为它包含着每一个像素的亮度和色度信息。视频解码最主要的工作则是提供高效的方式从码流中获得宏块中的像素阵列。 组成部分:一个宏块由一个 16×16 亮度像素和附加的一个 8×8 Cb 和一个 8×8 Cr 彩色像素块组成。每个图象中,若干宏块被排列成片的形式。 宏块中包含了宏块类型、预测类型、Coded Block Pattern、Quantization Parameter、像素的亮度和色度数据集等等信息。

(5)帧、片 与 宏块的关系

我们知道一帧代表的就是一张图像。其中 1 帧 = n 个片 1 片 = n 个宏块 1 宏块 = 16x16yuv 数据

image

image
从上图可看到一个序列的第一个图像叫做 IDR 图像(立即刷新图像),IDR 图像都是 I 图像。H.264 引入 IDR 图像是为了解码的重同步,当解码器解码到 IDR 图像时,立即将参考帧队列清空,将已解码的数据全部输出或抛弃,重新查找参数集,开始一个新的序列。这样,如果在前一个序列的传输中发生重大错误,如严重的丢包,或其他原因引起数据错位,在这里可以获得重新同步。IDR 图像之后的图像永远不会引用 IDR 图像之前的图像的数据来解码。

下图是 h264 的一个完整的码流分层结构:

4、预测编码的原理

了解 H264 编码之前,我们先了解一个概念,那就是 预测编码

  • 预测编码: 对于存在前后相关性的信息,预测编码 是一种非常简便且有效的方法。此时预测编码输出的不再是原始的信号值,而是信号的预测值与实际值的差。这样设计是因为相邻信号存在大量相同或相近的现象,通过计算其差值可减少大量保存与传输原始信息的数据体积。 下面用代码来举个例子说明一下预测编码的原理,假设有下面的10 个数字:
2 , 2 , 2 , 7 , 2 , 2 , 2 , 2 , 2 , 13

我们也可以用下面的方式来表示:

prediction = 2;
Difference = { (5, 3), (11, 9) };

上面表示的是目标信号的预测值为2,在第 511 个元素的位置存在残差,差值分别为 39。 通过预测编码,不仅降低了表示像素信息所需要的比特数,还可以保留视频图像的画面质量。

预测编码 并非H.264最先采用的技术。在早期的压缩编码技术中便采用了 预测数据+残差 的方法来表示待编码的像素。然而在这些标准中预测编码仅仅用于 帧间预测 来去除空间冗余,对于帧内编码仍然采用直接DCT+熵编码的方法,压缩效率难以满足多媒体领域的新需求。H.264 标准深入分析了 I 帧中空间域的信息相关性,采用了多种预测编码模式,进一步压缩了I帧中的空间冗余信息,极大提升了 I 帧的编码效率,为H.264 的压缩比取得突破奠定了基础。

(1)帧内预测压缩

帧内预测压缩 解决的是空域数据冗余问题. 什么是空域数据,就是这幅图里数据在宽高空间内包含了很多颜色,光亮.人的肉眼很难察觉的数据. 对于这些数据,我们可以认作冗余.直接压缩掉的.

(2)帧间预测压缩

帧间预测压缩 解决的是时域数据冗余问题。 在我们之前举例说明过,摄像头在一段时间内所捕捉的数据没有较大的变化,我们针对这一时间内的相同的数据压缩掉,这叫时域数据压缩。

以上的总结参考了并部分摘抄了以下文章,非常感谢以下作者的分享!:

1、雷霄骅的视频课《基于FFmpeg+SDL的视频播放器的制作-第1节-大纲和视音频基础知识》(PS:致敬音视频大神雷神雷晓华先生,谢谢你生前为我们留下来的无私分享成果)

2、云导播的《H.264/AVC 的分层结构与画面划分》

3、合肥懒皮的《H264系列十三 句法元素的分层结构》

4、Abson在简书的《深入浅出理解视频编码H264结构》

5、取次花丛懒回顾的《【H.264/AVC视频编解码技术详解】二十三、帧间预测编码(1):帧间预测编码的基本原理》

转载请备注原文出处,不得用于商业传播——凡几多