# 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>` 共享,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//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 插件解耦、零拷贝分发架构参考