之前视频基础,有讲到视频的原始数据YUV,相比RBG,数据确实减少了,但还是一个非常大数据量,会占用很大空间以及在给网络传输带来很大压力。所以必须要对视频进行压缩,减少占用空间。这里主要分享H264编码技术,压缩和编码是一回事。
H264压缩比是百分之一 ,能将100M的YUV数据压缩到接近1M数据大小。
什么是GOP?
一组强相关的图像帧。
将一个视频拉长,帧比较多的时候,对帧进行分组,分组的要求是每一组帧的相关性较强。举例 把做相同动作的帧放在一组。(这一组图像只是发生了细微的差别,变化较单调)。
I帧P帧B帧
- I帧(intraframe frame),关键帧。
采用帧内压缩技术。I帧是所有数据帧最关键的帧,如果缺少了I帧,后面的数据帧将无法使用。IDR帧属于I帧。举例我将GOP中第一帧就可以称作I帧。在编码时,I帧是不需要参考前后帧数据,是独立编码。GOP至少有一个I帧。
- P帧(forward Predicted frame),向前参考帧。
压缩时,只参考前面已经处理的帧,采用帧间压缩技术。它占I帧的一半大小。
- B帧(Bidirectionally predicted frame),双向参考帧。
压缩时,既参考前面已经处理的帧,也参考后面的帧,帧间压缩技术。它占I帧1/4大小。压缩率变高
既然B帧占用空间小?是不是B帧越多越好?
虽然B帧的压缩率是最高,但是他同时带来一个问题, 他占用的CPU以及耗时非常多,既然耗时,在实时直播视频情况就会导致一个延迟的情况。如果只是想减少空间大小,B帧将是一个很好的选择。根据情况,来选择对应的策略。所以一般在直播中是没有B帧,只有I帧和P帧。
** 编码后数据,根据I帧P帧B帧的特性,在解码的过程是按I帧、P帧和B帧进行解码,文件播放还是按I帧、B帧和P帧顺序播放。**
IDR帧和I帧的关系。
IDR(Instantannous Decoder Refresh) 解码器立即刷新
作用:在解码的过程,一旦有一帧数据出现错误,将是无法恢复的过程,后面数据帧不能使用。当有了IDR帧,解码器收到IDR帧时,就会将缓冲区的数据清空,找到第一个IDR帧,重新解码。I和IDR帧都使用帧内预测,在编码解码中为了方便,首个I帧要和其他I帧区别开,把第一个I帧叫IDR,这样方便控制编码和解码流程。IDR帧必须是一个I帧,但是I帧不一定是IDR帧,这个帧出现的时候,是告诉解码器,可以清除掉所有的参考帧,这是一个全新的序列,新的GOP已经开始。I帧有被跨帧参考的可能,IDR不会。
每个GOP中的第一帧就是IDR帧。
IDR帧是一种特殊的I帧。
帧与分组的关系:
SPS与PPS参数
成对出现的一组参数数据,在IDR帧之前
SPS(Sequence Parmeter Set)
序列参数集,作用于一串连续的视频图像。如seq_prameter_set_id、帧数及POC(picture order count)的约束、参考帧数目、解码图像尺寸和帧场编码模式选择标识等。GOP的参数设置。
PPS
图像参数集,作用于视频序列中的图像。如pic_parameter_set_id、熵编码模式选择标识、片组数目、初始量化和去方块滤波系数调整标识等
文末名片免费领取音视频开发学习资料,内容包括(C/C++,Linux 服务器开发,FFmpeg ,webRTC ,rtmp ,hls ,rtsp ,ffplay ,srs)以及音视频学习路线图等等。
H264的压缩技术
由一系列技术组成的压缩集。
有损压缩技术:
帧内压缩,解决的是空域数据冗余问题。例如:一个人物的背景图像是一样,那么可以使用非常小的数据量进行存储。
帧间压缩,解决的时域数据冗余问题。在时间上进行压缩,参考前面帧数据压缩。前面提到IBP帧就是。
无损压缩技术:
整数离散余弦变换(DCT),将空间上的相关性变为频域上无关的数据然后进行量化。
CABAC压缩
宏块
宏块是视频压缩操作的基本单元,把几个像素划分成一个宏块,例如8x8,4x4,4x8,8x4等。
无论是帧内压缩还是帧间压缩,它们都以宏块为单位。
如果图像细节较多,宏块一般要划分更小一些。对于背景细节较少,宏块可以设置大些,这样编码处理会更快。
划分后进行编码,得到数据将会很小,只要得到特定的纹理数据就行了。
宏块划分越仔细,对图像的压缩控制更加有效。
帧内压缩的理论
人对亮度的敏感度超出色度,YUV很容易将亮度与色度分开。
相邻像素差别不大,所以可以进行宏块预测。
进行预测出来的图像,不是直接拿来用,出来图像会有一些模糊,加入帧内预测残差值,得到更加准确的图像。
帧内预测残差值
得到的图像数据 = Prediction Mode Info + Resident Picture ,与原始图像对比,还有出现一些色度上的偏差。因为是损压缩,在一定上会有一些误差出现,影响不大。
帧间压缩技术
P帧和B帧压缩。
帧间压缩一定是在同一个GOP进行图像压缩。
- 参考帧,后面的帧参考前面的帧。记录运动矢量,运动估计(宏块匹配 + 运动矢量),运动补偿(解码 ,加入残差值)
- 宏块查找 做运动估计,查找宏块,对比两者间的相似性,相似度越高,就认为是目标宏块,并记录对应的宏块的坐标(运动矢量)。
- 宏块查找算法:三步搜索、二维对数搜索、四步搜索和钻石搜索。
宏块与宏块间,一样有差异,需要加入残差值。解码过程需要其运动矢量和残差值,才能得到与原始图像相近的图像。
问题查找:
视频花屏原因:
GOP分组中有帧丢失,会造成解码端的图像发生错误,这会出现马赛克。运动矢量和残差值都没有,更别说I帧,实际后面的所有数据都无法解码出来。
视频卡顿:
为了避免花屏问题的发生,当发现帧丢失时,就丢弃GOP内的所有帧,直到下一个IDR帧重新刷新图像。
I帧是按照帧周期来的,需要一个比较长的时间周期,如果在下一帧来之前不显示后来的图像,那么视频就静止不动了,这就是出现了所谓的卡顿现象。
经过有损压缩,还不够小,进一步压缩,在经过无损压缩—1、DCT变换:将分散的数据集中起来 2、CABAC压缩 H.264(VLC压缩 MPEG2)。
H264编码流程
编码:
帧内压缩 →帧内预测模式Choose →每个宏块预测模式计算出来→得到推算数据IN 与当前帧对比得到残差值→然后就是无损编码 →经过转换变换→量化 CABAC →拆包→打成NAL头
帧间压缩→经过运动评估ME(对宏块匹配查找) →得到运动矢量 MC→推算出图像数据→得到图片再与当前帧对比得到残差值→经过转换变换→量化 CABAC →拆包→打成NAL头
H264码流
- NAL层
Network Abstraction Layer ,视频数据网络抽象层,方便网络传输。出现丢包、乱序,NAL层可以起到纠错的功能。
- VCL层
Video Coding Layer 视频数据编码层。
VCL结构关系:
一般一个slice对应一个图像。
码流基本概念
- SODB String Of Data Bits 二进制数据串
帧内编码 帧间编码 熵编码出来的数据 没做任何处理的二进制数据串
原始数据比特流,长度不一定是8的倍数,故需要补齐。它是由VCL层产生的。
- RBSP Raw Byte Sequence Payload 按字节存储的数据
SODB+trailing bits 一般以8整数倍
算法是如果SODB最后一个字节不对齐,则补1和多个0。
- NALU
NAL Header(1B)+RBSP
NAL Unit单元
slien数据结构
如果要保存文件,需要加入Startcode,不然播放器不知道每个NAL的分隔符是什么,无法进行解码播放。如果是网络传输,RTP格式不需要startcode
MB data:宏块类型、宏块的预测值和残差值。