图片素材来自免费商用图库(pixabay),非本站项目实拍。

项目要点: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},实现远程监控闭环。

解析

层次 关键模块 职责
Web src/web 设备列表、开/停流、播放
Server MonitoringServer + DeviceManager HTTP 控流、TCP 管设备状态
Device Network + StreamManager + PushStreamer 协议交互 + 采集编码推流
Media nginx-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 → FFmpeg libx264 编码,音频 ALSA → 重采样 → AAC,再用 FFmpeg 按 URL 选 FLV(RTMP)或 RTSP 封装写出。ARM 上视频走 Rockchip VENC 硬件 H.264(CBR、NV12 输入),编码后的 MEDIA_BUFFER 转成 AVPacket 交给同一套 FFmpeg 输出上下文推流;音频仍多用软件 AAC。也就是说:编码可软可硬,推流出口统一走 FFmpeg,方便一套逻辑兼容 RTMP/RTSP。

解析

平台 视频编码 音频 推流
x64 SwEncoder + libx264 AAC FFmpeg RTMP/FLV 或 RTSP
ARM RK VENC H.264 AAC(软件) 同上

常见追问:为何硬编码还要 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 → HTTP start
  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/字节序等细节与实现不完全对齐时,重构应优先「帧格式正确性 + 心跳租约」,再谈功能扩展。


一、智能监控/音视频系统的典型架构

一套可用的视频联网系统通常分为:前端 IPC(网络摄像机)→ 接入交换机/PoE → NVR 或流媒体服务器(SRS/GB28181)→ AI 分析节点(边缘或中心)→ 用户终端。H.264 兼容性好,H.265/HEVC 带宽节省约 50% 但解码算力要求更高;码率、帧率、GOP 需按场景权衡,运动量大处提高码率、静止场景可降码率省存储。

二、边缘 AI 与视频云联网

边缘 AI 把人形/车辆/烟火等算法下沉到边缘盒子或 IPC,只在命中事件时上云,既降低带宽又能做到秒级告警;视频云联网通过 GB/T 28181 或厂商私有协议实现多网点汇聚,需注意上下行带宽、NAT 穿透与平台并发容量。海康等厂商提供 Web 控件/SDK(如 HCWebSDK)便于把实时视频嵌入业务系统,集成时关注浏览器兼容、设备鉴权与安全暴露面。

三、部署要点

PoE 供电距离不超过 100m;多路码流(主码流录像、子码流预览)分离;存储按”留存天数×路数×码率”估算;室外点位防雷防抖。安防系统涉及隐私合规,录像留存与访问需有明确授权边界。

相关阅读