1. H.264 编码数据概述
在我们观看的视频文件中,H.264 编码后的数据并不是直接以一帧一帧的图片存储,而是以压缩后的数据单元(NALU,Network Abstraction Layer Unit) 进行组织的。NALU 是 H.264 码流的基本组成部分,每个 NALU 都包含特定的视频数据,如 I 帧、P 帧、B 帧的部分内容。
在解码器接收到 H.264 码流后,会解析 NALU,将其转换为可显示的 YUV 图像数据,并最终呈现出完整的视频画面。
2. H.264 NALU 结构解析
每个 H.264 NALU 由起始码和NALU 头部 + 有效载荷组成,结构如下:
[Start Code] [NALU Header] [Payload (NAL Data)]
(1) NALU 起始码
NALU 起始码是 0x000001
或 0x00000001
,用于分隔不同的 NALU。
0x000001
(3 字节):常见于流媒体数据0x00000001
(4 字节):常见于 MP4 等封装格式
当 H.264 码流传输到解码器时,解码器可以通过扫描起始码来分割出不同的 NALU 单元。
(2) NALU 头部结构
NALU 头部是 1 字节(8 位),具体结构如下:
| 7 6 5 4 3 | 2 1 0 |
| NAL_REF_IDC | NAL_TYPE |
- NAL_REF_IDC(2~5 位): 表示该 NALU 的参考级别,值越大,越重要。
- NAL_TYPE(0~4 位): 表示该 NALU 的类型。
NALU 头部提取操作通常写作:
int nal_unit_type = byteData[4] & 31;
其中 & 31
(即 & 0x1F
)的目的是取出 NALU 头部的 低 5 位(NAL_TYPE),用于判断 NALU 类型。
(3) NALU 类型表
NALU Type | 说明 |
---|---|
1 | 非 IDR 图像(P 帧、B 帧) |
5 | IDR 图像(I 帧) |
6 | 补充增强信息(SEI) |
7 | 序列参数集(SPS) |
8 | 图像参数集(PPS) |
- SPS(序列参数集):包含视频的全局信息,如分辨率、帧率等。
- PPS(图像参数集):包含图像层的编码参数。
- SEI(补充增强信息):包含额外信息,如 HDR 元数据。
解码器需要先解析 SPS 和 PPS 才能正确解码视频帧。
3. H.264 帧类型解析
H.264 采用 帧内(Intra)和帧间(Inter)编码,帧的类型主要有:
(1) I 帧(关键帧,Intra Frame)
- 完整的一张图片,不依赖其他帧。
- 适合作为随机访问点,比如拖动进度条时。
- 码流中
NALU Type = 5
(IDR 帧)。
(2) P 帧(预测帧,Predicted Frame)
- 参考之前的 I 帧或 P 帧进行预测,仅存储变化部分。
- 占用空间较小,但如果丢失,可能影响多个后续帧的解码。
NALU Type = 1
(非 IDR 图像)。
(3) B 帧(双向预测帧,Bidirectional Frame)
- 参考前后帧进行预测,能达到更高的压缩比。
- 依赖前后的 I/P 帧,如果它们丢失,则 B 帧无法解码。
NALU Type = 1
(非 IDR 图像)。
(4) IDR 帧(Instantaneous Decoder Refresh Frame)
- 一种特殊的 I 帧,表示视频流的一个新片段。
- IDR 帧后续的 P 帧、B 帧不能参考之前的帧,避免长时间依赖。
NALU Type = 5
。
4. NALU 在视频流中的组织
H.264 码流的组织一般是:
[SPS] [PPS] [IDR帧] [P帧] [B帧] [P帧] [B帧] ...
例如,一个典型的视频帧序列可能是:
SPS → PPS → IDR(I 帧) → P 帧 → B 帧 → P 帧 → B 帧 → P 帧 ...
当解码器接收到数据后,通常会:
- 解析 SPS 和 PPS,获取解码信息。
- 解析 I 帧(IDR),作为参考帧。
- 解析 P 帧、B 帧,参考 I 帧、P 帧进行解码。
5. 为什么 outData[4] & 31
?
前面提到,NALU 头部的最后 5 位表示 NALU 类型,所以提取方式是:
int nal_unit_type = byteData[4] & 31;
示例:假设 byteData[4] = 0x65(二进制:01100101)
** = **
& 31
(即& 0x1F
):01100101
&00011111
=00000101
(十进制 5,表示 IDR 帧)
6. 结论
- H.264 码流由多个 NALU 组成,每个 NALU 具有不同的类型,如 SPS、PPS、I 帧、P 帧等。
- NALU 头部的低 5 位(& 31)用于获取 NALU 类型。
- H.264 采用帧内和帧间编码,I 帧、P 帧、B 帧在解码过程中各有不同作用。
理解这些知识,有助于更好地分析 H.264 码流,并在视频处理、流媒体应用中正确解析和播放 H.264 编码数据。