【音视频】RTMP拉流抓包分析

发布于:2025-06-30 ⋅ 阅读:(16) ⋅ 点赞:(0)

一、RTMP推流

2.1 ffmpeg 推流

  • 下面使用ffmpeg进行RTMP的推流,这是为我们的拉流做准备
ffmpeg -i 1.mp4 -vcodec h264 -acodec aac -f flv rtmp://10.22.79.251/live/livestream

2.2 RTMP推流抓包

  • 下面是推流的RTMP包,从三次握手开始确认连接,然后设置RTMP协议的属性,如Windows大小、Chunk大小等等,最后发布实时流…
  • 关于拉流的抓包我们就不分析了,主要讲解拉流的抓包,实际上二者都有重叠部分

在这里插入图片描述

二、RTMP拉流

2.1 ffplay 拉流

  • 使用ffplay对我们上面推流进行拉取
  • 下面是拉流的命令,拉取livestream这个流
ffplay -i  rtmp://10.22.79.251/live/livestream -x 800

2.2 RTMP三次握手

  • 和RTMP推流一样,拉流也需要先建立RTMP连接,也就是进行三次握手
  • 第一次握手是客户端发送C0+C1,第二次握手是服务器回复S0+S1+S2,第三次握手是客户端发送C2
  • 握手之后,接着客户端就可以发送connect报文请求服务器发送拉流数据了

在这里插入图片描述

第一次握手

  • 客户端→服务器:发送 C0(1 字节,版本号) + C1(1536 字节,含时间戳、零字段、随机数)

  • C0:版本声明(1 字节)

    • 字段:Protocol version: 03
    • 意义:RTMP 版本为 3(主流版本,支持明文 RTMP、加密 RTMPE 等)。若服务端不支持此版本,握手失败。
  • C1:握手数据(后续字节,因 TCP 分段仅显示部分)

    • C1 的标准结构为:[时间戳(4字节)] + [零字段(4字节)] + [随机数(1528字节)]

该报文是 RTMP 握手的起始包,客户端通过C0声明版本,通过C1发送初始握手参数,后续需依赖 TCP 分段传输完整 C1,并等待服务端回复S0+S1+S2完成握手

在这里插入图片描述

第二次握手

  • 阶段 2:服务端回 S0(版本,1 字节) + S1(握手数据,1536 字节) + S2(握手数据,1536 字节)

  • 版本协商(S0)

    • 字段:Protocol version: 03
    • 意义:服务端声明支持 RTMP 版本 3(与客户端 C0 的版本一致),版本协商成功。若版本不匹配,握手直接失败。
  • 握手数据(S1+S2,分段传输)

    • 标准 S1 和 S2 各为 1536 字节,结构如下:
      1. S1:[时间戳(4 字节)] + [零字段(4 字节)] + [随机数(1528 字节)](仿客户端 C1 结构,用于挑战客户端)。
      2. S2:[客户端 C1 的时间戳(4 字节)] + [客户端 C1 的零字段(4 字节)] + [响应随机数(1528 字节)](回应客户端 C1 的挑战)。

该报文是 RTMP 握手的服务端应答帧,核心作用是确认版本并启动双向挑战 - 响应认证。由于数据分段,需结合后续 TCP 段才能完整解析 S1 和 S2 的随机数交互逻辑,为最终 C2 报文的发送和连接建立铺路。

在这里插入图片描述

第三次握手

  • 阶段 3:客户端发 C2(握手数据,1536 字节)
  • RTMP 类型:Handshake C2,明确属于握手的最后一步
  • 标准 C2 为 1536 字节,结构固定:[ S1 的时间戳(4 字节) ] + [ S1 的零字段(4 字节) ] + [ 客户端响应随机数(1528 字节)]
  • 复制 S1 的时间戳和零字段:证明客户端正确解析了服务端的 S1(若解析错误,复制的数据会不匹配,服务端拒绝连接)
  • 客户端响应随机数:基于服务端 S1 的随机数生成,完成 挑战 - 响应认证(防止中间人伪造连接)

握手完成的意义

  • 连接建立:C2 发送后,RTMP 握手结束,双方进入 业务阶段(如后续的 connect 命令,声明流名称、参数;createStream 建立流通道等)
  • 安全保障:通过三次握手的随机数交互,确保连接双方是合法端点(中间人无法伪造匹配的随机数响应)

该报文是 RTMP 握手的收官步骤:客户端通过 C2 回应服务端的挑战,完成双向认证。

在这里插入图片描述

2.3 connect报文

在 RTMP 握手(C0+C1→S0+S1+S2→C2)完成后,客户端进入 业务命令阶段,首个核心命令就是 connect,用于:

  • 声明要连接的 应用名称(如直播应用 live)。
  • 协商双方支持的 编码格式(音频、视频 codec)、功能特性(如是否支持加密、分片等)。

这个报文是 RTMP 协议的 connect 命令,属于 握手完成后的业务层请求,用于客户端向服务端申请连接到指定的流媒体应用(如 live),并协商通信参数

RTMP 消息头解析
字段 值/意义
Chunk Stream ID 3 → RTMP 控制通道(固定用 CSID=3 传输命令,如 connect/createStream 等)。
Timestamp 0 → 若为首包,可能表示“相对时间起点”;或因Chunk类型为0(绝对时间),实际需结合后续包判断。
Length 199 → 消息体总长度(AMF0 编码的命令内容)。
Type ID 0x14(20)→ RTMP 定义的 Command 消息类型(用于传输业务命令)。
Format 0 → 消息体采用 AMF0 编码(Action Message Format,RTMP 默认序列化格式)。
消息体:connect 命令的核心内容

消息体遵循 AMF0 格式,结构为:

[命令名(字符串)] + [事务ID(数值)] + [连接参数(AMF0 对象)]  
(1) 命令名"connect"
  • 意义:明确告知服务端,这是一个 连接申请命令,服务端需回应 _result_error
(2) 事务ID1
  • 意义:异步响应的“标识号”(类似 HTTP 的 Cookie),服务端回复时会携带相同 ID,方便客户端匹配请求与响应。
(3) 连接参数(AMF0 对象)

包含 8个键值对Object (8 items)),常见字段如下(因抓包未完全展开,以下为典型场景):

  • app:要连接的应用名称(如 live,对应服务端的直播应用)。
  • flashVer:客户端 Flash 版本(如 WIN 32.0.0.465,用于兼容性协商)。
  • tcUrl:RTMP 连接的完整 URL(如 rtmp://10.22.79.251/live,明确服务端地址和应用)。
  • capabilities:客户端能力标识(如支持的协议特性,数值编码)。
  • audioCodecs:支持的音频编码(如 AAC、MP3 等,位掩码表示)。
  • videoCodecs:支持的视频编码(如 H.264、VP6 等,位掩码表示)。
  • videoFunction:视频功能(如是否支持实时流、录制等)。

该报文是 RTMP 会话的 “连接申请” 核心命令,客户端通过它向服务端声明“要连哪个应用、支持什么格式”,是流媒体会话建立的关键一步。

在这里插入图片描述

2.4 Windows ACK Size 报文

这个报文是 RTMP 协议的 Window Acknowledgement Size(窗口确认大小)控制消息,用于 应用层流量控制,告知对方 “接收方希望每接收多少字节后发送确认(ACK)”

  • 接收方(如本例中服务端 10.22.79.251)通过此报文,告诉发送方(客户端 10.22.75.58): “我最多缓存 N 字节数据,你发满 N 字节后必须等我确认,再继续发。”
  • 目的:防止接收方缓冲区溢出(尤其是音视频流大流量场景),保障传输稳定。
字段 抓包值 / 意义
Chunk Stream ID 2 → RTMP 控制通道(非命令通道,专用于流量控制、带宽协商等控制消息)。
Format 0 → 完整消息头(含 Timestamp、Length、Type ID,无压缩)。
Timestamp 0x000010(16)→ 时间戳(因是控制消息,值较小,代表相对时间起点)。
Body Size 4 → 消息体长度(仅 4 字节,存窗口大小的整数)。
Type ID 0x05(5)→ RTMP 预定义的 Window Acknowledgement 消息类型。
Window Size 2500000 → 接收方期望的确认窗口大小(单位:字节)。
  • 握手完成后(业务命令前),双方会交换窗口大小、带宽限制(Set Peer Bandwidth)等控制消息,初始化流量控制参数。
  • 传输过程中可动态调整(如网络拥塞时缩小窗口)。
Set Peer Bandwidth 的区别
消息类型 作用 类比 TCP 功能
Window Acknowledgement 接收方告诉发送方:“我要你每发 N 字节就 ACK” 滑动窗口的 窗口大小通告
Set Peer Bandwidth 接收方告诉发送方:“你最多每秒发 M 字节” 流量控制的 速率限制
两者配合,实现 “速率 + 窗口” 双层流量控制,避免丢包。

该报文是 RTMP 应用层流量控制的 “窗口大小通告”,客户端通过它告知服务端自己的接收缓冲区容量(2500000 字节),要求服务端发送数据时遵守此窗口限制,防止客户端缓冲区溢出。这是流媒体稳定传输的核心控制机制之一。

在这里插入图片描述

2.5 Set Peer BandWidth 报文

这是一条 RTMP 协议的 Set Peer Bandwidth(设置对端带宽)控制报文,用于 限制通信对端的发送速率,是 RTMP 应用层流量控制的核心机制之一

RTMP 通过 Set Peer Bandwidth 实现 “速率维度” 的流量控制

  • 发送方(本例中是 客户端 10.22.75.58,报文从客户端发往服务端 10.22.79.251)告诉接收方(服务端):
    “你最多每秒可以发送 X 字节数据,超过部分按规则处理(如丢弃或节流)。”
  • 目的:避免服务端发送速率过高,导致客户端网络拥塞(尤其弱网环境下,控制直播流速率更关键)。
(1) RTMP 头部(Chunk Header,Format 3)

RTMP 的 Chunk Header 有 4 种格式,此处为 Format 3(简化头)

  • Format 3:仅包含 Chunk Stream IDTimestamp Delta(时间戳增量),其余字段(如消息长度、类型)复用前一个 Chunk 的上下文(减少头部开销)。
  • Chunk Stream ID3 → 属于 控制 / 命令通道(RTMP 中 Chunk Stream ID=3 常用于命令或控制消息,需结合上下文判断)。
(2) 消息体:Set Peer Bandwidth 的核心参数

标准 Set Peer Bandwidth 消息体包含 两部分

  1. 带宽值(4 字节整数):表示对端允许的 最大发送速率(字节 / 秒)(抓包未完全展开,但逻辑上存在)。
  2. 控制标志(1 字节):定义超过速率后的处理策略:
    • 0x00(硬限制):超过速率的数据包 直接丢弃
    • 0x01(软限制):超过速率时 节流(降低发送速度),而非直接丢弃。

发送时机

  • 通常在 RTMP 握手完成后、业务数据传输前 发送(初始化速率协商);
  • 也可 动态调整(如网络变差时,客户端缩小带宽限制,要求服务端降速)。
Window Acknowledgement Size 的协同

RTMP 的流量控制是 “速率(时间)+ 窗口(空间)” 双层机制

消息类型 控制维度 类比意义
Set Peer Bandwidth 时间(每秒速率) 限制 “水流速度”
Window Acknowledgement 空间(缓冲区大小) 限制 “水桶容量”
两者配合,既防止服务端发得 太快(速率),又防止客户端存得 太满(缓冲区),从根本上避免网络拥塞。

在这里插入图片描述

2.6 Set Peer BandWidth 报文、Set Chunk Size 报文

这是一条 RTMP 协议的复合控制报文,包含两个核心控制消息:Set Peer Bandwidth(设置对端带宽)Set Chunk Size(设置分块大小),用于 初始化会话的传输参数,优化音视频流的传输效率和稳定性

报文组成:两个控制消息的 “复合传输”

RTMP 允许 同一个 TCP 包中传输多个 Chunk(只要属于同一 Chunk Stream 或不同 Stream 但按序排列)。本例中,服务端(10.22.79.251)向客户端(10.22.75.58)发送了 两个独立的 RTMP 控制消息,封装在同一个 TCP 包中:

消息 1:Set Peer Bandwidth(类型 ID:0x06
字段 抓包值 / 意义
Chunk Stream ID 2 → RTMP 控制通道(系统级消息专用,如流量控制、分块大小调整)。
Format 0 → 完整头部(含 Timestamp、Body Size、Type ID,确保控制消息可靠)。
Window Size 2500000 → 对端(客户端)允许的 最大未确认数据量(应用层滑动窗口大小)。
Limit Type Dynamic (2) → 带宽限制类型:动态调整(根据网络情况灵活限流,而非硬阻断)。
消息 2:Set Chunk Size(类型 ID:0x01
字段 抓包值 / 意义
Chunk Stream ID 2 → 复用控制通道(与 Set Peer Bandwidth 同通道,减少连接开销)。
Format 0 → 完整头部(独立消息,需明确标识)。
Chunk Size 60000 → 设置 RTMP 的 分块大小(默认 128 字节,此处大幅提升至 60KB)。

核心功能:优化传输的 “双调控”

(1) Set Peer Bandwidth:流量速率控制
  • 作用:告知客户端:“你发送数据时,最多允许 2500000 字节处于‘未确认’状态,超过后需等待我的 ACK。”
  • 动态限制(Dynamic):允许客户端根据网络状态 灵活调整发送速率(而非强制阻断,如 Hard 类型),平衡吞吐量和稳定性。
(2) Set Chunk Size:分块效率优化
  • 默认 vs 配置:RTMP 默认分块大小为 128 字节,此处提升至 60000 字节(60KB)。
  • 优化逻辑
    • 减少头部开销:更大的分块意味着每个数据块的 RTMP 头部占比更低(如 60KB 数据,头部仅占~0.02%)。
    • 适配大流量:视频流单帧可能超 128 字节,大分块减少分块次数,提升传输效率。
    • trade-off :分块过大可能增加延迟(需等分块填满才发送),但流媒体场景更看重吞吐量,故合理。

在这里插入图片描述

2.7 Window ACK Size报文、createStream报文、_chunlbw报文

这是一条 RTMP 协议的复合请求报文,包含 3 个独立的 RTMP 消息,用于 流量控制配置、媒体流创建、带宽探测,是 RTMP 会话从 “连接握手” 进入 “业务传输” 的关键步骤

消息 1:Window Acknowledgement Size(Chunk Stream ID=2,类型 0x05
字段 意义
Chunk Stream ID 2 → RTMP 控制通道(专用于流量控制、分块大小等系统级消息)。
Format 0 → 完整头部(含 Timestamp、Body Size、Type ID,确保控制消息可靠)。
Window Size 2500000 → 客户端声明 接收窗口大小(服务端发送数据时,未确认数据不能超过此值)。
消息 2:AMF0 Command createStream()(Chunk Stream ID=3,类型 0x14
字段 意义
Chunk Stream ID 3 → RTMP 命令通道(专用于业务命令,如 connectcreateStream)。
Format 1 → 简化头部(复用前一个同 Stream 的头部信息,减少开销)。
命令内容 - 命令名:"createStream"(请求服务端创建新的媒体流)。
- 事务 ID:2(用于匹配服务端的 _result 响应)。
- 参数:null(简单请求,无额外配置)。
3. 消息 3:AMF0 Command _checkbw()(Chunk Stream ID=3,类型 0x14
字段 意义
Chunk Stream ID 3 → 复用命令通道(与 createStream 同属业务命令,连续发送)。
Format 1 → 简化头部(同通道,复用前序头部的 Chunk Stream ID 等信息)。
命令内容 - 命令名:"_checkbw"(客户端发起 带宽探测,用于协商传输速率)。
- 事务 ID:3(匹配服务端响应)。
- 参数:null(基础探测,服务端可能返回带宽建议)。

核心功能:从 “连接” 到 “业务” 的过渡

(1) Window Acknowledgement Size:流量控制闭环
  • 客户端通过此消息,向服务端声明 自身接收缓冲区容量(2500000 字节),要求服务端发送数据时遵守 “未确认数据 ≤ 窗口大小”,避免客户端缓冲区溢出。
  • 与服务端之前发送的 Set Peer Bandwidth 配合,形成 “发送方速率限制 + 接收方窗口限制” 的双层流量控制。
(2) createStream:媒体流初始化
  • RTMP 会话中,connect 仅建立 “连接”,createStream 才会 分配独立的流 ID(如 1),用于后续音视频数据的传输(如 publish 推流、play 拉流)。
  • 服务端会回复 _result 消息,携带新创建的流 ID,客户端后续需通过该 ID 传输媒体数据。
(3) _checkbw:带宽动态协商
  • 客户端主动发起带宽探测,服务端会根据网络情况 调整发送速率(如降低码率、优化分块大小)。
  • 常见于弱网环境或直播场景,确保流媒体传输不卡顿。

交互逻辑:为什么 “复合发送”?

  • 效率优化:将多个逻辑请求打包在同一 TCP 包中,减少 TCP 握手次数,提升初始化效率。
  • 通道复用
    • Chunk Stream ID=2(控制通道)处理流量控制;
    • Chunk Stream ID=3(命令通道)处理业务命令;
      两者并行,互不干扰。

关键意义:会话进入 “数据传输阶段” 的标志

  • 此前的 connect 是 “连接申请”,本次的 createStream 是 “流创建申请”,之后服务端回应 _result 后,双方即可通过新分配的流 ID 传输音视频数据。
  • 流量控制和带宽探测的配置,为后续大流量的媒体数据传输保驾护航,避免拥塞或丢包。

在这里插入图片描述

2.8 _result报文

这是一条 RTMP 协议的 _result 响应报文,用于回复客户端此前发送的 业务命令(如 createStream_checkbw),标志 命令执行结果

  • 方向:服务端(10.22.79.251)→ 客户端(10.22.75.58),属于 “请求 - 响应” 闭环的一部分。
  • 通道Chunk Stream ID = 3(与客户端发送的命令同通道,确保响应关联)。

RTMP 头部解析(Format 0)

字段 意义与抓包值
Format 0 → 完整头部(含 Timestamp、Body Size、Type ID,确保响应的可靠性)。
Chunk Stream ID 3 → 复用 命令通道(客户端发送命令时用 CSID=3,服务端回复也用同通道)。
Timestamp 0 → 响应类消息的时间戳常设为 0(或相对时间起点,优先级低于业务数据)。
Body Size 29 → 消息体长度(AMF0 编码的命令响应内容)。
Type ID 0x14(20)→ AMF0 Command 类型(与请求的命令类型一致,用于标识响应)。

消息体:AMF0 编码的 _result 响应

RTMP 的命令响应遵循 AMF0 格式,结构为:

[响应类型(字符串)] + [事务 ID(数值)] + [结果数据(对象/空值)]  
(1) 响应类型:"_result"
  • 字符串类型(AMF0 标记 0x02),表示这是对 客户端请求的成功响应(若失败,通常会返回 "_error")。
(2) 事务 ID:Number 2
  • 数值类型(AMF0 标记 0x00),值为 2 → 匹配客户端发送命令时的 事务 ID(如 createStream 命令的事务 ID 为 2,确保请求 - 响应一一对应)。
(3) 结果数据:Null
  • 空值类型(AMF0 标记 0x05),表示 命令执行成功且无额外数据返回(若需返回流 ID 等信息,会用对象类型 0x03 封装)。

交互逻辑:响应的意义

  1. 关联请求
    • 客户端此前发送了 createStream 命令(事务 ID=2),服务端通过 _result 响应确认 媒体流创建成功
    • 后续双方将通过 隐式分配的流 ID(会话中协商,无需显式携带)传输音视频数据。
  2. 成功标识
    • RTMP 中,_result + Null 通常表示 命令执行成功;若失败,会返回 _error 并携带错误码(如 NetStream.Error)。
  3. 简化设计
    • createStream 的响应无需复杂数据,仅需确认成功,故用 Null 表示 “流已创建,可开始传输”。

在这里插入图片描述

2.9 getStreamLength报文、 play报文、Set Buffer Length报文

这是一条 RTMP 协议的复合请求报文,包含 3 个核心操作查询流长度启动播放配置缓冲区,是客户端拉流前的 初始化核心流程

报文结构:3 个 RTMP 消息的复合传输

RTMP 允许同一 TCP 包中承载 多个 Chunk(不同 Chunk Stream ID 或同 Stream 按序排列)。本例中,客户端(10.22.75.58)向服务端(10.22.79.251)发送 3 个逻辑消息,分属 两个通道

消息 1:AMF0 Command getStreamLength()(业务命令,Chunk Stream ID=8
字段 意义
Chunk Stream ID 8业务命令通道(专用于流操作,如查询、播放、暂停)。
Format 0 → 完整头部(含 Timestamp、Body Size、Type ID,确保命令可靠)。
命令内容 - 命令名:"getStreamLength"(查询 流的时长,如直播流的总长度)。
- 事务 ID:Number 4(匹配服务端响应,唯一标识此请求)。
- 参数:String "livestream"(目标流名称,明确查询哪个流)。
2. 消息 2:AMF0 Command play('livestream')(业务命令,Chunk Stream ID=8
字段 意义
Chunk Stream ID 8 → 复用业务命令通道(与 getStreamLength 同属流操作,连续发送)。
Format 0 → 完整头部(独立命令,需明确标识)。
命令内容 - 命令名:"play"(请求 播放指定流,启动拉流)。
- 事务 ID:Number 5(新事务 ID,区分不同命令)。
- 参数:String "livestream"(目标流名称,与查询一致)。
- 偏移:Number -2000(播放起点,-2000 通常表示 “从最新数据开始”,适配直播场景)。
3. 消息 3:User Control Message Set Buffer Length(控制消息,Chunk Stream ID=2
字段 意义
Chunk Stream ID 2系统控制通道(专用于缓冲区、带宽等底层配置)。
Format 1 → 简化头部(复用同通道前序消息的上下文,减少开销)。
消息内容 - 事件类型:Set Buffer Length (3)(设置客户端 接收缓冲区长度)。
- 缓冲区时长:13000ms(13 秒,平衡延迟与流畅度,缓存足够数据抗网络波动)。

核心功能:拉流初始化的 “三连击”

(1) getStreamLength:流信息探测
  • 客户端查询流的时长(如直播流的总时长,或回放流的长度),用于:
    • 展示播放进度条(如回放场景);
    • 预判流的可用性(如流是否存在、是否为空)。
(2) play:启动拉流
  • 核心播放命令,告知服务端 “开始推送 livestream 流的数据”,并通过 Number -2000 指定 播放起点(直播场景下,-2000 通常表示 “从当前最新数据开始播放”,避免回看历史数据)。
(3) Set Buffer Length:缓冲区配置
  • 客户端设置 13 秒的接收缓冲区,作用:
    • 抗网络抖动:网络短暂卡顿(如 1-2 秒)时,缓冲区的缓存数据可继续播放,避免画面冻结;
    • 延迟 trade-off:缓冲区越大,延迟越高(数据需先存满缓冲区),故 13 秒是 “流畅度 vs 延迟” 的平衡值(直播通常容忍 5-20 秒延迟)。

交互逻辑:为什么 “复合发送”?

  • 效率优化:将 “查询、播放、缓冲配置” 打包在同一 TCP 包中,减少 TCP 握手次数,加速拉流启动。
  • 通道复用
    • Chunk Stream ID=8(业务通道)处理流操作;
    • Chunk Stream ID=2(控制通道)处理缓冲区配置;
      两者并行,互不干扰,体现 RTMP 的 通道隔离设计(控制与业务分离)。

关键意义:拉流的 “起点信号”

  • 此前的 createStream 是 “创建流通道”,本次的 play 是 “启动数据传输”,标志会话从 “准备阶段” 进入 “实际拉流阶段”
  • getStreamLengthSet Buffer Length精细化控制:前者探测流信息,后者优化播放体验,让拉流更智能、更流畅。

在这里插入图片描述

2.10 Stream Begin 报文

这是一条 RTMP 协议的 User Control Message(用户控制消息),具体为 Stream Begin 事件,用于 告知客户端:指定媒体流已启动,即将开始传输数据

报文核心定位:流启动通知

  • 方向:服务端(10.22.79.251)→ 客户端(10.22.75.58),属于 服务端对客户端 play 命令的响应信号
  • 通道Chunk Stream ID = 2(RTMP 系统控制通道,专用于流生命周期、缓冲区等底层事件)。

RTMP 头部解析(Format 0)

字段 意义与抓包值
Format 0 → 完整头部(含 Timestamp、Body Size、Type ID,确保控制消息的可靠性)。
Chunk Stream ID 2 → 系统控制通道(与流创建、缓冲配置等消息复用同一通道)。
Timestamp 0 → 控制类消息的时间戳常设为 0(或相对时间起点,优先级低于业务数据)。
Body Size 6 → 消息体长度(包含 事件类型流 ID,共 6 字节)。
Type ID 0x04(4)→ 标识为 User Control Message(用户控制消息)。

消息体:Stream Begin 事件详情

RTMP 的 User Control Message 消息体结构为 “事件类型(2 字节) + 事件数据(4 字节)”

(1) 事件类型:Stream Begin (0x0000)
  • 2 字节整数,值为 0 → 表示 “流开始” 事件,告知客户端:服务端已准备好向指定流推送数据。
(2) 事件数据:Stream ID = 1
  • 4 字节整数,值为 1 → 对应客户端此前通过 createStream 创建的 媒体流 ID(如流 ID=1 关联 play('livestream') 命令)。

交互逻辑:流启动的 “信号弹”

  1. 前置动作
    客户端先发送 createStream(创建流)和 play('livestream')(请求播放)命令,服务端处理后,通过 Stream Begin 事件回应。

  2. 核心作用

    • 服务端明确告知客户端:“流 ID=1 的媒体流已启动,即将发送音视频数据,请做好接收准备。”
    • 客户端收到后,可初始化播放器状态(如清空缓冲区、启动解码线程),为后续数据传输铺路。

关键意义:流传输的 “启动标志”

  • 流程闭环:标志 RTMP 会话从 “播放请求阶段” 进入 “数据传输阶段”(服务端即将持续推送音视频 Chunk)。
  • 流 ID 绑定:通过 Stream ID=1,客户端明确知道 “即将接收的音视频数据属于哪个流”(避免多流混淆)。

在这里插入图片描述

2.11 Video Data 报文

这是一条 RTMP 协议的视频数据报文,用于传输编码后的视频帧(如 H.264 格式),是流媒体播放的核心承载报文

  • 方向:服务端(10.22.79.251)→ 客户端(10.22.75.58),属于 媒体数据下行传输(客户端拉流时,服务端推送视频帧)。
  • 通道标识Chunk Stream ID65(RTMP 通过 Chunk Stream ID 区分通道,视频流通常占用独立通道,如 CSID=6 或动态分配)。

2. RTMP 头部:分块传输优化(Format 2)

RTMP 采用 分块(Chunking)机制 适配网络 MTU,头部格式 Format 2 是关键优化:

  • Format 2:仅包含 Timestamp Delta(时间戳增量)Length(数据长度)、Type ID(类型),复用前一个 Chunk 的 Chunk Stream IDTimestamp 基准值,减少头部开销
  • 时间戳处理Timestamp delta 是当前 Chunk 与前一个 Chunk 的时间差(单位:毫秒),用于还原视频帧的播放时序。

3. 视频数据结构:FLV 标签封装

RTMP 的视频数据遵循 FLV 标签格式(FLV 是 RTMP 依赖的容器格式),核心字段:

(1) 视频标签头(前 11 字节)
字段 长度 意义
Frame Type 4 位 帧类型:0x17(关键帧,可独立解码)、0x27(增量帧,依赖前序帧)。
Codec ID 4 位 编码格式:0x07 代表 H.264(RTMP 中唯一支持的高清编码)。
Data Size 3 字节 视频数据长度(后续编码数据的字节数)。
Timestamp 3 字节 + 1 字节扩展 解码时间戳(DTS),处理音视频同步。
Composition Time 3 字节 显示时间戳偏移(PTS - DTS),解决 B 帧的时序差(若为 H.264,此值对应 CTS)。
(2) 视频负载(编码数据)

后续字节是 编码后的视频帧内容(如 H.264 的 NAL 单元),包含:

  • AVC 解码配置(仅关键帧携带):如 AVC Sequence Header,包含 SPS、PPS 等解码参数。
  • 视频帧数据:关键帧(I 帧)或增量帧(P/B 帧),依赖编码格式解析。
传输机制:分块与拼接

因视频帧可能很大(如 1080P 关键帧超 MTU),RTMP 会将 一个视频帧拆分为多个 Chunk 传输:

  • 首块用 Format 0(完整头,含绝对时间戳、长度、类型);
  • 后续块用 Format 2(仅传时间戳增量,复用首块的长度和类型);
  • 客户端接收后,按 Chunk Stream ID 拼接成完整视频帧,再解码播放。
    在这里插入图片描述

2.12 Audio Data报文

这是一条 RTMP 协议的音频数据报文,用于传输编码后的音频流(本例为 HE-AAC 格式),是流媒体音频播放的核心承载单元

  • 方向:服务端(10.22.79.251)→ 客户端(10.22.75.58),属于 媒体数据下行传输(客户端拉流时,服务端推送音频帧)。
  • 通道标识Chunk Stream ID = 4(RTMP 通过 Chunk Stream ID 区分通道,音频流通常占用独立通道,如 CSID=4 或动态分配)。
RTMP 头部:分块传输优化(Format 2)

RTMP 采用 分块(Chunking)机制 适配网络 MTU,头部格式 Format 2 是关键优化:

  • Format 2:仅包含 Timestamp Delta(时间戳增量)Length(数据长度)、Type ID(类型,此处为音频数据),复用前一个 Chunk 的 Chunk Stream IDTimestamp 基准值,减少头部开销
  • 时间戳处理
    • Timestamp delta: 6770207:当前 Chunk 与前一个音频 Chunk 的时间差(单位:毫秒);
    • Timestamp: 7984253(计算后):音频帧的 解码时间戳(DTS),用于音视频同步。
音频数据结构:RTMP 音频头 + AAC 负载

RTMP 音频数据遵循 “1 字节控制头 + 编码负载” 格式:

(1) 音频控制头(1 字节,Control: 0xA4

控制头编码了 音频格式、采样率、精度、声道 等参数:

  • 二进制解析0xA41010 0100
  • 字段映射(RTMP 音频头规范):
    • 高 4 位(1010:音频格式 ID,0x0A 代表 AAC(本例为 HE-AAC,属于 AAC 变种);
    • 低 4 位(0100
      • 采样率:01 → 11 kHz(RTMP 预定义的采样率枚举:00=5.5kHz, 01=11kHz, 10=22kHz, 11=44kHz);
      • 精度:0 → 8 bit(0=8bit, 1=16bit);
      • 声道:0 → 单声道(0= mono, 1= stereo)。
(2) 音频负载(AAC 编码数据)

后续字节是 编码后的 AAC 音频帧,包含:

  • AAC 原始数据块:若为 ADTS 格式,会去掉同步头(仅传音频数据);若为 RAW AAC,需依赖之前的 AudioSpecificConfig(音频配置消息)解析参数。
  • 抓包识别:已标注为 HE-AAC 11 kHz 8 bit mono,说明服务端和客户端已通过 AudioSpecificConfig 协商 了编码参数(如 SBR 扩展、采样率索引等)。

4. 传输机制:分块与同步

  • 分块逻辑:音频帧可能被拆分为多个 Chunk(若帧长超过 MTU),首块用 Format 0(完整头),后续块用 Format 2(仅传时间戳增量),客户端重组后解码。
  • 音视频同步:音频的 Timestamp 与视频的 Timestamp 对齐,通过 RTMP 的 时间戳同步机制 保证声画同步。
    在这里插入图片描述

更多资料:https://github.com/0voice