This commit is contained in:
2026-09-13 13:30:21 +08:00
commit a6bbd520cf
2744 changed files with 1598795 additions and 0 deletions
+237
View File
@@ -0,0 +1,237 @@
# fpv-relay (C++)
OpenIPC / wfb-ng 数字图传的地面端程序。单个进程完成无线采集、解密、转发、录制、RTSP 输出
和遥测中继,并提供 Qt 图形界面。
天空端固定参数(PixelPilot / DigitalFPV):`link_id=7669206`,视频 `radio_port=0`,
mavlink 下行 `radio_port=0x10`,上行 `radio_port=160`,`epoch=0`,密钥 `gs.key`。
## 功能
- 采集:内嵌 wfb-ng。Linux 用 pcap + monitor 网卡,Windows 用 devourer(用户态 USB 驱动)。
解密后的 RTP 直接回调到转发层,不经过外部 `wfb_rx` 进程和本地 UDP 回环。
- 转发:每路可配多个 `forward` 目标,裸 RTP/UDP 原样直推。
- 录制:把 H265 还原成 Annex-B 裸流,按时间或大小分片。
- RTSP:TCP interleaved 与 UDP 两种传输,H265 单轨,支持多客户端。
- 遥测:接收天空端 mavlink 下行(`radio_port 0x10`)转发给本机 QGC;
上行 mavlink/遥控经 wfb_tx 注入无线。
- 状态页:HTTP `/`、`/status`、`/metrics`。
- 图形界面:Qt Quick + FluentUI,多路状态卡片、实时预览、设置、录像回放。
## 平台支持
| 功能 | Linux | Windows |
|---|---|---|
| 无线采集 | pcap + monitor 网卡 | devourer(USB,需 WinUSB 驱动) |
| 上行 wfb_tx | AF_PACKET 注入 | devourer(USB) |
| 转发 / 录制 / RTSP / 状态页 | 支持 | 支持 |
| GUI 预览 | ffmpeg | ffmpeg |
Windows 上的无线采集和上行需要先用 [Zadig](https://zadig.akeo.ie/) 把 RTL8812AU 的驱动
替换为 WinUSB(一次性操作),之后该网卡专供本程序使用。
## 目录结构
```
CMakeLists.txt / CMakePresets.json
3rd/ 第三方库(yaml-cpp / spdlog / CLI11 / FluentUI / wfb-ng / devourer)
以及 Windows 运行依赖(win-deps = libusb+sodium,ffmpeg)
src/
common/ 日志、跨平台网络兼容层
config/ YAML 配置解析
capture/ 采集抽象、wfb(pcap/USB)、udp 采集、射频设置、USB 上行
relay/ 数据流、UDP 转发、DVR、H265 解包
rtsp/ status/ RTSP 输出、HTTP 状态页
gui/ Qt Quick + FluentUI 界面、ffmpeg 预览
config.example.yaml Linux 示例配置
config.windows.example.yaml Windows 示例配置
packaging/ 打包脚本
```
## 依赖
编译需要 CMake ≥ 3.16、C++20 编译器、pkg-config。
Linux:
- `libsodium-dev`、`libpcap-dev`
- 运行期 `iw`、`nmcli`、`ffmpeg`;采集需要 root,或对程序执行
`setcap cap_net_raw,cap_net_admin+eip`
```bash
sudo apt install build-essential cmake pkg-config libsodium-dev libpcap-dev ffmpeg
```
Windows(MinGW):
- Qt6、Ninja
- 无线采集与预览所需的 `libusb-1.0`、`libsodium`、`ffmpeg.exe` 已随仓库 vendored
(`3rd/win-deps`、`3rd/ffmpeg`),无需额外安装
- devourer(用户态 USB 驱动)已 vendored 在 `3rd/devourer`
- Qt 安装路径写在 `CMakePresets.json` 的 `windows-base`(默认 `E:/QT6.6.3/6.6.3/mingw_64`),按需修改
## 构建
Linux(Qt 路径通过环境变量 `QT_PREFIX` 指定):
```bash
export QT_PREFIX=$HOME/Qt6.3/6.6.3/gcc_64
cmake --preset linux-cli && cmake --build --preset linux-cli -j$(nproc)
cmake --preset linux-gui && cmake --build --preset linux-gui -j$(nproc)
```
Windows(PowerShell,Qt 路径已在 `CMakePresets.json` 里配置好,直接构建即可):
```powershell
cmake --preset windows-cli ; cmake --build --preset windows-cli
cmake --preset windows-gui ; cmake --build --preset windows-gui
```
> Qt 不在默认位置时,改 `CMakePresets.json` 里 `windows-base` 的 `FPC_QT_PREFIX`,
> 或直接传 `-DFPC_QT_PREFIX=<你的 Qt 路径>`。
可执行文件和运行期依赖(DLL、ffmpeg、Qt 运行库、示例配置、`gs.key`)会统一汇总到
`<build>/dist/`。Windows 打包可用 `.\packaging\build-win.ps1 -Gui`。
> Windows 上构建目录路径不能包含空格,否则 FluentUI 的版本资源编译会失败。
## 运行
```bash
# wfb 无线采集需要 root(设置 monitor 模式 / 打开 pcap)
sudo ./build/dist/fpv-relay -c config.yaml -v
```
每 5 秒打印一次各路统计。wfb 采集输出 `收包/数据/会话/解密错误/丢包/转发`。
## 配置
```yaml
captures:
- name: drone1
type: wfb # wfb 无线采集,或 udp 输入
iface: wfb0
key: /path/to/gs.key
link_id: 7669206 # channel_id = (link_id << 8) + radio_port
radio_port: 0
epoch: 0
channel: 161
bandwidth: HT20
region: BO
codec: h265
forward:
- "127.0.0.1:5700" # 本机低延迟播放口
- "192.168.1.50:5600" # 局域网接收端
```
Windows 用 `usb_vid` / `usb_pid` 指定网卡(见 `config.windows.example.yaml`),`iface` 可省略。
### 多卡
`captures` 里写多个 `type: wfb` 条目,每块卡用不同的 `iface`,即可同时收多路,各自的
`key` / `link_id` / `channel` / `forward` 相互独立。
多张同型号卡建议固定网卡名,否则开机时可能互换。可用 systemd `.link` 按 USB 物理端口
命名为 `wfb0` / `wfb1`(见 `tools/udev/README.md`)。
## 图形界面
界面基于 FluentUI + Qt 6.6。功能包括配置加载、启动/停止、多路状态卡片、实时日志、
深浅色切换、单路/多路实时预览、录像列表与回放。
预览由内置 RTSP 输出配合 ffmpeg 实现:程序始终在本地启动 RTSP 服务,预览窗口调用
`ffmpeg` 拉取 `rtsp://127.0.0.1:<port>/<name>` 并解码绘制,H264/H265 均可。预览需要先“启动”。
```bash
export QT_PREFIX=$HOME/Qt6.3/6.6.3/gcc_64
cmake --preset linux-gui && cmake --build --preset linux-gui -j$(nproc)
sudo ./build-gui/dist/fpv-relay-gui
```
接收端播放(低延迟 UDP 直推):
```bash
tools/play-udp.sh 5700 h265
```
## 上行链路
在配置里加 `uplink` 段,程序会内嵌 wfb-ng 的 wfb_tx,把本地收到的 mavlink/遥控经同一张
网卡注入无线发给天空端:
```yaml
uplink:
- enabled: true
iface: wfb0
key: /path/to/gs.key
link_id: 7669206
radio_port: 160 # 需与天空端 wfb_rx 一致
channel: 161
bandwidth: 20
mcs_index: 1
fec_k: 2
fec_n: 4
udp_port: 14551 # QGC/MAVProxy 把 mavlink 发到这里
```
然后让 QGroundControl / MAVProxy 把上行 mavlink 发到 `udp://127.0.0.1:14551`。
`radio_port` / `link_id` / 信道 / key 必须与天空端一致。
### 遥测下行
在采集路里加 `mavlink` 段,程序会另开一个接收流并把解出的 mavlink 转发给本机 QGC:
```yaml
mavlink:
enabled: true
radio_port: 16 # 0x10
target: "127.0.0.1:14550" # QGC 监听
```
需要天空端确实在发该流的 mavlink 数据。日志里出现 `SESSION` 表示会话已建立。
## 状态监控
```yaml
status:
enabled: true
address: ":8080"
```
- `http://<本机>:8080/` 状态面板
- `http://<本机>:8080/status` JSON
- `http://<本机>:8080/metrics` Prometheus 指标
字段:`online`、`recv`、`forwarded`、`session`(≥1 表示密钥配对成功)、`decErr`、`lost`。
也可用 `-s :8080` 临时开启。
## DVR 录制
```yaml
record:
enabled: true
dir: records # 录制根目录,其下按路名建子目录
segment_seconds: 300 # 分片时长
segment_mb: 0 # 分片大小上限(MB,0 不限)
```
文件形如 `records/drone1/drone1_20260910_210000.h265`。GUI 里可列出录像、回放,
并调用 ffmpeg 转封装为 MP4;录制也可通过卡片右键菜单动态开关。
## RTSP 输出
```yaml
rtsp:
enabled: true
address: ":8554"
udp_base: 8000
```
拉流地址:`rtsp://<本机>:8554/<name>`。支持 TCP interleaved 与 UDP、H265 单轨、多客户端,
SDP 带 sprop-vps/sps/pps,并发送 RTCP SR。低延迟场景仍建议用 `forward` 的 UDP 直推。
## 说明
- 采集端按 radiotap 的正确偏移过滤,只放行本路 `WB` + channel_id 的帧,并抑制会话建立前
的解密失败日志;正常运行时 `解密错误` 应为 0 或极少。
- 预览的延迟以 `forward` 的 UDP 直推为准。GUI 预览走 RTSP + ffmpeg,已做低延迟调参,
但不显示“延迟 ms”数值。
- Windows 不支持内核 monitor 驱动,无线采集/上行由 devourer 在用户态完成,需 WinUSB 驱动。