深入解析H.264码流:从16进制数据到NAL单元结构
H.264视频流的16进制数据解析指南 摘要: H.264视频流由NAL单元组成,每个单元以起始码(00 00 01或00 00 00 01)开头。关键信息存储在NAL头部(首字节): 第1位必须为0 2-3位表示重要性(00-11) 4-8位标识类型(0x01普通帧/0x05关键帧/0x07SPS/0x08PPS等) SPS(0x67)和PPS(0x68)包含核心编码参数,其长度不固定,需通过指
H.264(也称为AVC)是一种广泛使用的视频压缩标准。要从16进制数据中理解H.264文件,我们需要了解其基本结构和编码原理。
H.264基本结构
H.264流由一系列称为NAL单元(Network Abstraction Layer Units)的数据包组成。每个NAL单元包含一个头部和有效载荷。
NAL单元头部结构(1字节):
| forbidden_zero_bit(1) | nal_ref_idc(2) | nal_unit_type(5) |
- forbidden_zero_bit: 必须为0
- nal_ref_idc: 表示NAL单元的重要性(00-11)
- nal_unit_type: 表示NAL单元类型
常见NAL单元类型
| 类型值(16进制) | 类型名称 | 描述 |
|---|---|---|
| 0x01 | 非IDR图像的片 | 普通视频帧数据 |
| 0x05 | IDR图像的片 | 关键帧数据 |
| 0x06 | 补充增强信息(SEI) | 额外信息如时间戳等 |
| 0x07 | 序列参数集(SPS) | 重要编码参数 |
| 0x08 | 图像参数集(PPS) | 解码所需参数 |
| 0x09 | 访问单元分隔符 | 帧边界标记 |
如何分析16进制H.264数据
-
查找起始码:H.264通常以
00 00 00 01或00 00 01作为NAL单元起始码 -
解析NAL头部:起始码后的第一个字节是NAL头部
例如,看到以下16进制数据:
00 00 00 01 67 64 00 1E AC ...
00 00 00 01是起始码67是NAL头部:- 二进制
01100111 - forbidden_zero_bit = 0
- nal_ref_idc = 3 (高重要性)
- nal_unit_type = 7 (SPS)
- 二进制
-
参数集解析:
- SPS(0x67)和PPS(0x68)包含关键编码信息
- 需要特殊解析才能提取分辨率、帧率等
-
帧数据解析:
- IDR帧(0x65)是关键帧
- 普通帧(0x61, 0x41等)
实际分析示例
假设有以下16进制片段:
00 00 00 01 67 64 00 1E AC D9 40 A0 2F F9 70 11
00 00 00 01 68 E9 7B 2C 8B 00 00 00 01 65 B8 40
F0 8C 03 C2 21 1A 80 00 00 00 01 41 E2 01 10 5F
解析:
- 第一个NAL单元:
- 起始码:00 00 00 01
- NAL头部:67 → SPS
- 第二个NAL单元:
- 起始码:00 00 00 01
- NAL头部:68 → PPS
- 第三个NAL单元:
- 起始码:00 00 00 01
- NAL头部:65 → IDR帧(关键帧)
- 第四个NAL单元:
- 起始码:00 00 00 01
- NAL头部:41 → 普通帧
工具推荐
要更深入分析H.264流,可以使用:
- H.264比特流分析器:如Elecard StreamEye, CodecVisa
- 16进制编辑器:010 Editor, HxD
- FFmpeg:
ffmpeg -i input.h264 -c copy -bsf:v trace_headers -f null - 2>log.txt
SPS和PPS的长度是固定的吗
在H.264标准中,SPS(序列参数集)和PPS(图像参数集)的字节长度不是固定的,它们的长度会根据编码配置的不同而变化。以下是详细说明:
1. SPS和PPS的长度是可变的
SPS和PPS的内容是**可变长编码(VLC)**的,具体长度取决于:
- 编码配置参数(如分辨率、帧率、档次/级别等)
- 使用的H.264功能(如熵编码方式、参考帧数量等)
示例对比:
- 简单配置的SPS(如低分辨率、Baseline档次)可能只有 10~20字节。
- 复杂配置的SPS(如高分辨率、High档次支持多参考帧)可能达到 50字节以上。
2. 影响SPS/PPS长度的关键参数
SPS和PPS中存储的以下参数会影响其大小:
-
SPS:
profile_idc、level_idc(编码档次和级别)pic_width_in_mbs_minus_1、pic_height_in_map_units_minus_1(分辨率)log2_max_frame_num_minus_4(帧编号长度)num_ref_frames(参考帧数量)entropy_coding_mode_flag(CABAC/CAVLC选择)- 其他高级选项(如帧间预测、色度格式等)。
-
PPS:
entropy_coding_mode_flagnum_slice_groups_minus_1weighted_pred_flag(加权预测)deblocking_filter_control_present_flag(去块滤波控制)。
3. 如何从16进制数据中识别SPS/PPS的边界
虽然长度不固定,但可以通过以下方式定位:
- 起始码:SPS/PPS以
00 00 01或00 00 00 01开头。 - NAL单元类型:
- SPS的NAL头部通常是
0x67(nal_unit_type=7)。 - PPS的NAL头部通常是
0x68(nal_unit_type=8)。
- SPS的NAL头部通常是
- 结束位置:下一个起始码出现时,表示当前SPS/PPS结束。
示例:
以下16进制片段中:
00 00 00 01 67 64 00 0A AC 72 84 44 26 84 00 00 00 01 68 E9 7B 2C 8B
- 第一个NAL单元(SPS):
- 起始码:
00 00 00 01 - NAL头部:
67(SPS) - 内容:
64 00 0A AC 72 84 44 26 84(共9字节)。
- 起始码:
- 第二个NAL单元(PPS):
- 起始码:
00 00 00 01 - NAL头部:
68(PPS) - 内容:
E9 7B 2C 8B(共4字节)。
- 起始码:
4. 为什么长度可变?
H.264的设计目标是灵活性:
- 支持从移动设备(低分辨率、低码率)到广播级(高分辨率、高复杂度)的各种场景。
- 参数集需要适配不同编码配置,因此采用指数哥伦布编码(Exp-Golomb),进一步压缩数据,但导致长度不固定。
5. 实际应用中的注意事项
- 封装格式的影响:
- 在MP4或FLV等容器中,SPS/PPS可能被提取到文件头部(如
avcC盒子),此时可能不带起始码。 - 在裸流(.h264文件)中,通常以起始码分隔。
- 在MP4或FLV等容器中,SPS/PPS可能被提取到文件头部(如
- 解析工具:
- 使用
ffmpeg -i input.h264 -c:v copy -bsf:v trace_headers -f null -可打印SPS/PPS内容。 - 专业的H.264分析工具(如Elecard StreamEye)能可视化参数。
- 使用
总结
- SPS和PPS的长度不固定,取决于编码配置。
- 通过起始码和NAL头部类型可定位它们。
- 需要解析具体内容才能获取分辨率、帧率等关键信息。
关于SPS的字段解析
在H.264的SPS(序列参数集)中,profile_idc和level_idc是固定位置的字段,但后续参数需要通过**指数哥伦布编码(Exp-Golomb)**解析。以下是具体定位和解析方法:
1. SPS的16进制结构概览
一个典型的SPS NAL单元(NAL类型=0x67)的16进制格式如下:
00 00 01 | 67 | 64 00 0A AC 72 84 44 26 84 ...
00 00 01:起始码(或00 00 00 01)67:NAL头部(forbidden_zero_bit=0+nal_ref_idc=3+nal_unit_type=7)- 后续字节:SPS的实际内容(从
profile_idc开始)。
2. 固定位置的字段
SPS的前几个字段是按顺序固定的(无需哥伦布编码):
| 字段名 | 字节偏移(从SPS内容开始) | 长度 | 示例(67 64 00 0A AC...) |
|---|---|---|---|
profile_idc |
第1字节 | 1 | 64 |
constraint_setX_flags |
第2字节(低4位) | 4bit | 00的低4位是0000 |
level_idc |
第3字节 | 1 | 0A |
示例解析:
对于SPS内容部分 64 00 0A AC...:
profile_idc=0x64(100)→ High Profileconstraint_set0_flags=0x00 & 0x0F→0000(无约束)level_idc=0x0A(10)→ Level 1.0
3. 后续可变字段的解析
从第4字节开始(如AC),需要通过指数哥伦布编码解析,顺序固定但长度可变。关键字段包括:
seq_parameter_set_idlog2_max_frame_num_minus_4pic_order_cnt_typemax_num_ref_framespic_width_in_mbs_minus_1(分辨率相关)pic_height_in_map_units_minus_1
解析工具:
- 手动解析复杂,推荐使用工具:
输出示例:ffmpeg -i input.h264 -c:v copy -bsf:v trace_headers -f null - 2>&1 | grep "SPS"SPS: profile=100, level=10, width=176, height=144
4. 关键字段的16进制定位表
以SPS内容 64 00 0A AC 72 84 44 26 84 为例:
| 字段名 | 字节位置 | 值(16进制) | 解析结果 |
|---|---|---|---|
profile_idc |
1 | 64 |
High Profile (100) |
constraint_setX_flags |
2 | 00 |
无特殊约束 |
level_idc |
3 | 0A |
Level 1.0 |
seq_parameter_set_id |
4 | AC |
Exp-Golomb解码后通常为0 |
log2_max_frame_num_minus_4 |
后续 | 72... |
需按哥伦布编码逐bit解析 |
5. 常见profile_idc和level_idc对照表
Profile IDC
| 值(16进制) | 名称 | 用途 |
|---|---|---|
42 |
Baseline Profile | 低复杂度(移动设备) |
4D |
Main Profile | 通用视频 |
64 |
High Profile | 高质量(广播、存储) |
Level IDC
| 值(16进制) | 级别 | 最大分辨率/帧率 |
|---|---|---|
0A |
1.0 | 176x144@15fps |
1E |
3.0 | 720x480@30fps |
28 |
4.0 | 1920x1080@30fps |
6. 手动解析示例
假设SPS内容为 64 00 1E AC 72 84 44 26 84:
profile_idc=0x64→ High Profilelevel_idc=0x1E→ Level 3.0- 后续字段需按哥伦布编码解析:
AC→10101100→ 解析为seq_parameter_set_id=072→01110010→log2_max_frame_num_minus_4=4
总结
- **
profile_idc和level_idc**是SPS的第1和第3字节(跳过起始码和NAL头部后)。 - 后续字段需按哥伦布编码解析,建议使用工具(如FFmpeg)自动化提取。
- 分辨率等参数需要解析更深的字段,通常需借助专业分析工具。
关于PPS(图像参数集)的解析逻辑
PPS(图像参数集)的解析逻辑与SPS类似,但结构不同,关键区别在于字段顺序和内容。以下是详细对比和PPS的解析方法:
1. PPS与SPS的解析逻辑对比
| 特性 | SPS(序列参数集) | PPS(图像参数集) |
|---|---|---|
| NAL单元类型 | 0x67(NAL头部低5位=7) |
0x68(NAL头部低5位=8) |
| 核心字段顺序 | 固定顺序:profile_idc→level_idc→… |
固定顺序:pic_parameter_set_id→seq_parameter_set_id→… |
| 字段编码 | 前3字节固定,后续用哥伦布编码 | 全部字段用哥伦布编码(无固定长度头部) |
| 关键信息 | 分辨率、帧率、档次级别 | 熵编码模式、参考帧权重、去块滤波控制 |
2. PPS的16进制结构解析
典型PPS的16进制示例:
00 00 01 | 68 | E9 7B 2C 8B
00 00 01:起始码68:NAL头部(nal_unit_type=8表示PPS)E9 7B 2C 8B:PPS的实际内容(全部需哥伦布编码解析)
PPS字段解析顺序:
pic_parameter_set_id- 第一个Exp-Golomb编码值(示例中
E9→11101001→解码后通常为0)
- 第一个Exp-Golomb编码值(示例中
seq_parameter_set_id- 第二个Exp-Golomb编码值(关联对应的SPS)
entropy_coding_mode_flag0=CAVLC,1=CABAC(影响后续语法元素解析)
num_ref_idx_lX_active_minus1(参考帧列表控制)weighted_pred_flag(加权预测)deblocking_filter_control_present_flag(去块滤波)
3. 关键字段的16进制定位示例
以PPS内容 E9 7B 2C 8B 为例(需按比特流解析):
| 字段名 | 原始16进制 | Exp-Golomb解码结果 | 含义 |
|---|---|---|---|
pic_parameter_set_id |
E9 |
0 |
PPS ID=0 |
seq_parameter_set_id |
7B |
0 |
关联的SPS ID=0 |
entropy_coding_mode_flag |
2C |
1 |
使用CABAC熵编码 |
num_ref_idx_l0_active_minus1 |
8B |
0 |
前向参考帧数量=1 |
🔍 注:实际解析需将16进制转换为二进制后,按哥伦布编码规则逐bit读取。
4. 为什么PPS比SPS更简单?
- 字段更少:PPS通常仅需10~20字节,而SPS可能需要50+字节。
- 无分辨率/帧率:这些关键参数在SPS中定义,PPS仅补充解码控制参数。
- 依赖SPS:PPS通过
seq_parameter_set_id绑定到特定SPS。
5. 自动化解析工具推荐
-
FFmpeg:
ffmpeg -i input.h264 -c:v copy -bsf:v trace_headers -f null - 2>&1 | grep "PPS"输出示例:
PPS: entropy_coding_mode_flag=1, weighted_pred_flag=0 -
H.264分析工具:
- Elecard StreamEye:可视化PPS/SPS结构。
- CodecVisa:逐比特解析哥伦布编码字段。
6. 手动解析PPS的步骤
假设PPS内容为 68 E9 7B 2C 8B:
- 定位起始:跳过
00 00 01 68,从E9开始解析。 - 解析
pic_parameter_set_id:E9→11101001→ 哥伦布解码为0。
- 解析
seq_parameter_set_id:7B→01111011→ 解码为0(关联SPS ID=0)。
- 解析
entropy_coding_mode_flag:- 下一个比特
1→ 使用CABAC。
- 下一个比特
总结
- PPS的解析逻辑与SPS不同:全部字段需哥伦布编码,无固定头部。
- 关键字段:
pic_parameter_set_id、seq_parameter_set_id、熵编码模式。 - 工具优先:手动解析复杂,推荐用FFmpeg或专业工具提取参数。
关于H.264中的指数哥伦布编码(Exp-Golomb)解析详解
在H.264标准中,SPS(序列参数集)和PPS(图像参数集)的大部分参数都采用**指数哥伦布编码(Exp-Golomb)**进行压缩存储。这是一种变长编码(VLC)方式,用于高效表示小数值(如0、1、2)和较大的数值(如1000)。
1. 指数哥伦布编码的基本规则
指数哥伦布编码的二进制结构分为三部分:
[M个前导0] [1] [M个信息位]
M:由前导0的数量决定(即M = 前导0的个数)。1:分隔符,标志前导0结束。信息位:共M位,表示具体数值。
解码公式:
[
\text{Value} = 2^M - 1 + \text{信息位(二进制转十进制)}
]
2. 解码步骤(手动解析示例)
假设有一个二进制比特流片段:00010110(16进制 16),需要解析连续的Exp-Golomb编码值。
示例1:解析第一个值
- 查找前导0:
- 比特流:
00010110 - 前导0有 3个 →
M=3
- 比特流:
- 读取分隔符
1:- 消耗掉
0001
- 消耗掉
- 读取M=3位信息位:
- 剩余
0110→ 取前3位011
- 剩余
- 计算数值:
[
\text{Value} = 2^3 - 1 + \text{011(3)} = 8 - 1 + 3 = 10
]
解析结果:10 - 剩余比特流:
- 已消耗
0001011,剩余0(可能属于下一个Exp-Golomb编码)。
- 已消耗
示例2:解析SPS/PPS中的常见字段
假设SPS内容部分的一个字节 AC(二进制 10101100),解析步骤如下:
- 比特流:
10101100 - 解析
pic_parameter_set_id:- 前导0:
1(无前导0,M=0) - 分隔符:
1 - 信息位:无(
M=0) - 计算:
[
\text{Value} = 2^0 - 1 + 0 = 0
]
解析结果:0
- 前导0:
- 剩余比特流:
0101100(继续解析下一个值)。
3. H.264中常见的Exp-Golomb编码字段
| 字段名 | 所在位置 | 示例(二进制→值) |
|---|---|---|
seq_parameter_set_id |
SPS的第4字节 | AC→10101100→0 |
pic_parameter_set_id |
PPS的第1字节 | E9→11101001→0 |
log2_max_frame_num_minus_4 |
SPS的后续字段 | 72→01110010→4 |
num_ref_frames |
SPS的后续字段 | 84→10000100→4 |
4. 特殊情况:ue(v)、se(v)、me(v)
H.264定义了三种Exp-Golomb变体:
ue(v):无符号指数哥伦布编码(最常用,如seq_parameter_set_id)。- 直接按上述规则解析。
se(v):有符号指数哥伦布编码(用于表示负数)。- 先按
ue(v)解码,再转换:
[
\text{Value} = (-1)^{k+1} \times \lceil k/2 \rceil, \quad k = \text{ue(v)}
]
- 先按
me(v):映射指数哥伦布编码(用于宏块类型)。- 需查表转换。
5. 自动化解析工具
手动解析复杂,推荐:
- FFmpeg:
ffmpeg -i input.h264 -c:v copy -bsf:v trace_headers -f null - 2>&1 | grep "exp_golomb" - H.264分析软件:
- Elecard StreamEye:可视化比特流和哥伦布编码。
- CodecVisa:逐比特解析。
6. 总结
- Exp-Golomb编码 =
[前导0] [1] [信息位],数值计算为 (2^M - 1 + \text{信息位})。 - SPS/PPS的关键字段(如
seq_parameter_set_id)必须用此方法解析。 - 手动解析时:先转二进制,找前导0,计算数值。
- 实际应用:优先使用工具(FFmpeg)自动提取参数。
更多推荐


所有评论(0)