前言:最近在做的 Health Sync(骑行运动 App)里接入了大疆 Osmo Action 5 Pro 的实时推流。这套链路看起来简单——相机推 RTMP,服务器收流,前端播放——但真要把“BLE 控制 + RTMP 推流 + 服务端鉴权 + 本地录制”串起来,还是踩了不少坑。这篇文章把整个实现过程记录下来,给有同样需求的同学一个参考。
一、整体链路
先上一张最终效果截图,这是 Health Sync 里“共享轨迹”页面的推流配置面板:

整个数据流是这样的:
|
注意:手机在这里不是“中转站”,相机是直接连 Wi-Fi 推流;手机只通过 BLE 把 Wi-Fi 名、密码、RTMP 地址下发给相机。
开播后,App 端会显示“相机直播中”:

网页端则能看到实时视频面板和地图轨迹:

二、服务端:SRS 接收 RTMP 推流
虽然标题写了 NGINX-RTMP,但我实际生产环境用的是 SRS(Simple Realtime Server)。原因很朴素:SRS 的 DVR 录制、exec_publish 回调、HTTP 鉴权钩子都更开箱即用,对单人项目更友好。如果你确实想用 NGINX-RTMP,后面会给一个等价的配置片段。
2.1 SRS 核心配置
|
几个关键配置:
listen 1935:标准 RTMP 端口。on_publish:推流前必须通过这个鉴权接口,否则拒绝推流。dvr_plan session:一次推流生成一个 FLV 文件,结束后自动落盘。dvr_wait_keyframe on:从关键帧开始录,避免首帧花屏。
2.2 等价的 NGINX-RTMP 配置
如果你更熟悉 NGINX-RTMP,可以这样配:
|
功能对等:鉴权钩子、录制 FLV、唯一文件名。SRS 和 NGINX-RTMP 在这里只是实现方式不同,协议层面都是标准 RTMP。
三、推流鉴权:防止被恶意盗推
鉴权接口 http://127.0.0.1:8085/api/v1/publish_auth 是 Go 服务(blog_api)提供的。它会校验 URL 里的 auth_key 参数,符合阿里云直播 URL 鉴权 A 方式:
|
Android 端生成带签名的推流地址:
|
这样即使有人拿到推流域名,没有密钥也无法伪造合法的 auth_key。
四、Android 端:BLE 控制大疆 Action 5 Pro
这是整套链路里最“黑盒”的部分。大疆没有公开 Action 5 Pro 的直播控制协议,这部分是参考 MIT 开源项目 datagutt/node-osmo 的 BLE 协议,用 Kotlin 在 Android 上重新实现的。
4.1 发现与连接
相机开机后会以 BLE 广播,Manufacturer Data 前两个字节是 0x08AA(DJI 厂商 ID)。App 扫描到后连接 GATT,服务 UUID 是 0000fff0-...,主要操作 fff3(写命令)、fff4(读/通知)、fff5(电量通知)。
|
4.2 配对
连接成功后,相机会通过 fff4 发一个触发包,App 回复配对请求,PIN 固定为 love(node-osmo 逆向值):
|
4.3 开播状态机
配对完成后并不是直接开播,而是要走一套状态机:
|
对应代码:
|
为什么要先 STOP_STREAM?因为相机会记忆上一次的直播状态,直接开播可能冲突。先清场再重新走完整流程最稳。
4.4 RTMP 地址下发
|
目前固定 1080P/30fps/6Mbps。Action 5 Pro 收到后并不会立刻推流,需要再发一个特殊的确认帧,把 STOP_STREAM 的 payload 最后一位改成 0x01:
|
这个确认帧是 OA5 特有的,少了它相机只会“假装”开播,实际不推流。
五、纯代码 RTMP 客户端(备用)
除了相机直推,App 里还有一个轻量的 RtmpPublisher,用于实时语音推流,不依赖第三方库:
|
它自己实现了 RTMP 握手、connect/createStream/publish 命令、AMF0 编解码、FLV Tag 分块发送。这个类是给语音直播用的,不是给 Action 5 Pro 视频用的,但协议实现本身是通用的。
六、HUD 实时叠加:把心率/速度/配速烧进视频
推流成功后,下一步就是在视频上叠加运动数据。我的方案是:相机推原始流到 SRS,SRS 通过 exec_publish 触发一个 Python 脚本,用 FFmpeg 拉流、drawtext 叠加、再推回 SRS 的另一个流名。
|
live_stream_hud.py 会从 blogapi.awen.me/api/v1/gps/track 拉取实时数据,包括心率、速度、配速、距离、时长,然后用 FFmpeg drawtext 滤镜渲染到画面上。前端播放 STREAM_hud 即可看到带 HUD 的直播。
SRS 配置里加一行 exec_publish 就能自动触发:
|
七、踩坑记录
BLE MTU 必须协商
大疆部分命令包超过 20 字节,默认 MTU 23 会把通知截断,导致解析失败。连接后要先requestMtu(512)。Action 5 Pro 需要确认帧
下发START_STREAM后,必须再发一个confirmStartStreamingPayload(),否则相机不真正推流。一定要先 STOP 再 START
相机记忆上次直播状态,直接开播大概率失败。每次开播前先清场。Wi-Fi 扫描权限坑
Android 13+ 扫描 Wi-Fi 需要NEARBY_WIFI_DEVICES,但触发扫描和读取结果还分别需要CHANGE_WIFI_STATE和ACCESS_WIFI_STATE。三个权限都要在 Manifest 里声明。SRS 的鉴权钩子只对 RTMP 生效
HLS 播放地址如果也要保护,需要另外做 referer 或 token 校验,不能指望同一个on_publish。
八、总结
这套方案的成本很低:一台阿里云 ECS 跑 SRS,一个自己实现的 Android BLE 控制层,就能把大疆 Action 5 Pro 变成骑行直播相机。后续还可以继续优化:
- 把 HUD 渲染从服务端 FFmpeg 下沉到相机端(如果大疆开放接口)。
- 用 WebRTC 替代 RTMP,进一步降低直播延迟。
- 把本地录制的 FLV 自动转 MP4 并上传到 OSS,实现“直播结束即回放”。
目前这套链路已经能稳定跑通:App 配置 Wi-Fi → BLE 连接相机 → 下发 RTMP → 相机直推 → SRS 收流并录制 → FFmpeg 叠加 HUD → 前端播放。对一个人项目来说,够用了。
评论
0 条评论