H.264

H.264/AVC,又称为 MPEG-4第10部分,高级视频编码(MPEG-4 Part 10 Advanced Video Coding,缩写为 MPEG-4 AVC)是一种面向块,基于运动补偿的视频编码标准。由 ITU-T视频编码专家组ISO/IEC 联合工作组(MPEG,动态图像专家组)联合组成的联合视频组(JVT,Joint Video Team)发布

H.264 项目的目的是为了创建一个更佳的视频压缩标准,在更低的比特率的情况下依然能够提供良好视频质量的标准。同时,还要不会太大的增加设计的复杂性。H.264 的另外一个目标是提供足够的灵活性,以允许该标准能够应用于各种各样的网络和系统上,包括低和高比特率、低和高分辨率视频、广播、DVD存储、RTP/IP 分组网络和 ITU-T 多媒体电话系统。H.264 标准可以被视为由多个不同的应用框架/配置文件组成的“标准系列”

为什么需要对视频进行编码压缩

视频本质上是由一张张的图像组成的,将这些图像以一定的时间间隔连续播放就是我们所看到的视频。若有一个分辨率为 1080P,帧率为 60FPS 的视频(使用 YUV 存储)不经压缩每秒钟需要占用的空间约为:1920 * 1080 * 3/2 * 60 = 186624000B ≈ 178MB,200Mbps 的带宽每秒钟的下载速度是 25MB/s 左右,需要花费 7s 才能将这一秒的视频下载下来,这是完全不能满足实时播放的需求的,要满足实时播放就需要至少 1.4Gbps 的带宽。H.264 的压缩比能达到 1:100 ~ 1:50,就能将 355.95MB 的视频能压缩到 1.8MB ~ 3.6MB,最高只需要 29 Mbps 的带宽就能满足实时播放的需求

H.264 基础概念

在 H.264/AVC 在概念上可以分为两层:视频编码层(VCL,Video Coding Layer)网络抽象层(NAL,Network Abstraction Layer)。视频编码层面负责高效的表示视频数据内容(H.264 编码压缩的核心,主要负责将视频数据进行编码/压缩和切分),网络抽象层负责格式化数据并提供头信息,以保证数据适合在各种信道和存储介质上传播

H.264 可以分为序列(GOP)、图像(Pictrue)、⽚(Slice)、宏块(Macroblock)、⼦宏块(Sub-Macroblock)五个层次。H.264 把图像分为帧(Frame)和场(Field,分为顶场和底场,一帧相当于两场),其中帧可以分为一个或几个片;片由宏块组成,宏块是编码处理的基本单元,宏块包含一个 16x16 像素的亮度块和两个相应的色度块。对于 H.264 标准来说,I 帧、B 帧、P 帧都是我们把图像这个概念具体化和细小化了,通常说的 “帧” 是指不分场的图像

H.264 码流

H.264 的码流由一个个的 NAL 单元(NAL unit,网络抽象层单元)组成,每个 NAL 单元可以封装一个 Slice 或者 SPS、PPS 等信息。H.264 码流也可称为 NAL 单元流(NAL unit stream),NAL 单元流的组成形式分为两种:Annex B 和 AVCC,Android 硬解码只支持 Annex B,苹果的 VideoToolbox 和浏览器的 MSE 只支持 AVCC。Annex B 和 AVCC 只是在 NAL 单元流的组织形式上有所不同,NAL 单元的结构是一致的遵循同一标准

Annex B

又称 MPEG-2 Transport Stream(MPEG-TS,ts 格式)。每个 NAL 单元使用起始码分隔开,起始码有两种 0x000001(3 Byte)0x00000001(4 Byte)。在标准中只有 3 字节的起始码前缀的说法(start_code_prefix_one_3bytes = 0x000001),所谓的 4 字节起始码是由 zero_byte(0x00) + start_code_prefix_one_3bytes 组成

以下两种情况使用 4 字节起始码,其他的情况使用 3 字节起始码:

  1. 该 NAL 单元类型是 SPS(NAL unit type == 7) 或 PPS(NAL unit type == 8)(NAL 单元类型会在下文展开)
  2. 若该 NAL 单元是一个访问单元(Access unit,一组 NAL 单元)的第一个 NAL 单元

防竞争字节(Emulation Prevention Byte)

由于 NAL 单元会使用 0x0000010x00000001 做为起始码,为了防止在 NAL 单元内部出现起始码将一个 NAL 单元错误的分成几个,H.264 使用防竞争字节来解决该问题(0x30)。当编码器编完一个 NAL 单元时,应检测 NAL 单元内部是否出现如下左侧的四个字节序列,如果存在则在最后一个字节中间插入 0x30,在解码过程中再将防竞争字节去除即可

1
2
3
4
0x000000 => 0x00000300    (0x000000,可作为当前 NAL 单元的结束标志)
0x000001 => 0x00000301 (0x000001,起始码)
0x000002 => 0x00000302 (0x000002,作为保留使用)
0x000003 => 0x00000303 (0x000003,避免 NAL 单元内部原本就存在字节序列 0x000003 的情况)

虽然 AVCC 没有使用起始码来分隔 NAL 单元但是也会进行防字节竞争处理,依据为下文的 “NAL unit 语法” 部分描述的 NAL 单元内部的防竞争码处理并不区分 Annex B 或 AVCC

实例分析

红色框为起始码(以下序号对应图上字序号):

  1. 00 00 00 01,为 4 字节起始码,是一个 AUD 单元
  2. 00 00 00 01,为 4 字节起始码,是一个 SPS 单元
  3. 00 00 00 01,为 4 字节起始码,是一个 PPS 单元
  4. 00 00 01,为 3 字节起始码,是一个 SEI 单元
  5. 00 00 01,为 3 字节起始码,是一个 IDR 图像单元

蓝色框为被防竞争处理过的数据(以下序号对应图上字序号):

  1. 00 00 03 00,原数据为 00 00 00
  2. 00 00 03 01,原数据为 00 00 01
  3. 00 00 03 00,原数据为 00 00 00

AVCC

又称为 AVC1、MPEG-4 格式,用于 mp4、flv、mkv。每个 NAL 单元前都有一个固定长度的 NAL unit Length(通常是 4 字节)表示该 NAL 单元的大小(字节),该 NAL unit Length 占用几字节需要从 extradata 获取。extradata 在 MP4 封装的文件中一般存储在 MOOV 的 avc1 box 中(MOOV/trak/mdia/minf/stbl/stsd/avc1),实例分析见下文

extradata 格式:

SPS、PPS、SPS 扩展具体内容及结构请查看后续文章《H.264 标准语法分析》

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
aligned(8) class AVCDecoderConfigurationRecord {
unsigned int(8) configurationVersion = 1; // 8 bit,总是 0x01
unsigned int(8) AVCProfileIndication; // 8 bit,表示所使用的 profile,SPS 中的第一字节内容
unsigned int(8) profile_compatibility; // 8 bit,SPS 中第二字节的内容,指示是否强制使用某个 profile
unsigned int(8) AVCLevelIndication; // 8 bit,编码时使用的 level,值越大对解码器要求越高,SPS 中的第三字节的内容
bit(6) reserved = ‘111111’b; // 6 bit,保留
unsigned int(2) lengthSizeMinusOne; // 2 bit,值为 NAL unit length - 1
bit(3) reserved = ‘111’b; // 3 bit,保留
unsigned int(5) numOfSequenceParameterSets; // 5 bit,值为 SPS 个数
for (i=0; i < numOfSequenceParameterSets; i++) { // 遍历所有的 SPS
unsigned int(16) sequenceParameterSetLength ; // 16 bit,值为当前 SPS 长度
bit(8*sequenceParameterSetLength) sequenceParameterSetNALUnit; // SPS 数据
}
unsigned int(8) numOfPictureParameterSets; // 8 bit,值为 PPS 个数
for (i=0; i < numOfPictureParameterSets; i++) { // 遍历所有的 PPS
unsigned int(16) pictureParameterSetLength; // 16 bit,值为当前 PPS 长度
bit(8*pictureParameterSetLength) pictureParameterSetNALUnit; // PPS 数据
}
if (profile_idc == 100 || profile_idc == 110 || // 若 profile 类别为 100、110、122、144
profile_idc == 122 || profile_idc == 144) { // 则还包含以下信息
bit(6) reserved = ‘111111’b; // 6 bit,保留
unsigned int(2) chroma_format; // 2 bit,表示使用的 YUV 类型
bit(5) reserved = ‘11111’b; // 5 bit,保留
unsigned int(3) bit_depth_luma_minus8; // 3 bit,亮度比特深度 - 8
bit(5) reserved = ‘11111’b; // 5 bit,保留
unsigned int(3) bit_depth_chroma_minus8; // 3 bit,色度比特深度 - 8
unsigned int(8) numOfSequenceParameterSetExt; // 8 bit,SPS 扩展个数
for (i=0; i < numOfSequenceParameterSetExt; i++) { // 遍历 SPS 扩展
unsigned int(16) sequenceParameterSetExtLength; // 16 bit,值为当前 SPS 扩展单元长度
bit(8*sequenceParameterSetExtLength) sequenceParameterSetExtNALUnit; // SPS 扩展单元数据
}
}

ISO_IEC_14496-15-AVC-format-2012 5.2.4.1.1 Syntax

实例分析

如下图为 MP4 封装的文件的 avc1 box

  • 白色框

    前四字节(00 00 00 38)表示该 avc1box 的长度为 56 字节,后四字节(61 76 63 43)表示该 box 的类型为 avcC

  • 红色框

    为 extradata 开始部分,第一字节(01)表示 configurationVersion 值为 1;第二字节(64)表示 AVCProfileIndication 值为 100;第三字节(00)表示 profile_compatibility 值为 0;第四字节(2A)表示 AVCLevelIndication 值为 42;第五字节(FF)最后两位表示 lengthSizeMinusOne 值为 3

  • 橙色框

    第一个橙色框第一字节(E1)最后五位表示 SPS 个数值为 1;第二个橙色框(00 1A)表示 SPS 长度,值为 26

  • 蓝色框

    第一个蓝色框(01)表示 PPS 的个数,值为 1;第二个蓝色框(00 07)表示 PPS 长度,值为 7

  • 黄色框

    第一字节(FD)最后两位表示 chroma_format,值为 1,表示使用 YUV 4:2:0;第二字节(F8)最后三位表示 bit_depth_luma_minus8,值为 0;第三字节(F8)最后三位表示 bit_depth_chroma_minus8 值为 0

  • 紫色框

    表示 SPS 扩展个数,值为 0

分析工具(macOS)

  1. Hex fiend
  2. YUView

Reference

评论

Your browser is out-of-date!

Update your browser to view this website correctly.&npsb;Update my browser now

×