03 SVP视频处理
SVP(Smart Video Processing)是智能视频处理的核心模块,为开发人员提供了一套完整的API接口,支持人形、人脸、车辆、烟火、DMS(驾驶员监控系统)等多种智能分析算法。
本文档以 YOLOv5 人形检测为例,完整讲解 NPU 从模型加载到推理结果输出的智能视觉管线全流程。
1. 整体架构概览
GK7206 芯片内部集成了专用的 NPU(神经网络处理单元),可以高效执行卷积神经网络推理。整体数据流如下:

关键硬件模块说明:
| 模块 | 全称 | 功能 |
|---|---|---|
| VI | Video Input | 接收 Sensor 采集的原始图像 |
| VPSS | Video Processing Sub-System | 图像缩放、裁剪,输出多路不同分辨率 |
| NPU | Neural Processing Unit | 神经网络推理(卷积、池化、激活等) |
| VGS | Video Graphics Sub-System | 在图像上叠加矩形框、文字等 OSD 信息 |
| VENC | Video Encoder | H.264/H.265 视频编码 |
| MMZ | Media Memory Zone | 媒体专用物理连续内存管理 |
2. SVP视频开发管线
摄像头画面在到达 NPU 之前,需要经过一系列硬件模块处理:
Sensor → VI → VPSS → 通道0: 大图(1920×1080) → VENC(主码流) / VO(显示)
└→ 通道1: 小图(640×360) → NPU推理
└→ 通道2: 中图(1280×720) → VENC(子码流) / NPU(大图模型)为什么需要缩放?
- NPU 模型在训练时使用固定分辨率(如 640×360)
- VPSS 硬件自动完成缩放,无需 CPU 参与
- 缩放后的帧直接在物理内存中传递给 NPU,实现零拷贝
相关代码位置:sample_svp_main.c:1108-1161
3. SVP视频处理完整流程
3.1 初始化 SVP 子系统
SVP(Smart Vision Platform)是 GK7206 的智能视觉平台接口。使用 NPU 前必须先初始化:
// 文件: sample_svp_main.c → sample_svp_start()
xmedia_s32 ret;
// 第一步:初始化 SVP 子系统
ret = xmedia_svp_init();
if (ret != XMEDIA_SUCCESS) {
printf("xmedia_svp_init error.\n");
return XMEDIA_FAILURE;
}注意:
xmedia_svp_init()在整个应用生命周期中只需调用一次。
3.2 加载模型与分配内存
NPU 需要专用的物理连续内存来存放模型权重和中间计算结果。
3.2.1 配置模型信息
以人形检测为例,配置模型参数:
xmedia_svp_modules modules[8]; // 最多支持 8 个模型
xmedia_svp_task_cfg task_cfg;
// 配置模型 0:人形检测
modules[0].alg_type = XMEDIA_SVP_ALG_TYPE_PERSON; // 算法类型
modules[0].load_mode = XMEDIA_SVP_MODEL_FILE; // 从文件加载
modules[0].format = XMEDIA_SVP_INPUTDATA_FORMAT_RGB888; // 输入格式
modules[0].pathname = "./model/gnn_person_detect_640x360_rgb888hwc_v0103_20251203.bin";
task_cfg.module_num = 1; // 本任务使用 1 个模型
task_cfg.task_type = XMEDIA_SVP_TASK_DETECT; // 检测类任务
task_cfg.modules = modules;模型配置字段说明:
| 字段 | 说明 | 可选值 |
|---|---|---|
alg_type | 算法类别 | XMEDIA_SVP_ALG_TYPE_PERSON、XMEDIA_SVP_ALG_TYPE_FACE、XMEDIA_SVP_ALG_TYPE_CAR 等 |
load_mode | 加载方式 | XMEDIA_SVP_MODEL_FILE(从文件)、XMEDIA_SVP_MODEL_MEM(从内存) |
format | 输入图像格式 | XMEDIA_SVP_INPUTDATA_FORMAT_RGB888、XMEDIA_SVP_INPUTDATA_FORMAT_YUV420SP |
pathname | 模型文件路径 | .bin 格式的 NPU 专用模型文件 |
3.2.2 查询模型内存需求
// 查询模型所需的内存大小
xmedia_cl_mem_info model_mem_info;
ret = xmedia_cl_graph_query_model_info_from_file(
modules[0].pathname,
&model_mem_info,
XMEDIA_CL_MEM_INFO
);
// model_mem_info 中包含:
// worksize - NPU 工作缓冲区大小(中间计算用)
// inputsize - 输入缓冲区大小(存放输入图像)
// outputsize- 输出缓冲区大小(存放推理原始结果)3.2.3 分配 NPU 专用内存
xmedia_svp_cfg svp_cfg;
xmedia_svp_get_config(&svp_cfg);
svp_cfg.reuse_type = XMEDIA_SVP_MEM_TYPE_BLOCK; // 分块复用模式
// 分配工作缓冲区(NPU 内部计算用,需要 cache 属性)
sample_mmz_alloc_and_map_cache(
XMEDIA_NULL, "npu_work_mem",
&svp_cfg.workbuf_reuse_mem.phyaddr, // 物理地址
&svp_cfg.workbuf_reuse_mem.viraddr, // 虚拟地址
svp_cfg.workbuf_reuse_mem.size // 大小
);
// 分配输入缓冲区(存放输入图像数据)
sample_mmz_alloc_and_map(
XMEDIA_NULL, "npu_input_mem",
&svp_cfg.input_reuse_mem.phyaddr,
&svp_cfg.input_reuse_mem.viraddr,
svp_cfg.input_reuse_mem.size
);
// 分配输出缓冲区(存放推理原始结果)
sample_mmz_alloc_and_map_cache(
XMEDIA_NULL, "npu_output_mem",
&svp_cfg.output_reuse_mem.phyaddr,
&svp_cfg.output_reuse_mem.viraddr,
svp_cfg.output_reuse_mem.size
);
// 将内存配置设给 SVP
xmedia_svp_set_config(&svp_cfg);3.3 创建推理任务
将模型配置和内存准备好后,创建 SVP 任务(此时模型真正加载到 NPU):
xmedia_s32 svp_handle;
ret = xmedia_svp_task_create(&svp_handle, task_cfg);
if (ret != XMEDIA_SUCCESS) {
printf("xmedia_svp_task_create failed!\n");
return XMEDIA_FAILURE;
}
// svp_handle 是后续所有推理操作的句柄核心概念:一个
svp_handle代表一路完整的推理流程,包含模型加载、前后处理等全部资源。
3.4 设置推理参数
创建任务后,可以调整推理参数(阈值、追踪等):
// YOLOv5 检测属性
xmedia_svp_yolov5_attr yolov5_attr;
yolov5_attr.detect_threshold = 0.65f; // 检测置信度阈值(低于此值的目标被丢弃)
yolov5_attr.classifier_threshold = 0.8f; // 分类器置信度阈值
yolov5_attr.iou_threshold = 0.5f; // NMS 交并比阈值(重叠框过滤)
yolov5_attr.max_target_num = 10; // 单帧最大目标数(不超过 50)
yolov5_attr.bytetrack_enable = XMEDIA_TRUE; // 启用 ByteTrack 目标追踪
yolov5_attr.motionless_filter_enable = XMEDIA_TRUE; // 启用运动状态检测
yolov5_attr.stillness_thres = 0.9f; // 静止判定灵敏度
yolov5_attr.movement_fps_thres = 5; // 连续帧阈值
yolov5_attr.smart_venc_enable = XMEDIA_FALSE; // 智能编码
yolov5_attr.smart_ae_enable = XMEDIA_FALSE; // 智能曝光
ret = xmedia_svp_task_set_attr(svp_handle, &yolov5_attr);参数调优建议:
| 参数 | 建议值 | 调高效果 | 调低效果 |
|---|---|---|---|
detect_threshold | 0.65 | 漏检增加,误检减少 | 漏检减少,误检增加 |
iou_threshold | 0.5 | 保留更多重叠框 | 合并更多重叠框 |
max_target_num | 10 | 处理更多目标,耗时略增 | 限制目标数,性能更稳 |
bytetrack_enable | TRUE | 跨帧追踪,输出 tracker_id | 仅单帧检测,无追踪 |
3.5 启动推理线程
初始化完成后,启动独立线程进入推理循环:
// sample_svp_info 结构体保存了所有运行时信息
sample_svp_info svp_info;
svp_info.detect_type = SAMPLE_SVP_ALG_TYPE_PERSON;
svp_info.svp_handle = svp_handle;
svp_info.vpss_pipe = vpss_pipe;
svp_info.vpss_ochn[1] = small_channel; // 小图通道
svp_info.venc_chn[1] = venc_channel; // 编码通道
svp_info.big_stream = XMEDIA_FALSE;
g_svp_start_flag = XMEDIA_TRUE;
// 创建推理线程
pthread_create(&g_svp_thread, NULL, sample_svp_proc, &svp_info);4. 帧获取与推理循环
sample_svp_proc() 是推理的主循环线程,不断从 VPSS 取帧、送 NPU 推理、处理结果。
4.1 获取摄像头帧
// sample_svp_main.c → sample_svp_proc()
while (g_svp_start_flag == XMEDIA_TRUE) {
xmedia_video_frame_info video_frame;
xmedia_s32 milli_sec = 20000; // 超时 20 秒
// 从 VPSS 获取一帧小图(640×360)
ret = xmedia_vpss_acquire_ochn_frame(
svp_info->vpss_pipe, // VPSS 管道
svp_info->vpss_ochn[1], // 输出通道 1(小图)
&video_frame, // 输出帧信息
milli_sec // 超时时间
);
if (ret != XMEDIA_SUCCESS) {
printf("get vpss small frame failed!\n");
continue; // 取帧失败,重试
}video_frame 包含的关键信息:
video_frame (xmedia_video_frame_info)
├── frame.width = 640
├── frame.height = 360
├── frame.addr.y_phy_addr → Y 分量物理地址
├── frame.addr.uv_phy_addr → UV 分量物理地址
├── frame.pixel_format = YUV420SP
└── pool_id → VB 缓冲池 ID注意:帧数据在物理内存中,不需要拷贝。NPU 通过物理地址直接访问。
4.2 提交 NPU 推理
将帧打包为 NPU 输入格式并提交推理:
// 打包输入
xmedia_svp_task_input task_input;
xmedia_video_frame_info frame_info[2];
frame_info[0] = video_frame; // 第 0 帧 = 小图
task_input.frame_num = 1; // 单帧输入
task_input.frame = frame_info;
// 如果需要大图(如车牌识别需要 1920×1080)
if (svp_info->big_stream == XMEDIA_TRUE) {
xmedia_video_frame_info video_frame_big;
ret = xmedia_vpss_acquire_ochn_frame(
svp_info->vpss_pipe, svp_info->vpss_ochn[2],
&video_frame_big, milli_sec
);
frame_info[1] = video_frame_big; // 第 1 帧 = 大图
task_input.frame_num = 2; // 双帧输入
}
// ★★★ 核心:提交推理(同步阻塞调用)★★★
xmedia_svp_yolov5_output result = {0};
ret = xmedia_svp_task_process(
svp_info->svp_handle, // SVP 任务句柄
&task_input, // 输入帧
&result // 输出检测结果
);
if (ret != XMEDIA_SUCCESS) {
printf("xmedia_svp_task_process failed!\n");
}4.3 解析检测结果
推理返回后,result 中已经包含了结构化的检测结果:
if (result.target_num > 0) {
xmedia_video_rect target_rect[XMEDIA_SVP_MAX_TARGET_NUM];
for (xmedia_s32 i = 0; i < result.target_num; i++) {
// 目标边界框(浮点坐标,对应 640×360 图像)
xmedia_float x1 = result.targets[i].rect.x1;
xmedia_float y1 = result.targets[i].rect.y1;
xmedia_float x2 = result.targets[i].rect.x2;
xmedia_float y2 = result.targets[i].rect.y2;
// 对齐到偶数像素(硬件要求)
xmedia_s32 px1 = (xmedia_s32)roundf(x1 / 2) * 2;
xmedia_s32 py1 = (xmedia_s32)roundf(y1 / 2) * 2;
xmedia_s32 px2 = (xmedia_s32)roundf(x2 / 2) * 2;
xmedia_s32 py2 = (xmedia_s32)roundf(y2 / 2) * 2;
// 目标类别
xmedia_svp_class_type cls = result.targets[i].class_type;
// 例如:XMEDIA_SVP_CLASS_TYPE_PERSON
// 置信度 (0.0 ~ 1.0)
xmedia_float score = result.targets[i].detect_score;
// 追踪 ID(启用 ByteTrack 时有效)
xmedia_s32 tracker_id = result.targets[i].tracker_id;
// 运动状态
xmedia_svp_motion_state motion = result.targets[i].motion_state;
// XMEDIA_SVP_MOTION_STATE_STATIC = 静止
// XMEDIA_SVP_MOTION_STATE_MOVING = 运动
// 构造画框用的矩形
target_rect[i].x = px1;
target_rect[i].y = py1;
target_rect[i].width = ABS(px2 - px1);
target_rect[i].height = ABS(py2 - py1);
}4.4 画框与送编码
// 步骤 1:用 VGS 硬件在帧上画检测框(红色矩形)
sample_svp_draw(&target_rect[0], &video_frame, result);
// 步骤 2(可选):叠加 OSD 文字信息
// 需要编译时定义 USE_OSD
#ifdef USE_OSD
xmedia_char info_text[64];
snprintf(info_text, sizeof(info_text),
"id[%d]scr[%.2f]cls[%.2f]mv[%d]",
result.targets[0].tracker_id,
result.targets[0].detect_score,
result.targets[0].classfier_score,
result.targets[0].motion_state);
sample_target_osd(&video_frame, px1, py1, info_text);
#endif
} // end if (result.target_num > 0)
// 步骤 3:将画好框的帧送给视频编码器
ret = xmedia_venc_send_frame(
svp_info->venc_chn[1],
&video_frame,
milli_sec
);
// 步骤 4:释放帧缓冲(归还给 VPSS)
ret = xmedia_vpss_release_ochn_frame(
svp_info->vpss_pipe,
svp_info->vpss_ochn[1],
&video_frame
);
} // end while → 回到循环开头,取下一帧5. 关键数据结构
5.1 模型配置
// 单个模型的配置(xmedia_svp.h:173-180)
typedef struct {
xmedia_svp_model_type load_mode; // 加载方式(文件/内存)
xmedia_svp_inputdata_format format; // 输入格式(RGB888/YUV420SP)
xmedia_char *pathname; // 模型文件路径
xmedia_u8 *buf; // 内存模式的模型数据
xmedia_u32 len; // 内存模式的模型长度
xmedia_svp_alg_type alg_type; // 算法类型
xmedia_void *priv; // 私有数据
} xmedia_svp_modules;
// 任务配置(xmedia_svp.h:182-187)
typedef struct {
xmedia_svp_task_type task_type; // 任务类型
xmedia_svp_modules *modules; // 模型数组
xmedia_u8 module_num; // 模型数量
xmedia_void *priv; // 私有数据
} xmedia_svp_task_cfg;5.2 推理输入
// 任务输入(xmedia_svp.h:167-170)
typedef struct {
xmedia_video_frame_info *frame; // 帧数组
xmedia_u8 frame_num; // 帧数量(1=单帧, 2=双帧)
} xmedia_svp_task_input;5.3 检测结果
// YOLOv5 检测输出(xmedia_svp.h:239-242)
typedef struct {
xmedia_u32 target_num; // 检测到的目标数量
xmedia_svp_detect_result targets[XMEDIA_SVP_MAX_TARGET_NUM]; // 目标数组(最多50)
} xmedia_svp_yolov5_output;
// 单个检测结果(xmedia_svp.h:116-127)
typedef struct {
xmedia_svp_alg_type alg_type; // 算法类型
xmedia_svp_class_type class_type; // 目标类别
xmedia_float detect_score; // 检测置信度 (0.0~1.0)
xmedia_float classfier_score; // 分类置信度 (0.0~1.0)
xmedia_s32 tracker_id; // 追踪 ID
xmedia_u32 tracker_age; // 追踪年龄(存活帧数)
xmedia_svp_rect rect; // 边界框坐标 (x1,y1,x2,y2)
xmedia_bool special_target; // 是否特殊目标
xmedia_float distance; // 目标距离
xmedia_svp_motion_state motion_state; // 运动状态
} xmedia_svp_detect_result;
// 边界框坐标(xmedia_svp.h:102-108)
typedef struct {
xmedia_float x1; // 左上角 X
xmedia_float y1; // 左上角 Y
xmedia_float x2; // 右下角 X
xmedia_float y2; // 右下角 Y
} xmedia_svp_rect;5.4 推理参数
// YOLOv5 检测参数(xmedia_svp.h:225-237)
typedef struct {
xmedia_float detect_threshold; // 置信度阈值,建议 0.65
xmedia_float classifier_threshold; // 分类器阈值,建议 0.8
xmedia_float iou_threshold; // NMS IOU 阈值,建议 0.5
xmedia_u32 max_target_num; // 最大目标数,最大 50
xmedia_bool bytetrack_enable; // 目标追踪开关
xmedia_bool motionless_filter_enable; // 运动状态检测开关
xmedia_float stillness_thres; // 静止灵敏度,建议 0.9
xmedia_u8 movement_fps_thres; // 连续帧阈值,建议 5
xmedia_bool smart_venc_enable; // 智能编码开关
xmedia_bool smart_ae_enable; // 智能曝光开关
} xmedia_svp_yolov5_attr;6. 支持的算法类型
6.1 单模型检测
| 算法类型 | 枚举值 | 模型文件 | 任务类型 |
|---|---|---|---|
| 人形检测 | XMEDIA_SVP_ALG_TYPE_PERSON | gnn_person_detect_640x360_rgb888hwc.bin | XMEDIA_SVP_TASK_DETECT |
| 人脸检测 | XMEDIA_SVP_ALG_TYPE_FACE | gnn_face_detect_640x360_rgb888hwc.bin | XMEDIA_SVP_TASK_DETECT |
| 车形检测 | XMEDIA_SVP_ALG_TYPE_CAR | gnn_car_detect_640x360_rgb888hwc.bin | XMEDIA_SVP_TASK_DETECT |
| 宠物检测 | XMEDIA_SVP_ALG_TYPE_PET | gnn_pet_detect_640x360_rgb888hwc.bin | XMEDIA_SVP_TASK_DETECT |
| 人头检测 | XMEDIA_SVP_ALG_TYPE_HEAD | gnn_head_detect_640x360_rgb888hwc.bin | XMEDIA_SVP_TASK_DETECT |
| 非机动车 | XMEDIA_SVP_ALG_TYPE_NON_MOTORIZED_VEHICLE | gnn_nocar_detect_640x360_rgb888hwc.bin | XMEDIA_SVP_TASK_DETECT |
| 烟火检测 | XMEDIA_SVP_ALG_TYPE_FIREWORKS | gnn_fireworks_detect_640x360_rgb888hwc.bin | XMEDIA_SVP_TASK_DETECT |
| 包裹检测 | XMEDIA_SVP_ALG_TYPE_PACKAGE | gnn_package_detect_640x360_rgb888hwc.bin | XMEDIA_SVP_TASK_DETECT |
6.2 多模型级联
| 算法类型 | 任务类型 | 模型数量 | 说明 |
|---|---|---|---|
| 人体关键点 | XMEDIA_SVP_TASK_DETECT_AND_KEYPOINT | 1 | 检测人形 + 关键点 |
| 手势识别 | XMEDIA_SVP_TASK_GESTURE | 2 | 手部检测 + 手势分类 |
| 人脸表情 | XMEDIA_SVP_TASK_EMOTION_CLASSIFITION | 3 | 人脸检测 + 关键点 + 表情分类 |
| 人脸识别 | XMEDIA_SVP_TASK_FACE_RECOGNITON | 3 | 人脸检测 + 关键点 + 特征提取 |
| 二阶段检测 | XMEDIA_SVP_TASK_RCNN | 2 | 初检测 + 精细化 |
| ADAS | XMEDIA_SVP_TASK_ADAS | 5 | 车+人+非机动车+车牌+车道线 |
| DMS | XMEDIA_SVP_TASK_DMS | 多个 | 人脸 + 疲劳 + 手机 + 香烟 |
| 车牌识别 | XMEDIA_SVP_TASK_PLATE | 多个 | 车牌检测 + 字符识别 |
| 车辆识别 | XMEDIA_SVP_TASK_VEHICLE | 多个 | 车辆检测 + 颜色/类型识别 |
6.3 输出类别
// 检测结果的目标类别枚举(xmedia_svp.h:62-89)
typedef enum {
XMEDIA_SVP_CLASS_TYPE_PERSON, // 人形
XMEDIA_SVP_CLASS_TYPE_FACE, // 人脸
XMEDIA_SVP_CLASS_TYPE_CAR, // 车辆
XMEDIA_SVP_CLASS_TYPE_PET, // 宠物
XMEDIA_SVP_CLASS_TYPE_HEAD, // 人头
XMEDIA_SVP_CLASS_TYPE_ELECTRIC_BICYCLE, // 电瓶车
XMEDIA_SVP_CLASS_TYPE_MASK, // 口罩
XMEDIA_SVP_CLASS_TYPE_BIKE, // 自行车
XMEDIA_SVP_CLASS_TYPE_BIKER, // 骑自行车的人
XMEDIA_SVP_CLASS_TYPE_MOTOR, // 摩托车
XMEDIA_SVP_CLASS_TYPE_MOTORER, // 骑摩托车的人
XMEDIA_SVP_CLASS_TYPE_TRICYCLE, // 三轮车
XMEDIA_SVP_CLASS_TYPE_TRICYCLER, // 骑三轮车的人
XMEDIA_SVP_CLASS_TYPE_FIREWORKS_FIRE, // 火焰
XMEDIA_SVP_CLASS_TYPE_FIREWORKS_SMOKE, // 烟雾
XMEDIA_SVP_CLASS_TYPE_PACKAGE, // 包裹
} xmedia_svp_class_type;7. 模型文件说明
7.1 模型文件格式
NPU 使用 .bin 格式的专用模型文件,命名规则:
gnn_<算法>_<输入分辨率>_<输入格式>_<版本号>_<日期>.bin示例:
gnn_person_detect_640x360_rgb888hwc_v0103_20251203.bin
│ │ │ │ │ │
│ │ │ │ │ └─ 日期:2025-12-03
│ │ │ │ └─ 版本:v01.03
│ │ │ └─ 输入格式:RGB888 HWC 排列
│ │ └─ 输入分辨率:640×360
│ └─ 功能:人形检测
└─ 前缀:GNN(通用神经网络)7.2 模型转换流程

注意:
.bin文件是经过量化和编译的 NPU 专用格式,无法直接用原始的.pt或.onnx文件推理。
8. 多模型级联示例
以人脸识别为例,展示多模型级联的使用方式:
// 人脸识别需要 3 个模型级联
xmedia_svp_modules modules[3];
// 模型 1:人脸检测(定位人脸位置)
modules[0].alg_type = XMEDIA_SVP_ALG_TYPE_FACE;
modules[0].load_mode = XMEDIA_SVP_MODEL_FILE;
modules[0].format = XMEDIA_SVP_INPUTDATA_FORMAT_RGB888;
modules[0].pathname = "./model/gnn_face_detect_640x360_rgb888hwc_v0103_20251209.bin";
// 模型 2:人脸关键点(定位 5 个面部特征点)
modules[1].load_mode = XMEDIA_SVP_MODEL_FILE;
modules[1].format = XMEDIA_SVP_INPUTDATA_FORMAT_RGB888;
modules[1].pathname = "./model/gnn_face_keypoint_48x48_rgb888hwc_v0101_20250818.bin";
// 模型 3:人脸特征提取(生成 512 维特征向量)
modules[2].load_mode = XMEDIA_SVP_MODEL_FILE;
modules[2].format = XMEDIA_SVP_INPUTDATA_FORMAT_RGB888;
modules[2].pathname = "./model/gnn_face_recognition_112x112_rgb888hwc_v0101_20250818.bin";
task_cfg.module_num = 3;
task_cfg.task_type = XMEDIA_SVP_TASK_FACE_RECOGNITON;
task_cfg.modules = modules;
// 创建任务
xmedia_svp_task_create(&handle, task_cfg);推理调用方式相同,SDK 内部自动完成级联:
// 推理调用与单模型完全一致
xmedia_svp_fr_output fr_output = {0};
ret = xmedia_svp_task_process(handle, &task_input, &fr_output);
// fr_output.face_num → 检测到的人脸数量
// fr_output.fr_result[i] → 每个人脸的 512 维特征向量 + 坐标9. 内存管理策略
9.1 内存复用模式
SDK 支持三种内存复用模式以节省内存:
typedef enum {
XMEDIA_SVP_MEM_TYPE_BLOCK, // 分块复用(推荐)
XMEDIA_SVP_MEM_TYPE_AINR_SHARE, // 与 AINR 共享
XMEDIA_SVP_MEM_TYPE_COMPLETE, // 完全独立
} xmedia_svp_mem_reuse_type;9.2 生命周期管理
应用启动
│
├── xmedia_svp_init() // 初始化 SVP
├── xmedia_cl_graph_query_model_info() // 查询内存需求
├── MMZ 分配 (work/input/output) // 分配物理连续内存
├── xmedia_svp_set_config() // 配置内存
├── xmedia_svp_task_create() // 创建任务(加载模型)
│
│ ┌── while 循环 ──────────────────┐
│ │ acquire_frame → task_process │ // 推理循环
│ │ → draw → venc → release_frame │
│ └────────────────────────────────┘
│
├── xmedia_svp_task_destroy() // 销毁任务(卸载模型)
├── MMZ 释放 (work/input/output) // 释放内存
└── xmedia_svp_uninit() // 反初始化 SVP9.3 MMZ 内存操作
// 分配物理连续内存
xmedia_u64 phy_addr = xmedia_mmz_alloc("mmz_name", "buf_name", size);
// 映射到用户空间虚拟地址
void *virt_addr = xmedia_mmz_map(phy_addr, size, cache_enabled);
// 访问内存(读写)
memcpy(virt_addr, src, size);
// 解除映射
xmedia_mmz_unmap(virt_addr);
// 释放物理内存
xmedia_mmz_free(phy_addr);10. 常见问题与调试
10.1 推理返回失败
| 错误现象 | 可能原因 | 解决方法 |
|---|---|---|
xmedia_svp_task_process 返回非 0 | 模型文件损坏或不存在 | 检查 .bin 文件路径和权限 |
| 推理偶发失败 | 帧获取超时 | 增大 milli_sec 超时时间 |
| 内存分配失败 | MMZ 空间不足 | 检查 mmz 配置,减小 buffer 大小 |
| 目标数为 0 | 置信度阈值过高 | 降低 detect_threshold |
10.2 性能调优
// 开启耗时统计(编译时定义 SAMPLE_TIME_DEBUG)
#define SAMPLE_TIME_DEBUG 1
// 推理耗时打印
TIME_COST_START();
xmedia_svp_task_process(handle, &input, &result);
TIME_COST_END();
TIME_COST_PRINT("svp process all");
// 输出示例: svp process all cost time: 25000 us10.3 YUV 文件离线测试
当没有摄像头时,可以使用 YUV 文件作为输入进行离线测试:
// 编译时定义 READ_YUV
#define READ_YUV
// 推理线程会自动从 ./yuv_dir/ 目录读取 .yuv 文件
// 文件分辨率需要与模型输入匹配(如 640×360 的 YUV420SP)10.4 OSD 文字叠加
需要在编译时定义 USE_OSD 宏,并链接 canvas 和 canvas_font 库:
#ifdef USE_OSD
xmedia_char text[64];
snprintf(text, sizeof(text), "id[%d] score[%.2f]", id, score);
sample_target_osd(&video_frame, x, y, text);
#endif11. API 速查表
11.1 SVP 生命周期 API
| API | 功能 | 调用时机 |
|---|---|---|
xmedia_svp_init() | 初始化 SVP 子系统 | 应用启动时,仅一次 |
xmedia_svp_uninit() | 反初始化 SVP | 应用退出时 |
xmedia_svp_set_config() | 设置 SVP 内存配置 | 创建任务前 |
xmedia_svp_get_config() | 获取 SVP 内存配置 | 分配内存前 |
xmedia_svp_task_create() | 创建推理任务 | 加载模型 |
xmedia_svp_task_destroy() | 销毁推理任务 | 卸载模型 |
xmedia_svp_task_set_attr() | 设置任务属性 | 创建后任意时间 |
xmedia_svp_task_get_attr() | 获取任务属性 | 任意时间 |
xmedia_svp_task_process() | 执行推理 | 循环调用 |
xmedia_svp_get_version() | 获取 SVP 版本 | 任意时间 |
11.2 帧管理 API
| API | 功能 |
|---|---|
xmedia_vpss_acquire_ochn_frame() | 从 VPSS 获取帧(阻塞等待) |
xmedia_vpss_release_ochn_frame() | 释放帧(归还缓冲池) |
xmedia_venc_send_frame() | 将帧送给编码器 |
11.3 绘制 API
| API | 功能 |
|---|---|
xmedia_vgs_init() | 初始化 VGS |
xmedia_vgs_create_job() | 创建 VGS 任务 |
xmedia_vgs_add_task_cover() | 添加画框任务 |
xmedia_vgs_add_task_line() | 添加画线任务 |
xmedia_vgs_add_task_osd() | 添加 OSD 叠加任务 |
xmedia_vgs_add_task_scale() | 添加缩放任务 |
xmedia_vgs_submit_job() | 提交 VGS 任务 |
xmedia_vgs_wait_job() | 等待 VGS 完成 |
xmedia_vgs_cancel_job() | 取消 VGS 任务 |
11.4 内存管理 API
| API | 功能 |
|---|---|
xmedia_mmz_alloc() | 分配物理连续内存 |
xmedia_mmz_map() | 映射到虚拟地址 |
xmedia_mmz_unmap() | 解除虚拟地址映射 |
xmedia_mmz_free() | 释放物理内存 |
附录:关键源文件索引
| 文件路径 | 说明 |
|---|---|
source/gmp/include/xmedia_svp.h | SVP API 定义(所有结构体和函数声明) |
sample/npu/demo_ai/sample_svp_main.c | SVP视频开发完整示例(主流程) |
sample/npu/demo_ai/sample_svp_main.h | 示例头文件(类型定义) |
source/gmp/usr/svp/src/post_process/yolov5.c | YOLOv5 后处理实现 |
source/gmp/usr/svp/src/post_process/yolov5.h | YOLOv5 后处理头文件 |
sample/npu/demo_ai/model/ | 模型文件目录 |
source/gmp/include/xmedia_mmz.h | MMZ 内存管理 API |
source/gmp/include/xmedia_vgs.h | VGS 图形绘制 API |
