H264
单纯传输视频画面,视频量非常大,对现有的网络和存储来说是不可接受的。
为了能够使视频便于传输和存储,人们发现视频有大量重复的信息,如果将重复信息在发送端去掉,在接收端恢复出来,这样就大大减少了视频数据的文件,因此有了H.264视频压缩标准。
I帧
又称为关键帧或者帧内编码帧,采用帧内压缩技术。
是一种自带全部信息的独立帧,无需参考其他图像便可独立进行解码,可以简单理解为一张静态画面。视频序列中的第一个帧始终都是I帧,因为它是关键帧。
P帧
又称为
向前参考帧
或帧间预测编码帧
,采用帧间压缩技术。
除了I帧
之外的所有帧,全部向前依赖。
所有帧都只保存与前一帧的差异,以达到高压缩率的效果。
解码时需要用之前缓存的画面叠加上本帧定义的差别,生成最终画面。
B帧
又称为刷
双向参考帧
,属于帧间压缩技术。
即参考前一帧,也参考后一帧。以达到比P帧
更高的压缩效果。
也就是说要解码B帧,不仅要取得之前的缓存画面,还要解码之后的画面,通过前后画面的与本帧数据的叠加取得最终的画面。对于直播业务,B帧比P帧永远要慢一点。
B帧压缩率高,但是对解码性能要求较高。
比较
-
I帧只需考虑本帧
-
P帧记录的是与前一帧的差别
-
B帧记录的是前一帧及后一帧的差别
能节约更多的空间,视频文件小了,但相对来说解码的时候就比较麻烦。 因为在解码时,不仅要用之前缓存的画面,而且要知道下一个I或者P的画面,对于不支持B帧解码的播放器容易卡顿。 复制代码
视频监控系统中预览的视频画面是实时的,对画面的流畅性要求较高。采用I帧、P帧进行视频传输可以提高网络的适应能力,且能降低解码成本所以现阶段的视频解码都只采用I帧和P帧进行传输。
GOP
Group of Pictures 一组帧
相似画面的一组帧
如下图所示,两个I帧
之间的所有帧,叫做一组帧。
具体的划分细节,在下面《帧分组》的部分会提到
SPS
序列参数集 Sequence Parameter Set
包含一组帧中:存放帧数、参考帧数目、解码图像尺寸、帧场编码模式选择标识等
PPS
图像参数集 Picture Parameter Set
包含一组帧中:存放熵编码选择模式标识、片组数目、初始量化参数和去方块过滤波系数调整标识等
在一组帧中,SPS与PPS也属于I帧。
视频出现花屏、卡顿的原因
-
丢帧造成花屏
当一组帧中丢失了某一帧,就会造成某个部分没有完成更新。造成花屏。
-
丢GOP造成卡顿
为了避免花屏的问题,当发现I帧或P帧丢失,则不现实本GOP中所有的内容。知道下一个I帧到达后重新刷新图像。
视频编解码器
-
x264/x265
x264是目前使用最广泛的H264编解码器(主要用来编码,解码用ffmpeg)。 x265的压缩率比x264更高,性能的消耗也更大。
-
openH264
相对x264性能较低,但支持SVC技术。
SVC可以将视频分层传输:
可以对用户带宽进行不同策略的定制方案:将一帧数据分为小、中、大三个部分,根据对方网络情况分别追加发送。
接收到的部分越多,最后组合起来的视频就越清晰。
但由于很多手机不支持SVC编码,所以需要使用软编处理,会对CPU产生损耗。
-
vp8/vp9
Google出品,分别对应x264/x265
H264压缩技术
这部分最后发现李超老师自己已经写过博客了,建议去看原文
帧内预测压缩
解决空域数据的冗余问题
空域数据,类似音频中的超声波段,不容易甚至不会被人类注意识别。
帧间预测压缩(运动估计与补偿)
解决时域数据的冗余问题
时域数据,对于监控之类静止不动的画面,对帧与帧之间重复的数据进行计算压缩。
整数离散余弦变换(DCT)
将空间上的相关性变为频域上无关的数据然后进行量化
CABAC压缩(无损压缩)
类似哈夫曼无损编码
宏块划分
对于一段视频,首先会被送到 H264 编码器的缓冲区中,并为每一帧图片进行宏块的划分
-
划分宏块
H264默认是使用 16X16 大小的区域作为一个宏块,也可以划分成 8X8 大小。
-
计算宏块的象素值
对宏块中的每一个像素点进行计算
最终一幅图会变成这个样子 -
划分子块
对于复杂的图片或局部,H264可以对宏块进行更细致的划分以达到更高的压缩率,比如8X16、 16X8、 8X8、 4X8、 8X4、 4X4
这样对于小局部像素颜色相同的子块,就可以用很少的信息进行表示
帧分组
宏块划分好后,还需要对编码器缓存中所有的图片进行分组(GOP)
帧间预测压缩
主要在这里解决时域数据的冗余问题
:
对于某些关联特别密切的帧,其实我们只需要保存一帧的数据,其它帧都可以通过这一帧再按某种规则预测出来,所以说视频数据在时间上的冗余是最多的。
如何判定两帧处在一个GOP中?以一个的台球桌的视频为例:
H264编码器会按顺序,每次取出两幅相邻的帧进行宏块比较,计算两帧的相似度。如下图:
通过宏块扫描与宏块搜索可以发现这两个帧的关联度是非常高的。进而发现这一组帧的关联度都是非常高的。因此,上面这几帧就可以划分为一组。其算法是:在相邻几幅图像画面中,一般有差别的像素只有10%以内的点,亮度差值变化不超过2%,而色度差值的变化只有1%以内,我们认为这样的图可以分到一组。
帧间压缩技术(运动估计与补偿)
也叫
运动估计与补偿
,用于压缩时间层面的冗余,清除相同数据。
对于一组帧,需要计算运动物体的运动矢量:
H264编码器首先按顺序从缓冲区头部取出两帧视频数据,然后进行宏块扫描。当发现其中一幅图片中有物体时,就在另一幅图的邻近位置(搜索窗口中)进行搜索。如果此时在另一幅图中找到该物体,那么就可以计算出物体的运动矢量了。
下面这幅图就是搜索后的台球移动的位置
H264依次把每一帧中球移动的距离和方向都记录下来就成了下面的样子
运动矢量计算出来后,将相同部分(也就是绿色部分)减去,就得到了补偿数据。我们最终只需要将补偿数据进行压缩保存,以后在解码时就可以恢复原图了。压缩补偿后的数据只需要记录很少的一点数据。如下所示
帧内压缩技术
人眼对图象都有一个识别度,对低频的亮度很敏感,对高频的亮度不太敏感。所以基于一些研究,可以将一幅图像中人眼不敏感的数据去除掉。这样就提出了帧内预测技术。
H264的帧内压缩与JPEG很相似。一幅图像被划分好宏块后,对每个宏块可以进行 9 种预测模式
。找出与原图最接近的一种预测模式。帧内预测后的图像与原始图像的对比如下:
将预测图像与原图像对比得到残差值
,解码时根据记录下来的预测模式
与残差值
,即可还原出原本的图像。
DCT压缩
可以将
残差值
做整数离散余弦变换
,去掉数据的相关性,进一步压缩数据。
比如:
压缩后变成
VLC与CABAC(无损压缩)
根据信息出现的频率,对整体进行压缩
参考哈夫曼编码:对高频信息使用短码,而低频信息使用长码进行压缩。
MPEG-2
中使用的VLC
就是这种算法
而在H264中,使用CABAC
进行压缩,不只对频率进行压缩,还根据上下文进行进一步压缩
对于视频帧,在有了上下文之后,剩下的帧会进一步压缩
H264结构与码流
H264结构
从大到小,H264的视频结构如下所示 视频流 => N个视频帧 => N个切片 => 切片头+N个宏块 => N个子块
H264编码分层
-
NAL层
网络抽象层 以太网单个数据包限制为1500字节,NAL可以将单帧数据进行拆包与组包处理,以进行传输。
-
VCL层
视频编码层 对视频的原始数据进行压缩
H264码流
-
SODB(String Of Data Bits)
原始数据比特流
由NAL层产生。长度不一定是8字节的倍数
-
RBSP(Raw Byte Sequence Packet)
为
SODB
末尾补1,然后补零成8位。
-
EBSP(Encapsulate byte sequence payload)
起始标记的格式化
-
NALU(NAL Unit)
在
EBSP
前加一个1B的网络头
NALU
NALU HEADER
NALU 头部信息,由三部分构成
对于Type(nal_unit_type):
1, 2, 3, 4, 5及12的NAL单元称为VCL的NAL单元,其他类型的NAL单元为非VCL的NAL单元。
0:未规定
1:非IDR图像中不采用数据划分的片段
2:非IDR图像中A类数据划分片段
3:非IDR图像中B类数据划分片段
4:非IDR图像中C类数据划分片段
5:IDR图像的片段
IDR帧属于I帧,此位置代表关键帧的一部分
6:补充增强信息 (SEI)
7:序列参数集/SPS
8:集图像参数/PPS
SPS和PPS都是特殊的NALU。一个MP4文件只有一个SPS,但是有很多PPS,SPS必须在所有NALU的最开头。
9:分割符
10:序列结束符
11:流结束符
12:填充数据
13 – 23:保留
24 – 31:未规定 (27、28表示为分片NALU)
复制代码
NAL
单一类型
一个RTP数据包中只包含一个NALU(切片)
很多P帧、B帧都是单一类型
组合类型
一个RTP数据包中包含多个NALU
比如SPS、PPS通常就会放在同一个RTP数据包内进行发送
分片类型
一个NALU被分片成多个RTP数据包发送
图像的存储格式
RGB
红、绿、蓝。每个元素1字节,共24位
YUV
从电视系统中衍生出来的一套颜色编码方式
-
Y
明亮度(灰阶值)。基础信号,非黑即白
-
U&&V
色彩和饱和度。用于指定像素颜色
-
YUV的格式
YUV常见格式可以参阅:YUV格式介绍
其中最常见的是YUV 4:2:0
,相对RGB 8:8:8
的格式,节省了很多空间。
YUV 4:2:0
并不意味着没有V分量,而是只在相邻的分行扫描中一行采用YUV 4:2:0
,下一行采用YUV 4:0:2
这种抽样存储。
-
YUV的存储格式
可以参阅视频存储格式YUV420 NV12 NV21 i420 YV12