最近在总结学习的音视频知识,主要参考Android音视频开发这本书总结的。
(一) 视频编码的原理
时间相关性:在一组视频序列中,相邻两帧只有极少的不同之处,这便是时间相关性。
空间相关性:在同一帧中,相邻象素之间有很大的相关性,两象素越近,则相关性越强。
一个图像或者一个视频序列进行压缩,产生码流。对图像的处理即是:帧内预测编码其预测值P,是由已编码的图像做参考,经运动补偿得到的。预测图像P和当前帧Fn相减,得到两图像的残差值Dn,Dn在经过转换T,量化Q,去处空间冗余,得到系数X,将X重排(使数据更加紧凑),熵编码(加入运动矢量。。。一些图像相关得信息),得到nal数据。对视频序列的处理:帧间预测编码预测值P,是由当前片中,己编码的宏块预测得到的(亮度4×4或者16×16预测,色度8×8预测)。当前待处理的块,减去预测值P,得残差值Dn,Dn在经过转换T,量化Q,得到系数X,将X重排(使数据更加紧凑),熵编码,得到nal数据。大概知道原理就行了具体实现算法不再学习范围内。
(二)H264编码框架:
H.264码流文件分为两层:
(1) VCL(Video Coding Layer,视频编码层):负责高效的视频内容表示, VCL数据即编码处理的输出,它表示被压缩编码后的视频数据序列。
(2) NAL (Network Abstraction Layer,网络提取层);负责以网络所要求的恰当的方式对 数据进行打包和传送,是传输层。不管是在本地播放还是在网络上播放(通常是RTP协议),都要通过这一层来传。
(三)H264码流分析:
在VCL数据被传输或存储之前,这些编码的VCL数据先被映射或封装进NAL单元中。每个NAL单元包括一个原始字节序列负载(RBSP,Raw Byte Sequence Playload)和一组对应于视频编码的NAL头信息(1个字节)。RBSP的基本结构:在原始编码数据的后面添加了结尾标记,一个比特“1”和若干比特“0”以便字节对齐。H264码流NAL单元序列如图所示:
Nal头信息的每一位说明如下:
F:占1bit,全称forbidden_zero_bit,禁止位,作用:当网路发现nal单元有比特错误时,可以设置为1,以便接收方丢掉改单元。
NRI:占2bit,全称nal_ref_idc,重要性指示位,作用:标志改NAL单元用于重建时的重要性,值越大越重要,取值范围00~11。
TYPE: 占5bit,全称nal_unit_type,NAL类型。它的值说明如下:
1~23表示单个NAL包,24~31需要分包或组包发送。具体如下:
0:没有定义。
1:不分区,非IDR图像的片。
2:片分区A。
3:片分区B。
4:片分区C。
5:IDR图像中的片。
6:补充增强信息单元(SEI)。
7:SPS(Sequence Parameter Set),序列参数集,作用于一串连续的视频图像,即视频序列。
8:PPS(Picture Parameter Set),图像参数集,作用于视频序列中的一个或多个图像。
9:序列结束。
10:序列结束。
11:码流结束。
12:填充。
13~23:保留。
24:STAP-A单一时间的组合包。
25:STAP-B单一时间的组合包。
26:MTAP-16单一时间的组合包。
27:MTAP-24多个时间的组合包。
28:FU-A分片单元。
29:FU-B分片单元。
30和31未定义。
来看看结构图:
其中SODB是string of data bits。SODB 数据比特串 是编码后的原始数据.
RBSP 原始字节序列载荷 在原始编码数据的后面添加了 结尾比特。一个 bit “1” 若干比特 “0”,以便字节对齐。
在编码时,每个NALU前面添加startcode(占4字节0x00000001或者3字节0x000001),实际上startcode只占3字节,4字节的起始部分 = zero_byte + start_code_prefix_one_3bytes,
就是说无论啥时候其实startcode都是3字节,关键就在于zero_byte。包含sps,pps的NALU前面要加zero_byte(4字节)。当一帧被分为多个slice时,首个NALU前面要加zero_byte(4字节)。
下图为 H264 码流分层图:
片(slice)一个片 = Slice Header + Slice Data片是 H.264 提出的新概念,实际原始视频图像数据保存在 VCL 层级的 NAL Unit 中,这部分数据在码流中被称作是片(slice)。一个 slice 包含一帧图像的部分或全部数据,换言之,一帧视频图像可以编码为一个或若干个 slice。一个 slice 最少包含一个宏块,最多包含整帧图像的数据。在不同的编码实现中,同一帧图像中所构成的 slice 数目不一定相同。一个 slice 编码之后被打包进一个 NALU,所以 slice = NALU那么为什么要设置片呢?设置片的目的是为了限制误码的扩散和传输,应使编码片相互间是独立的。某片的预测不能以其他片中的宏块为参考图像,这样某一片中的预测误差才不会传播到其他片中。在上图中,可以看到每个图像中,若干宏块(Macroblock)被排列成片。一个视频图像可编成一个或更多个片,每片包含整数个宏块 (MB),每片至少包含一个宏块。
slice 组成每一个 slice 总体来看都由两部分组成,一部分作为 slice header,用于保存 slice 的总体信息(如当前 slice 的类型等),另一部分为 slice body,通常是一组连续的宏块结构(或者宏块跳过信息)
宏块(Macroblock)刚才在片中提到了宏块,那么什么是宏块呢?宏块是视频信息的主要承载者。一个编码图像通常划分为多个宏块组成.包含着每一个像素的亮度和色度信息。视频解码最主要的工作则是提供高效的方式从码流中获得宏块中像素阵列。一个宏块由一个 16×16 亮度像素和附加的一个 8×8 Cb 和一个 8×8 Cr 彩色像素块组成。
宏块分类 意义:
I 宏块 利用从当前片中已解码的像素作为参考进行帧内预测
P 宏块 利用前面已编码图像作为参考进行帧内预测
B 宏块 利用双向的参考图像(当前和未来的已编码图像帧)进行帧内预测
(四)H264传输:
H264的编码视频序列包括一系列的NAL单元,每个NAL单元包含一个RBSP。典型的RBSP单元序列如图。每个单元都按独立的NAL传送。NAL单元的信息头定义了RBSP单元的类型,NAL单元的其余部分为RBSP数据。
RBSP各个部分的解释如下图:
前面我们说过H264分为两层,VCL和NAL。VCL数据被封装到NAL单元后才能可以传输或存储。H264码流NAL单元序列如下图:
NAL类型如下:
SPS:序列参数集,作用于一系列连续的编码图像。
PSS:图像参数集,作用于编码视频序列中一个或多个独立的图像。
参数集是一个独立的数据单位,不依赖于参数集外的其他句法元素。一个参数集不对应装 一个特定的图像或序列,同一序列参数集可以被一个或者多个图像参数集引用,同理,同一个 图像参数集也可以被一个或者多个图像引用。只在编码器认为需要更新参数集的内容时,才会 家出新的参数集。
在H.264协议里定义了3种帧,完整编码的帧叫I帧,参考之前的I帧,生成的只对差异部分进行编码的帧叫P帧,还有一种参考前后的顿进行编码的帧叫B帧。在H.264中图像以序列为单位进行组织,一个序列是一段图像编码后的数据流,以I帧开始,到下一个I帧结束,中间部分也被称为一个GOP。一个序列的第一个图像叫作IDR图像(立即刷新图像), IDR图像都是I帧图像。H.264引入IDR图像是为了解码的重新同步,当解码器解码到IDR图像时,立即将参考帧队列清空,将已解码的数据全部输出或抛弃,重新查找下一个参数集,开始解码一个新的序列。这样,如果前一个序列出现重大错误,在这里可以获得重新同步的机会。IDR图像之后的图像永远不会使用IDR之前的图像的数据来解码。一个序列就是一段内容差异不太大的图像编码后生成的一串数据流。当运动变化比较少时,一个序列可以很长,因为运动变化少就代表图像画面的内容变动很小,所以就可以是一个I帧,然后一直是P帧、B帧。当运动变化多时,一个序列可能会比较短,比如只包含一个I帧和几个P帧、B帧。
I 帧 帧内编码帧,又称 intra picture I 帧通常是每个 GOP( Group of Pictures)是一组连续的画面)(MPEG 所使用的一种视频压缩技术)的第一个帧,经过适度地压缩,做为随机访问的参考点,可以当成图象。I帧可以看成是一个图像经过压缩后的产物
P 帧 前向预测编码帧,又称 predictive-frame 通过充分将低于图像序列中前面已编码帧的时间冗余信息来压缩传输数据量的编码图像,也叫预测帧
B 帧 双向预测帧,又称 bi-directional interpolated prediction frame 既考虑与源图像序列前面已编码帧,也顾及源图像序列后面已编码帧之间的时间冗余信息来压缩传输数据量的编码图像,也叫双向预测帧
I frame: 自身可以通过视频解压算法解压成一张单独的完整的图片;
P frame:需要参考其前面的一个 I frame 或者 B frame 来生成一张完整的图片;
B frame: 则要参考其前一个 I 或者 P帧 及其后面的一个 P 帧来生成一张完整的图片;
PTS(Presentation Time Stamp) PTS 主要用于度量解码后的视频帧什么时候被显示出来
DTS(Decode Time Stamp) DTS 主要是标识内存中的 bit 流什么时候开始送入解码器中进行解码
在H264里,视频可以没有B帧。当没有B帧的时候DTS=PTS。DTS是解码时间,PTS是显示时间。