编解码:H.264原理浅析
一 视频编码的原因
目前市面上主流的视频已经是1080p及以上了,包括4k、8k等越来越流行,硬件设备支持度越来越高,假设一个FPS为60的4K视频(主流手机如iphone等拍摄的视频),则一张图片需要3840 X 2160 X 3 X 8 = 190Mb,1s视频数据需要190Mb X 60 = 11Gb。显然,网络带宽是远远满足不了的,因此有了视频编码,以便于在网络上进行传送时,节省传送带宽,而且对于本地也能节省存储空间
二 视频编码的步骤
RGB采集数据 —— YUV源数据 —— 帧类型分析 —— 帧内/帧间预测 —— 整数离散余弦变换 (DCT)与量化 —— 滤波 —— 熵编码 —— 得到压缩视频数据
1 RGB到YUV的预处理
采集的源数据一般为RGB数据(444),然后经过编码成为YUV(420),两者需要的数据量是2/1,能够很好的节省带宽。
2 帧类型分析
I帧:关键帧,采用帧内压缩技术,不参考或者只参考自身
P帧:向前参考帧,在压缩时,只参考前面已经处理的帧
B帧:双向参考帧,在压缩时,它即参考前而的帧,又参考它后面的帧
IDR帧:I帧的一种,告诉解码器,解码参数(SPS\PPS)需要refresh,否则解码画面异常
SPS(Sequence Paramater Set “序列参数集”),SPS中保存了一组编码视频序列(Coded Video Sequence)的全局参数。该类型保存的是和编码序列相关的参数。
PPS(Picture Paramater Set “图像参数集”),该类型保存的是整体图像相关的参数。
GOP:图像组,就是一段连续图像帧且画面之间变化不大,主要用作形容一个 I 帧 到下一个 I 帧之间的间隔,一般用M来表示。还有一个N是用来表示同一个GOP中,I帧到P帧的间隔,用于限制B帧的数目。M增大或者N增大,则 I 帧减少,则能减少编码后的视频体积,但是也会降低视频质量,参考帧太少
3 帧内/帧间预测
划分宏块/子块
宏块是视频信息的主要承载者,包含像素的亮度(Y)和色度信息(Cb,Cr)
帧内预测----处理空域数据冗余
首先根据图片的内容信息划分出16X16、8X16、 16X8、 8X8、 4X8、 8X4、 4X4 的宏块或者子块,然后用它们和经过计算估计选择的预测模型预测的YUV数据做差值计算,得到残差数据宏块,这样我们在码流中,就直接传输残差数据宏块以及其预测模式的标志位就行,极大节省了码流
帧间预测----处理时域数据冗余
对于关联紧密的帧(一般来说画面没有剧烈变化),只需要保存一帧的数据,其它帧可以通过该帧按算法预测出来,将这些帧进行分组,第一帧为I帧或者IDR帧,其他分别为P帧或者B帧,这样的一组数据称为GOP。对于一个GOP,H.264编码器顺序取出两帧视频数据,对其进行宏块扫描分析。当发现其中一幅图片中某个东西,在另一个图片中出现了,根据计算得到运动矢量,将其保留下来。将所有具有运动矢量的位置记录下来后,排除两个图像相同的数据,即为补偿数据,这样就只需要记录一点补偿数据以及第一帧的经过帧内预测的压缩数据(I帧),极大的节省了码流
4 整数离散余弦变换 (DCT)与量化
图像编码中,图像以矩阵形式存储,是一个二维数组,对图像进行二维DCT,可以将时域图像转为频域能量分布图,实现能量集中从而去除空间冗余:
1)首先将图像分割成8x8或16x16的宏块或子块;
2)对每个块进行DCT变换;
3)舍弃高频系数(AC系数),保留低频信息(DC系数)。高频系数一般保存的是图像的边界、纹理信息,低频信息主要是保存的图像中平坦区域信息。
4)图像的低频和高频,高频区域指的是空域图像中突变程度大的区域(比如目标边界区域),通常的纹理丰富区域。
例如存在经过预测后得到的残差数据宏块矩阵:
10 10 10 10
10 10 10 10
10 10 10 10
10 10 10 10
对其进行DCT变换后,变为:
40.000000 0.000001 -0.000002 0.000002
0.000001 0.000000 -0.000000 0.000000
-0.000002 -0.000000 0.000000 -0.000000
0.000002 0.000000 -0.000000 0.000000
可以见到,大多数能量集中在了左上角低频处。因此在图像中,低频分量可以看作是基本图像,高频分量为边缘轮廓细节信息(也可能是噪声)。绝大多数能量都包含了大量平坦区域,因此大部分能量集中于低频区域(左上角),从而可以达到去除空间冗余的目的(其中,DCT变换尺寸越大,DCT去相关性能越好,但是DCT的计算复杂度会随之增大)
经过DCT变换得到的系数是稀疏的,也就是只有少数位置的值是比较大的, 也就是上面的40,其他的都接近于0,因此我们就用0来代替,这样就可以省下了不少的存储空间。原本的4 X 4 的数据只需要保留1个,因此数据量极大的压缩了
量化就是取整。用一个==Q(量化矩阵)对得到的C(DCT系数)==进行量化,Z(量化系数) = 【C/Q】,【】代表的是取整,因此会导致出现信息损失。编码器中是用整形变量代表像素值(一般为0-255),Q越大,相应的需要存储的信息就越少,压缩比就越大,但是丢掉的高频信息就越多,并且还原的低频信息也会越不准确,即造成的失真就越大,块效应也会越大,视频编码的质量损失主要来源于此。
5 滤波
在解码器反变换量化后会出现块效应。块效应产生的原因以及主要形式:梯形噪声,由于DCT高频系数被量化为0,使得强边缘在跨边界处出现锯齿状;格形噪声,经常出现在平坦区域,由于量化导致本来平缓变换的亮度块DC系数发生跳跃,造成变换块的基础色调改变。因此,需要去块滤波器改善视频画面质量
具体细节参考:https://www.cnblogs.com/TaigaCon/p/5500110.html
6 熵编码
熵编码压缩是一种无损压缩,其实现原理是使用新的编码来表示输入的数据,从而达到压缩的效果。常见的熵编码方式有Cavlc、哈夫曼编码等
哈夫曼编码原理,给高频的数据一个短码,给低频数据一个长码从而达到数据压缩的目的
CABAC也是给高频数据短码,给低频数据长码,并根据上下文相关性进行压缩,更高效
具体的编码细节就不多深究了,有兴趣的可以查一下
7 封装
最后再将其封装成字节流格式(AnnexB)、AVCC 、RTP打包格式,即得到了网络传输的码流或者和音频编码出来的码流一起封装成我们常见的mp4等格式
最后和音频编码出来的码流一起封装成我们常见的mp4等格式