应用框架
应用框架(Application Framework)位于应用层与组件层之间,将媒体、AI、录像等底层能力收敛为一组功能级 API:业务程序无需了解 VI→VPSS→VENC 的初始化顺序,一次调用即可完成整条通路。同一组 API 支持同进程直调与跨进程 IPC 两种形态——媒体管道始终单一进程归属,业务程序、命令行工具与脚本以客户端身份共用同一路硬件,互不干扰。
读者对象:在 Hi-AIoT-Solution 上开发业务的嵌入式应用开发者。 前置条件:已阅读《软件架构》。
1 设计动机与收益
| 面临的问题 | 设计做法 | 对开发者的价值 |
|---|---|---|
| 底层接口粒度细、初始化顺序有约束 | 收敛为功能级 API,内部按序初始化并管理状态 | 减少样板代码,无需掌握初始化顺序 |
| 媒体管道对 MPP 是独占资源 | 管道只在单一进程建立 | 多个应用、工具与脚本共享同一路摄像头 |
| 命令行、脚本、业务程序均需操作硬件 | 各类调用方接入同一套 IPC 通道 | 无需为每种调用方单独封装 |
| 多客户端接入,需防越权与滥用 | SERVER 端客户端注册鉴权:模块权限隔离、连接数量配额 | 越权调用被拒,连接数量受控,各端互不干扰 |
| 跨进程传输码流开销大 | 以地址传递替代数据拷贝 | 大码流跨进程传输开销低 |
| 嵌入式存储与内存受限 | Kconfig(COMP_FW_API_*)按需编译 |
只包含实际使用的能力 |
以上设计共同服务于:同一套 API 支撑单进程直调与跨进程 IPC 两种部署形态。
2 架构设计
2.1 总体框架
应用框架是应用与底层能力之间的一层:向上提供统一的 api_* 接口,向下对接组件层与芯片 SDK。调用方经三条路径抵达框架:业务程序在 SERVER 层内直调;命令行工具 fw_cli 以 CLIENT 身份经 UDS 接入;micropython 技能脚本经 Python 封装接口调用。AI Agent(zeroclaw)产生的操作由模型按 SKILL.md 执行 micropython 技能脚本(如 capture_picture.py),经 Python 封装接口与命令行工具汇入同一 CLIENT 通道——无论何种调用方,抵达的都是同一组 API 与同一路硬件(见图 1)。

图 1 应用框架总体结构。自上而下为图例、应用层、应用框架、组件层。应用框架内部由 CLIENT 进程与 SERVER 层两个子框构成,经 UDS 通信层对接。CLIENT 进程有两条入口:CLI Proxy(fw_cli)接入 Client API 层;AI Agent(zeroclaw)调用 MicroPython 执行技能脚本(如 capture_picture.py),经 python_api 封装接口汇入同一 Client API 层,再经消息处理层、UDS Client 通信层抵达 SERVER 层。SERVER 层由应用层的业务程序启动,内部链路为 UDS Server 通信层(含客户端注册与鉴权)→ 直调 API 层 → 业务处理 → 消息处理层 → 组件适配层,最终对接组件层。
框架的设计取向可归纳为三点:
| 设计要点 | 说明 |
|---|---|
| 统一 API | 音视频、AI、录像等能力收敛为功能级接口,应用只依赖框架头文件 |
| 双运行形态 | 同一组 API 支持 DIRECT(本进程直调)与 CLIENT/SERVER(跨进程)两种部署方式 |
| 单一硬件归属 | 媒体管道只在单个进程建立,业务、工具与脚本通过 IPC 共用同一路硬件 |
2.2 分层结构
框架源码位于 components/media/framework/,依赖方向单向:应用层 → 框架层 → 组件层。应用框架内部自上而下分为以下几层:
| 分层 | 组成 |
|---|---|
| 接入层 | CLI Proxy(fw_cli)、MicroPython(执行技能脚本,如 capture_picture.py) |
| Python 封装接口 | python_api 封装的接口 |
| Client API 层 | CLIENT 进程统一入口,CLI 与 Python 两条路径在此汇合 |
| 消息处理层 | 同步与异步消息分发 |
| UDS 通信层 | UDS Client ↔ UDS Server,服务端含客户端注册与鉴权 |
| 直调 API 层 | SERVER 层内直调接口 |
| 业务处理 | 业务逻辑处理 |
| 组件适配层 | 对接组件层 |
2.3 关键设计
同接口、双实现:业务代码只维护一份。链接 api_media 即为本进程直调,链接 api_media_client 即为跨进程调用,业务代码无需修改。
控制与数据通道分离:控制类小消息经 Unix Domain Socket 同步或异步传递;编码码流等大数据由 SERVER 下发缓冲地址,调用方映射后直接读取,不产生数据拷贝;编码回调与 AI 结果跨进程对上层透明。
场景化参数:音视频参数预置为场景(CAPTURE、FACTORY_LCD、ZEROCLAW、DUAL_SENSOR 等),一次初始化即可完成整条通路的参数选择,无需逐项配置 ISP 与 VENC 参数。
3 能力清单
| 模块 | 提供的能力 | 跨进程 |
|---|---|---|
api_media |
媒体系统、音视频采集/编解码/显示、抓拍与 OSD | 支持 |
api_aidetect |
AI 目标检测(人脸、人体、车辆、宠物等) | 支持 |
api_fr |
人脸识别与人脸库管理 | 支持 |
api_human_track |
人体/目标跟踪与结果叠加 | 支持 |
api_liveserver |
点播服务,视频/音频推流 | 支持 |
api_record |
MP4 录像与 SD 卡存储 | 支持 |
api_webrtc |
WebRTC 点对点音视频对讲 | 支持 |
模块能力由 Kconfig 开关控制,仅编译实际使用的部分。接口参数与返回值见框架层接口文档。
4 使用指南
4.1 运行模式选择
| 适用场景 | 建议模式 |
|---|---|
| 单进程功能验证、对时延敏感 | DIRECT |
| 多调用方共享硬件,或需要命令行、脚本随时接入 | CLIENT/SERVER |
| 需要进程隔离:媒体栈故障不拖累业务进程,或按权限拆分部署 | CLIENT/SERVER |
两种模式使用同一组 API,业务代码无需修改;切换部署形态时更换链接库并调整初始化入口(CLIENT 需连接服务端端点,SERVER 需增加 channel_server_init)。
注意:同一时刻硬件管道只能归属一个进程。SERVER 内部同样基于直调实现建立管道,若再运行一个 DIRECT 应用,则两个进程重复初始化同一套硬件而发生冲突,二者不可同时运行。
4.2 编译配置
# 以 framework_media 示例为例,编译后得到 DIRECT / SERVER / CLIENT 三个可执行文件与 fw_cli
bash scripts/build.sh build --target cv610_ev_board samples framework_media
能力开关位于 components/media/framework/Kconfig(COMP_FW_API_MEDIA、COMP_FW_API_AIDETECT、COMP_FW_API_RECORD 等)。
4.3 调用方式
以抓拍一张 JPEG 为例,三类调用方的写法如下:
| 调用方 | 接入方式 | 抓拍调用 |
|---|---|---|
| C 应用 | 包含 api_media.h;直连链接 api_media,跨进程链接 api_media_client |
hi_fw_media_capture_jpeg(0, "/tmp/photo.jpg", 1); |
| 命令行 | 板端运行 fw_cli,以 CLIENT 身份连接服务端 |
./fw_cli camera_capture /tmp/photo.jpg 1 0 |
| MicroPython | 使用 hi_media_encode 模块(CLIENT 构建) |
hi_media_encode.photo("/mnt/photo.jpg") |
4.4 最小示例
# 板端:先启动服务端,媒体管道在其中建立
/root/sample_framework_media_server &
# 通过命令行代理抓拍(capture 场景的 JPEG 通道为 venc0)
./fw_cli camera_open capture
./fw_cli camera_capture /tmp/photo.jpg 1 0
./fw_cli camera_close
# 亦可使用 MicroPython:对应 micropython_sample 的 media_server,监听 /var/run/media_server/ipc_media.sock,与上例 framework_media(/tmp/media_pipeline.sock)各自独立
import hi_media_encode
hi_media_encode.init("/var/run/media_server/ipc_media.sock")
hi_media_encode.photo("/mnt/photo.jpg")
hi_media_encode.deinit()
4.5 注意事项
- SERVER 必须先于 CLIENT 启动,且调用方的 endpoint 需与服务端监听地址一致(
fw_cli默认/tmp/media_pipeline.sock,MicroPython 默认/var/run/media_server/ipc_media.sock)。 - 抓拍通道号需与已建立的场景匹配:
capture与zeroclaw场景使用 venc0,factory_lcd场景使用 venc1;管道已由其它程序建立时,不应再执行camera_open。
5 应用示例:Zeroclaw 场景
5.1 场景结构
apps/cv610_ev_board/references/zeroclaw_base 是 zeroclaw 智能体在 CV610 上的基础镜像案例,其形态为"一个媒体服务进程 + 多个业务客户端进程",可用于验证多客户端共享同一路音视频硬件。
服务端进程 zeroclaw_base_main 启动时建立以下通路并常驻:
| 通路 | 配置 |
|---|---|
| 视频 | ZEROCLAW 场景,双 VENC:venc0 用于 JPEG 抓拍(VPSS chn1,768×448),venc1 用于 H.265 推流(VPSS chn0,2560×1440) |
| 音频 | ZEROCLAW 场景,双 AENC:h0 为 AAC,供推流取流;h1 为 OPUS,供本地语音;ADEC(MP3)→ AO 用于 TTS 播放 |
| AI | aidetect 直连初始化 |
| IPC | channel_server_init("/tmp/media_pipeline.sock", ...) 对外提供服务 |
上板后由 init 脚本按序启动:加载内核模块 → 启动 zeroclaw_base_main → 启动 push_stream。
接入同一服务端的客户端进程及其分工:
| 客户端 | 注册模块 | 用途 |
|---|---|---|
push_stream |
media | 注册 VENC 与 AENC 回调,取 venc1 码流与 AENC h0 音频,推送 RTMP |
local_voice |
media | 注册 ACAP 回调获取 16 kHz PCM(供 KWS/ASR),启动 OPUS AENC h1;TTS 经 ADEC 下发播放 |
fw_cli |
media | 命令行抓拍,ZEROCLAW 场景的 JPEG 通道为 venc0 |
| zeroclaw 技能脚本 | media | MicroPython CLIENT 模式,capture_picture.py 抓拍、ai_component_skill 目标检测,显式指定 /tmp/media_pipeline.sock |
5.2 服务端业务流程
sequenceDiagram
participant C as 客户端进程
participant S as 服务端 channel_server
participant A as 权限上下文 client_auth
C->>S: channel_client_init(endpoint)
C->>S: MSG_CLIENT_REGISTER 声明所用模块
S->>A: 分配模块 slot 并登记连接
A-->>C: 返回 client_id
C->>S: 业务消息(携带 client_id)
S->>A: 校验 client_id、连接绑定与模块权限
A-->>S: 校验通过
S-->>C: 返回处理结果
流程说明:
- 服务端启动:
channel_server_init(endpoint, &handle, module_count)打开 Unix Domain Socket 并进入监听,建立权限上下文,并按编译开关自动注册内置模块的处理函数(media、liveserver、aidetect、fr、human_track、record),业务层无需手工注册。 - 接入连接:每 accept 到一个连接,服务端为其分配独立线程与 client_id。
- 客户端注册:客户端
channel_client_init(endpoint)后发送MSG_CLIENT_REGISTER声明所需模块(各api_*_client_init已自动完成),服务端在该模块的客户端池中分配 slot 并返回 client_id。 - 请求校验:后续每条消息均需通过权限校验——client_id 有效、slot 已占用、连接与注册记录一致(防止跨连接重放)、消息所属模块在该客户端的权限掩码内;任一条件不满足则返回
CHN_EAUTH。 - 断开回收:连接断开时服务端触发断连通知并回收 slot,供后续客户端复用。
module_count 需与编译进服务端的模块数一致。zeroclaw_base 启用 media、liveserver、record、aidetect 共 4 个模块,故取 4;少于实际数量会导致服务端初始化失败。
5.3 权限模型与配置
| 维度 | 配置方式 | 说明 |
|---|---|---|
| 模块可见性 | 构建期 Kconfig(COMP_FW_API_*) |
决定服务端注册哪些模块;未启用的模块不注册,客户端无法连接使用 |
| 客户端配额 | client_auth_module_config_register(module_id, max_count) |
每个模块维护独立的客户端池,默认上限为 media 4、liveserver 4、aidetect 8、fr 8、human_track 8、record 4,超出返回 CHN_EAUTH_MAX_CLIENTS |
| 模块权限位 | 客户端注册时自动授予 | 客户端注册哪个模块即获得该模块的权限位,采用 1024 bit 掩码,校验复杂度为 O(1) |
| 自定义权限上下文 | channel_server_set_auth_context |
默认配额不满足时,可自建 client_auth_context 后挂载;模块存在活跃客户端时不允许重配置 |