H.264压缩编码算法介绍

来源:互联网 发布:windows redstone 编辑:程序博客网 时间:2024/04/29 16:13

在这里我总结了许多博客专家对H.264压缩编码算法的理解,得出了我个人的一些见解。现在本人正在研究Android视频直播这一方面的知识,只是设备是定制的Android设备,不是很正规的Android系统。所以这一套的算法放在Android上运行很流畅也不见得可以在定制的设备上完美的运行。无奈之下只得从头开始分析源代码,坚持将自己的学习过程记录下来。一是给自己每天的学习做一个记录,二是通过分享自己的学习经验可以认识更多志同道合的朋友一起学习和希望可以帮助到正在研究直播的朋友

  • H.264的相关介绍
  • H.264的特点
  • 算法是怎么工作的

H.264的相关介绍

H.264是由ITU-T视频编码专家组(VCEG)和ISO/IEC动态图像专家组(MPEG)联合组成的联合视频组(JVT,Joint Video Team)提出的高度压缩数字视频编解码器标准。全称是MPEG-4 AVC(通常被称之为H.264/AVC或者AVC/H.264或者H.264/MPEG-4 AVC或MPEG-4/H.264 AVC),是由两部分的开发者共同完成的。视频压缩的由来是因为摄像头和麦克风采集的原始视频和音频数据量过大,不便于网络的传输分享,理论上原始采集的视频数据获得的一部电影可能要几十G或者更大,所以引入视频压缩编码很有必要。H.264也正是这众多压缩编码标准中的一员,并且目前使用的非常普遍。尤其是在视频直播点播等相关领域,H.264因为它的高性能、国际标准、公正的无差别许可制度受到了人们的热捧。

H.264的特点

1.更高的编码效率:H.264比其前身H.263和MPEG-4节约了将近50%的带宽;
2.高质量的视频画面:H.264能够在低码率情况下提供高质量的视频图像,在较低带宽上提供高质量的图像传输是H.264的应用亮点。
3.提高网络适应能力:H.264可以工作在实时通信应用(如视频会议)低延时模式下,也可以工作在没有延时的视频存储或视频流服务器中。
4.采用混合编码结构: H.264与之前的H.261、H.263一样,也是采用的是混合编码的结构即DCT变换编码加DPCM的差分编码。(在压缩算法的地方会详细提到)同时,H.264为提高压缩编码的效率,在混合编码的结构下引入了新的编码方式,增加了如多模式运动估计、帧内预测、多帧预测、基于内容的变长编码、4x4二维整数变换等新的编码方式,提高了编码效率。
5.H.264的编码选项较少:在H.263中编码时往往需要设置相当多选项,增加了编码的难度,而H.264做到了力求简洁的“回归基本”,降低了编码时复杂度。
6.H.264可以应用在不同场合:H.264可以根据不同的环境使用不同的传输和播放速率,并且提供了丰富的错误处理工具,可以很好的控制或消除丢包和误码。
7.错误恢复功能:H.264提供了解决网络传输包丢失的问题的工具,适用于在高误码率传输的无线网络中传输视频数据。
8.较高的复杂度:264性能的改进是以增加复杂性为代价而获得的。据估计,H.264编码的计算复杂度大约相当于H.263的3倍,解码复杂度大约相当于H.263的2倍。

多模式运动估计

H.264高精度估计
在H.263中采用了半像素估计,在H.264中则进一步采用1/4像素甚至1/8像素的运动估计。即真正的运动矢量的位移可能是以1/4甚至1/8像素为基本单位的(一般采用的1/4像素,对于1/2像素运动的估计,系统运行时有这个明显的增益。但是即使使用的是1/8像素,系统的增益已经不明显,所以没有何必去花费大量的性能开销)。显然,运动矢量位移的精度越高,则帧间剩余误差越小,传输码率越低,即压缩比越高。

多宏块划分模式估计
在H.264的预测模式中,一个宏块(MB)可划分成7种不同模式的尺寸,这种多模式的灵活、细微的宏块划分,更切合图像中的实际运动物体的形状,于是,在每个宏块中可包含有1、2、4、8或16个运动矢量。

多参数帧估计
在H.264中,可采用多个参数帧的运动估计,即在编码器的缓存中存有多个刚刚编码好的参数帧,编码器从其中选择一个给出更好的编码效果的作为参数帧,并指出是哪个帧被用于预测,这样就可获得比只用上一个刚编码好的帧作为预测帧的更好的编码效果。

小尺寸4×4的整数变换
视频压缩编码中以往的常用单位为8*8块。在H.264中却采用小尺寸的4*4块,由于变换块的尺寸变小了,运动物体的划分就更为精确。这种情况下,图像变换过程中的计算量小了,而且在运动物体边缘的衔接误差也大为减少。当图像中有较大面积的平滑区域时,为了不产生因小尺寸变换带来的块间灰度差异,H.264可对帧内宏块亮度数据的16个4×4块的DCT系数进行第二次4×4块的变换,对色度数据的4个4×4块的DC系数(每个小块一个,共4个DC系数)进行2×2块的变换。H.263不仅使图像变换块尺寸变小,而且这个变换是整数操作,而不是实数运算,即编码器和解码器的变换和反变换的精度相同,没有“反变换误差”。

更精确的帧内预测
在H.264中,每个4?4块中的每个像素都可用17个最接近先前已编码的像素的不同加权和来进行帧内预测。

统一的VLC
H.264中关于熵编码有两种方法。
统一的VLC(即UVLC:Universal VLC)。UVLC使用一个相同的码表进行编码,而解码器很容易识别码字的前缀,UVLC在发生比特错误时能快速获得重同步。
内容自适应二进制算术编码(CABAC:Context Adaptive Binary Arithmetic Coding)。其编码性能比UVLC稍好,但复杂度较高。
上述内容来自 H.264与压缩算法的介绍

算法是怎么工作的

在介绍那么多特点之后,我个人更加倾向于了解算法是怎么实现压缩编码的。H.264的压缩编码现在主要是由X.264静态库作为实现的基础,首先给编码器配置好视频数据相关适合的颜色空间,将传过来的原始音视频数据进行简单地转换之后在将数据输入到编码器进行编码压缩。在摄像头的回调函数里获取的是设置好格式的一帧帧数据(一帧YUV数据大小是width*height*3/2,数据格式是YUV420,具体的一般看你设置以及设置所支持的格式,一般设备支持NV21和YV12,当然你可以将设备支持的格式打印出来,方法如下:)

//打印支持的格式    List<Integer> list = params.getSupportedPreviewFormats();    for(Integer f:list){        Log.i("fm","Formats"+f);    }

原始的音视频数据一般需要转换成标准的YUV420格式才可以输入到编码器进行编码,即设置颜色空间进行转换,一般有NV21转NV12,NV21转I420等等。由于是实时进行转换的,所以把几帧图像分为一组(GOP,也就是一个序列),为防止运动变化,帧数不宜取多。在我的程序里设置的是48帧为一组(这里就有点大,因为对于定制的设备跑起来就有一点费劲)。然后将每组内各帧图像定义为三种类型,即I帧、B帧和P帧;定义好之后以I帧做为基础帧,以I帧预测P帧,再由I帧和P帧预测B帧,最后将I帧数据与预测的差值信息(p帧b帧)进行存储和传输。

在H264中图像以序列为单位进行组织,一个序列是一段图像编码后的数据流,以I帧开始,到下一个I帧结束。 一个序列的第一个图像叫做 IDR 图像(立即刷新图像),IDR 图像都是 I 帧图像。H.264 引入 IDR 图像是为了解码的重同步,当解码器解码到 IDR 图像时,立即将参考帧队列清空,将已解码的数据全部输出或抛弃,重新查找参数集,开始一个新的序列。这样,如果前一个序列出现重大错误,在这里可以获得重新同步的机会。IDR图像之后的图像永远不会使用IDR之前的图像的数据来解码。一个序列就是一段内容差异不太大的图像编码后生成的一串数据流。当运动变化比较少时,一个序列可以很长,因为运动变化少就代表图像画面的内容变动很小,所以就可以编一个I帧,然后一直P帧、B帧了。当运动变化多时,可能一个序列就比较短了,比如就包含一个I帧和3、4个P帧。此小段内容摘自H.264编码原理以及I帧B帧P帧

H.264的编解码流程主要包括5个部分:帧间和帧内预测(Estimation)、变换(Transform)和反变换、量化(Quantization)和反量化、环路滤波(Loop Filter)、熵编码(Entropy Coding)。

在这里首先介绍一下IPB帧的概念:
I帧:基本帧,帧内编码帧 ,关键帧,完整保留了该图像的所有信息,相比原始数据帧,压缩率7~10;解码时只需要本帧数据就可以完成(因为包含完整画面),不需要其他帧作为参考同时是PB帧的参考帧,I帧是帧组GOP的基础帧(第一帧),在一组中只有一个I帧;

P帧:前向预测编码帧(只参考前面最靠近它的I帧或P帧)。是在I 帧的基础上取与I 帧的差异,压缩率20;P帧表示的是这一帧跟之前的一个关键帧(或P帧)的差别,解码时需要用之前缓存的画面叠加上本帧定义的差别,生成最终画面(P帧的预测与重构:P帧是以I帧为参考帧,在I帧中找出P帧“某点”的预测值和运动矢量,取预测差值和运动矢量一起传送。在接收端根据运动矢量从I帧中找出P帧“某点”的预测值并与差值相加以得到P帧“某点”样值,从而可得到完整的P帧。)。也就是差别帧,P帧没有完整画面数据,只有与前一帧的画面差别的数据。P帧是I帧后面相隔1~2帧的编码帧;

B帧:双向预测内插编码帧(由前面的I或P帧和后面的P帧来进行预测的)。也就是B帧记录的是本帧与前后帧的差别,B帧的压缩率高,解码时CPU会比较累;压缩率50;要解码B帧,不仅要取得之前的缓存画面,还要解码之后的画面,通过前后画面的与本帧数据的叠加取得最终的画面(B帧的预测与重构:B帧以前面的I或P帧和后面的P帧为参考帧,“找出”B帧“某点”的预测值和两个运动矢量,并取预测差值和运动矢量传送。接收端根据运动矢量在两个参考帧中“找出(算出)”预测值并与差值求和,得到B帧“某点”样值,从而可得到完整的B帧。)。

例IPB序列:I、B、B、P、B、B、P、B、B、I、B、B、P…(I帧后面相隔1~2帧是P帧,中间是B帧。P帧与P帧之间是B帧)

接下来说一下H.264的编解码流程5个部分的主要功能:

1)帧间和帧内预测(Estimation)

帧内预测编码是H.264区别于其它编码标准的一个重要特征,用来缩减图像的空间冗余.为了提高H.264帧内编码的效率,帧内压缩是生成I帧的算法,所以压缩率不是很高。相对于直接对该帧编码而言,可以大大减小码率.

帧间预测编码利用连续帧中的时间冗余来进行运动估计和补偿.H.264的运动补偿支持以往的视频编码标准中的大部分关键特性,而且灵活地添加了更多的功能,帧间压缩是生成B帧和P帧的算法。它通过比较本帧与相邻帧之间的差异,仅记录本帧与其相邻帧的差值,这样可以大大减少数据量,压缩率较高

2)变换(Transform)

在变换方面,H.264使用了基于4×4像素块的类似于DCT的变换,但使用的是以整数为基础的空间变换,不存在反变换.与浮点运算相比,整数DCT变换会引起一些额外的误差,但因为DCT变换后的量化也存在量化误差,与之相比,整数DCT变换引起的量化误差影响并不大.此外,整数DCT变换还具有减少运算量和复杂度,有利于向定点DSP移植的优点.变换后得到的DCT系数是与每个像素都相关的,这些系数代表了被变换数据的基础色调与细节.

3)量化(Quantization)

量化是在不降低视觉效果的前提下减少图像编码长度,减少视觉恢复中不必要的信息。H264采用标量量化技术,它将每个图像样点编码映射成较小的数值。H.264中可选32种不同的量化步长,这与H.263中有31个量化步长很相似,但是在H.264中,步长是以12.5%的复合率递进的,而不是一个固定常数.在H.264中,变换系数的读出方式也有2种:之字形(Zigzag)扫描和双扫描.大多数情况下使用简单的之字形扫描;双扫描仅用于使用较小量化级的块内,有助于提高编码效率.h.264在DCT变换后对DCT系数进行了量化,量化能有效去除相邻像素间的空间冗余,也就是说会抹去元素数据的部分细节。比较理想的情况是量化抹去人眼无法识别的细节部分,但是在低码率的情况下就会导致原始数据的细节丢失过多。而且,DCT变换时基于块的,即将8x8或者4x4的像素残差进行变换后得到8x8或者4x4DCT系数,此时如果进行了低码率的量化,就会使得相邻两个块的相关性变差,从而出现块效应。.

4)环路滤波(Loop Filter)

为了减轻和消除视频图像中的块效应,通常会使用滤波器对块边界处的像素进行滤波以平滑像素值的突变.同时可以达到降低噪音的效果

5)熵编码

视频编码处理的最后一步就是熵编码,在H.264中采用了2种不同的熵编码方法:通用可变长编码(UVLC)和基于文本的自适应二进制算术编码(CABAC).熵编码即编码过程中按熵原理不丢失任何信息的编码。

以上的流程什么的全是纸上谈兵,我仅仅是了解了一些基本的流程以及原理。可以说出个大概。但要想深入了解就需要深入去研究H.264编码的实际算法了。任重而道远!!!

总结

以上全是我总结大牛的简介总结出的个人理解,相关的引用我也在相应的地方指明出处。如有不对之处,还望谅解并且指出。我定当采纳并改进。我是Mr.小艾。

1 0