Files
2026-09-13 13:30:21 +08:00

238 lines
8.2 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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 驱动。