179 lines
6.2 KiB
Markdown
179 lines
6.2 KiB
Markdown
# Rave
|
||
|
||
纯 Rust 实现的全协议流媒体服务器引擎,零第三方依赖。
|
||
|
||
受 [lal (Go)](https://github.com/q191201771/lal) 和 [Monibuca v6 (Rust)](https://monibuca.com/) 启发,但除 `tokio` 异步运行时外不依赖任何外部 crate。
|
||
|
||
## 协议支持
|
||
|
||
| 协议 | 推流 | 拉流 | 状态 |
|
||
|------|:----:|:----:|:----:|
|
||
| RTMP | ✅ | ✅ | 握手、Chunk 协议、AMF0、Publish/Play |
|
||
| RTSP/RTP | ✅ | ✅ | ANNOUNCE/RECORD 推流;DESCRIBE/PLAY 拉流 |
|
||
| HTTP-FLV | — | ✅ | HTTP 长连接 + FLV 实时流 |
|
||
| WebSocket-FLV | — | 🚧 | 框架已搭建 |
|
||
| HLS | — | 🚧 | 框架已搭建 |
|
||
|
||
## 编解码支持
|
||
|
||
- **视频**: H.264 (AnnexB + AVCC)、H.265/HEVC
|
||
- **音频**: AAC (ADTS + raw)、G.711 (A-law / μ-law)
|
||
- **容器**: FLV、MPEG-TS
|
||
|
||
## 快速开始
|
||
|
||
```bash
|
||
# 构建
|
||
cargo build --release
|
||
|
||
# 启动服务器
|
||
cargo run --release
|
||
|
||
# 可选:指定配置文件
|
||
cargo run --release -- rave.conf
|
||
```
|
||
|
||
## 推流与拉流
|
||
|
||
```bash
|
||
# RTMP 推流
|
||
ffmpeg -re -i video.mp4 -c copy -f flv rtmp://localhost:1935/live/test
|
||
|
||
# RTSP 推流(TCP 传输)
|
||
ffmpeg -re -i video.mp4 -c copy -f rtsp -rtsp_transport tcp rtsp://localhost:5544/live/test
|
||
|
||
# RTMP 拉流
|
||
ffplay rtmp://localhost:1935/live/test
|
||
|
||
# HTTP-FLV 拉流
|
||
ffplay http://localhost:8080/live/test.flv
|
||
|
||
# RTSP 拉流
|
||
ffplay rtsp://localhost:5544/live/test
|
||
```
|
||
|
||
## 跨协议转发
|
||
|
||
推流端和拉流端可以使用不同协议,服务器自动进行协议转换:
|
||
|
||
| 推流 → 拉流 | RTMP | HTTP-FLV | RTSP |
|
||
|:-----------:|:----:|:--------:|:----:|
|
||
| **RTMP** | ✅ | ✅ | ✅ |
|
||
| **RTSP** | ✅ | ✅ | ✅ |
|
||
|
||
## HTTP API 接口
|
||
|
||
所有 HTTP 端点运行在 HTTP-FLV 服务器端口(默认 `8080`):
|
||
|
||
| 端点 | 方法 | 说明 |
|
||
|------|------|------|
|
||
| `/api/stats` | GET | 服务器运行统计(带宽、帧率、连接数) |
|
||
| `/api/streams` | GET | 活跃流列表(编解码器、订阅者数、GOP 缓存) |
|
||
| `/{app}/{stream}.flv` | GET | HTTP-FLV 实时拉流 |
|
||
|
||
详细接口文档见 [api.md](api.md)。
|
||
|
||
## 配置
|
||
|
||
默认端口和插件开关可在 `rave.conf` (TOML 格式) 中配置:
|
||
|
||
```toml
|
||
rtmp.port = 1935
|
||
httpflv.port = 8080
|
||
rtsp.port = 5544
|
||
log.level = "info"
|
||
|
||
# 插件开关(设为 false 禁用对应协议)
|
||
# rtmp.enabled = false
|
||
# rtsp.enabled = false
|
||
```
|
||
|
||
## 架构
|
||
|
||
```
|
||
src/
|
||
├── main.rs # 入口:配置加载、插件注册、banner、优雅关闭
|
||
├── lib.rs # 模块根
|
||
├── config.rs # 手写 TOML 解析器
|
||
├── logger.rs # 最小化 stderr 日志
|
||
├── stats.rs # 服务器统计
|
||
├── core/ # 引擎内核
|
||
│ ├── buffer.rs # 无锁 SPMC 环形缓冲区
|
||
│ ├── dispatcher.rs # 单读广播分发器
|
||
│ ├── publisher.rs # 发布者(写入轨道)
|
||
│ ├── subscriber.rs # 订阅者(有界队列 + 背压)
|
||
│ ├── stream.rs # 流(GOP 缓存 + 订阅者管理)
|
||
│ ├── group.rs # StreamManager(流注册表)
|
||
│ └── track.rs # 音视频轨道
|
||
├── sdk/ # 插件契约层
|
||
│ ├── types.rs # AVFrame、编解码器枚举、StreamPath
|
||
│ ├── traits.rs # PublisherApi、SubscriberApi、StreamManagerApi
|
||
│ ├── plugin.rs # Plugin / ProtocolPlugin trait
|
||
│ ├── context.rs # EngineContext(IoC 容器)
|
||
│ └── registry.rs # PluginRegistry(生命周期管理 + 配置开关)
|
||
├── codec/ # 编解码器
|
||
│ ├── h264.rs # H.264 NALU 解析、AVCC 编码
|
||
│ ├── h265.rs # H.265 NALU 类型
|
||
│ ├── aac.rs # AAC ADTS 解析
|
||
│ ├── flv.rs # FLV tag 编解码
|
||
│ └── ts.rs # MPEG-TS 打包
|
||
├── protocol/ # 协议实现
|
||
│ ├── mod.rs # all_plugins() 内置插件清单函数
|
||
│ ├── rtmp/ # RTMP 插件、握手、Chunk、AMF0、Session
|
||
│ ├── rtsp/ # RTSP 插件、信令、RTP、Depacketizer
|
||
│ ├── httpflv*.rs # HTTP-FLV 插件 + 服务端
|
||
│ ├── hls.rs # HLS 框架
|
||
│ └── wsflv.rs # WebSocket-FLV 框架
|
||
└── remux/ # 协议转换
|
||
├── rtmp2flv.rs # RTMP ↔ FLV
|
||
└── flv2ts.rs # FLV ↔ MPEG-TS
|
||
```
|
||
|
||
### 性能设计
|
||
|
||
- **无锁 SPMC 环形缓冲区**: Publisher 通过 `fetch_add` 原子操作写入,Subscriber 各自维护读取游标
|
||
- **零拷贝**: 帧数据通过 `Arc<Vec<u8>>` 共享,Subscriber 间不复制媒体负载
|
||
- **单读广播**: Dispatcher 每帧只读取一次,分发给所有 Subscriber
|
||
- **背压控制**: 每个 Subscriber 有独立有界队列(1024 帧),慢消费者丢帧不阻塞发布者
|
||
|
||
### SDK 插件架构
|
||
|
||
插件仅依赖 `sdk/` 层的 trait 契约,不直接引用 `core/` 内部实现:
|
||
|
||
```
|
||
sdk/types.rs → sdk/traits.rs → sdk/plugin.rs → sdk/context.rs → sdk/registry.rs
|
||
↑
|
||
core/ (实现 sdk traits) |
|
||
|
|
||
protocol/ (仅依赖 sdk:: traits + types) ───────────────────┘
|
||
```
|
||
|
||
**内置插件**通过 `protocol::all_plugins()` 自动注册,新增内置协议只需:
|
||
1. 在 `protocol/<name>/plugin.rs` 实现 `Plugin` + `ProtocolPlugin` trait
|
||
2. 在 `protocol/mod.rs` 的 `all_plugins()` 中添加一行
|
||
|
||
**外部插件**通过 `registry.register()` 手动注册。
|
||
|
||
## 测试
|
||
|
||
```bash
|
||
# 运行全部测试(513 个)
|
||
cargo test
|
||
|
||
# 运行特定测试
|
||
cargo test test_rtmp_handshake
|
||
cargo test test_fu_a_reassembly
|
||
cargo test test_depacketize_aac
|
||
```
|
||
|
||
## 设计约束
|
||
|
||
- **零第三方依赖**(除 `tokio` 异步运行时):所有编解码、协议解析、并发原语均手写实现
|
||
- Edition 2024,使用最新 Rust 惯用法
|
||
- 全部代码中文注释,技术术语保留英文原文
|
||
|
||
## 致谢
|
||
|
||
- [lal](https://github.com/q191201771/lal) — Group 模式、GOP 缓存、Remux 层架构参考
|
||
- [Monibuca v6](https://monibuca.com/) — SDK 插件解耦、零拷贝分发架构参考
|