1.H.264编码概念
1.1 VCL和NAL
视频编码中采用的如预测编码、变化量化、熵编码等编码工具主要工作在 slice 层或以下,这一层通常被称为“视频编码层”(Video Coding Layer, VCL)。
相对的,在 slice 以上所进行的数据和算法通常称之为“网络抽象层”(Network Abstraction
Layer, NAL)。设计定义 NAL 层的主要意义在于提升 H.264 格式的视频对网络传输和数据存储的亲和性。
1.2 档次与级别
为了适应不同的应用场景,H.264 也定义了三种不同的档次:
-
基准档次(Baseline Profile):主要用于视频会议、可视电话等低延时实时通信领域;支持 I 条带和 P 条带,熵编码支持 CAVLC 算法。
-
主要档次(Main Profile):主要用于数字电视广播、数字视频数据存储等;支持视频场编码、B 条带双向预测和加权预测,熵编码支持CABAC和CAVLC算法。
-
扩展档次(Extended Profile):主要用于网络视频直播与点播等;支持基准档次的所有特性,并支持 SI 和 SP 条带,支持数据分割以改进误码性能,支持 B 条带和加权预测,但不支持 CABAC 和场编码。
1.3 常见编码
其中 H.264 编码器中最著名的两个当属 JM 和 X264,这二者都属于 H.264 编码标准的一种实现形式。
1.4 序列(Sequence)
序列可以理解为有相同特点的一段图像数据。但是如果某个图像与之前的图像变换很大,很难参考之前的帧来生成新的帧,那么就结束上一个序列,开始下一个序列。重复上述做法,生成新的一段序列。
1.5 帧类型
H.264 结构中,一个视频图像编码后的数据叫做一帧,一帧由一个片(slice)或多个片组成,一个片由一个或多个宏块(MB)组成,一个宏块由 16x16 的 yuv 数据组成。宏块作为 H264 编码的基本单位。
H.264协议中分别定义了3种类型的帧分别是I帧、P帧,B帧。
1.6 IDR帧
在编码解码中为了方便,将 GOP 中首个 I 帧要和其他 I 帧区别开,把第一个 I 帧叫 IDR,这样方便控制编码和解码流程,所以 IDR 帧一定是 I 帧,但 I 帧不一定是 IDR 帧;IDR 帧的作用是立刻刷新,使错误不致传播,从 IDR 帧开始算新的序列开始编码。I 帧有被跨帧参考的可能,IDR不会。
1.7 GOP(Group of Pictures图像组)
1.8 压缩方式
H264 采用的核心算法是帧内压缩和帧间压缩,帧内压缩是生成 I 帧的算法,帧间压缩是生成 B 帧和 P 帧的算法。
1.9 分层结构
H264 的主要目标是为了有高的视频压缩比和良好的网络亲和性,为了达成这两个目标,H264 的解决方案是将系统框架分为两个层面,分别是视频编码层(VCL)和网络抽象层面(NAL),如下图:
VCL 层是对核心算法引擎、块、宏块及片的语法级别的定义,负责有效表示视频数据的内容,最终输出编码完的数据 SODB;
NAL 层定义了片级以上的语法级别(如序列参数集参数集和图像参数集,针对网络传输,后面会描述到),负责以网络所要求的恰当方式去格式化数据并提供头信息,以保证数据适合各种信道和存储介质上的传输。NAL 层将 SODB 打包成 RBSP 然后加上 NAL 头组成一个 NALU 单元。
SODB: 数据比特串,是编码后的原始数据。
RBSP: 原始字节序列载荷,是在原始编码数据后面添加了结尾比特,一个bit “1” 和若干个比特“0”,用于字节对齐。
1.10 仿校验字节(0x03)
H264 规定,当检测到 0x000000 时,也可以表示当前 NALU 的结束。那这样就会产生一个问题,就是如果在 NALU 的内部,出现了 0x000001 或 0x000000 时该怎么办?
在 RBSP 基础上填加了仿校验字节(0x03)它的原因是:在 NALU 加到 Annexb 上时,需要填加每组 NALU 之前的开始码 StartCodePrefix,如果该 NALU 对应的 slice为一帧的开始则用 4 位字节表示,0x00000001,否则用 3 位字节表示 0x000001.
为了使 NALU 主体中不包括与开始码相冲突的,在编码时,每遇到两个字节连续为 0,就插入一个字节的 0x03。解码时将 0x03 去掉。也称为脱壳操作。
2.H.264的码流结构
首先是H.264的码流结构图:
2.1 NALU
NALU 的起始码为 0x000001 或 0x00000001(起始码包括两种:3 字节(0x000001) 和 4 字节(0x00000001),在 SPS、PPS 和 Access Unit 的第一个 NALU 使用 4 字。
在实际的网络数据传输过程中 H264 的数据结构是以 NALU(NAL 单元)进行传输的,传输数据结构组成为[NALU Header]+[RBSP],如下图所示:
2.2 NAL头
- NAL 单元的头部是由 forbidden_bit(1bit),nal_reference_bit(2bits)nal_unit_type(5bits)(类型)三个部分组成的。
- F(forbiden):禁止位,占用 NAL 头的第一为,当禁止位值为1时表示语法错误。
- NRI:参考级别,占用 NAL 头的第二到第三位,值越大,说明该NAL越重要
- Type:Nal 单元数据类型,也就是标识该 NAL 单元的数据类型是哪种,占用 NAL 头的第四到第 8 个位;
下图为3个组成部分:
下图为单元数据结构:
2.3 非 VCL 的 NAL 数据类型
- SPS(序列参数集):SPS 对如标识符、帧数以及参考帧数目、解码图像尺寸和帧场模式等解码参数进行标识记录。
- PPS(图像参数集):PPS 对如熵编码类型、有效参考图像的数目和初始化等解码参数进行标志记录。
- SEI(补充增强信息):这部分参数可作为 H264 的比特流数据而被传输,每一个 SEI 信息被封装成一个 NAL 单元。SEI 对于解码器来说可能是有用的,但是对于基本的解码过程来说,并不是必须的。
编辑
2.4 VCL 的 NAL 数据类型
- 头信息块,包括宏块类型,量化参数,运动矢量。这些信息是最重要的,因为离开他们,被的数据块种的码元都无法使用。该数据分块称为 A 类数据分块。
- 帧内编码信息数据块,称为 B 类数据分块。它包含帧内编码宏块类型,帧内编码系数。对应的 slice 来说,B 类数据分块的可用性依赖于 A 类数据分块。和帧间编码信息数据块不通的是,帧内编码信息能防止进一步的偏差,因此比帧间编码信息更重要。
- 帧间编码信息数据块,称为 C 类数据分块。它包含帧间编码宏块类型,帧间编码系数。它通常是 slice 种最大的一部分。帧间编码信息数据块是不重要的一部分。它所包含的信息并不提供编解码器之间的同步。C 类数据分块的可用性也依赖于 A 类数据分块,但于 B 类数据分块无关。
以上三种数据块每种分割被单独的存放在一个 NAL 单元中,因此可以被单独传输。
2.5 NAL 单元与片,宏
一帧 = 多个片:一片 = 多个宏块 一个宏块= 16x16yuv 数据;
在一个宏块中,又包含了宏块类型、宏块预测、残差数据。
2.6 NAL Unit
生成的 H264 视频帧是由多个切片组成的,一个 H264 的帧至少由一个切片组成,不能没有切片,可以是一个到多个不能没有。在网络传输的时候一个 H264 帧可能需要切开去传,一个一次传不完,这就按照切片来切。每一个切片组成一个 NAL Unit。
3.AAC编码
3.1 ACC 音频文件格式类型
ADIF:Audio Data Interchange Format 音频数据交换格式。这种格式的特征是可以确定的找到这个音频数据的开始,不需进行在音频数据流中间开始的解码,即它的解码必须在明确定义的开始处进行。故这种格式常用在磁盘文件中
AAC 的 ADIF 文件格式如下图:
ADTS:Audio Data Transport Stream 音频数据传输流。这种格式的特征是它是一个有同步字的比特流,解码可以在这个流中任何位置开始。它的特征类似于 mp3 数据流格式。
简单说,ADTS 可以在任意帧解码,也就是说它每一帧都有头信息。ADIF 只有一个统一的头,所以必须得到所有的数据后解码。这两种的 header 的格式也是不同的,一般编码后的和抽取出的都是 ADTS 格式的音频流。
AAC 的 ADTS 文件中一帧的格式如下图:其两边的空白矩形表示一帧前后的数据。
3.2 ADIF 的 Header 结构
ADIF 的头信息如下图:
ADIF 头信息位于 AAC 文件的起始处,接下来就是连续的 Raw Data Blocks。
组成 ADIF 头信息的各个域如下所示:
3.3 ADTS 的 Header 头结构
ADTS 的固定头信息:
ADTS 的可变头信息:
- 帧同步目的在于找出帧头在比特流中的位置,13818-7 规定,AAC ADTS 格式的帧头同步字为 12 比特的“1111 1111 1111”.
- ADTS 的头信息为两部分组成,其一为固定头信息,紧接着是可变头信息。固定头信息中的数据每一帧都相同,而可变头信息则在帧与帧之间可变。
3.4 AAC文件处理流程
- 判断文件格式,确定为 ADIF 或 ADTS
- 若为 ADIF,解 ADIF 头信息,跳至第 6 步。
- 若为 ADTS,寻找同步头。
- 解 ADTS 帧头信息。
- 若有错误检测,进行错误检测。
- 解块信息。
- 解元素信息。