iOS 音视频(二) - 视频编码-H264概念与原理

2024-05-13  本文已影响0人  顶级蜗牛

相关文献:
iOS 音视频(一) - 基础知识
iOS 音视频(二) - 视频编码-H264概念与原理
iOS 音视频(三) - 视频编码-实现H264编解码
iOS 音视频(四) - 音频AAC编解码

文章结掌握内容:
1.H264基础知识
2.H264编码原理
3.宏块划分 与 帧分组
4.帧间压缩原理
5.帧内压缩原理
6.VLC压缩/CABAC压缩
7.H264结构与编码分层
8.H264码流

一、H264基础知识

1.了解IPB帧

举个例子,如果摄像头对着你拍摄,1秒之内,实际你发生的变化是非常少的.1秒钟之内实际少很少有大幅度的变化.摄像机一般一秒钟会抓取几十帧的数据.比如像动画,就是25帧/s,一般视频文件都是在30帧/s左右.对于一些要求比较高的,对动作的精细度有要求,想要捕捉到完整的动作的,高级的摄像机一般是60帧/s.那些对于一组帧的它的变化很小.为了便于压缩数据,那怎么办了?将第一帧完整的保存下来.如果没有这个关键帧后面解码数据,是完成不了的.所以I帧特别关键.

视频的第一帧会被作为关键帧完整保存下来.而后面的帧会向前依赖.也就是第二帧依赖于第一个帧.后面所有的帧只存储于前一帧的差异.这样就能将数据大大的减少.从而达到一个高压缩率的效果.

2.GOF(Group of Frame)一组帧

GOF和GOP(Group of Picture)是一个东西。

如果在一秒钟内,有30帧.这30帧可以画成一组.如果摄像机或者镜头它一分钟之内它都没有发生大的变化.那也可以把这一分钟内所有的帧画做一组.

什么叫一组帧?
就是一个I帧到下一个I帧的这一组的数据,包括B帧/P帧,被称为GOF.

3.SPS/PPS

在直播的时候对一段一段的视频帧数据进行传输是没有办法做到解码的,需要SPS/PPS这样的解码参数来进行解码。

SPS/PPS实际上就是存储GOP的参数.

SPS: (Sequence Parameter Set,序列参数集)存放帧数,参考帧数目,解码图像尺寸,帧场编码模式选择标识等.

PPS:(Picture Parameter Set,图像参数集).存放熵编码模式选择标识,片组数目,初始量化参数和去方块滤波系数调整标识等.(与图像相关的信息)

只要记住,在一组帧之前我们首先收到的是SPS/PPS数据。如果没有这组参数的话,我们是无法解码。

4.视频花屏/卡顿的原因

我们在观看视频时,会遇到花屏或者卡顿现象.那这个GOF就息息相关了.

总结:花屏是因为你丢了P帧或者I帧.导致解码错误. 而卡顿是因为为了怕花屏,将整组错误的GOP数据扔掉了.直达下一组正确的GOP再重新刷屏.而这中间的时间差,就是我们所感受的卡顿.

二、H264编码原理

H264编码实际上就是对视频的冗余数据进行压缩。

三、宏块划分 与 帧分组

1.宏块划分

将一个图片(图1)中的左上角用宏块描述,就是宏块是8*8的元素,取出的颜色,像图2的去描述颜色。
将整张图片全部用宏块描述就如下图3:

图3

那么基本的图片的宏块划分就完成了。
那是不是每个宏块都是8*8了?并不是的,还有子块划分。在这个大的宏块里,可以再细化:

比如我们中间这个全部都是蓝色的这个宏块,就可以用一个色块,更加简单描述就行了。没必要全部蓝色宏块都去描述。

子宏块

对比旁边的MPEG 2H.264:MPEG2存储时还说比较完整,占用的空间相对于比较多;而H.264还是减少了很多空间,像重复的颜色他们就用非常简单的色块描述了。

2.帧分组
假设台球桌

举例:一个台球从一个位置移动到另外一个组。可以发现它的桌面背景是一样的,只是球体位置发生了变换,这个就可以把这一组帧划分为一组。

四、帧间压缩原理

帧间压缩是针对于P/B帧的,因为它解决的是时间的数据冗余。

1.组内宏块查找

如下图,台球从一角滚到另外一角,相邻的两幅图做组内的宏块查找。
将图逐行扫描,扫描到第三行发现了台球,然后围绕它的周围查找.发现了有类似的图块,把这些的图块放在同一张图片中。

2.运动估算

查找到有类似的图块,就会把这些的图块放在同一张图片中,如图4。
就是说台球刚开始从位置1到移动到位置2,这之间有一个运动矢量(矢量会包含运动的方向和距离)。
将所有的图都两两比较.最后就形成了图5。就是图5中红色部分。
每一个红色的箭头标注都是一个运动矢量.很多帧就会形成一个连续的运动估算.

3.运动矢量与补偿压缩

最终将连续的运动估算换算成下图所表现的。
就是对齐进行压缩,所有帧的背景都是一样的。变换在哪里了?变换就是它的运动矢量还有台球的数据。

实际经过我们一运算后,它留下的就只是运动矢量数据+残差值的数据。经过这样的一个计算,帧间压缩数据我们就可以看到实际我们只需要存储一点点数据,而不像以前要将几十帧的所有图片数据保存下来,这就达到了压缩的效果。

整个过程被称之为帧间压缩技术的原理

五、帧内压缩原理

帧内压缩是针对于I帧的.因为它解决的是空间的数据冗余。

首先将图片划分为宏块,对多个宏块进行颜色的排序,针对排序结果去选择宏块去采用不同的模式运算。

当每个宏块都选定了模式之后,就形成了下图的这样的色块分布效果(预测图)。
每个宏块都选择一个帧内预测的模式,帧内预测一共有9种模式。

帧内预测9种模式原理介绍(1)
帧内预测9种模式原理介绍(2)

预测图

让每个宏块挑选好模式之后,我们就可以使用块预测模式,预测完了之后,它就得到一个张"预测图"。

预测图&原图

计算的预测图和原图是有差别的,这时就做两张图的差计算。
通过预测与原图的差得出一个结果,这个灰色图就是残差值

预测模式与残差值压缩:
拿到参差值之后,我们就进行压缩,压缩时保存 残差数据和每个宏块选择的模式信息数据
那么有了这2个数据之后,当我们解码时,首先通过宏块的模式信息计算出预测图,然后将预测图与我们的残差值进行累积,就能还原成原图像。
那这个过程就是"帧内压缩原理"

预测宏块信息+残差值

六、DCT压缩

DCT压缩也是整数余弦压缩技术。

将图片划分成可量化的宏块 将量化的宏块根据DCT数学方法进行压缩 达到数据量减少作用的最终结果

DCT压缩原理(1)
DCT压缩原理维基百科

六、VLC压缩(无损压缩)

VLC类似哈夫曼码.,用短码来记录高频数据.用长码记录低频数据;频率高的就编为短码,频率低的就编为长码。

VLC用短码记录高频数据 长码记录低频数据

VLC实际上是MPEG2使用的技术。

CABAC压缩(上下文适应无损压缩技术)

H264使用的是CABAC。
CABAC除了使用哈夫曼短码高频,长码高频的方式;还加上了上下文适应的技术,根据上下文就可以加大压缩比。

对比VLC / CABAC

七、结构与编码分层

1.H264结构

在H264结构中,一个视频图像编码后的数据叫做一帧;
一帧由一个片 (slice) 或多个片组成;一个片由一个或多个宏块(MB)组成;一个宏块由16x16的yuv数据组成。宏块作为H264编码的基本单位

H264结构图

H264视频压缩后会成为一个序列帧;帧里包含图像;图像分为很多片;每个片可以分为宏块;每个宏块由许多子块组成。

一帧最少包含一个切片 片与宏块的关系
2.H264编码分层

八、H264码流

1.了解码流

左边的三帧视频帧是发送給编码器之前的数据,开发者必须将原始图像数据封装为CVPixelBuufer的数据结构。
右侧是经过编码器后的H264码流。需要注意的是这些码流是不可以单独使用的,因为解码器并不能对其直接解码。

需要将H264码流合并成H264文件:

码流的种类

解释EBSP:

每个NAL前有一个起始码 0x00 00 01(或者0x00 00 00 01 ),解码器检测每个起始码,作为一个NAL的起始标识,当检测到下一个起始码时,当前NAL结束。
同时H.264规定,当检测到0x00 00 01时,也可以表征当前NAL的结束。那么NAL中数据出现0x000001或0x000000时怎么办?H.264引入了防止竞争机制,如果编码器检测到NAL数据存 在0x000001或0x000000时,编码器会在最后个字节前插入一个新的字节0x03,这样:

0x000000 ->0x00000300
0x000001 ->0x00000301
0x000002 ->0x00000302
0x000003 ->0x00000303

解码器检测到0x000003时,把03抛弃,恢复原始数据(脱壳操作)。解码器在解码时,首先逐个字节读取NAL的数据,统计NAL的长度,然后再开始解码。

2.了解NALU (NAL Unit 码流单元)

NAL Unit = NALU Header + 一个切片RBSP
一个切片 = 切片Header切片数据

H264结构图提到过一个H264的帧是由多个切片构成的,因为一帧数据一次有可能传不完。

码流分层图

提问:NAL编码层会把一帧图片拆分成很多片,那是怎么知道我当前的片到底是属于I帧、P帧、B帧?还是SPS?PPS?

通过NALU Header(1bit)去获取nal_unit_type:

NALU Header解析(1bit=8位)

NALU类型参考图
举例一个单一类型的NALU:
NALU Header数据是 十六进制 0x67
转二进制 0 11 00111
将4-8位转十进制:00111 -> 7

对应上图中的表,7则是序列参数级SPS。
3.NALU类型介绍:
单一类型的RTP包

单一类型:
第1位:F; 第2-3位:NRI; 第4-8位:TYPE。

组合类型的RTP包 分片类型的RTP包

分片类型:
•第1个字节:FU indicator,分片单元指示符;
•第2个字节:FU Header,分片单元头。有多个片,就由FU Header组合起来。

FU Header是分片类型的RTP包会有的。

*FU Header

• S:start bit,用于指明分片的开始。在网络传输时,一个个包,我们知道它是分片的包,但是如何判断它是开始的包还是末尾的包被?如果为1,分片的开始。
• E:end bit,用于指明分片的结束
• R:未使用,设置为0

• Type:指明分片NAL类型。网络传输完成后,还是需要将分片组合成NALU单元。这个NAL单元是关键帧还是非关键帧,是SPS还是PPS,就需要根据Type来判断。

思考:我们在传输过程中将一个帧切割成多个片,如果在传输过程顺序打乱了,或者丢失了其中某个片,我们怎么判断NALU单元传输完整了?

答:依据FU Header 的S/E位并借助于RTP包的包头,在RTP的包头包括了每个包的序列号,如果我收到的包,收到了S包,也收到了E包,中间的包的序号是连续的,那就说明我们所有的包是完整的;如果是不连续就是丢包了,如果没有丢包就可以组合起来。

上一篇 下一篇

猜你喜欢

热点阅读