当前位置: 首页 > news >正文

AV1 码流 RTP 封装

注:近期文章均来自我的个人笔记,现在公开到博客上。如果有错误,欢迎指正。

一、整体码流结构

012301234567890123456789012345678901+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+|V=2|P|X|CC|M|PT|sequence number|+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+|timestamp|+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+|synchronizationsource(SSRC)identifier|+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+|contributingsource(CSRC)identifiers||....|+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+|0x100|0x0|extensions length|+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+|ID|hdr_length||+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+||||dependencydescriptor(hdr_length #bytes)||||+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+||Other rtp header extensions...|+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+|AV1aggr hdr||+-+-+-+-+-+-+-+-+||||Bytes2..NofAV1payload||||+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+|:OPTIONALRTPpadding|+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

关键说明

  • RTP 包的 Payload Type 可以由 SDP 协商决定
  • Dependency Descriptor 扩展头非必须,但是 WebRTC 在使用 AV1 时是强制启用的。原因是缺少该扩展头的话,无法区分 SVC 编码中不同的时域帧和空域帧
  • Aggregation header位于 RTP 头 + 扩展头之后的第一个字节。官方文档并没有说明是否必须使用,但是在 WebRTC 的实现中是每个包都会加的

WebRTC 打包说明

以下 3 种 OBU 类型会被丢弃:

  • OBU_TEMPORAL_DELIMITER
  • OBU_TILE_LIST
  • OBU_PADDING

WebRTC 打包代码位于:

  • src\modules\rtp_rtcp\source\rtp_packetizer_av1.cc
  • src\modules\rtp_rtcp\source\rtp_packetizer_av1.h

二、Dependency Descriptor 扩展头结构

SVC 编码时需要用到,后续的 《SVC 编码技术》 再介绍


三、Aggregation Header

占用一个字节,结构如下:

01234567+-+-+-+-+-+-+-+-+|Z|Y|W|N|-|-|-|+-+-+-+-+-+-+-+-+

字段说明

比特位字段说明
bit 0Z如果当前 RTP 包的第一个 OBU 是前一个 RTP 包中 OBU 的延续部分,则设置为 1;否则为 0
bit 1Y如果当前 RTP 包的最后一个 OBU 是一个片段,且将在下一个 RTP 包中继续,则设置为 1;否则为 0
bits 2-3W表示当前 RTP 包中包含的 OBU 元素的数量
bit 4N如果当前 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 前都有长度字段)
012301234567890123456789012345678901+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+|Z|Y|00|N|-|-|-|OBUelement1size(leb128)||+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+|:::OBUelement1data:::|||+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+||OBUelement2size(leb128)|+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+:::OBUelement2data:::||+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+:::...:::+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+|OBUe...Nsize||+-+-+-+-+-+-+-+-+OBUelementNdata+-+-+-+-+-+-+-+-+||+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
示例 2:W = 2(最后一个 OBU 前无长度字段)
012301234567890123456789012345678901+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+|Z|Y|10|N|-|-|-|OBUelement1size(leb128)||+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+|||:::OBUelement1data:::|||+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+|||+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+|||:::OBUelement2data:::||+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

注:
W =b10= 2
leb128格式见上篇《AV1 视频编码技术》

封装示例

单个 OBU 封装示例
-Z0(不是前一个包的延续)-Y0OBU不会在下一个包中继续)-W1(包含一个OBU元素)-N1(如果是编码视频序列的第一个包,如 Sequence HeaderOBU
多个 OBU 封装示例
-Z0(不是前一个包的延续)-Y0OBU不会在下一个包中继续)-W2(包含2OBU元素)-N1(如果是编码视频序列的第一个包,如 Sequence HeaderOBU+Frame HeaderOBU合封时,设置为1
OBU 分片封装示例
第一个分片:-Z0(不是前一个包的延续)-Y1OBU将在下一个包中继续)-W1(包含一个OBU元素)-N0(不是编码视频序列的第一个包) Aggregation Header:`01111000`,即0x78中间分片:-Z1(是前一个包的延续)-Y1OBU将在下一个包中继续)-W1(包含一个OBU元素)-N0(不是编码视频序列的第一个包) Aggregation Header:`11101000`,即0xE8最后一个分片:-Z1(是前一个包的延续)-Y0OBU不会在下一个包中继续)-W1(包含一个OBU元素)-N0(不是编码视频序列的第一个包)

四、参考文档

AV1 RTP 封装规范

http://www.jsqmd.com/news/610480/

相关文章:

  • 打包后读取到 NODE_ENV=production + 配置的 BASE_URL/ 自定义变量
  • 2026年碑好的沈阳工厂搬家公司用户好评推荐 - 行业平台推荐
  • 产教融合共建失智老年人照护实训室实践路径
  • OpenClaw夜间值守:Qwen3.5-9B监控服务器报警截图
  • DRV8718智能驱动技术揭秘:从多级栅极控制到汽车座椅应用实战
  • 武汉高三复读班机构排名
  • 可信AI:政务智能化建设中的伦理与安全框架
  • LangChain4j的ChatMemoryProvider实战:如何为不同用户/线程创建独立的AI对话记忆?
  • 半导体芯片展哪家好?平台汇聚,打通芯片设计制造封测全链 - 品牌2026
  • Redis性能调优实战:如何用libjemalloc替代glibc内存分配器
  • 基于转子磁链模型的滑模观测器改进:自适应反馈增益拓宽低速运行区间仿真研究
  • 【建议收藏】数据人转型AI大模型全攻略:零基础入门,高薪就业不是梦
  • 2026年液冷规模化元年:全球科技巨头整体转向液冷
  • FastAPI + Vue3 + Vite 跨域报错全解:从 `Access-Control-Allow-Origin missing` 到彻底修复
  • 告别命令行恐惧!用Docker Desktop可视化界面5分钟搞定Ollama部署(附端口映射避坑指南)
  • JMS, ActiveMQ 学习一则谝
  • Python拉取视频流的性能优化实战
  • 2026年比较好的铜陵全屋定制用户好评公司 - 行业平台推荐
  • Vulnhub sar
  • 车载嵌入式C#开发生死线(CAN总线+UI线程死锁大揭秘):3个被90%团队忽略的实时性陷阱
  • OpenClaw安全实践:Qwen3-14B私有镜像+本地化数据边界方案
  • Carsim与Simulink联合仿真:基于Dugoff轮胎模型与无迹卡尔曼滤波的车辆状态估计...
  • 2026流化床干燥机技术解析:选型、适配与节能改造指南 - 优质品牌商家
  • Python数值计算安全指南:用NumPy和条件判断优雅绕过NoneType错误
  • EEPROM页写机制导致的I2C数据异常解析
  • OpenClaw技能开发入门:为Qwen2.5-VL-7B定制图文处理模块
  • 从 0 到 1 搭建美股回测数据体系:API 获取 + 清洗 + 校验完整方案
  • C# 13 unsafe上下文管控实战手册(.NET 8.0.3+强制合规清单)
  • 从零到链:以太坊DApp开发实战指南
  • 【GUI-Agent】阶跃星辰 GUI-MCP 解读---()---命令解析和工具映射蓉