应用开发参考

Version 1.0


1. 总体框架

本文档仅描述各个模块的基本使用流程,详细的接口及参数描述请查阅各个模块的API手册。

软件的总体框架如下图,开发人员通过limmi_xxx.so库提供的接口来调用实际的硬件模块。

常用的基本模块

简称 全称 功能职责
SNR Sensor 获取摄像头接口信息、调整分辨率和帧率等功能
VIF Video Input interface MIPI/BT656信号采集模块,VIF支持预缩放功能以在特定的场景下减少系统频宽占用,一路Sensor视频输入,VIF可以同时输出一路源尺寸和一路缩放尺寸(¼)到DRAM上
VPE Video Process Engine 对视频数据进行缩放、裁剪、降噪、图像增强等
DIVP Deinterlace & Video Post Process Engine DIVP Engine主要有如下两个功能: 1、对Interlace的数据进行De处理; 2、对视频数据做Scale、Rotate等。
VENC Video Encoder H264/H265/MotionJpeg编码器,对输入的YUV数据进行编码处理,输出ES流
RGN Region Overlay&Cover RGN模块主要提供两个功能: 1、Overlay支持在VPE、DIVP上叠加,如OSD字幕; 2、Cover支持在VPE/DIVP上叠加遮挡区域。
IVE Intelligent Video Engine 提供图像智能识别算法中的基本算子支持
AI Audio Input Interface 音频数据采集模块,负责从Micro In采集音频数据
AO Audio Output Interface 音频数据输出模块,支持PCM格式音频输出到Lineout/IIS Out
IPU Intelligent Process Unit 图像智能处理单元,对接Artificial Intelligence网络模型

各个模块之间通过sys模块的bind接口串联起来,模块之间的buffer传递如下图:

由上图可以看到Bind有frame mode跟realtime mode两种模式

模式 特点 使用场景
Realtime mode 硬件直连,不占用DRAM内存 只有单sensor时可以使用
Frame mode 占用多张yuv内存。(由depth设置决定) 单/多sensor都可以使用

Frame mode的depth概念

可以通过如下接口设置模块输出口depth参数(如前文所述,模块Input port buffer是上一级输出的Output port buffer)

1. /* 
2.  * BufQueueDepth:port能同时申请的最多buffer块数,默认为4; 
3.  * UserFrameDepth:客户能通过MI_SYS_ChnOutputPortGetBuf()同时取到的最多buffer块数; 
4.  * BufQueueDepth >= UserFrameDepth; 
5. */  
6. MI_S32 MI_SYS_SetChnOutputPortDepth(MI_SYS_ChnPort_t *pstChnPort , MI_U32 u32UserFrameDepth , MI_U32 u32BufQueueDepth);

2. 基本模块介绍

以下所有的模块均依赖sys模块,在整个app的生命周期里必须且只能初始化一次MI_SYS_Init()。


2.1. Sensor模块

初始化流程:

1. // 设置plane mode  
2. MI_SNR_SetPlaneMode(eSnrPadId, true)  
3. // 查询sensor支持的分辨率  
4. MI_SNR_QueryResCount(eSnrPadId, &u32ResCount)  
5. // 查询index对应的分辨率参数  
6. for(u8ResIndex = 0; u8ResIndex < u32ResCount; u8ResIndex++)  
7.     MI_SNR_GetRes(eSnrPadId, u8ResIndex, &stRes)  
8. // 设置出图分辨率  
9. MI_SNR_SetRes(eSnrPadId, u8ChocieRes)  
10. // 设置sensor出图帧率  
11. MI_SNR_SetFps(eSnrPadId, SENSOR_FPS)  
12. // 使能sensor  
13. MI_SNR_Enable(eSnrPadId)  
14. // 查询当前出图分辨率  
15. MI_SNR_GetCurRes(eSnrPadId, &u8CurResIdx, &stCurRes)

2.2. VIF模块

VIF模块只有输出,没有输入,其基本使用流程为:

1. // SSA330 Sensor pad2与pad0是同一组mipi分出来的,pad2使用vifDev 1  
2. vifDev = (s32vifDev == 2) ? 1 : s32vifDev;  
3. vifChn = vifDev * 4;  
4. // 设置vif device属性  
5. MI_VIF_SetDevAttr(vifDev, &stDevAttr)  
6. // 使能vif device  
7. MI_VIF_EnableDev(vifDev)  
8. // 设置output port属性  
9. MI_VIF_SetChnPortAttr(VifChn, VifPort, &stChnPortAttr)  
10. // 使能output port  
11. MI_VIF_EnableChnPort(VifChn, VifPort)

2.3. VPE模块

VPE模块对一幅输入的图像首先进行图像质量调整,包括降噪,锐化,亮度调整等,然后再分别缩放到一定的分辨率通过各个output port 口输出。该模块另外包含HDR,旋转,裁剪等功能。

VPE单端输入多端输出,且不同芯片的处理流程不完全一致,从《MI_VPE_API》文档中可以找到SSA330芯片的VPE模块的处理逻辑如下图:

可以看到,且各个端口可以分别配置不同的功能,在使用时需根据内部处理的流程配置合适的参数,基本的使用流程如下:

1. VpeChannel = s32vifDev  
2. MI_VPE_SetChannelParam(VpeChannel, &stVpeChnParam)  
3. MI_VPE_CreateChannel(VpeChannel, &stChannelVpeAttr)  
4. MI_VPE_StartChannel(VpeChannel)  
5. MI_VPE_GetPortMode(VpeChannel, VpePort, &stVpeMode)  
6. // Change some parameter  
7. MI_VPE_SetPortMode(VpeChannel, VpePort, &stVpeMode)  
8. if(need crop)  
9.     MI_VPE_SetPortCrop(VpeChannel, VpePort, &stOutCropInfo)  
10. MI_SYS_SetChnOutputPortDepth(&stChnPort, 0, 5)  
11. MI_VPE_EnablePort(VpeChannel, VpePort)

2.4. DIVP模块

DIVP模块支持图像裁剪、图像像素格式转换、图像的旋转、图像的镜像操作以及图像的拉伸和缩放,单输入输出。不同芯片支持的功能不完全一致,从MI_DIVP_API中可以找到SSA330芯片的DIVP模块处理流程为:

SSA330芯片支持的输入输出图像格式及功能如下表格:

CLK 384Mhz
input base address 16 align
pixel format YUV422 NV12 RGB565 ARGB8888/ABRG8888
stride alignment 32 16 32 64
width alignment 2
height alignment 2
min size rotate:128x12
no rotate:32x4
max size 3840x3840
output pixel format YUV422 NV12 RGB565 ARGB8888/ABRG8888
stride alignment 32 16 32 64
width alignment 2
height alignment 2
min size rotate:16x2
no rotate:32x4
max size 3840x3840
rotate NV12/YUV422
input w/h:64 align
output w:16 align
output h:2 align
64 align
unsupport crop
unsupport scaling
unsupport mirror/flip
scaling H 6/V 4
crop x/y/w/h 2 align
mirror/flip H/V/HV
realtime mode unsupport

在同时开启DIVP的多个功能(crop、rotate、mirror等)时需注意以上处理逻辑的先后顺序,以免无法得到预期的结果。DIVP模块的基本使用流程为:

  1. MI_DIVP_CreateChn(u32DivpChn, &stDivpAttr)

  2. MI_DIVP_StartChn(u32DivpChn)

  3. MI_DIVP_SetOutputPortAttr(u32DivpChn, &stDivpOutputAttr)


2.5. DISP模块

DISP是一个视频显示单元,主要功能是对前端输出的图像做硬件拼图,并对硬件拼图后的图像进行颜色空间转换,最终通过HDMI/VGA/MIPI/TTL等接口输出到显示器或LCD。SSA330的DISP模块流程框图为:

基本使用流程为:

1. DispDev = 0

2. DispLayer = 0

3. // Set disp pub attribute

4. MI_DISP_SetPubAttr(DispDev,  &stPubAttr)

5. MI_DISP_Enable(DispDev)

6. // Set layer

7. MI_DISP_BindVideoLayer(DispLayer,DispDev)

8. MI_DISP_SetVideoLayerAttr(DispLayer, &stLayerAttr)

9. MI_DISP_EnableVideoLayer(DispLayer)

10. // Set input port attribute

11. MI_DISP_SetInputPortAttr(DispLayer, u8DispInport, &stInputPortAttr)

12. MI_DISP_EnableInputPort(DispLayer, u8DispInport)

13. MI_DISP_SetInputPortSyncMode(DispLayer, u8DispInport, E_MI_DISP_SYNC_MODE_FREE_RUN)

2.6. PANEL模块

1. MI_PANEL_IntfType_e eLinkType = E_MI_PNL_INTF_TTL

2. /* 如果是SPI屏需先给屏下发SPI参数! */

3. MI_PANEL_Init(eLinkType)

4. // 获取panel分辨率参数,给divp/disp使用

5. MI_PANEL_GetPanelParam(eLinkType, &stParamCfg)

2.7. RGN模块

RGN模块可以用于绘制OSD(时间、人脸框等)或区域遮盖,它可以贴在vpe或divp的output port上

1. // init  
2. MI_RGN_Init()   // 传入调色板  
3. MI_RGN_Create()  
4. MI_RGN_AttachToChn()  
5. // get canvas  
6. MI_RGN_GetCanvasInfo()  
7. // Draw on canvas  
8. // Update canvas  
9. MI_RGN_UpdateCanvas()

2.8. IQ Server

IQSERVER(Image Quality tuning Server)图像质量调节服务,用来完成调节工具(IQ Tool)和开发板之间的数据通信,包括ISP参数设置、获取图像、上传/下载相关文件等功能。在创建完vpe通道后调用OPEN接口即可。

1. /* 
2. * width: Sensor输出分辨率宽度 
3. * height: Sensor输出分辨率高度 
4. * vpeChn: vpe通道号 
5. */  
6. MI_IQSERVER_Open(width, height, vpeChn)

IQ Tool工具连接主板调节完参数后会生成一个IQ参数文件给用户app使用。


2.9. ISP模块

ISP模块是对Video source输入的数据进行分析、处理,设定相关视频参数以及进行Camera的调整,以实现黑电平校正、镜头校正、3A、2D/3D降噪、CCM、Gamma…等功能。一般情况下普通用户app只会用这个模块提供的接口来加载调好的IQ参数文件,加载流程如下:

1. do  
2. {  
3.     MI_ISP_IQ_GetParaInitStatus(Vpechn,&bstatus)  
4.     if(bstatus.stParaAPI.bFlag != 1)  
5.     {  
6.         // 检查退出条件以免死循环  
7.         if(timeout)  
8.         {  
9.             break;  
10.         }  
11.         continue;  
12.     }  
13.     // pConfigPath为已调好的IQ参数文件路径  
14.     MI_ISP_API_CmdLoadBinFile(Vpechn, (char*)pConfigPath,  1234)  
15. }  
16. while();

3. 双Sensor应用示例


3.1. 基本数据流

常见的用户场景为:两路sensor(RGB+IR)分别出图送到算法处理,同时通过RTSP出流。RGB Sensor送到LCD上显示。

添加一个switch用于支持切换lcd的显示内容,可切换显示sensor-0、sensor-1或黑屏(通过Inject Task注入黑色数据,为了在不出图的情况下正常显示GUI)

使用中如果divp不够用可以根据实际场景将crop/scale/rotate放到vpe0中处理,这边拆分到显示部分的divp中处理是为了去除接口耦合,以便用户能更灵活的配置“竖屏横用”或“横屏竖用”等场景。


3.2. DIVP抓图流程

通过sys模块接口获取到divp output port描述符,使用此接口读取divp的输出数据,基本代码流程如下:

1. MI_SYS_GetFd(&stChnPort, &s32Fd)  
2. MI_SYS_SetChnOutputPortDepth(&stDivpChnOutput, 1, 5)  
3. while(1)  
4. {  
5.         FD_ZERO(&read_fds);   
6.         FD_SET(s32Fd, &read_fds);  
7.         TimeoutVal.tv_sec  = 1;  
8.         TimeoutVal.tv_usec = 0;  
9.   
10.         /*Waiting for frame*/  
11.         s32Ret = select(s32Fd + 1, &read_fds, NULL, NULL, &TimeoutVal);  
12.         if(s32Ret > 0 && FD_ISSET(s32Fd, &read_fds))  
13.         {  
14.             /* Get a frame from divp */  
15.             if(MI_SUCCESS  == MI_SYS_ChnOutputPortGetBuf(&stDivpChnOutput, &stBufInfo, &hHandle))  
16.             {  
17.             #if 0  
18.                 if(stBufInfo.stFrameData.ePixelFormat == E_MI_SYS_PIXEL_FRAME_YUV_SEMIPLANAR_420)  
19.                 {  
20.                     //memcpy(dstbuf, (char *)stBufInfo.stFrameData.pVirAddr[0], stBufInfo.stFrameData.u16Width * stBufInfo.stFrameData.u16Height * 3 >> 1);  
21.                 }  
22.                 else if((stBufInfo.stFrameData.ePixelFormat  == E_MI_SYS_PIXEL_FRAME_YUV422_YUYV))  
23.                 {  
24.                     //memcpy(dstbuf, stBufInfo.stFrameData.pVirAddr[0], stBufInfo.stFrameData.u16Width * stBufInfo.stFrameData.u16Height * 2);  
25.                 }  
26.   
27.                 else if((stBufInfo.stFrameData.ePixelFormat  == E_MI_SYS_PIXEL_FRAME_RGB565))  
28.                 {  
29.                     //memcpy(dstbuf, (char *)stBufInfo.stFrameData.pVirAddr[0], stBufInfo.stFrameData.u16Width * stBufInfo.stFrameData.u16Height * 2);  
30.                 }  
31.                 else if(stBufInfo.stFrameData.ePixelFormat  == E_MI_SYS_PIXEL_FRAME_ARGB8888)  
32.                 {  
33.                     //memcpy(dstbuf, (char *)stBufInfo.stFrameData.pVirAddr[0], stBufInfo.stFrameData.u16Width * stBufInfo.stFrameData.u16Height * 4);  
34.                 }  
35.             #endif  
36.                 /*Free frame*/  
37.                 s32Ret = MI_SYS_ChnOutputPortPutBuf(hHandle);  
38.                 if(s32Ret != MI_SUCCESS)  
39.                 {  
40.                     ST_ERR("MI_SYS_ChnOutputPortPutBuf failed.s32Ret:0x%x !\n", s32Ret);  
41.                 }  
42.   
43.             }  
44.             else  
45.             {  
46.                 ST_ERR("MI_SYS_ChnOutputPortGetBuf failed!\n");  
47.             }  
48.         }  
49. }  
50. MI_SYS_CloseFd(s32Fd)

3.3. RGN及FB绑定位置选择

RGN及FB支持绑定到VPE或DIVP的输出口,从绑定位置起后续所有的数据流均带有绑定上去的数据,这意味着后续所有的对数据流的处理均会影响到绑定上去的内容。选择绑定位置的原则是根据输出口的属性(主要是分辨率参数)及数据流的影响范围确定一个最合适的位置。比如:

  • 通过RGN画人脸框,算法识别的是原始尺寸的图片,给的人脸框坐标必然也是基于原图计算出来的,要将人脸框显示到正确的位置的话那么就将RGN attach到vpe0的port2;

  • 在FB上画GUI,LCD竖屏横用的情况,FB应该绑定到divp2(for crop and scale)的output,因为这个输出口的图像就是实际显示到LCD上的图像,后续的rotate处理GUI也将同时旋转,以便获取预期的显示效果。


4. 常用Debug信息

在/proc/mi_modules/目录各个模块的子文件夹下可以查看当前运行的debug信息,如:

  • Sensor debug

  • Vpe debug

  • Divp debug

  • Venc debug