一、H.264 码流层次结构
H.264 标准将视频数据分为两大层:
- VCL(Video Coding Layer):负责视频内容的压缩编码(如帧、宏块、预测、变换等)。
- NAL(Network Abstraction Layer):负责将 VCL 数据封装成适合网络传输的单元(NAL 单元)。
二、NAL 单元结构
1. NAL 单元定义
每个 H.264 码流由一系列 NAL 单元组成。每个 NAL 单元包括:
- 起始码前缀:
0x000001或0x00000001 - NAL Header:1 字节
- Payload:具体数据(如 SPS、PPS、Slice 等)
2. NAL Header 结构
| Bit | 名称 | 说明 |
|---|---|---|
| 1 | forbidden_zero_bit | 必须为 0 |
| 2 | nal_ref_idc | 参考优先级(0~3) |
| 5 | nal_unit_type | 单元类型(如 SPS=7, PPS=8, IDR=5, 非IDR=1等) |
示例:NAL Header 字节结构
+----------------+----------------+----------------+
| 1bit | 2bit | 5bit |
| forbidden_zero | nal_ref_idc | nal_unit_type |
+----------------+----------------+----------------+
3. NAL 单元类型(常见)
| 类型 | 名称 | 说明 |
|---|---|---|
| 1 | 非IDR片段 | 普通编码帧(P/B帧) |
| 5 | IDR片段 | 关键帧(I帧) |
| 6 | SEI | 辅助增强信息 |
| 7 | SPS | 序列参数集 |
| 8 | PPS | 图像参数集 |
| 9 | 分隔符 | 分隔NAL单元 |
三、SPS/PPS 数据结构
1. SPS(Sequence Parameter Set)
- 描述一组视频序列的全局参数(如分辨率、帧率、色彩格式、参考帧数等)
- 只需解析一次,后续帧均可复用
SPS 结构常见字段:
- profile_idc(编码配置文件)
- level_idc(编码等级)
- seq_parameter_set_id
- log2_max_frame_num_minus4
- pic_order_cnt_type
- frame_mbs_only_flag
- pic_width_in_mbs_minus1
- pic_height_in_map_units_minus1
- vui_parameters_present_flag(可选,包含宽高比、帧率等)
SPS示例解析:
profile_idc: 100
level_idc: 40
pic_width_in_mbs_minus1: 79 // 宽度 = (79+1)*16 = 1280
pic_height_in_map_units_minus1: 44 // 高度 = (44+1)*16 = 720
2. PPS(Picture Parameter Set)
- 描述一组图像的参数(如熵编码方式、量化参数等)
- 可为不同Slice指定不同PPS
PPS结构常见字段:
- pic_parameter_set_id
- seq_parameter_set_id
- entropy_coding_mode_flag(0:CAVLC, 1:CABAC)
- num_slice_groups_minus1
- num_ref_idx_l0_active_minus1
- weighted_pred_flag
- deblocking_filter_control_present_flag
四、Slice 结构
1. Slice Header
每个 Slice(片)包含一个头部,描述当前片的信息:
- first_mb_in_slice:本片第一个宏块编号
- slice_type:I/P/B/…
- pic_parameter_set_id:PPS编号
- frame_num:帧号
- idr_pic_id:IDR帧编号
- slice_qp_delta:量化参数调整
- direct_spatial_mv_pred_flag:空间预测标志
2. Slice 数据
- 由一系列宏块(Macroblock)组成
- 每个宏块包含类型、运动矢量、预测模式、残差数据等
五、宏块(Macroblock)结构
1. 宏块类型
- I宏块:帧内预测
- P宏块:帧间预测
- B宏块:双向预测
2. 宏块字段
- mb_type:宏块类型
- mb_pred:预测模式(帧内/帧间,块划分方式)
- mb_qp_delta:本宏块的量化参数调整
- mb_mv:运动矢量(帧间宏块)
- mb_residual:变换残差数据
3. 分块结构
- 宏块可进一步分为 16x16, 8x8, 4x4 等大小的子块
- 每个子块有单独的预测、变换、量化参数
六、码流分析举例
以原始 H.264 码流为例,常见结构如下:
00 00 00 01 [NAL Header] [SPS 数据]
00 00 00 01 [NAL Header] [PPS 数据]
00 00 00 01 [NAL Header] [IDR Slice 数据]
00 00 00 01 [NAL Header] [Non-IDR Slice 数据]
...
可用工具(如 H264Visa、Elecard StreamEye)解析,得到:
- NAL 单元类型分布
- SPS/PPS内容
- 每帧的Slice结构和宏块信息
七、码流分析工具操作
1. 用 H264Visa 分析
- 打开 .264 文件
- 查看 NAL 单元列表,识别 SPS、PPS、IDR、P/B帧
- 点击帧,可见 Slice Header、宏块分布、运动矢量等详细数据
2. 用 FFmpeg 查看结构
ffprobe -show_packets -select_streams v input.h264
可输出每个 NAL 单元的类型和偏移。
八、进阶:NAL 单元与容器格式
- 原始 H.264 码流是 NAL 单元拼接
- MP4、TS 等封装格式会对 NAL 单元做打包(去掉起始码,加入长度前缀)
九、SPS(Sequence Parameter Set)详细字段解析
1. SPS 字段顺序(简化版)
| 字段名 | 说明 |
|---|---|
| profile_idc | 配置文件(如66=baseline, 77=main, 100=high) |
| constraint_set_flags | 配置约束标志 |
| level_idc | 等级(如30, 31, 40, 41, 50等) |
| seq_parameter_set_id | SPS编号 |
| log2_max_frame_num_minus4 | 最大帧号 |
| pic_order_cnt_type | POC类型 |
| pic_width_in_mbs_minus1 | 宽度(以16像素为单位) |
| pic_height_in_map_units_minus1 | 高度(以16像素为单位) |
| frame_mbs_only_flag | 仅帧编码标志 |
| direct_8x8_inference_flag | 8x8预测推断标志 |
| frame_cropping_flag | 裁剪标志 |
| vui_parameters_present_flag | VUI参数存在标志 |
2. SPS 二进制举例
假设有一段 SPS 数据(16进制):
67 42 00 1e 95 a8 14 01 6e 9b 80 80 80 a0 01 00 04 68 ce 3c 80
- 67:NAL Header(type=7,SPS)
- 42:profile_idc = 66(baseline)
- 00:constraint_set_flags = 0
- 1e:level_idc = 30
- …(后续为sps字段,需Exp-Golomb解码)
真实解析通常需要用 bitstream 工具或代码逐比特分析。
3. SPS 字段解析工具
- H264 SPS PPS Parser 在线工具
- H264Visa、Elecard StreamEye
十、PPS(Picture Parameter Set)字段详细解析
| 字段名 | 说明 |
|---|---|
| pic_parameter_set_id | PPS编号 |
| seq_parameter_set_id | 所属SPS编号 |
| entropy_coding_mode_flag | 0=CAVLC, 1=CABAC |
| num_slice_groups_minus1 | Slice组数-1 |
| num_ref_idx_l0_active_minus1 | L0参考帧数-1 |
| weighted_pred_flag | 加权预测标志 |
| deblocking_filter_control_present_flag | 去块滤波控制标志 |
PPS 也需用 Exp-Golomb 解码,通常紧随 SPS 后出现。
十一、Slice Header 字段详细解析
每个 Slice(NAL type=1或5)都有头部,主要字段如下:
| 字段名 | 说明 |
|---|---|
| first_mb_in_slice | 当前Slice第一个宏块编号 |
| slice_type | Slice类型(I/P/B/…) |
| pic_parameter_set_id | PPS编号 |
| frame_num | 帧号 |
| idr_pic_id | IDR帧编号(仅IDR帧) |
| pic_order_cnt_lsb | POC低位计数 |
| slice_qp_delta | 量化参数偏移 |
Slice Header 之后紧跟着宏块数据。
Slice Header 解析举例
假设 Slice Header 二进制如下:
00 00 00 01 65 88 84 00 0a f2 ...
- 65:NAL Header(type=5,IDR帧)
- 88 84 00 0a f2 …:Slice Header及后续数据
用 H264Visa 打开后可看到 first_mb_in_slice=0, slice_type=I, frame_num=0 等。
十二、宏块(Macroblock)结构与数据
1. 宏块基本结构
| 字段名 | 说明 |
|---|---|
| mb_type | 宏块类型(Intra/Inter) |
| mb_pred | 预测信息(模式、参考帧等) |
| mb_qp_delta | 量化参数调整 |
| mb_mv | 运动矢量(Inter宏块) |
| mb_residual | 残差(变换系数) |
2. 宏块类型举例
- I_16x16:帧内16x16预测
- I_4x4:帧内4x4预测
- P_L0_16x16:帧间16x16预测
- P_L0_L0_8x8:帧间8x8预测
3. 宏块残差与运动矢量
- 残差通过变换、量化后存储
- 运动矢量为 Inter 宏块指定参考帧及偏移
4. 宏块数据解析工具
- H264Visa:可显示每个宏块的类型、预测模式、运动矢量、残差等
- StreamEye:可可视化宏块划分和运动矢量分布
十三、实际码流结构举例
00 00 00 01 67 ... // SPS
00 00 00 01 68 ... // PPS
00 00 00 01 65 ... // IDR Slice(I帧)
00 00 00 01 41 ... // 非IDR Slice(P/B帧)
...
每个 NAL 单元可被工具逐项解析,SPS/PPS 只需解一次,Slice/宏块每帧解码。
十四、码流分析实操建议
-
用 H264Visa 打开 .264 文件
- 查看 NAL 单元分布,定位 SPS/PPS/Slice
- 选中 Slice,浏览 Header 和宏块详细信息
- 可导出宏块分布和运动矢量图
-
用 FFprobe 查看 NAL 单元类型
ffprobe -show_packets -select_streams v input.h264 -
用在线 SPS/PPS 解析器粘贴 NAL 数据,查看参数含义
十五、H.264 码流二进制解析流程概览
- 找到起始码(0x000001 或 0x00000001)
- 读取 NAL Header,判断类型
- 若为 SPS/PPS,按 Exp-Golomb 编码解析参数
- 若为 Slice,先解析 Slice Header,再逐宏块解码
- 宏块数据需结合预测、运动矢量、残差等信息联合解码
十六、进阶推荐
- 阅读 H.264 标准附录A(码流语法)和附录B(NAL单元封装)
- 用 x264 编码一段视频,导出 .264 文件,逐字节分析 SPS/PPS/Slice
- 结合码流分析工具与标准文档,对照理解每个字段和实际数据
4018

被折叠的 条评论
为什么被折叠?



