上一篇我们分享了 MPP 硬解码和 RGA 硬加速的实战经验,把 8 路 1080P 视频处理的 CPU 占用降到了 20% 以下。但解码能力上来之后,新的问题又来了——同一个摄像头,客户既想跑实时人员入侵检测(每秒 10 帧),又想跑定时视频诊断(每 2 小时抽一帧),还想跑定时烟火检测(每 30 分钟抽一帧)。难道要对同一路视频拉三次流、解三次码?本文分享我们的「同源多任务调度」设计,以及如何用一路视频流同时支撑多个算法任务。
一、背景:边缘视频分析的任务多样性
做工业 AI 视觉,很少有客户只需要一个算法任务。真实场景里,同一个摄像头往往要同时承担多种检测任务。
举个典型的例子——某工厂园区的周界摄像头:
- 实时人员入侵检测:7×24 小时运行,每秒分析 10 帧,有人进入警戒区域立即告警
- 定时摄像头遮挡检测:每 2 小时抽一帧,检测摄像头是否被遮挡、偏转、模糊
- 定时烟火检测:每 30 分钟抽一帧,检测是否有烟雾或明火
- 工作时间违章停放检测:工作日 8:00-18:00 运行,实时检测是否有车辆违停
这四个任务,针对的是同一个摄像头的同一路视频流,但它们的特性完全不同:
| 任务 | 触发模式 | 频率 | 实时性要求 | 算力需求 |
|---|---|---|---|---|
| 人员入侵 | 实时流 | 10 帧/秒 | 高(秒级告警) | 高 |
| 遮挡检测 | 定时抽帧 | 1 帧/2 小时 | 低 | 极低 |
| 烟火检测 | 定时抽帧 | 1 帧/30 分钟 | 低 | 低 |
| 违章停放 | 实时流(仅工作时间) | 5 帧/秒 | 中 | 中 |
实时流任务需要持续拉流、持续解码、持续推理,对实时性要求高,算力需求大。
定时抽帧任务只需要在特定时间点取一帧分析,对实时性要求低,算力需求极小。
这两种任务混在一起,怎么调度?这就是我们要解决的问题。
二、踩坑实录:「每个任务单独拉流」的三大浪费
刚开始做的时候,我们的方案很简单粗暴:每个任务独立拉流、独立解码、独立推理。
人员入侵任务拉一路 RTSP 流,遮挡检测任务再拉一路,烟火检测再拉一路……同一个摄像头,被拉了三四路流。
跑起来之后发现问题很大。
浪费一:带宽翻倍,摄像头连接数超限
每拉一路 RTSP 流,就要占用一份带宽。1080P 视频流的码率通常是 4-8Mbps,拉 4 路就是 16-32Mbps。一个园区几十路摄像头,带宽直接爆了。
更严重的是,很多网络摄像头(IPC)的并发连接数有限——便宜的摄像头可能只支持 2-3 路并发 RTSP 连接,好一点的支持 5-8 路。我们拉 4 路流,可能就把摄像头的连接数占满了,其他系统(比如客户原有的视频监控平台)就连不上了。
客户的反馈很直接:「你们装了 AI 分析之后,我们原来的监控平台看不了这个摄像头的画面了,怎么回事?」
浪费二:解码算力重复占用
每一路流都要独立解码。虽然我们用了 MPP 硬解码,CPU 占用不高,但 MPP 的解码通道数也是有限的——RK3588 虽然能硬解 16 路以上 1080P,但如果每个摄像头都重复解码 3-4 次,实际能支持的摄像头数量就大打折扣。
而且重复解码还会增加内存占用——每路解码都要分配一组输入输出缓冲区,4 路就是 4 组,内存浪费严重。
浪费三:系统复杂度飙升,故障排查困难
每个任务独立拉流,意味着每个任务都要管理自己的 RTSP 连接、重连、解码、错误处理。同一个摄像头的 4 个任务,可能这个任务连接正常,那个任务断线了,另一个任务解码花屏了——状态不一致,排查起来非常痛苦。
有一次客户说「这个摄像头的入侵检测不告警了」,我们查了半天,发现入侵检测任务的 RTSP 连接断了没重连,但遮挡检测任务的连接是好的——因为是独立连接,一个断了不影响另一个,但用户看到的是「这个摄像头时好时坏」。
「每个任务单独拉流」这个方案,本质上是把同一个物理资源(摄像头的视频流)重复使用了多次,既浪费带宽、浪费算力,又增加了系统复杂度。
三、我们的方案:同源多任务复用调度 [Yuewell Inside]
踩了这些坑之后,我们重新设计了调度机制。核心思想很简单:同一个摄像头的视频流,只拉一次、只解一次,多个任务共享这一路解码后的帧。
我们把任务分成两种模式:
模式一:LIVE(实时长连任务)
需要持续分析视频流的任务(如人员入侵、违章停放),采用 LIVE 模式。
- 系统对该摄像头建立一条常驻 RTSP 长连接
- MPP 硬解码持续运行,把最新的帧写入越微自研共享帧池
- 所有 LIVE 任务从共享帧池取帧,按各自的采样频率送检
- 比如人员入侵任务每 100ms 取一帧(10fps),违章停放任务每 200ms 取一帧(5fps)
关键点:不管有多少个 LIVE 任务,RTSP 只拉一路、解码只做一次。 多个任务只是从同一个帧池里按各自的节奏取帧,互不干扰。
模式二:CRON(定时抽帧任务)
只需要在特定时间点取一帧分析的任务(如遮挡检测、烟火检测),采用 CRON 模式。
- 任务到期时,不单独拉流,而是从该摄像头当前的共享帧池里取最新一帧
- 给这一帧打上该任务的 ID,单帧送入推理
- 推理完成后,结果按该任务的规则处理(告警、推送、记录)
关键点:CRON 任务「借道」LIVE 任务的长连接和解码,零额外开销。 对 LIVE 任务完全没有影响——只是从帧池里多取了一帧而已。
闲置相机:按需拉流,阅后即焚
如果某个摄像头没有任何 LIVE 任务(只有 CRON 任务,或者所有任务都在非工作时间),那怎么办?
我们的策略是按需拉流:
- CRON 任务到期时,临时建立 RTSP 连接
- 拉流、硬解第一张合规的 I 帧(关键帧,不需要等前面的帧)
- 把这一帧送入推理
- 推理结束后立即断开连接、释放解码内存
- 系统回到静默状态,等待下一次任务触发
我们把这个策略叫做「阅后即焚」——用完就断,不占资源。
对于只有定时任务的摄像头(比如仓库里的烟火检测,每小时抽一帧),这个策略能节省 99% 以上的带宽和解码资源——因为大部分时间摄像头是静默的,只在抽帧的那一瞬间短暂连接。
点播复用:客户端预览也不重复拉流
还有一种情况:运维人员用客户端(UI/交互层进程)实时预览某路摄像头的画面。这时候也不应该重复拉流——如果该摄像头已经有 LIVE 任务在跑,预览直接从当前的解码帧路径订阅复用,和 CRON 任务一样「借道」。
如果该摄像头没有 LIVE 任务,那预览就触发一次按需拉流,预览结束后断开。
总之,整个系统中,同一个摄像头在任何时刻最多只有一路 RTSP 连接、一个解码会话。 所有需要帧的消费者(LIVE 任务、CRON 任务、客户端预览)都从这一路解码输出中取帧,共享复用。
四、调度机制的几个关键设计
关键设计一:越微自研共享帧池,生产者-消费者模式
整个调度机制的核心是共享帧池——一个摄像头对应一个帧池,MPP 解码是生产者,持续把最新的帧写入帧池;各个任务是消费者,按各自的节奏从帧池取帧。
帧池的设计要点:
- 只保留最新一帧:帧池不需要存很多帧,只需要存当前最新的一帧。因为 AI 分析只关心最新的画面,旧帧没有意义。这样内存占用极小。
- 线程安全:生产者(解码线程)和多个消费者(任务线程)并发访问帧池,需要用锁或无锁队列保证线程安全。
- 零拷贝:帧池里存的是 DMA-BUF fd(硬解码输出的硬件缓冲区句柄),消费者取帧的时候只是增加引用计数,不拷贝图像数据。用完之后减少引用计数,引用计数为 0 时归还 MPP。
关键设计二:任务级别的采样频率控制
不同的 LIVE 任务有不同的采样频率——人员入侵要 10fps,违章停放 5fps 就够了。我们在任务级别控制采样频率,而不是统一按解码帧率送检。
这样做的好处是:
- 节省 NPU 算力——不需要每个任务都按 25fps 送检,按实际需求来
- 任务之间互不干扰——一个任务调整采样频率,不影响其他任务
- 灵活适配不同场景——高安全级别的区域用高帧率,低风险区域用低帧率
关键设计三:时间窗控制
很多任务不是 7×24 小时运行的——比如违章停放检测只在工作日 8:00-18:00 运行,夜间不需要。我们支持按时间窗控制任务的启停。
时间窗的设计:
- 每个任务可以配置「运行时间窗」(如工作日 8:00-18:00)
- 进入时间窗时,任务激活,开始从帧池取帧送检
- 离开时间窗时,任务休眠,不再取帧
- 如果一个摄像头的所有 LIVE 任务都进入休眠,且没有预览,那 RTSP 连接也会断开,回到静默状态
时间窗控制能进一步节省资源——非工作时间,整个系统的负载会大幅下降。
关键设计四:CRON 任务强制单帧确认
CRON 任务是定时抽帧,几小时才一帧,这种任务不适合做「连续 N 帧确认」的事件融合(因为两帧之间隔了几小时,根本不是连续的)。
所以我们对 CRON 任务强制单帧确认——检测到目标就立即告警推送,不需要连续多帧确认。
这样做的原因:
- 定时任务两帧间隔太久,连续帧确认没有意义
- 定时任务通常用于状态检测(如摄像头是否被遮挡、仓库里是否有烟火),一帧就能判断状态
- 避免和跳帧策略冲突——定时任务本身就是低频抽帧,如果还要求多帧确认,可能永远凑不齐
但定时任务的单帧确认意味着误报率可能比实时任务高一些——因为没有连续帧过滤。所以定时任务更依赖 ROI 过滤和模型本身的精度。对于误报率要求高的定时任务,我们会建议用更精准的专用模型(如烟火检测用专模,而不是通用检测模型)。
五、实战案例:某园区 16 路相机的调度优化
我们在一个客户现场做了调度优化前后的对比。这个客户有 16 路摄像头,每路摄像头平均配置 3 个任务(1 个实时任务 + 2 个定时任务)。
优化前:每个任务单独拉流
- RTSP 连接数:16 路 × 3 任务 = 48 路连接
- 带宽占用:48 路 × 4Mbps = 192Mbps(客户的千兆网络都快扛不住了)
- MPP 解码通道:48 路(很多摄像头的连接数超限,频繁掉线)
- 系统状态:不稳定,频繁出现某个任务断线、某个摄像头连接失败的情况
优化后:同源多任务复用
- RTSP 连接数:16 路(每个摄像头一路,有实时任务的常驻,只有定时任务的按需拉流)
- 带宽占用:16 路 × 4Mbps = 64Mbps(按需拉流的摄像头大部分时间静默,实际带宽更低)
- MPP 解码通道:16 路(每个摄像头解一次,所有任务共享)
- 系统状态:稳定运行,不再出现连接数超限的问题
优化效果:连接数降到原来的 1/3,带宽降到原来的 1/3,系统稳定性大幅提升。 而且因为解码只做一次,CPU 占用也进一步下降。
客户的运维人员说:「优化之后,原来的监控平台也能正常看画面了,再也没有出现过摄像头连不上的情况。」
六、踩坑实录
同源多任务调度的实现过程中,我们也踩了不少坑。
坑一:共享帧池的竞态条件,偶发花屏
共享帧池被生产者(解码线程)和多个消费者(任务线程)并发访问,如果同步机制做得不好,就会出现竞态条件——消费者正在读一帧,生产者刚好把这一帧释放了,消费者读到一半数据就变了,导致花屏。
我们一开始用简单的互斥锁保护帧池,但在高并发下锁竞争严重,影响性能。后来改成了无锁队列 + 引用计数的方式,性能和稳定性都好了很多。
经验:共享资源的并发访问是嵌入式系统中最容易出问题的地方,一定要充分测试,特别是长时间运行的稳定性测试。
坑二:按需拉流的「第一张 I 帧」问题
闲置相机的按需拉流策略是「临时连接 → 硬解第一张 I 帧 → 推理 → 断开」。但实际实现中,「第一张 I 帧」并不总是那么好拿——
- 有些摄像头的 I 帧间隔很长(比如 5 秒一个 I 帧),连接后可能要等好几秒才拿到 I 帧
- 有些摄像头的码流开头是 P 帧(非关键帧),没有前面的 I 帧就解不出来
- 网络抖动可能导致前几个包丢失,第一个 I 帧可能丢了
我们的解决方案是:连接后设置一个超时时间(比如 3 秒),在超时时间内等第一个 I 帧;如果超时还没拿到,就重试一次;重试还不行就告警,标记该摄像头抽帧失败。
经验:按需拉流看起来简单,但「拿第一帧」的细节很多,要做好超时和重试机制。
坑三:时间窗切换时的状态不一致
时间窗控制中,任务在进入/离开时间窗时会激活/休眠。如果多个任务的时间窗不一样(比如人员入侵是 7×24,违章停放是工作日 8-18 点),在时间窗切换的瞬间,可能出现状态不一致——
- 违章停放任务离开时间窗休眠了,但它的推理请求还在处理中
- 人员入侵任务还在跑,但摄像头因为「所有 LIVE 任务都休眠了」被断开了(实际上人员入侵还在跑)
我们的解决方案是:用引用计数管理摄像头的连接状态——每个 LIVE 任务激活时增加引用计数,休眠时减少引用计数;只有当引用计数降到 0 时,才断开摄像头连接。这样就不会出现「还有任务在跑但摄像头被断开」的情况。
⚠️ 工程坑点与技术壁垒警告
提示:同源多任务调度的思想不难理解,但工程落地中有几个高壁垒问题:
多消费者无锁帧池的稳定性:一个生产者 + N 个消费者的无锁帧池,在长时间高并发运行下,任何一个引用计数的 race condition 都可能导致偶发花屏、内存泄漏或进程崩溃。越微团队在内核态与用户态构建了专属的无锁队列与帧同步状态机,经过上百小时的压测和故障注入才确保零崩溃运行。
按需拉流的异常码流与 I 帧等待:工业现场摄像头品牌杂,按需拉流时可能遇到 I 帧间隔过长、码流开头异常、网络抖动丢包等问题。简单的「连接→取帧→断开」流程在真实环境中会频繁失败。越微自研的按需拉流引擎做了多层超时、重试、降级处理,才能在复杂现场环境中稳定运行。
这些细节不是看几篇博客就能搞定的,需要在真实设备上反复调试、压测、故障注入。越微团队在这上面投入了大量时间,才打磨出稳定的同源多任务调度引擎。
七、几点经验总结
回头看同源多任务调度的设计和落地过程,总结几点:
1. 边缘视频分析,「拉流次数」是比「解码性能」更先遇到的瓶颈
很多人一开始关注的是「RK3588 能解多少路」,但实际项目中,先遇到的瓶颈往往是「摄像头能支持多少路并发连接」和「网络带宽够不够」。同源复用把拉流次数降到最低,是比硬解码更优先的优化。
2. 越微自研共享帧池 + 零拷贝,是同源复用的技术基础
多个任务共享一路解码输出,核心是共享帧池的设计。帧池要做到只存最新帧、线程安全、零拷贝。引用计数管理 DMA-BUF fd 的生命周期,是保证不内存泄漏、不花屏的关键。这个机制看起来简单,但实现细节很多,race condition 很容易出问题,要充分测试。
3. 「阅后即焚」的按需拉流,对只有定时任务的摄像头特别有效
很多摄像头(比如仓库、库房)不需要实时分析,只需要定时抽帧检测烟火、遮挡。这种摄像头如果常驻拉流,99% 的时间都是浪费。按需拉流、用完就断,能把带宽和解码资源节省到极致。对于大规模部署(几十上百路摄像头),这个策略能显著降低整体资源需求。
4. 任务级别的采样频率控制,比统一帧率更灵活、更省算力
不同任务对帧率的需求不同——入侵检测要高帧率,违章停放低帧率就够。在任务级别控制采样频率,而不是统一按解码帧率送检,既能满足不同任务的需求,又能节省 NPU 算力。NPU 是边缘设备最宝贵的资源,能省则省。
5. 时间窗控制是被低估的节能手段
很多任务只在特定时间运行(工作时间、白天)。支持时间窗控制,让任务在非运行时间休眠,甚至让整个摄像头的拉流都断开,能让系统在非高峰时段的负载大幅下降。这不仅省电,也减少了硬件的长时间高负载运行,延长设备寿命。
写在最后
同源多任务调度,本质上是「资源共享」思想在边缘视频分析中的具体应用——同一个摄像头的视频流,是一种有限的物理资源(带宽、连接数、解码能力),不应该被重复浪费。通过越微自研共享帧池、按需拉流、任务级采样控制,我们让一路视频流同时支撑多个算法任务,把资源利用率提到最高。
这些经验都是我们(越微智能)在实际项目中踩坑踩出来的。我们团队一直在做工业 AI 视觉、边缘计算部署、机器人二次开发这些落地工作,边缘 AI 视频分析系统是我们的核心产品之一。后面的文章我们会继续拆解——零拷贝跨进程通信、多模型推理、事件融合与证据链、部署与 OTA 升级,把更多实战经验分享出来。
如果你也在做边缘视频分析、多路视频调度、RK3588 开发相关的工作,欢迎交流,我们一起踩坑、一起进步。
关于作者与团队:
越微智能(Yuewell)是一支专注具身智能与工业 AI 视觉落地的技术团队,提供工业级视觉算法定制(30+ 算法)、RK3588 边缘一体机、具身机器人调度管理平台、全品牌机器人二次开发(适配宇树/优必选/智元/傅利叶等)、ROS2 系统开发等产品和服务,支持从算法、硬件到产线实机部署的全栈交付。
我们将这套经过大规模现场验证的同源多任务调度引擎,封装为了工业级边缘 AI 视觉基座(Yuewell Edge Framework)的核心模块,支持硬件/算法快速二次开发,帮助客户跳过最痛苦的工程踩坑阶段。
📌 获取更多技术白皮书、工业 AI 视觉方案与产品交流,欢迎访问越微智能官网:https://yuewell.com/
下一篇预告: 《零拷贝跨进程通信:边缘服务和算法服务之间如何做到近零 CPU 负载的图像传输》,我们将分享边缘 AI 系统中进程间通信的瓶颈、基于 DMA-BUF 的无锁零拷贝共享内存环形缓冲区设计、背压控制策略(队列深度为 1、忙则跳帧),以及零拷贝 vs 传统传输的性能对比,敬请关注。