RTMP 协议
实时消息传输协议(RTMP)是一种基于 TCP 的协议,设计用于在服务器和客户端之间传输音频、视频和数据。本文档描述了 RTMP 在 Monibuca(m7s)流媒体服务器中的实现,重点关注协议的架构、握手过程、消息格式和媒体处理能力。
架构概述
Monibuca 中的 RTMP 实现被构建为一个插件,支持通过 RTMP 发布(推流)和播放(拉流)媒体流。该插件自动在 1935 端口注册标准 RTMP 支持,也可以处理安全的 RTMPS 连接。
核心组件
RTMP 插件由以下主要组件组成:
组件 | 描述 |
---|---|
RTMPPlugin | 主插件结构,包含配置和初始化逻辑 |
RTMPServer | 处理传入连接的服务器实现 |
RTMPClient | 处理主动发起向远端服务器请求(拉流或者推流)的实现 |
NetConnection | 管理 RTMP 连接状态和消息交换 |
NetStream | 媒体传输的逻辑通道 |
该插件使用 Monibuca 的插件系统注册,并实现了推流和拉流所需的必要接口。
RTMP 协议流程
连接建立
当客户端连接到 RTMP 服务器时,会发生以下序列:
- 建立 TCP 连接
- 执行 RTMP 握手
- 交换 Connect 命令
- 创建流
- 开始发布或播放操作
握手过程
RTMP 握手是一个三步过程,包括以下步骤:
- C0/S0:单字节版本交换(通常为 0x03)
- C1/S1:交换 1536 字节,包含时间、版本和随机数据
- C2/S2:交换另一个 1536 字节,回显对等方的时间戳
Monibuca 支持简单和复杂(加密)握手:
C0: 版本字节 (0x03)
C1: 时间 (4 字节) + 零 (4 字节) + 随机数据 (1528 字节)
S0: 版本字节 (0x03)
S1: 时间 (4 字节) + 零 (4 字节) + 随机数据 (1528 字节)
C2/S2: 时间 (4 字节) + Time2 (4 字节) + 随机数据 (1528 字节)
对于复杂握手,服务器计算并验证 HMAC-SHA256 摘要以验证客户端身份。
消息格式和分块处理
分块格式
RTMP 将消息作为分块传输,以实现多路复用和带宽控制。每个分块都有一个根据类型不同而变化的头部:
分块类型 | 头部大小 | 内容 |
---|---|---|
类型 0 (完整) | 12 字节 | 时间戳 (3) + 消息长度 (3) + 消息类型 ID (1) + 消息流 ID (4) |
类型 1 | 8 字节 | 时间戳增量 (3) + 消息长度 (3) + 消息类型 ID (1) |
类型 2 | 4 字节 | 时间戳增量 (3) |
类型 3 | 1 字节 | 无额外头部(继续) |
分块头部以基本头部开始,包含分块流 ID 和分块类型。
分块处理
NetConnection 类通过以下主要函数处理分块:
- readChunk():从连接读取分块
- readChunkStreamID():从头部提取分块流 ID
- readChunkType():处理分块类型并组装消息
- sendChunk():将消息分割成分块进行传输
消息类型
RTMP 定义了多种消息类型,由实现处理:
消息类型 ID | 描述 |
---|---|
1 | 设置分块大小 |
2 | 中止消息 |
3 | 确认 |
4 | 用户控制消息 |
5 | 窗口确认大小 |
6 | 设置对等带宽 |
8 | 音频消息 |
9 | 视频消息 |
20 | AMF0 命令 |
RecvMessage()
函数处理这些消息并根据类型将它们分派到适当的处理程序。
媒体数据处理
视频处理
RTMP 实现支持多种视频编解码器,包括:
- H.264 (AVC):标准视频编解码器
- H.265 (HEVC):高效视频编解码器
- AV1:下一代视频编解码器(实验性支持)
RTMP 中的视频数据格式化为带有指示帧类型和编解码器 ID 的头部字节,后跟合成时间和实际编码数据。
RTMPVideo
结构实现了 IAVFrame
接口,提供以下方法:
- Parse():从视频帧中提取编解码器信息
- Demux():将 RTMP 视频格式转换为原始 NAL 单元
- Mux():将原始 NAL 单元转换为 RTMP 视频格式
- ConvertCtx():从序列头创建编解码器上下文
对于 H.264/H.265,实现处理序列头(SPS/PPS/VPS)并可以过滤有问题的 NAL 单元。
音频处理
实现支持多种音频格式:
- AAC:高级音频编码
- PCMA:A-law PCM
- PCMU:μ-law PCM
RTMP 中的音频数据包括指示编解码器类型、采样率、采样大小和通道数的头部字节。
RTMPAudio
结构也实现了 IAVFrame
接口,具有与 RTMPVideo
类似的方法。
流管理
发布和播放
RTMP 区分两种主要操作:
- 发布:向服务器发送媒体数据
- 播放:从服务器接收媒体数据
实现通过命令消息处理这些操作。
实现创建 NetStream
对象来管理单个流,并将它们连接到 Monibuca 核心的 Publisher
和 Subscriber
组件。
配置和初始化
RTMP 插件可以配置以下设置:
设置 | 默认值 | 描述 |
---|---|---|
ChunkSize | 1024 | RTMP 分块大小 |
KeepAlive | false | 启用连接保活 |
C2 | false | 验证 C2 握手包 |
初始化时,插件注册其功能和地址格式:
rtmp://{hostName}/{streamPath} (端口 1935)
rtmp://{hostName}:{port}/{streamPath} (自定义端口)
rtmps://{hostName}/{streamPath} (端口 443)
rtmps://{hostName}:{port}/{streamPath} (自定义端口)
与 Monibuca 核心集成
RTMP 插件通过多种机制与 Monibuca 核心系统集成:
- 通过
m7s.InstallPlugin
进行插件注册 - 用于连接处理的任务系统
- 用于媒体处理的 Publisher/Subscriber 接口
- 用于高效数据处理的内存分配系统
这种设计使 RTMP 功能能够无缝集成,同时保持整个系统的模块化。
总结
Monibuca 中的 RTMP 协议实现为流媒体应用程序提供了坚实的基础。它支持:
- 具有简单和复杂握手的完整 RTMP 协议
- 多种视频(H.264、H.265、AV1)和音频(AAC、PCMA、PCMU)编解码器
- 发布和播放操作
- 通过 RTMPS 的安全连接
- 媒体数据的内存高效处理
此实现使 Monibuca 能够与各种 RTMP 客户端交互,包括媒体编码器、播放器和其他流媒体服务器。