2.1 OBU 架构与 NAL 单元对照


2.1 OBU 架构与 NAL 单元对照

本节摘要:H.264/HEVC 用 NAL 单元切分码流,AV1 用 OBU 切分码流。两者都解决"把压缩数据切成可寻址的单元"这个问题,但 OBU 把自描述性做到了字节级:类型、扩展标志、长度全在头部声明,解析器不需要猜。本节给出两种封装的逐项对照与一段可上手的十六进制验证方法。

两种封装世界观

NAL(Network Abstraction Layer)的设计初衷是面向网络传输:单元之间用起始码 00 00 01 分隔( Annex-B 格式)或用长度前缀分隔(MP4 封装),单元类型编码在头部的几个比特里。这个设计在流媒体场景工作良好,但也有代价——起始码可能与载荷内容冲突,需要防竞争字节(emulation prevention)兜底;封装格式不同,分隔方式就不同,解析器要适配两套逻辑。

OBU 的思路是把"自描述"进行到底。每个 OBU 头至少一字节,包含类型、扩展标志、是否有长度字段等位级声明;如果声明了带长度,紧跟一个可变长编码的载荷长度。解析逻辑因此只有一条路径:读头、读长、跳载荷,不依赖外部封装格式,也不需要防竞争处理。

对照项 NAL(H.264/HEVC) OBU(AV1)
单元分隔 起始码或长度前缀,随封装变化 头内声明,封装无关
类型声明 头部 5 位枚举 4 位类型 + 扩展位 + 长度标志
防冲突机制 起始码防竞争字节 无需(长度自描述)
时间分层 头内 temporal_id(扩展) 扩展头携带 temporal_id/spatial_id
顶层单元示例 SPS/PPS/切片 Sequence Header/Frame/Tile Group/Metadata

动手验证:读一个 OBU 头

概念讲十遍不如看一遍字节。下面是一个真实 AV1 码流开头附近的十六进制片段(示意值,任何 AV1 文件都可以这样分析):

0A 0B 0A 01 08 0C 00 1A 0A ... │ │ │ └─ 载荷长度 = 11(可变长编码) └─ OBU 头 0x0A = 0000 1010 ├─ forbidden_bit = 0 ├─ type = 1 (OBU_SEQUENCE_HEADER) ├─ extension_flag = 0 └─ has_size_field = 1(自描述长度)

用 FFmpeg 的码流探针也能看到同样信息:

# 列出码流中的 OBU 序列与帧信息 ffmpeg -v trace -i output.ivf 2>&1 | findstr /C:"OBU" | more # 或用 ffprobe 确认容器与编解码器识别 ffprobe -v error -show_entries stream=codec_name,profile,pix_fmt output.mkv

对照 H.264 的经验:你会花同样的动作去找 67(SPS)、68(PPS)、65(IDR 切片)这类 NAL 头字节。差别在于 H.264 的 NAL 头只有两个比特的有效语义位加五个类型位,剩余信息要从 SPS/PPS 里"跨单元"拼出来;OBU 则尽量把声明留在本单元内。

层级关系:Temporal Unit 是新东西吗

AV1 把"一个显示时刻的全部数据"定义为 Temporal Unit(TU),一个 TU 内含时间定界符 OBU、可选的序列头 OBU、一个或多个 Frame OBU 与元数据 OBU。H.264 没有对应的显式概念——一帧的多个切片靠 first_mb_in_slice 等语法元素隐式关联,接入点靠 IDR 帧标记。对照之下 AV1 的显式 TU 带来两个工程红利:

  • 随机访问更省心:播放器 seek 到某个 TU,只要该 TU 带关键帧,解析器从定界符开始顺序消费即可,不需要回溯切片归属;
  • 并行与低延迟有抓手:Frame 内部还能拆 Tile Group OBU,网络差时可以先发部分 Tile Group、后续再补,直播与云游戏场景直接受益。

⚠️ 注意一个易错点:OBU 序列头只在首个 TU 强制出现,后续可在分辨率或参数变化时重复。自己写解析器时不要假设"每个 TU 都有序列头",也不要假设"序列头只出现一次"。

从封装差异看设计哲学

把 NAL 与 OBU 的差异收敛成一句话:NAL 把复杂性留给封装与组合,OBU 把复杂性一次性收进标准。前者的好处是 2003 年就能跑在当时的传输设施上,后者的好处是 2018 年可以直接按现代流媒体的需求设计,不必背历史包袱。这不是谁更聪明的问题,而是出生年代的问题——也再次呼应第 1 章的结论:每代标准都是对自身时代约束的回应。

下一节把"说明书"展开:序列头与帧头各自声明哪些元数据,H.264 的 SPS/PPS 在 AV1 里对应什么。

常见追问

问:实际部署里 AV1 用什么容器装 OBU?
答:WebM(MKV 家族)是天然搭档,MP4 家族的后续版本也定义了 AV1 的封装样本条目。流媒体传输场景里,OBU 序列被切成分段(如 DASH/CMAF 的分片),Temporal Unit 边界与分片边界对齐即可。对照 H.264 时代 Annex-B 与 MP4 两套分隔方式的"双轨烦恼",AV1 的封装适配面窄得多——这正是自描述设计的红利。

问:自己写解析器,最容易在哪个字段上翻车?
答:可变长长度字段(leb128 编码)与"序列头可能重复出现"这两处。前者编码器合法地使用多字节表示小数值,解析器按固定宽度读就出错;后者让状态机不能假设"全局参数只在流头出现一次"。先把这两点处理对,解析器就立住了大半。

问:OBU 会带来额外的封装开销吗?
答:每单元一至两字节的头加长度字段,开销在千分之一量级,对视频码流可忽略。换来的是免起始码扫描、免防竞争处理、容器无关解析——工程账怎么算都划算。

本节要点回顾

  • 封装自描述:OBU 头声明类型与长度,解析路径唯一;NAL 依赖起始码或长度前缀,随封装变化。
  • 动手可验证:用十六进制查看器或 FFmpeg 探针即可验证 OBU 结构,是学习 AV1 门槛最低的入口。
  • TU 显式化:Temporal Unit 让随机访问与 Tile Group 分片传输有了明确锚点。
  • 哲学差异:NAL 留复杂度给封装,OBU 把复杂度收进标准,出生年代决定设计取向。

作者与出处
原作者: 灏天文库
来源:灏天文库
整理: 灏天文库整理
由灏天文库平台收录,内容或由平台用户上传,仅供学习交流
发布者: 作者: 灏天文库 转发
评论区 (0)
U