白话H264编码

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/CrystalShaw/article/details/94455897

一、概述

二、帧内、帧间编码

YUV原始数据量非常大,以YUV420为例,一个像素点就需要1.5个字节,1080P分辨率下,一帧YUV420的图像就需要

1920*1080*1.5=3110400字节=2.97M,若是按照30fps计算,一秒钟就要占用712.8mbps带宽。数据量非常惊人的大。

不过视频数据有时间冗余和空间冗余,编码通过去除时间、空间冗余,可以达到压缩数据,降低码率的目的。

帧内帧间编码的意义可以通过上式表达:

1、编码器编码当前块时,可以通过参考原始块(这个原始块是本帧,就是帧内编码,非本帧,就是帧间编码)进行相减,得到一个残差。传输时,仅需要传输原始块和残差值,就可以计算出当前块的值。

2、很明显传输残差,要比传输原始数据,占用的bit位少。如上图当前数据里面,传输8数字需要4个bit,但是传输残差0/1仅需要一个bit。

四、DCT变换

传输残差会降低码率,但是残差值分布没有规律,若能把数据尽量排列的有规律,并且还可逆,可以还原到原始数据。就能进一步降低码率。

DCT变换的核心理念就是把图像的低频信息(对应大面积平坦区域)变换到系数矩阵的左上角,而把高频信息变换到系数矩阵的右下角,这样就可以在压缩的时候(量化)去除掉人眼不敏感的高频信息(位于矩阵右下角的系数)从而达到压缩数据的目的。

离散余弦变换原理,这个链接介绍的比较直观:https://thecodeway.com/blog/?p=353

DCT变换公式

整个一张图片计算DCT效果当然是最好的,但是这样计算量就会非常大,所以在264算法里面会将一张图片分割成若干个宏块,以宏块为单位,进行DCT变换,例如以8*8块计算:

而每一次都以一个8*8的块来执行DCT的转换:

经由DCT的转换后会产生1个DC系数及63个AC 系数: 

能量会集中在几个低频的数值上:

示例:

DCT变换后数据,分布虽然有规律了,但是若是将低频和高频区数据相差不是很大的数据,变成同一个值,视频数据量还可以 再压缩一下。这就引入量化功能。

五、量化

公式:

q(x, y) = round(F(x, y) / Q + 0.5);

示例:

再经过锯齿扫描(之字扫描)

将二维数组转换成一维数组,例如上面量化后数据,可以以9、0、-1、0、-1、0、0、0、0、0、0、0、0、0、0、0形式保存在一维数组里面。下面就可以 将这些数据进行熵编码,继续压缩了。

六、CAVLC熵编码

在H.264的CAVLC(基于上下文自适应的可变长编码)中,通过根据已编码句法元素的情况动态调整编码中使用的码表,取得了极高的压缩比。

CAVLC用于亮度和色度残差数据的编码。残差经过变换量化后的数据表现出如下特性:

1、4*4块数据经过预测、变换、量化后,非零系数主要集中在低频部分,而高频系数大部分是零;

2、量化后的数据经过zig-zag扫描,DC系数附近的非零系数值较大,而高频位置上的非零系数值大部分是+1和-1;

3、相邻的4*4块的非零系数的数目是相关的。

CAVLC充分利用残差经过整数变换、量化后数据的特性进行压缩,进一步减少数据中的冗余信息,为H.264卓越的编码效率奠定了基础。

找到一篇《熵编码之CAVLC》,这里就不展开了。

参考

《新一代视频压缩编码标准H.264》

比较好的介绍哈夫曼编码:https://thecodeway.com/blog/?p=522

猜你喜欢

转载自blog.csdn.net/CrystalShaw/article/details/94455897