注:近期文章均来自我的个人笔记,现在公开到博客上。如果有错误,欢迎指正。
一、整体码流结构
javascript
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|V=2|P|X| CC |M| PT | sequence number |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| timestamp |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| synchronization source (SSRC) identifier |
+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
| contributing source (CSRC) identifiers |
| .... |
+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
| 0x100 | 0x0 | extensions length |
+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
| ID | hdr_length | |
+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ |
| |
| dependency descriptor (hdr_length #bytes) |
| |
| +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| | Other rtp header extensions...|
+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
| AV1 aggr hdr | |
+-+-+-+-+-+-+-+-+ |
| |
| Bytes 2..N of AV1 payload |
| |
| +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| : OPTIONAL RTP padding |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
关键说明
- RTP 包的 Payload Type 可以由 SDP 协商决定
- Dependency Descriptor 扩展头非必须,但是 WebRTC 在使用 AV1 时是强制启用的。原因是缺少该扩展头的话,无法区分 SVC 编码中不同的时域帧和空域帧
- Aggregation header 位于 RTP 头 + 扩展头之后的第一个字节。官方文档并没有说明是否必须使用,但是在 WebRTC 的实现中是每个包都会加的
WebRTC 打包说明
以下 3 种 OBU 类型会被丢弃:
OBU_TEMPORAL_DELIMITEROBU_TILE_LISTOBU_PADDING
WebRTC 打包代码位于:
src\modules\rtp_rtcp\source\rtp_packetizer_av1.ccsrc\modules\rtp_rtcp\source\rtp_packetizer_av1.h
二、Dependency Descriptor 扩展头结构
SVC 编码时需要用到,后续的 《SVC 编码技术》 再介绍
三、Aggregation Header
占用一个字节,结构如下:
javascript
0 1 2 3 4 5 6 7
+-+-+-+-+-+-+-+-+
|Z|Y| W |N|-|-|-|
+-+-+-+-+-+-+-+-+
字段说明
| 比特位 | 字段 | 说明 |
|---|---|---|
| bit 0 | Z | 如果当前 RTP 包的第一个 OBU 是前一个 RTP 包中 OBU 的延续部分,则设置为 1;否则为 0 |
| bit 1 | Y | 如果当前 RTP 包的最后一个 OBU 是一个片段,且将在下一个 RTP 包中继续,则设置为 1;否则为 0 |
| bits 2-3 | W | 表示当前 RTP 包中包含的 OBU 元素的数量 |
| bit 4 | N | 如果当前 RTP 包是一个编码视频序列(coded video sequence)的第一个包,则设置为 1;否则为 0 |
W 位详细说明
- 如果设置为 0,则每个 OBU 元素前必须有一个长度字段(超过 3 个,则固定设为 0)
- 如果设置为非 0 值(即 1、2 或 3 ),则最后一个 OBU 元素前不应有长度字段,其长度可通过以下方式计算:
- 最后一个 OBU 的长度 = RTP Payload 的总长度 - Aggregation Header 的长度 - 前面所有 OBU(包括其长度字段)的总长度
- 非 0 时,读取长度字段的次数 = W - 1 次
- 例如:W = 1 时,表示只有一个 OBU 元素,并且读取 1 - 1 = 0 次长度字段,也就是 Aggregation header 之后直接为 OBU 元素数据
W 位设置示例
示例 1:W = 0(每个 OBU 前都有长度字段)
javascript
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|Z|Y|0 0|N|-|-|-| OBU element 1 size (leb128) | |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
: :
: OBU element 1 data :
: :
| |
| +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| | OBU element 2 size (leb128) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
: :
: OBU element 2 data :
: :
| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
: :
: ... :
: :
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|OBU e... N size| |
+-+-+-+-+-+-+-+-+ OBU element N data +-+-+-+-+-+-+-+-+
| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
示例 2:W = 2(最后一个 OBU 前无长度字段)
javascript
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|Z|Y|1 0|N|-|-|-| OBU element 1 size (leb128) | |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| |
: :
: OBU element 1 data :
: :
| |
| +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| | |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| |
: :
: OBU element 2 data :
: :
| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
注:
W =
b10= 2
leb128格式见上篇《AV1 视频编码技术》
封装示例
单个 OBU 封装示例
javascript
- Z:0(不是前一个包的延续)
- Y:0(OBU 不会在下一个包中继续)
- W:1(包含一个 OBU 元素)
- N:1(如果是编码视频序列的第一个包,如 Sequence Header OBU)
多个 OBU 封装示例
javascript
- Z:0(不是前一个包的延续)
- Y:0(OBU 不会在下一个包中继续)
- W:2(包含 2 个 OBU 元素)
- N:1(如果是编码视频序列的第一个包,如 Sequence Header OBU + Frame Header OBU 合封时,设置为 1)
OBU 分片封装示例
javascript
第一个分片:
- Z:0(不是前一个包的延续)
- Y:1(OBU 将在下一个包中继续)
- W:1(包含一个 OBU 元素)
- N:0(不是编码视频序列的第一个包)
Aggregation Header:`01111000`,即 0x78
中间分片:
- Z:1(是前一个包的延续)
- Y:1(OBU 将在下一个包中继续)
- W:1(包含一个 OBU 元素)
- N:0(不是编码视频序列的第一个包)
Aggregation Header:`11101000`,即 0xE8
最后一个分片:
- Z:1(是前一个包的延续)
- Y:0(OBU 不会在下一个包中继续)
- W:1(包含一个 OBU 元素)
- N:0(不是编码视频序列的第一个包)