【音视频】 H264 H265
概述
项目中接触到一些音视频领域的技术,主要对自己接触到的技术,结合自己的学习内容,进行阶段性总结,如有不正确的地方恳请指正
安防领域摄像头的编码格式目前主流的是H265,但是也存在H264的视频流。项目中经常需要获取H264 H265的视频流或者是将这两种视频流推送到指定的客户端,测试可以使用ZLM这种流媒体框架,具体应用开发中遇到了将视频流推送到GB28181平台。文章的主要重点也只聚焦在编解码
H264是2003年完成,一般简称为AVC 或 MPEG-4 AVC;H265则是2013年开发完成,其是基于H264基础上,进一步提高视频压缩效率,尤其是针对高分辨视频(4K 8K)和下一代视频的应用
H265在带来高分辨的同时,同时也带来了更高的编码和解码复杂度,其也需要更加强大的计算资源,对硬件资源的要求也相应的会高
H264
NALU
简述
NALU是H.264视频编码标准中用于组织和传输编码数据的基本单元,可以简单的理解为NALU就是H.264视频码流中的数据包,其与网络抽象层和视频编码层有很大关系
网络抽象层(NAL):H.264 标准被设计为可以适应各种不同的网络传输环境。NAL 的作用就是将视频编码层 (VCL - Video Coding Layer) 生成的压缩数据,封装成适合在不同网络上传输的单元,这就是 NALU。 它将视频内容与传输机制解耦
视频编码层(VCL):VCL 负责实际的视频压缩编码工作,例如帧内预测、帧间预测、变换、量化等。VCL 生成的数据是编码后的视频内容本身
主要作用总结
- 封装VCL的数据:这也是NALU的主要作用,用于封装VCL的编码数据,例如编码后的宏块数据、参数集、补充增强信息
- 提供头部信息:每个NALU都有一个小的头部信息,主要就是用于标识NALU的类型、重要性的,方便解码器可以正确的解析和进行相应的处理
- 适应网络传输:NALU的结构设计让其可以在各种网络协议中进行传输(着重介绍其RTP传输)
基本结构
该图不仅展示了NALU的基本结构,同时也有说明H264最后封包的结构
主要构成分析
- NALU start code(NALU起始码)
- 主要作用:解码器通过查询特定的字节序列来识别一个新的NALU的开始,也就是找到一个包里的所有NALU
- 起始码大小并不固定,正常是三字节
- 解码过程分析:一般解码器在接收到H264视频流后,会不断的扫描字节流,寻找start code。一旦找到起始码,也就表明一个新的NALU开始
0 1 2 3 4 5 6 7
+-+-+-+-+-+-+-+-+
|F|NRI| Type |
+-+-+-+-+-+-+-+-+
- NALU Header
- 主要作用:只是当前NALU的数据类型,H264中重要的type主要是SYS PPS I帧
- F (forbidden_zero_bit): 1 bit - 禁止位,必须为 0。 如果解码器遇到 F=1 的 NALU,通常应将其视为错误,并采取相应的错误处理措施
- NRI (nal_ref_idc - NAL Ref IDC): 2 bits - NALU 优先级指示 (NAL Ref IDC - NAL Unit Reference Indication)。 用于指示 NALU 的重要性级别,取值范围为 0-3
- Type (nal_unit_type): 5 bits - NALU 类型 (NAL Unit Type)。 这是 NALU Header 中最核心的字段,指示了 NALU Payload 中数据的类型
- NALU Payload(NALU 载荷)
- 作用:这里存储的是NALU实际传输的数据内容,其中的具体内容主要取决于NALU的类型
编码
H264码流主要有两种类型,在封装成RTP包之前,NALU需要依据这两种格式进行处理
结构1:SPS + PPS + IDR(具体参考上图)
- 使用场景:H264码流的开始位置、场景切换、码流重新初始化
- 解码流程:解码器首先收到SPS 和 PPS,获取解码所需要的参数信息。然后接收到IDR帧,IDR帧是可以单独解码,作为视频序列的起始帧。后续的帧就可以都依赖于IDR帧进行解码
结构2:Non -IDR
- 该结构主要用于表示一个普通的非IDR帧,例如一个P帧或者B帧
- 解码流程:加码器接收到一个non-IDR帧后,需要参考之前已经解码的帧(例如之前已经已经成功解码了IDR帧或者之前的P/B帧)才能进行解码
主要类型
总结H264流格式中常见的一些NALU 类型
视频编码层
- Type 1: Coded slice of a non-IDR picture (非 IDR 图像的编码切片)
- 含义: 包含 P 帧、B 帧等非 IDR 帧的编码数据切片。这些帧依赖于之前的帧进行解码(代码实现的时候注意,不要忽略)
- 重要性: 构成视频序列的主体部分,用于表示帧间预测编码的图像
- Type 5: Coded slice of an IDR picture (IDR 图像的编码切片)
- 含义: 包含 IDR 帧 (Instantaneous Decoding Refresh frame) 的编码数据切片。 IDR 帧是关键帧,可以独立解码,无需参考之前的帧
- 重要性: 作为视频序列的起始点,或者在需要随机访问、错误恢复时使用。 IDR 帧的频率会影响随机访问性能和码率
非视频编码层
- Type 6: Supplemental Enhancement Information (SEI)
- 含义: 包含补充增强信息 (SEI) 消息。SEI 消息携带与视频解码过程无关的附加信息,例如显示信息 (Display info)、定时信息 (Timing info)、用户数据 (User data) 等
- 重要性: SEI 信息不是解码必需的,但可以用于改善显示效果、同步播放、添加元数据等
- 该信息在封装RTP包的时候可以不用
- Type 7: Sequence Parameter Set (SPS)
- 含义: 序列参数集 (SPS) 包含了 整个视频序列 的解码参数,例如 Profile (档次), Level (级别), 图像分辨率, 帧率, 编码工具配置等
- 重要性: 解码器必须先获得 SPS 才能正确解码视频序列。 SPS 通常在码流的开始位置传输一次,或者在视频序列参数发生变化时更新
- Type 8: Picture Parameter Set (PPS)
- 含义: 图像参数集 (PPS) 包含了 解码当前图像 (或一组图像) 所需的参数,例如熵编码模式、slice group 设置、量化参数等
- 重要性: 解码器必须先获得 PPS 才能正确解码图像切片。 PPS 通常在每个图像 (或一组图像) 之前传输,或者在图像参数发生变化时更新
H265
NALU
H265的NALU主要有三个部分组成
1. 起始码前缀
与H264一样,H265也会用特定大小的前缀来标识NALU的开始,一般情况下是3、4个字节,项目中经历的是4个字节
2. NALU Header(NALU头部)
放在起始码后面的2个字节,其中包含了很多重要信息,H.265的头部信息也比H.264更复杂
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|F| Type | LayerId | TID |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- F (forbidden_zero_bit): 1 bit - 必须为 0。如果解码器遇到 F=1 的 NALU,应将其视为错误
- Type (nal_unit_type): 6 bits - NALU 类型,指示 NALU 载荷中数据的类型。 H.265 定义了比 H.264 更多的 NALU 类型,以支持其更丰富的功能。 NALU Type 值范围是 0-63
- LayerId (nuh_layer_id): 6 bits - 层 ID (Layer ID),用于 分层编码 (SHVC - Scalable HEVC)。 当使用 SHVC 时,不同的层 (例如基本层、增强层) 的 NALU 会有不同的 LayerId 值。 在非分层编码中,LayerId 通常为 0
- TemporalId (nuh_temporal_id_plus1): 3 bits - 时间 ID (Temporal ID),用于 时间分层 (Temporal Scalability)。 时间分层允许视频码流包含多个时间层级,可以根据网络带宽或解码能力选择性地解码不同时间层级的帧。 TemporalId 值越高,时间层级越高,帧率也越高
3. NALU载荷
NALU Header 之后的部分就是 NALU Payload,包含了实际的数据内容。 Payload 的具体格式和内容由 NALU Type 决定。 Payload 可以包含视频编码数据 (例如切片数据)、参数集 (VPS, SPS, PPS, APS)、补充增强信息 (SEI) 等
主要类型
视频编码层
- Type 19: Coded slice segment of a non-IDR picture (非 IDR 图像的编码切片片段)
- 含义: 类似于 H.264 的 Type 1 (非 IDR 图像切片),包含 P 帧、B 帧等非 IDR 帧的编码数据切片片段。H.265 将切片进一步细分为切片片段 (slice segment)
- 重要性: 构成视频序列主体,表示帧间预测编码图像
- Type 20: Coded slice segment of an IDR picture (IDR 图像的编码切片片段)
- 含义: 类似于 H.264 的 Type 5 (IDR 图像切片),包含 IDR 帧 (Instantaneous Decoding Refresh frame) 的编码数据切片片段
- Type 21: Coded slice segment of a CRA picture (CRA 图像的编码切片片段)
- 含义: CRA (Clean Random Access) 图像切片片段。CRA 图像是 H.265 引入的一种新的随机访问点,比 IDR 帧更灵活,允许更好的压缩效率和随机访问性能平衡
- 重要性: 提供更优的随机访问和码率效率
- Type 22: Coded slice segment of a TRAIL picture (TRAIL 图像的编码切片片段)
- 含义: TRAIL (Trailing) 图像切片片段。 TRAIL 图像是解码顺序上跟随在随机访问点 (IDR 或 CRA) 之后的图像
非视频编码层
- Type 32: Video Parameter Set (VPS)
- 含义: 视频参数集 (VPS)。 H.265 新增的参数集,包含了 适用于整个视频序列 的更高级别的参数,例如 Profile, Level, Tier, 序列级 VUI (Video Usability Information) 等
- 重要性: 解码器必须先获得 VPS 才能正确解码 H.265 视频序列。 VPS 是最先解码的参数集,提供了最基础的序列级信息(编写代码的时候一定要注意,H265一定要加上VPS)
- Type 33: Sequence Parameter Set (SPS)
- 含义: 序列参数集 (SPS)。 H.265 的 SPS 功能类似于 H.264,但内容和结构不同。 H.265 SPS 包含了 适用于一个或多个视频序列 的参数,例如图像分辨率, 编码工具配置, 图像级 VUI 等。 H.265 中可以有多个 SPS 实例
- 重要性: 解码器必须获得 SPS (以及 VPS) 才能解码视频序列
- Type 34: Picture Parameter Set (PPS)
- 含义: 图像参数集 (PPS)。 H.265 PPS 功能类似于 H.264,但内容和结构不同。 包含了 解码一个或多个图像 所需的参数,例如 Tile 设置, slice segment header 配置, 量化参数等。 H.265 中可以有多个 PPS 实例
- 重要性: 解码器必须获得 PPS (以及 VPS, SPS) 才能解码图像切片
- Type 39: Supplemental Enhancement Information (SEI)
- 含义: 补充增强信息 (SEI)。 与 H.264 SEI 类似,包含了与视频解码过程 无关 的附加信息
- 重要性: 非解码必需,但用于改善显示、同步、元数据等
- Type 48-55: Adaptation Parameter Set (APS)
- 含义: 自适应参数集 (APS)。 H.265 新增的参数集,用于传输 图像或切片级别 的自适应参数,例如量化矩阵, 环路滤波器参数, 采样点偏移 (SAO) 参数等
- 重要性: APS 可以更频繁地更新图像或切片级别的参数,提高编码效率和质量的灵活性