应用开发参考
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模块的基本使用流程为:
-
MI_DIVP_CreateChn(u32DivpChn, &stDivpAttr)
-
MI_DIVP_StartChn(u32DivpChn)
-
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