1
我们为什么要进行压缩?
2
视频信息为什么可以被压缩?
3
视频压缩算法概述
(一)我们为什么要进行压缩?
原始的视频数据YUV(RGB)很大,举个例子:
1080p@60fps,2h的电影,其YUV大小:1920x1080x1.5Bytes*60*3600*2≈1.35TB
1080p@30fps的YUV,占用带宽为:1920x1080x12bit*30≈750Mbps
如果不经过压缩,这么大的数据量对于存储以及传输而言都会造成巨大的压力。
(二)视频信息为什么可以被压缩?
视频数据中存在大量的冗余信息,所以可以通过一些算法来去除这些冗余。很多视频压缩的算法中出现最多的描述就是利用xx相关性/去除xx冗余,可以说绝大多数的压缩算法都是基于这个思想在做的。
同样的,我们来举个例子——
屏幕共享播视频,暂停了,这时相同的帧(图像)按照时间顺序组成了一个视频。从原始YUV的角度来计算的话,此时的数据量是
SIZE(YUV) = FRAMES * PER_FRAME_SIZE

那么,我们仔细思考下,真正的信息量有那么大吗?其实只有第一帧包含信息量,后面的帧存在很大程度的冗余。
当然,上述的例子只是个特殊情况,实际情况中帧与帧之间是存在着变化的。但即使这样,大多数情况下还是存在着大量的冗余的,比如背景区域等等。因此视频压缩其实是一种信源编码的方法,目的就是极大程度的去除这种冗余,减少数据量。
(三)视频压缩算法概述
1. 视频压缩
视频压缩算法的输入一般是YUV数据,Y表示亮度, 也就是我们常数的灰度图,UV表示色度。之所以采用这种格式而不直接使用RGB数据,主要有两个原因:
(1) Y分量表示画面的亮度部分,单独显示也可以,可以解决彩色电视机与黑白电视的兼容问题
(2)U/V包含细节较少,可以通过下采样减少数据量(也就是我们经常听到的YUV420格式)
上面的图从上到下,从左到右分别是原始YUV,Y,U,V几个通道的数据,可以看到Y分量数据量相对丰富,可以表达整个图的主要信息,相比而言UV分量的信息量就比较少,高频分量也较少。
其实视频压缩比较类似于我们说的加密算法,输入的YUV数据经过编码器处理变成码流数据,而解码器则是把收到的码流数据解码成YUV数据以供后续使用。
下图是一个实际的码流文件用文本编辑器打开看到的情况,其实码流就是一串0 1字符串,本身没有任何意义,由于编解码器共同遵守一套流程(一般是由标准规定的),所以解码器可以据此来恢复出原始数据。我们常说的264,265就是视频编码标准,265解码器只能解码符合265标准的码流,264解码器也同样。
虽说视频压缩与加密解密存在一些共性,但还是有一定的差异的,下面我简单地以自己的理解列了一个对比表:
2. 视频编解码框图
最近的视频编码标准都采用基于块的混合编码框架,包括预测、变换、量化以及熵编码等模块,如下图所示。该框架中基本的模块基本都贯穿了之前说的利用xx相关性/去除xx冗余的思想,其中
帧内预测:去除空域冗余
帧间预测:去除时域冗余
变换:从像素域到频域, 将能量集中
量化:唯一的有损模块,去除一些信息量的冗余
熵编码:去除统计冗余
下图是从一个码流分析仪中截取到的一帧,在实际编码中,并不是直接对整帧进行的,而是将原始数据划分为一个个的块去编码。
下面我们来看看各个模块都干了些什么事情吧~
3. 帧内预测——去除空域冗余
一幅图像内相邻像素值之间的相关性很强,相邻像素值之差的统计分布应该集中在零附近。下图是多幅实际图像的水平方向相邻像素差值的概率密度,不难看出对于灰度范围为0~255的常见图像,差值信号绝对值的80%~90%都落在0~20范围内,符合拉普拉斯分布:
帧内预测的主要思想是——纹理是连续的,可以使用相邻的已解码的像素预测未知像素,下面我们来看下实际的帧内预测是怎么做的。
帧内预测一般包含很多方向(当然也包括DC,Planar等模式),假设纹理是连续的,当前纹理信息可以从周边的像素(比如上边和左边)预测出来。如下图所示,当前块利用它上边和左边的像素来预测(实际上就是该位置的像素是这个方向延伸出去找到的参考像素对应位置的值,当然实际使用过程中会存在对参考像素进行滤波/插值等操作),最终能得到右边的预测块。
然后原始块减去预测块,得到残差块(如下图所示)。实际编码时只对残差块进行操作,这样数据量可以减少。
TIPS:我们通常所知的I帧中的所有块只能采用帧内预测,P/B帧中的块可以选择采用帧内预测(一般是当前帧新出现的区域)
4. 帧间预测——去除时域冗余
对视频内容而言,除非存在场景切换,一般相邻帧之间往往存在很强的相关性。如下图所示是相邻两帧的差值,偏黑的部分接近于0,偏白的部分接近255, 不难看出两帧之间的差值也基本集中在0附近(很多论文表明其满足拉普拉斯分布)。
帧间预测的思想是——同一物体在相邻帧会重复出现,且运动具有一定的连续性。目前帧间预测使用的方法为基于运动矢量(MV)的预测模型,也就是用块匹配的方式找到当前块在参考帧中的位置,并计算对应的位移(即MV)。下图最右边就是MV情况,可以看到手的位置的MV都是向右下方的,由于人物在做端水杯的动作,所以当前帧中的手在前一帧中偏右下的位置。
TIPS: 只有P帧或者B帧中的块才能采用帧间预测方式,I帧中的块只能使用帧内预测。
小科普:为什么I帧往往比P/B帧大?
P/B帧既可以使用帧内预测,也可以使用帧间预测,从中选择最好的预测模式,所以说P/B帧<=I帧。一般而言视频内容是连续的,时域的相关性更大,所以一般而言帧间预测的压缩效率更高,因此往往P/B帧会更小 (下图左边是帧内预测的残差情况,右边是帧间预测的残差情况,接近灰色表示残差较小,接近黑白色表示残差较大)。(当然也有例外,如果刚刚发生了场景切换,这个时候往往I/P/B帧的大小都差不多)
既然P/B帧很小,为什么我们还需要I帧呢?其实P/B帧的解码需要依赖其他帧,所以在一些网络损伤的场景下,其他帧丢失可能会导致当前帧无法解码。
5. 变换——聚集信号能量
空间域相关性较强的像素值通过正交变换,其分布会发生改变:数据集中在少数直流或者低频分量。数据分布集中有利于通过量化去除大部分接近0的值,再使用较高效的表达方式(如Zig-Zag扫描,变长编码等),以达到减少数据量的目的。下图是从码流分析仪得到的变换前(左边)后(右边)的数据, 可以看出变换后能量集中在了左上角,右下角的数据大多数变成了0。
几代标准(如H.264,H.265)中一般对残差块进行变换,变换核的选择:DCT/DST,优点:可分离, 蝶形运算速度很快。
6. 量化——去除视觉冗余
量化是数据压缩的有效方法之一,也是压缩产生失真的根源之一。目前H.264,H.265中用的都是标量量化的方法,具体做法是将变换后的系数分为不同的区间,每个区间的多个数值只用一个标号来解决,对于0附近对应的区间,会被量化为0,该部分称为死区,如下图所示。
量化过程丢弃了一部分对人眼视觉贡献不大的数据,该模块是有损的,不可逆。在量化中一个很重要的参数是QP(Quantization Parameter),一般来说:

QP越大,码率越小,质量越差;QP越小,码率越大,质量越好。有一大类码率控制算法,就是通过研究编码帧复杂度以及目标码率等情况,通过调整QP(或者lambda—拉格朗日乘子),使得编码码率满足目标码率,视频质量尽可能高。(PS: 相关的算法也在整理中,敬请期待~)
7. 熵编码——去除统计冗余
如果说前面处理的步骤还能勉强看到每个数字代表什么意思,到这步结束以后就完全不知道啦。熵编码的思想是对较高概率的符号分配较短的码字,对较低概率的符号分配较长的码字,使得平均码长最短。
同样地,举个例子——对下面这副牌进行编码,如果利用左边这种定长编码的方法,00表示2, 01表示3,....以此类推,那么要表示这些牌组成的符号的话平均需要2bit。但是假如我们知道2出现的概率是1,其他几个数字出现的概率是0,那么我们就可以用0来表示2,10表示3,110表示4,111表示A,那么同样编码这些牌组成的额符号的话平均就只需要1bit了。
熵编码就是利用这种符号概率的思想来进行处理的,目前H.265中使用的较多的编码方式是基于上下文的自适应算术编码——CABAC,Context-based Adaptive Binary Arithmetic Coding,具体的流程图如下: (该模块比较复杂,在这里就不再展开了)
当然,也不是所有的元素都使用CABAC编码的,一般来说表示比特流高层的语法元素,由于本身信息较少,使用定长编码,放在比特流比较显著的位置,便于其他应用提取。对于比特流中比例较大的残差系数等信息,则采用CABAC的算法,减少数据量。
8. 环路滤波——提升重建质量
在视频编码中,编码端除了做编码以外,还包含解码过程,因此存在一个环路。那么为什么要包含解码环路呢?因为量化引入了失真,不可逆,且当前帧需要被后续帧参考。为了保证编解码端可以得到一致的参考帧,因此编码端在当前帧编码结束后会进行解码操作,获得重建帧,将其放入参考帧缓存,作为后续帧的参考帧。
环路滤波作用在解码重建之后,下一帧编码之前,主要的作用是—(1) 提升当前帧的主客观质量; (2)当前帧被后续帧参考时提升预测精度,减小所需传输的残差。在H.265中包含两种环路滤波器,去块滤波器和样点自适应偏移滤波器(SAO)。
去块滤波器
由于视频编码分块进行,块边界重建像素存在不连续性。当边界两侧较为平坦时,这种不连续就表现为了块效应,如下图所示:
去块滤波器主要分辨实际图像边界或者编码产生的边界,如果判定为编码产生的不连续时进行平滑处理,以提升主观质量,下图为去块滤波后的效果:
样点自适应偏移滤波器(SAO, Sample Adaptive Offset)
在编码时往往会对高频分量的进行较大的量化,这会会导致高频信息的丢失,重建像素会在原始值上下波动,称为吉布斯现象(振铃效应)。如下图所示,虚线所示为实际像素值,点表示重建值,会存在波动情况。
SAO的思想是在像素域上进行补偿。首先对像素分类,每一类计算一个offset,对每个重建像素加一个offset,分类方法分为边缘补偿和条带补偿两种方式。该滤波器本质上是码率与质量的折中。
名词解释——率失真优化
上面介绍了编码器中的重点模块,其实对于编码器而言,还有一个极为重要的名词——率失真优化(RDO, Rate-Distortion)。这里的率通常指的是码率(Rate),失真(Distortion)可以是不同的形式,包括MSE, SSIM, VMAF等。
根据香农信息论的原理,码率与失真的关系如下图中曲线所示,码率越高,失真越小,反之亦然。用一套特定的编码参数(量化步长,编码模式选择等)对视频序列进行编码,计算编码码率以及重建失真,可以得到码率和失真的一个R-D工作点(如下图所示的实心三角)。用不同的若干套的编码参数重复上述编码过程,获得若干个R-D工作点。率失真优化的目标就是寻找一套编码参数,使它所代表的工作点尽可能地接近于理想RD曲线:(下图中靠近曲线的实心三角编码效率要更高)
编码是一个给定约束条件的最优化问题,此类问题往往使用拉格朗日乘子法来进行优化。在编码器内部,会通过比较RD-cost来确定最优模式,RD-cost = D + lambda * R (lambda是拉格朗日乘子,理论上当lambda正好等于理想RD曲线的斜率时最优,实际编码器中lambda一般都是提前确定的值)。通常做法是遍历每个块划分,对于每个块,遍历所有的预测模式,找出编码代价最小的作为预测模式。但该做法特别耗时,因此这里可以做很多快速算法,尽量利用一些信息减少遍历的次数,提升编码器的速度。
往期推荐
1
2
3
4
请随时与我们联系并分享您的需求:
腾讯多媒体实验室
编辑:Yihan
继续阅读
阅读原文