视频输入 (VI)
概述
本文档主要介绍VI的API和数据类型。
视频输入(VI)模块实现的功能:通过 MIPI Rx(含 MIPI 接口、LVDS 接口),BT.1120,BT.656,BT.601,DC 等接口接收视频数据。VI 将接收到的数据存入到指定的内存区域,实现视频数据的采集。
基本概念
DEV 设备
视频输入设备支持若干种时序输入,负责对时序进行解析。
PIPE 管道
视频输入 PIPE 绑定在设备后端,负责设备解析后的数据再处理。(目前暂未实现内容,采用直通方式,同 Dev 相同 id 设置即可)。
CHANNEL 通道
视频输入最后一级的获取通道,如 Dev 为 ISP 时输出有 3 个 channel。
CAC 色差纠正
CAC (Chromatic Aberration Correction)模块用于修正图像中的色差问题,色差通常由于透镜和光学元件的制造或设计不完美引起。通过调整颜色补偿系数微调图像中的不同颜色,以改善颜色准确性,从而提高整体图像质量,特别适用于消除边缘区域和高对比度区域的紫边。
功能描述
功能框图
VI 在软件层次上划分 3 个部分。
VI 从软件上划分了输入设备(Dev),输入 PIPE(采用 Dev 直通到 chn,暂未实现)、输出通道(channel)三个层级。
各芯片的设备、PIPE、通道个数差异如下所示:
| 芯片 | Dev | PIPE | channel |
|---|---|---|---|
| A210 | 4 | 4 | 3 |
说明:
例如 A210 支持 4 个 Dev 表示可以最大支持 4 路 sensor 输入,4 条 PIPE 对应 4 个 sensor,每条 PIPE 有 3 个 channel 输出。
VI 处理流程框图如下所示。

A210 VI 硬件处理流程框图如下所示。其中 A210 支持 ISP 多路输出。

注意:
如 VI 使用过程无赋值 aEntityName(参考 VI_ISP_OPT_S 结构体定义),则默认 chn0_out 对应mainpath,chn1_out 对应 selfpath,chn2_out 对应 fbcpath。多路 ISP 使用时建议通过
dev/pipe/channel使用默认定义。
各路输出分辨率限制如下表:
| aEntityName | name | max output | support output fmt |
|---|---|---|---|
| /dev/videox_pipe0 | zhisp_mainpath | 3840×2160, 最大支持 8 倍缩放 | RAW/NV12/NV16/YUYV/UYVY |
| /dev/videox_pipe1 | zhisp_selfpath1 | 19201080, 最大支持 8 倍缩放 | NV12/NV16/YUYV/UYVY |
| /dev/videox_pipe2 | zhisp_selfpath2 | 19201080, 最大支持 8 倍缩放 | NV12/NV16/YUYV/UYVY |
注意:
A210 支持的 4 条 PIPE 是分时复用一个 ISP 硬件,使用 4k@60fps 时仅支持一条 PIPE 运行。4 条 PIPE 运行时最大支持每条 PIPE 输出 1080p@30fps。
示例代码
TEST_VI_CTX_S *ctx;
ctx = reinterpret_cast<TEST_VI_CTX_S *>(malloc(sizeof(TEST_VI_CTX_S)));
memset(ctx, 0, sizeof(TEST_VI_CTX_S));
ctx->width = 1920;
ctx->height = 1080;
ctx->devId = 0;
ctx->pipeId = ctx->devId;
ctx->channelId = 1;
ctx->loopCountSet = 100;
//0. get dev config status
s32Ret = ZH_MPI_VI_GetDevAttr(ctx->devId, &ctx->stDevAttr);
if (s32Ret == ZH_ERR_VI_NOT_CONFIG) {
//0-1.config dev
s32Ret = ZH_MPI_VI_SetDevAttr(ctx->devId, &ctx->stDevAttr);
if (s32Ret != ZH_SUCCESS) {
ZH_LOGE("ZH_MPI_VI_SetDevAttr %x", s32Ret);
goto __FAILED1;
}
} else {
ZH_LOGE("ZH_MPI_VI_SetDevAttr already");
}
//1.get dev enable status
s32Ret = ZH_MPI_VI_GetDevIsEnable(ctx->devId);
if (s32Ret != ZH_SUCCESS) {
//1-2.enable dev
s32Ret = ZH_MPI_VI_EnableDev(ctx->devId);
if (s32Ret != ZH_SUCCESS) {
ZH_LOGE("ZH_MPI_VI_EnableDev %x", s32Ret);
goto __FAILED1;
}
//1-3.bind dev/pipe
ctx->stBindPipe.u32Num = ctx->pipeId;
ctx->stBindPipe.PipeId[0] = ctx->pipeId;
s32Ret = ZH_MPI_VI_SetDevBindPipe(ctx->devId, &ctx->stBindPipe);
if (s32Ret != ZH_SUCCESS) {
ZH_LOGE("ZH_MPI_VI_SetDevBindPipe %x", s32Ret);
goto __FAILED2;
}
} else {
ZH_LOGE("ZH_MPI_VI_EnableDev already");
}
//2.config channel
ctx->stChnAttr.stSize.u32Width = ctx->width;
ctx->stChnAttr.stSize.u32Height = ctx->height;
s32Ret = ZH_MPI_VI_SetChnAttr(ctx->pipeId, ctx->channelId, &ctx->stChnAttr);
if (s32Ret != ZH_SUCCESS) {
ZH_LOGE("ZH_MPI_VI_SetChnAttr %x", s32Ret);
goto __FAILED2;
}
//3.enable channel
s32Ret = ZH_MPI_VI_EnableChn(ctx->pipeId, ctx->channelId);
if (s32Ret != ZH_SUCCESS) {
ZH_LOGE("ZH_MPI_VI_EnableChn %x", s32Ret);
goto __FAILED2;
}
//4.save debug file
if (ctx->stDebugFile.bCfg) {
s32Ret = ZH_MPI_VI_ChnSaveFile(ctx->pipeId, ctx->channelId, &ctx->stDebugFile);
ZH_LOGE("ZH_MPI_VI_ChnSaveFile %x", s32Ret);
}
while (loopCount < ctx->loopCountSet) {
//5.get the frame
s32Ret = ZH_MPI_VI_GetChnFrame(ctx->pipeId, ctx->channelId, &ctx->stViFrame, waitTime);
if (s32Ret == ZH_SUCCESS) {
void *data = ZH_MPI_MB_Handle2VirAddr(ctx->stViFrame.pMbBlk);
//6.get the channel status
s32Ret = ZH_MPI_VI_QueryChnStatus(ctx->pipeId, ctx->channelId, &ctx->stChnStatus);
//7.release the frame
s32Ret = ZH_MPI_VI_ReleaseChnFrame(ctx->pipeId, ctx->channelId, &ctx->stViFrame);
if (s32Ret != ZH_SUCCESS) {
ZH_LOGE("ZH_MPI_VI_ReleaseChnFrame fail %x", s32Ret);
}
loopCount++;
} else {
ZH_LOGE("ZH_MPI_VI_GetChnFrame timeout %x", s32Ret);
}
usleep(10*1000);
}
//8. disable one chn
s32Ret = ZH_MPI_VI_DisableChn(ctx->pipeId, ctx->channelId);
ZH_LOGE("ZH_MPI_VI_DisableChn %x", s32Ret);
//9.disable dev(will disabled all chn)
__FAILED2:
s32Ret = ZH_MPI_VI_DisableDev(ctx->devId);
ZH_LOGE("ZH_MPI_VI_DisableDev %x", s32Ret);
详细测试 DEMO,请参考发布文件: test_mpi_vi.cpp。
API 参考
该功能模块为用户提供以下 API:
- ZH_MPI_VI_SetDevAttr:设置 VI 设备属性。
- ZH_MPI_VI_GetDevAttr:获取 VI 设备属性。
- ZH_MPI_VI_EnableDev:启用 VI 设备。
- ZH_MPI_VI_DisableDev:禁用 VI 设备。
- ZH_MPI_VI_SetDevBindPipe:绑定 dev 和 PIPE。
- ZH_MPI_VI_GetDevBindPipe:获取 dev 绑定的 PIPE 属性。
- ZH_MPI_VI_GetDevIsEnable:获取 VI 设备是否使能。
- ZH_MPI_VI_SetChnAttr:设置 VI 通道属性。
- ZH_MPI_VI_GetChnAttr:获取 VI 通道属性。
- ZH_MPI_VI_EnableChn:启用 VI 通道。
- ZH_MPI_VI_DisableChn:禁用 VI 通道。
- ZH_MPI_VI_PauseChn:暂停指定 VI 通道的数据流。
- ZH_MPI_VI_ResumeChn:恢复指定 VI 通道的数据流。
- ZH_MPI_VI_GetChnFrame:获取 VI 通道一帧数据。
- ZH_MPI_VI_ReleaseChnFrame:释放 VI 通道一帧数据。
- ZH_MPI_VI_ChnSaveFile:保存 VI 通道数据。
- ZH_MPI_VI_QueryChnStatus:获取 VI 通道状态。
- ZH_MPI_VI_GetChnFd:获取 VI 通道对应的设备文件句柄。
- ZH_MPI_VI_CloseChnFd:关闭 VI 通道对应的设备文件句柄。
- ZH_MPI_VI_SetChnFreeze:设置 VI 通道视频输出冻结。
- ZH_MPI_VI_GetChnFreeze:获取 VI 通道视频输出冻结。
- ZH_MPI_VI_RegChnEventCallBack:注册 VI 通道事件回调接口。
- ZH_MPI_VI_SetSwcacConfig:设置 VI 通道的 CAC 配置信息。
- ZH_MPI_VI_GetSwcacConfig:获取 VI 通道的 CAC 配置信息。
ZH_MPI_VI_SetDevAttr
描述
设置 VI 设备参数。
语法
ZH_S32 ZH_MPI_VI_SetDevAttr(VI_DEV ViDev, const VI_DEV_ATTR_S *pstDevAttr);
参数
| 参数名 | 数据类型 | 描述 | 输入/输出 |
|---|---|---|---|
| ViDev | VI_DEV | VI 设备号。取值范围:[0,VI_MAX_DEV_NUM)。 | 输入 |
| pstDevAttr | const VI_DEV_ATTR_S* | VI 设备属性。静态属性。 | 输入 |
返回值
| 返回值 | 描述 |
|---|---|
| 0 | 成功。 |
| 非 0 | 失败,请参见 VI 错误码。 |
注意事项
同一个进程在设置设备属性之前需要先查询 VI 的属性是否已经设置过,同一个进程只能设置一次属性,如果要重新设置需要先禁用后再重新设置。
ZH_MPI_VI_GetDevAttr
描述
获取 VI 设备属性。
语法
ZH_S32 ZH_MPI_VI_GetDevAttr(VI_DEV ViDev, VI_DEV_ATTR_S *pstDevAttr);
参数
| 参数名 | 数据类型 | 描述 | 输入/输出 |
|---|---|---|---|
| ViDev | VI_DEV | VI 设备号。取值范围:[0,VI_MAX_DEV_NUM)。 | 输入 |
| pstDevAttr | VI_DEV_ATTR_S* | VI 设备属性。 | 输出 |
返回值
| 返回值 | 描述 |
|---|---|
| 0 | 成功。 |
| 非 0 | 失败,请参见 VI 错误码。 |
注意事项
- 获取的属性为前一次配置的属性。
- 如果从未配置过属性,则返回属性未配置的错误。
ZH_MPI_VI_EnableDev
描述
启用 VI 设备。
语法
ZH_S32 ZH_MPI_VI_EnableDev(VI_DEV ViDev);
参数
| 参数名 | 数据类型 | 描述 | 输入/输出 |
|---|---|---|---|
| ViDev | VI_DEV | VI 设备号。取值 范围:[0,VI_MAX_DEV_NUM)。 | 输入 |
返回值
| 返回值 | 描述 |
|---|---|
| 0 | 成功。 |
| 非 0 | 失败,请参见 VI 错误码。 |
注意事项
- 要求在启用前配置 VI 设备属性,否则会返回属性未配置的错误。
- 如果 VI 设备已经启用,重复启用,则返回正在使用中的错误。
ZH_MPI_VI_DisableDev
描述
禁用 VI 设备。
语法
ZH_S32 ZH_MPI_VI_DisableDev(VI_DEV ViDev);
参数
| 参数名 | 数据类型 | 描述 | 输入/输出 |
|---|---|---|---|
| ViDev | VI_DEV | VI 设备号。取值范围:[0,VI_MAX_DEV_NUM] | 输入 |
返回值
| 返回值 | 描述 |
|---|---|
| 0 | 成功。 |
| 非 0 | 失败,请参见 VI 错误码。 |
注意事项
- 如果 VI 设备未启用,则返回未启用的 VI 错误码。
- 禁用 VI 设备会禁用设备下所有 VI 通道。如果只有关闭一个通道,调用关闭通道函数即可。
ZH_MPI_VI_SetDevBindPipe
描述
设置 VI 设备与 PIPE 的绑定关系。
语法
ZH_S32 ZH_MPI_VI_SetDevBindPipe(VI_DEV ViDev, const VI_DEV_BIND_PIPE_S *pstDevBindPipe);
参数
| 参数名 | 数据类型 | 描述 | 输入/输出 |
|---|---|---|---|
| ViDev | VI_DEV | VI 设备号。取值范围:[0,VI_MAX_DEV_NUM)。 | 输入 |
| pstDevBindPipe | const VI_DEV_BIND_PIPE_S* | 绑定到 Dev 的 PIPE 信息的结构体指针。静态属性。 | 输入 |
返回值
| 返回值 | 描述 |
|---|---|
| 0 | 成功。 |
| 非 0 | 失败,请参见 VI 错误码。 |
注意事项
- 必须先使能 VI 设备后才能绑定 PIPE。
- 不支持动态绑定。
ZH_MPI_VI_GetDevBindPipe
描述
获取 VI 设备与 PIPE 的绑定关系。
语法
ZH_S32 ZH_MPI_VI_GetDevBindPipe(VI_DEV ViDev, VI_DEV_BIND_PIPE_S *pstDevBindPipe);
参数
| 参数名 | 数据类型 | 描述 | 输入/输出 |
|---|---|---|---|
| ViDev | VI_DEV | VI 设备号。取值范围:[0,VI_MAX_DEV_NUM)。 | 输入 |
| pstDevBindPipe | VI_DEV_BIND_PIPE_S* | 绑定到 Dev 的 PIPE 信息的结构体指针。 | 输出 |
返回值
| 返回值 | 描述 |
|---|---|
| 0 | 成功。 |
| 非 0 | 失败,请参见 VI 错误码。 |
注意事项
使用本接口前,需先配置 DEV 属性,使能设备并绑定设备跟 PIPE,否则返回失败。
ZH_MPI_VI_GetDevIsEnable
描述
获取设备是否使能。
语法
ZH_S32 ZH_MPI_VI_GetDevIsEnable(VI_DEV ViDev);
参数
| 参数名 | 数据类型 | 描述 | 输入/输出 |
|---|---|---|---|
| ViDev | VI_DEV | VI 设备号。取值范围:[0,VI_MAX_DEV_NUM)。 | 输入 |
返回值
| 返回值 | 描述 |
|---|---|
| 0 | 已经使能。 |
| 非 0 | 未使能。 |
ZH_MPI_VI_SetChnAttr
描述
设置 VI 通道属性。
语法
ZH_S32 ZH_MPI_VI_SetChnAttr(VI_PIPE ViPipe, VI_CHN ViChn, const VI_CHN_ATTR_S *pstChnAttr);
参数
| 参数名 | 数据类型 | 描述 | 输入/输出 |
|---|---|---|---|
| ViPipe | VI_PIPE | VI PIPE 号。取值范围:[0,VI_MAX_PIPE_NUM)。 | 输入 |
| ViChn | VI_CHN | VI 通道号。取值范围:[0,VI_MAX_CHN_NUM)。 | 输入 |
| pstChnAttr | const VI_CHN_ATTR_S* | VI 通道属性结构体指针。静态属性。 | 输入 |
返回值
| 返回值 | 描述 |
|---|---|
| 0 | 成功。 |
| 非 0 | 失败,请参见 VI 错误码。 |
注意事项
通道属性的各项配置限制如下:
| 配置 | 限制 |
|---|---|
| 目标图像大小 stSize | 必须配置,且大小需要在 VI 支持的范围内且不超过 VI 的缩放倍数限制。 |
| 通道 buff 类型 enBufType |
|
| 采集数据选项 stIspOpt | 当采 集的数据为 ISP 输入或者直通时,需要配置:
|
| PIPE | PIPE 必须已绑定到设备,否则会返回失败。 |
ZH_MPI_VI_GetChnAttr
描述
获取 VI 通道属性。
语法
ZH_S32 ZH_MPI_VI_GetChnAttr(VI_PIPE ViPipe, VI_CHN ViChn, VI_CHN_ATTR_S *pstChnAttr);
参数
| 参数名 | 数据类型 | 描述 | 输入/输出 |
|---|---|---|---|
| ViPipe | VI_PIPE | VI PIPE 号 。取值范围:[0,VI_MAX_PIPE_NUM)。 | 输入 |
| ViChn | VI_CHN | VI 通道号。取值范围:[0,VI_MAX_CHN_NUM)。 | 输入 |
| pstChnAttr | VI_CHN_ATTR_S* | VI 通道属性结构体指针。静态属性。 | 输入 |
返回值
| 返回值 | 描述 |
|---|---|
| 0 | 成功。 |
| 非 0 | 失败,请参见 VI 错误码。 |
注意事项
- 启用 VI 通道前,必须先启用其所属的 VI 设备,否则返回设备未启动的 VI 错误码。
- 通道属性需先设置后才可获取。
ZH_MPI_VI_EnableChn
描述
启用 VI 通道。
语法
ZH_S32 ZH_MPI_VI_EnableChn(VI_PIPE ViPipe, VI_CHN ViChn);
参数
| 参数名 | 数据类型 | 描述 | 输入/输出 |
|---|---|---|---|
| ViPipe | VI_PIPE | VI PIPE 号。取值范围:[0,VI_MAX_PIPE_NUM)。 | 输入 |
| ViChn | VI_CHN | VI 通道号。取值范围:[0,VI_MAX_CHN_NUM)。 | 输入 |
返回值
| 返回值 | 描述 |
|---|---|
| 0 | 成功。 |
| 非 0 | 失败,请参见 VI 错误码。 |
注意事项
启用 VI 通道前,必须先启用其所属的 VI 设备,否则返回设备未启动的 VI 错误码。
ZH_MPI_VI_DisableChn
描述
禁用 VI 通道。
语法
ZH_S32 ZH_MPI_VI_DisableChn(VI_PIPE ViPipe, VI_CHN VIChn);
参数
| 参数名 | 数据类型 | 描述 | 输入/输出 |
|---|---|---|---|
| ViPipe | VI_PIPE | VI PIPE 号。取值范围:[0,VI_MAX_PIPE_NUM)。 | 输入 |
| ViChn | VI_CHN | VI 通道号。取值范围:[0,VI_MAX_CHN_NUM)。 | 输入 |
返回值
| 返回值 | 描述 |
|---|---|
| 0 | 成功。 |
| 非 0 | 失败,请参见 VI 错误码。 |
注意事项
PIPE 必须已绑定设备,否则会返回失败。
ZH_MPI_VI_PauseChn
描述
暂停指定 VI 通道的数据流。
语法
ZH_S32 ZH_MPI_VI_PauseChn(VI_PIPE ViPipe, VI_CHN VIChn);
参数
| 参数名 | 数据类型 | 描述 | 输入/输出 |
|---|---|---|---|
| ViPipe | VI_PIPE | VI PIPE 号。取值范围:[0,VI_MAX_PIPE_NUM)。 | 输入 |
| ViChn | VI_CHN | VI 通道号。取值范围:[0,VI_MAX_CHN_NUM)。 | 输入 |
返回值
| 返回值 | 描述 |
|---|---|
| 0 | 成功。 |
| 非 0 | 失败,请参见 VI 错误码。 |
注意事项
PIPE 必须已绑定设备,否则会返回失败。
ZH_MPI_VI_ResumeChn
描述
恢复指定 VI 通道的数据流 。
语法
ZH_S32 ZH_MPI_VI_ResumeChn(VI_PIPE ViPipe, VI_CHN VIChn);
参数
| 参数名 | 数据类型 | 描述 | 输入/输出 |
|---|---|---|---|
| ViPipe | VI_PIPE | VI PIPE 号。取值范围:[0,VI_MAX_PIPE_NUM)。 | 输入 |
| ViChn | VI_CHN | VI 通道号。取值范围:[0,VI_MAX_CHN_NUM)。 | 输入 |
返回值
| 返回值 | 描述 |
|---|---|
| 0 | 成功。 |
| 非 0 | 失败,请参见 VI 错误码。 |
注意事项
PIPE 必须已绑定设备,否则会返回失败。
ZH_MPI_VI_GetChnFrame
描述
从 VI 通道获取采集的图像。
语法
ZH_S32 ZH_MPI_VI_GetChnFrame(VI_PIPE ViPipe, VI_CHN ViChn, VIDEO_FRAME_INFO_S *pstFrameInfo, ZH_S32 s32MilliSec);
参数
| 参数名 | 数据类型 | 描述 | 输入/输出 |
|---|---|---|---|
| ViPipe | VI_PIPE | VI PIPE 号。取值范围:[0,VI_MAX_PIPE_NUM)。 | 输入 |
| ViChn | VI_CHN | VI 通道号。取值范围:[0,VI_MAX_CHN_NUM)。 | 输入 |
| pstFrameInfo | VIDEO_FRAME_INFO_S* | 输出图像的帧信息结构指针。 | 输入 |
| s32MilliSec | ZH_S32 | 获取数据的超时时间。
| 输入 |
返回值
| 返回值 | 描述 |
|---|---|
| 0 | 成功。 |
| 非 0 | 失败,请参见 VI 错误码。 |
注意事项
- PIPE 必须已绑定设备,否则会返回失败。
- s32MilliSec 的值必须大于等于 -1,等于 -1 时采用阻塞模式发送数据,等于 0 时采用非阻塞模式发送数据,大于 0 时,阻塞 s32MilliSec 毫秒后,则返回超时并报错。
- 获取的缓存信息来自 VI 内部使用的 MediaBuffer,因此使用完之后,必须要调用 ZH_MPI_VI_ReleaseChnFrame 接口释放其内存。
- 如果通过 ZH_MPI_SYS_Bind 将 VI 绑定到了其他设备,需要设置 VI_CHN_ATTR_S 的 u32Depth 大于0,否则此接口将获取不到数据。
ZH_MPI_VI_ReleaseChnFrame
描述
释放一帧从 VI 通道获取的图像。
语法
ZH_S32 ZH_MPI_VI_ReleaseChnFrame(VI_PIPE ViPipe, VI_CHN ViChn, const VIDEO_FRAME_INFO_S *pstFrameInfo);
参数
| 参数名 | 数据类型 | 描述 | 输入/输出 |
|---|---|---|---|
| ViPipe | VI_PIPE | VI PIPE 号。取值范围:[0,VI_MAX_PIPE_NUM)。 | 输入 |
| ViChn | VI_CHN | VI 通道号。取值范围:[0,VI_MAX_CHN_NUM)。 | 输入 |
| pstFrameInfo | const VIDEO_FRAME_INFO_S* | 输出图像的帧信息结构指针。 | 输入 |
返回值
| 返回值 | 描述 |
|---|---|
| 0 | 成功。 |
| 非 0 | 失败,请参见 VI 错误码。 |
注意事项
- PIPE 必须已绑定设备,否则会返回失败。
- 此接口必须与 ZH_MPI_VI_GetChnFrame 配对使用。
ZH_MPI_VI_ChnSaveFile
描述