ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

音视频项目实战--智能监控平台核心分析

音视频项目实战--智能监控平台核心分析

文章目录

    • Q1:请介绍一下这个智能监控平台的整体架构和数据流?
    • Q2:RockX 行人检测是怎么集成进推流链路的?检测框如何叠加到画面?
    • Q3:为什么不是每帧都做行人检测?你会如何权衡检测频率?
    • Q4:软硬件 H.264 编码分别怎么做?推流封装用的是什么?
    • Q5:自定义 TCP 协议长什么样?注册、心跳、推流控制如何交互?
    • Q6:Socket 超时、心跳超时、断线重连具体怎么做的?还有哪些可改进点?
    • Q7:从 Web 点击「开始推流」到画面出来,完整调用链是什么?
    • Q8:视频卡顿、设备离线、推流中断,你会怎么用 GDB / Wireshark 排查?
    • Q9:如果推流稳定性出问题,你会从采集、编码、网络哪几侧优化?
    • Q10:自定义协议相对 MQTT/gRPC 有何取舍?若让你重构设备通信,怎么设计?

项目要点:RockX 行人检测与画面叠加、软硬件 H.264 推流、自定义 TCP(注册/心跳/推流控制)、Socket/心跳超时与断线重连、GDB/Wireshark 故障排查。
项目主链路:Web → Server(HTTP+TCP) → Device → RTMP 推流 → 流媒体 → Web 拉流。


Q1:请介绍一下这个智能监控平台的整体架构和数据流?

这是一个四层监控系统:前端 React 负责设备管理和播放;监控服务器基于 Muduo,同时提供 HTTP API(约 8001)和设备 TCP 接入(约 8081);设备端负责注册、心跳、采集、AI 检测、编码和推流;流媒体服务器接收设备 RTMP/RTSP 推流,供 Web 通过 HLS/HTTP-FLV 拉流播放。用户点击开流后,Web 调 HTTP 接口,服务器通过长连接 TCP 下发推流命令和 URL,设备再推到rtmp://媒体IP/Streaming_Channels/{deviceId}_{channelId},实现远程监控闭环。

解析

层次关键模块职责
Websrc/web设备列表、开/停流、播放
ServerMonitoringServer+DeviceManagerHTTP 控流、TCP 管设备状态
DeviceNetwork+StreamManager+PushStreamer协议交互 + 采集编码推流
Medianginx-rtmp 等收推流、对外拉流

串起来就是:

Web ──HTTP──► Server ──TCP──► Device ──RTMP──► 流媒体 ──拉流──► Web 播放

「四层」= 前端 + 业务服务器 + 摄像头设备 + 流媒体

面试官常追问「为什么设备不用 HTTP 轮询」:因为开流是服务端主动下发,需要长连接保持deviceId → TcpConnection映射。


Q2:RockX 行人检测是怎么集成进推流链路的?检测框如何叠加到画面?

在 ARM/Rockchip 路径上,相机经 RKMedia VI 采集 NV12,再经 RGA 送入 AI 线程;使用rockx_create加载ROCKX_MODULE_PERSON_DETECTION_V2,调用rockx_person_detect做人检测。为降低时延,约每 5 帧检测一次,中间帧复用上一帧框;检测结果用 OpenCV 在 NV12 的 Y 平面上画矩形和文字,再把同一块 buffer 送给 VENC 做 H.264 硬件编码,因此叠加结果会直接进入推流码流,观众端无需再画框。

相机采 NV12 → RGA 给 AI → RockX 做人检测(约每 5 帧一次)→ OpenCV 在画面上画框 → VENC 硬编 H.264 推流。

解析

Camera/ISP → VI(NV12) → RGA ↓ RockX 检测(约 1/5 帧) ↓ OpenCV 画框(改 Y 平面) ↓ VENC H.264 → FFmpeg 封装推 RTMP
  • 关键实现:push_streamer.cpp中rkmedia_vi_rockx_thread()。
  • 为何改 Y 平面:NV12 亮度在 Y,灰度框/字在编码前写入,成本低且无需额外叠加图层。
  • 独立 Demo(rkmedia_rockx_person_detection.cpp)走 VO 本地显示,产品路径走 VENC+推流,面试时要分清。

Q3:为什么不是每帧都做行人检测?你会如何权衡检测频率?

单次 RockX 检测大约几十毫秒量级,若每帧都跑,容易拖垮整条实时链路,造成采集积压、编码/推流卡顿。项目里用detect_threshold = 5,隔帧检测并复用上一帧结果,在「框略滞后」和「实时流畅」之间折中。实际还可按分辨率、CPU/NPU 负载、目标运动速度动态调整:静止场景可更疏,高速移动可更密,或把检测放到独立线程并限制队列长度,避免阻塞编码线程。

解析

  • 收益:降低 AI 算力占用,保证 VENC/推流节奏稳定。
  • 代价:框有短暂延迟,快速穿越画面时可能「跟不上」。
  • 可答优化:跟踪(Track)补帧、异步检测+最新结果覆盖、按 ROI 检测、降分辨率检测再映射回原图坐标。

Q4:软硬件 H.264 编码分别怎么做?推流封装用的是什么?

非 ARM/x64 走软件路径:V4L2 采集 → 格式转成 YUV420P → FFmpeglibx264编码,音频 ALSA → 重采样 → AAC,再用 FFmpeg 按 URL 选 FLV(RTMP)或 RTSP 封装写出。ARM 上视频走 Rockchip VENC 硬件 H.264(CBR、NV12 输入),编码后的MEDIA_BUFFER转成AVPacket交给同一套 FFmpeg 输出上下文推流;音频仍多用软件 AAC。也就是说:编码可软可硬,推流出口统一走 FFmpeg,方便一套逻辑兼容 RTMP/RTSP。

解析

平台视频编码音频推流
x64SwEncoder+libx264AACFFmpeg RTMP/FLV 或 RTSP
ARMRKVENCH.264AAC(软件)同上

常见追问:为何硬编码还要 FFmpeg?——VENC 只出裸 H.264,RTMP 需要 FLV 复用、时间戳、网络写;FFmpeg 负责这一层。


Q5:自定义 TCP 协议长什么样?注册、心跳、推流控制如何交互?

协议是二进制头 + JSON 体:魔数0xAA、版本0x01、命令字、payload 长度、messageId、时间戳、16 字节 deviceId,后面跟 UTF-8 JSON。设备连上后发REGISTER_REQUEST(0x01),服务器回REGISTER_RESPONSE(0x02)并下发心跳间隔;之后设备周期性发HEARTBEAT_REQUEST(0x03)上报状态与各通道是否在推流;Web 开流时服务器发STREAM_CONTROL_REQUEST(0x07)(含start_stream/stop_stream和streamUrl),设备执行后回STREAM_CONTROL_RESPONSE(0x08)。这样控制面走 TCP,媒体面走 RTMP,职责分离。

解析

MessageHeader: magic | version | command | length | messageId | timestamp | deviceId[16] + JSON payload
命令方向作用
0x01 / 0x02设备 ↔ 服务器注册
0x03 / 0x04设备 ↔ 服务器心跳
0x07 / 0x08服务器 ↔ 设备推流控制

流地址由服务器分配,设备不自己拼业务路径,便于统一管理和鉴权扩展。


Q6:Socket 超时、心跳超时、断线重连具体怎么做的?还有哪些可改进点?

设备连接时设置SO_RCVTIMEO/SO_SNDTIMEO约 5 秒,避免阻塞读写卡死;收包线程在非阻塞模式下遇EAGAIN短暂休眠继续等。心跳线程按间隔(注册后服务器常指定约 5 秒)发送;若发送失败、对端关闭(recv==0)或致命读错误,则走reconnect:断开 → 睡约 2 秒 → 重连 → 重新注册,失败再隔约 5 秒重试。配置里虽有heartbeatTimeout,当前更依赖「TCP 断开判定离线」;若要更严,应在服务器用定时器扫lastHeartbeatTime,超时主动踢下线并通知前端。

解析

  • 已有机制:发送超时、读超时、断线重连、重注册。
  • 薄弱点(可主动说,体现思考):
    1. 设备侧heartbeatTimeout读取后未充分用于业务判定;
    2. 服务器主要靠 TCP close 标离线,弱网「假在线」可能存在;
    3. 协议头未统一网络字节序、CRC 设计与实现不完全一致时,要讲清风险与兼容前提(同端序部署)。

Q7:从 Web 点击「开始推流」到画面出来,完整调用链是什么?

前端请求服务器 HTTP 开流接口;MonitoringServer校验设备在线后,拼出媒体 URL,经 Muduo TCP 连接向设备发STREAM_CONTROL_REQUEST;设备Network解析命令,Device/StreamManager创建或启动对应通道的PushStreamer:采集 →(可选 RockX 叠加)→ 软/硬编码 → FFmpeg 推 RTMP;成功后回STREAM_CONTROL_RESPONSE,前端再用返回的播放地址从流媒体拉 HLS/HTTP-FLV。停流则反向发stop_stream,停采集编码并断开推流会话。

解析(步骤清单)

  1. Web → HTTPstart
  2. Server:查DeviceManager→ 组 URL → TCP 下发
  3. Device:handleCommand→StartStream
  4. PushStreamer::Start:采集/AI/编码/推流线程起来
  5. Media 收流就绪 → Web 播放器拉流

面试加分:说明控制面(TCP)与媒体面(RTMP)失败要分别处理,例如命令成功但推流失败需把错误带回响应或下次心跳的isStreaming。


Q8:视频卡顿、设备离线、推流中断,你会怎么用 GDB / Wireshark 排查?

先分层定位:卡顿优先看采集是否跟得上、编码耗时、发送阻塞;离线看 TCP 是否断、心跳是否停;推流中断看 RTMP 握手/写失败还是上游命令没到。GDB 挂设备进程,对卡顿线程看调用栈(是否堵在 RockX、av_write_frame、VENC GetBuffer);对崩溃看 core、空指针和缓冲生命周期。Wireshark 抓设备↔服务器端口看自定义协议帧是否粘包/半包、心跳是否规律;抓设备↔媒体 1935 看 RTMP chunk、是否重连、TCP 重传与窗口。两边时间线对齐,往往能区分「协议控制断了」还是「媒体链路断了」。

解析(可复述的排查表)

现象优先怀疑工具手段
画面卡、延迟升AI 过密、编码慢、网络上行不足GDB 栈、耗时日志、CPU
设备显示离线TCP 断、重连失败、服务器踢连接Wireshark TCP、服务端连接表
有命令无画面URL 错、RTMP 鉴权/拒绝、编码器未出帧Wireshark RTMP、推流日志
间歇中断弱网重传、心跳与业务争用、缓冲区满抓包重传率 + 应用重连日志

Q9:如果推流稳定性出问题,你会从采集、编码、网络哪几侧优化?

采集侧保证缓冲队列有界、丢旧保新,避免积压导致延迟雪崩;AI 与编码解耦,检测失败不能阻塞送帧到 VENC。编码侧 ARM 优先硬编、合理 GOP/码率 CBR,关键帧间隔可调;软编则限制 preset/线程,防止 CPU 打满。网络侧对 RTMP 写失败快速失败并触发有限次重推;控制面 TCP 与媒体面分离,心跳只带轻量 JSON;必要时降分辨率/帧率做自适应。项目里已通过「隔帧检测 + 硬编 + 断线重连」覆盖常见稳定性点,线上再补指标(推流码率、丢帧、重连次数)闭环。

解析

  • 采集:队列长度、背压策略。
  • 编码:软硬切换、码率、IDR。
  • 网络:超时、重连退避、与心跳线程协作避免同时狂重试。
  • 可量化:端到端延迟、重连成功率、平均检测耗时——体现工程化思维。

Q10:自定义协议相对 MQTT/gRPC 有何取舍?若让你重构设备通信,怎么设计?

自定义 TCP 足够轻、与嵌入式设备契合,二进制头解析快,JSON 体便于扩展字段,Muduo 长连接也方便服务端主动推命令。代价是要自己处理粘包半包、心跳租约、重连、版本兼容和安全(加密鉴权)。若重构,我会保留「控制面长连接 + 媒体面 RTMP」分层;协议上明确大端序与长度字段、完整 CRC 或 length-prefix 帧、心跳超时双向强制离线;安全上 TLS 或至少 token 注册;实现上可用长度字段状态机解析,并加命令幂等(commandId)防止重连后重复开流。

解析(对比一句话版)

方案优点缺点
自定义 TCP(现状)可控、轻量、易嵌工程细节多、易有帧/超时漏洞
MQTT现成会话与 QoS需 Broker,嵌入式集成与运维成本
gRPC强契约、流式设备体积与依赖更重

结合本项目可主动提:当前协议设计里 CRC/字节序等细节与实现不完全对齐时,重构应优先「帧格式正确性 + 心跳租约」,再谈功能扩展。


RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进