# 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`)会统一汇总到 `/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:/` 并解码绘制,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/`。支持 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 驱动。