Skip to content

Latest commit

 

History

History
250 lines (129 loc) · 14.2 KB

视频H264编解码基础知识.md

File metadata and controls

250 lines (129 loc) · 14.2 KB

视频H264编解码基础知识

1 基础概念

1.1 为什么要编码

视频实际上是一帧一帧的图片组成的,当图片切换够快时(一般每秒15帧以上才不会觉得卡顿),就能达到画面动起来的效果。

一般衡量视频有个关键的指标:

FPS:帧率,每秒的画面数量,一个静止画面也就是一帧。

帧率越大。画面就越流畅。

但视频的原始数据体积是非常大的。

一份720P的视频数据,1280*720个像素,一个像素大约3个字节,以每秒30帧为例,那么一秒的视频原始大小约为79M。

1280*720*3*30/1024/1024 = 79M

那么一分钟,就得传输4.6G的数据。

如此庞大的原始数据是不适合在网络间传输和存储。因此才有视频编码技术。

1.2 编码技术

编码技术实际上的目的就是将数据进行压缩,过程是将一种视频格式转换成另外一种视频格式。只是不同的编码技术,使用的规则和原理不一样。市面上比较普遍的是H.264,以及新出的H.265。同时还有谷歌提出VP8,VP9编码技术。对iOS而言,系统的<VideoToolbox>框架,实现了H.264、H.265的编码功能。

1.3 编码分类

软编:软件编码,使用CPU进行编码。

硬编:硬件编码,不使用CPU进行编码,使用GPU等图像处理芯片来做编码处理。

优缺点

软编:实现和调用简单,调整参数方便,容易升级,兼容性好。但对CPU负载压力大。一般在低码率的视频编码中比硬编码好一些。

硬编:性能高,但依赖于图像处理芯片。iOS 8.0之后<VideoToolbox>开放了硬件编码解码的功能。但Mac OS下是一直有的。

1.4 编码原理

编码的目的都是压缩视频。针对视频,怎么样才能高效压缩?

猜想下,如果当一张图片都是同样的色值。实际上并不需将所有数据都传递,只需要传递一个色值和一个范围即可。

如果一段视频,大部分的画面是重复的,那只需传递变化的画面数据。这些重复的数据,可以当做视频数据的冗余信息。

如上图,背景都是不动的,只有部分动画在动。

所以视频传递时,将第一帧画面进行完整传输,后续的帧将变化的数据传递过来即可。当然大部分视频情况比上图复杂得多,光影和色彩的变化,冗余信息就需要通过复杂的模型去计算。所以高效高质量的处理冗余信息就是编码技术的关键。

1.5 编码技术实现方式

视频是由不同帧画面连续播放出来的,编码操作会将原始视频数据压缩成三种不同类型的帧:

I帧:关键帧,完整的编码的帧,不依赖于其他画面,可以当成是一张完整的画面。因为是完整数据,所以数据较大,压缩率相当于对图片进行压缩,压缩率大概为7。

P帧:帧间预测编码帧,需要参考前面的I帧或P帧的不同部分进行编码显示,单独的P帧不可以显示画面。因为是部分数据,所以数据较小,压缩率较大,大概为20。

B帧:双向预测编码帧,需要参考前面和后面的帧不同部分进行编码,压缩率最高,大概为50-200。因为需要依赖后续的帧,所以不适合实时视频传输(视频会议、门铃画面等)

1.5.1 两种核心算法

帧内编码:压缩一张完整的图片时,如上述所说,存在大部分相同的部分时可以进行压缩处理。帧间压缩可以当成是一张图片的压缩,压缩率和压缩图片差不多,不依赖于其他帧,可以完整解码出一张画面。I帧内的压缩即为帧内编码。

下图中,通过12345的编码,推算出6,就可以不用对6进行编码。

帧间编码:相连的帧是有很大关联性的,存在着前后帧信息变化小的特征。利用处理冗余信息进行压缩,可以大大减少数据量。帧间压缩一般是无损的。

下图中,两张连续的帧其实基本没变化。这个时候帧间编码压缩率就很高。

1.5.2 有损压缩和无损压缩

有损压缩:解压缩后的数据与压缩前的不一致,压缩过程中丢失感知不到的不重要的数据。且丢失的部分不可恢复。

无损压缩:压缩前和压缩后的数据一致。优化数据排列等。

1.5.3 DTS和PTS

DTS:主要用于视频的解码,在解码过程中使用。(解码用的时间戳)

PTS:主要用于视频同步和输出,渲染的时候使用。(显示用的时间戳)但没有B帧的情况下,DTS和PTS的输出顺序是一样的。

上图中,I帧的解析是不用依赖于任何帧。P帧依赖于前面的I帧和P帧。B帧依赖于前面最近的一个I帧或P帧和其后的一个P帧。

2 编码数据码流结构

2.1 计算机中的颜色信号

2.1.1 RGB

以前的美术课都有教过,任何颜色都可以通过三原色按照一定的比例合成出来。三原色为红色(red)、绿色(green)、蓝色(blue)。也就是对应的RGB。

计算机里面,R、G、B称为“基色分量”。取值是从0-255,一共256个等级(2的8次方)。任何颜色都可以用三个数值表示出来。

这种方式,一共可以表达256x256x256=16777216种颜色,也称1600万色。RGB三色,每色有8bit,表示出来的颜色也被称为24位色。

2.1.2 YUV

YUV是另外一种颜色的表示方式。RGB不利于压缩,所以大多都使用YUV方式。YUV加入了亮度的概念。据研究,人体眼睛对亮暗的分辨要比颜色的分辨更加精细一些,敏感度更高。

所以,工程师认为,存储视频中,没有必要把所有颜色的信号存起来。把更多的位置留给黑-白信号,也就是亮度,只留部分位置给彩色的信号,也就是色度。这就有了YUV。

Y是亮度,U和V是色度。

大家偶尔会见到的Y'CbCr,也称为YUV,是YUV的压缩版本,不同之处在于Y'CbCr用于数字图像领域,YUV用于模拟信号领域,MPEG、DVD、摄像机中常说的YUV其实就是Y'CbCr。

通过图像来说明YUV是如何成像的:

YUV的存储格式其实与采样的方式密切相关。

主流的采样方式有三种:

YUV4:4:4

YUV4:2:2

YUV4:2:0

YUV 4:4:4采样,每一个Y对应一组UV分量。 YUV 4:2:2采样,每两个Y共用一组UV分量。 YUV 4:2:0采样,每四个Y共用一组UV分量。

如下图:

通常使用的是YUV4:2:0的采样方式,能获得1/2的压缩率。

4:2:0以下几种格式比较常见:

I420: YYYYYYYY UU VV =>YUV420P YV12: YYYYYYYY VV UU =>YUV420P NV12: YYYYYYYY UVUV =>YUV420SP NV21: YYYYYYYY VUVU =>YUV420SP

2.2 H.264原始码流

H.264原始码流(又称为裸流),是一个接一个的NALU组成的,而它的功能分为两层,VCL(视频编码层)和 NAL(网络提取层)。

NALU = NALU头 + RBSP

数据传输或存储之前,这些编码的 VCL 数据,先被映射或封装进 NAL 单元中。每个 NALU 包括一个原始字节序列负荷(RBSP, Raw Byte Sequence Payload)、一组对应于视频编码的 NALU 头部信息。RBSP 的基本结构是:在原始编码数据的后面填加了结尾比特。一个 bit“1”若干bit“0”,以便字节对齐。

一个NAL单元一般是[StartCode] + [NALU Header] + [NALU Payload]组成。

StartCode : Start Code 用于标示这是一个NALU 单元的开始,必须是”00 00 00 01” 或”00 00 01”

NALU Header:接着StartCode表明该段单元的类型。解码时,根据StartCode后的一个字节可以用 & 0x1F 得到对应的类型。

下图,列出了所有类型。

其中说下类型5、7、8。

立即刷新IDR:一个序列的第一个图像叫做 IDR 图像(立即刷新图像),IDR 图像都是 I 帧图像。

引入 IDR 图像是为了解码的重同步,当解码器解码到 IDR 图像时,立即将参考帧队列清空,将已解码的数据全部输出或抛弃,重新查找参数集,开始一个新的序列。这样,如果前一个序列出现重大错误,在这里可以获得重新同步的机会。IDR图像之后的图像永远不会使用IDR之前的图像的数据来解码。

序列参数集SPS:包含一段I帧间中所有编码图像的共享编码参数。

SPS的内容大致可以分为几个部分:1、自引ID;2、解码相关信息,如档次级别、分辨率、子层数等;3、某档次中的功能开关标识及该功能的参数;4、对结构和变换系数编码灵活性的限制信息;5、时域可分级信息;6、VUI。

图像参数集PPS:包含一幅图像所用的公共参数,即一幅图像中所有片段SS(Slice Segment)引用同一个PPS。

PPS包含每一帧可能不同的设置信息,其内容同H.264中的大致类似,主要包括:1、自引信息;2、初始图像控制信息,如初始QP等;3、分块信息。

在解码开始的时候,所有的PPS全部是非活动状态,而且在解码的任意时刻,最多只能有一个PPS处于激活状态。当某部分码流引用了某个PPS的时候,这个PPS便被激活,称为活动PPS,一直到另一个PPS被激活。

通常,SPS 和PPS 在片的头信息和数据解码前传送至解码器。

下图是一般IDR与非IDR帧的具体码流

2.3 H.264码流传输的格式

H.264标准中指定了视频如何编码成独立的包,但传输和存储一般有两种打包方法。

一种是Annex B格式,另一种是AVCC格式。

Annex B格式

Annex B格式用起始码(Start Code)来区分每个NALU,它在每个NALU的开始处添加三字节或四字节的起始码0x000001或0x00000001。通过定位起始码,解码器就可以很容易的识别NALU的边界。

AVCC格式

AVCC格式不使用起始码作为NALU的分界,这种格式在每个NALU前都加上一个指定NALU长度的大端格式表示的前缀。

这个前缀可以是1、2或4个字节,所以在解析AVCC格式的时候需要将指定的前缀字节数的值保存在一个头部对象中,这个都通常称为extradata或者sequence header。同时,SPS和PPS数据也需要保存在extradata中。

iOS的硬解识别标准采用的就是AVCC格式。

3 基础知识补充

3.1 视频数据的封装

对于任何一部视频来说,只有图像,没有声音,肯定是不行的。所以,视频编码后,加上音频编码,要一起进行封装。

封装:就是封装格式,简单来说,就是将已经编码压缩好的视频轨和音频轨按照一定的格式放到一个文件中。再通俗点,视频轨相当于饭,而音频轨相当于菜,封装格式就是一个饭盒,用来盛放饭菜的容器。

目前主要的视频容器有如下:MPG、VOB、MP4、3GP、ASF、RMVB、WMV、MOV、Divx、MKV、FLV、TS/PS等。

封装之后的视频,就可以传输了,你也可以通过视频播放器进行解码观看。

3.2 视频标准和H.265

视频编码格式的标准是由ITU(国际电信联盟)来定制的。

过去的三十多年,提出了许多标准。

H.261、H.262、H.263、H.263+、H.263++,这些统称为H.26X系列,主要应用于实时视频通信领域,如会议电视、可视电话等。

MPEG1、MPEG2、MPEG4、MPEG7、MPEG21,统称为MPEG系列。

其中有一项新出的标准HEVC,也就是H.265标准。

H.265标准相对于H.264有极大的性能提升。

H.265标准围绕H.264编码标准,保留原有的某些技术,同时对一些技术进行改进,编码结构大致上和H.264的架构类似。

存在以下区别

头部不同:同H.264一样,H.265也是以NALU的形式组织起来。而在NALU header上,H.264的HALU header是一个字节,而H.265则是两个字节。Type的获取使用的是NALU头的第一字节 & 0x7E 再 >> 1。

参数不同:除了有SPS、PPS外,还需多添加一个VPS。视频参数集。VPS用于解释编码过的视频的整体结构,包括时域子层依赖关系等,主要目的在于兼容H.265标准在系统的多子层方面的扩展。