一、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字节)]
- C1 的标准结构为:
该报文是 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 字节,结构如下:
- S1:
[时间戳(4 字节)] + [零字段(4 字节)] + [随机数(1528 字节)]
(仿客户端 C1 结构,用于挑战客户端)。 - S2:
[客户端 C1 的时间戳(4 字节)] + [客户端 C1 的零字段(4 字节)] + [响应随机数(1528 字节)]
(回应客户端 C1 的挑战)。
- S1:
- 标准 S1 和 S2 各为 1536 字节,结构如下:
该报文是 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) 事务ID:1
- 意义:异步响应的“标识号”(类似 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 ID
和Timestamp Delta
(时间戳增量),其余字段(如消息长度、类型)复用前一个 Chunk 的上下文(减少头部开销)。 - Chunk Stream ID:
3
→ 属于 控制 / 命令通道(RTMP 中 Chunk Stream ID=3 常用于命令或控制消息,需结合上下文判断)。
(2) 消息体:Set Peer Bandwidth
的核心参数
标准 Set Peer Bandwidth
消息体包含 两部分:
- 带宽值(4 字节整数):表示对端允许的 最大发送速率(字节 / 秒)(抓包未完全展开,但逻辑上存在)。
- 控制标志(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 命令通道(专用于业务命令,如 connect 、createStream )。 |
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
封装)。
交互逻辑:响应的意义
- 关联请求:
- 客户端此前发送了
createStream
命令(事务 ID=2),服务端通过_result
响应确认 媒体流创建成功。 - 后续双方将通过 隐式分配的流 ID(会话中协商,无需显式携带)传输音视频数据。
- 客户端此前发送了
- 成功标识:
- RTMP 中,
_result
+Null
通常表示 命令执行成功;若失败,会返回_error
并携带错误码(如NetStream.Error
)。
- RTMP 中,
- 简化设计:
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
是 “启动数据传输”,标志会话从 “准备阶段” 进入 “实际拉流阶段”。 getStreamLength
和Set 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')
命令)。
交互逻辑:流启动的 “信号弹”
前置动作:
客户端先发送createStream
(创建流)和play('livestream')
(请求播放)命令,服务端处理后,通过Stream Begin
事件回应。核心作用:
- 服务端明确告知客户端:“流 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 ID
为6
和5
(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 ID
和Timestamp
基准值,减少头部开销。 - 时间戳处理:
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 ID
和Timestamp
基准值,减少头部开销。 - 时间戳处理:
Timestamp delta: 6770207
:当前 Chunk 与前一个音频 Chunk 的时间差(单位:毫秒);Timestamp: 7984253
(计算后):音频帧的 解码时间戳(DTS),用于音视频同步。
音频数据结构:RTMP 音频头 + AAC 负载
RTMP 音频数据遵循 “1 字节控制头 + 编码负载” 格式:
(1) 音频控制头(1 字节,Control: 0xA4
)
控制头编码了 音频格式、采样率、精度、声道 等参数:
- 二进制解析:
0xA4
→1010 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
)。
- 采样率:
- 高 4 位(
(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 的 时间戳同步机制 保证声画同步。