SSD_SENSOR应用开发参考


1. 概述


1.1. 总体框架

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

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


1.2. 常用模块

简称 全称 功能职责
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传递如下图:

  • Input portbuffer是上一级输出的OutputportBuf;

  • 模块之间buffer的传递通过sys模块实现。

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

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

Frame mode的depth概念

特点:

  • YUV在模块使用时申请, 最大不超过QueueDepth的设定值, 当所有该YUV的消费者都使用完后立即释放。

  • QueueDepth如果设置太小,在CPU繁忙的时候可能会由于没有缓冲队列,而导致丢帧。

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

/* 
* BufQueueDepth:port能同时申请的最多buffer块数,默认为4; 
* UserFrameDepth: 用户能通过MI_SYS_ChnOutputPortGetBuf()同时取到的最多buffer块数; 
* BufQueueDepth >= UserFrameDepth; 
*/  
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模块

SNR(sensor)模块实现获取摄像头接口信息、调整分辨率和帧率的功能。

初始化流程:

// 设置plane mode  
MI_SNR_SetPlaneMode(eSnrPadId, true)  
// 查询sensor支持的分辨率  
MI_SNR_QueryResCount(eSnrPadId, &u32ResCount)  
// 查询index对应的分辨率参数  
for(u8ResIndex = 0; u8ResIndex < u32ResCount; u8ResIndex++)  
    MI_SNR_GetRes(eSnrPadId, u8ResIndex, &stRes)  
// 设置出图分辨率  
MI_SNR_SetRes(eSnrPadId, u8ChocieRes)  
// 设置sensor出图帧率  
MI_SNR_SetFps(eSnrPadId, SENSOR_FPS)  
// 使能sensor  
MI_SNR_Enable(eSnrPadId)  
// 查询当前出图分辨率  
MI_SNR_GetCurRes(eSnrPadId, &u8CurResIdx, &stCurRes)

2.2. VIF模块

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

/  
vifDev = (s32vifDev == 2) ? 1 : s32vifDev;  
vifChn = vifDev * 4;  
// 设置vif device属性  
MI_VIF_SetDevAttr(vifDev, &stDevAttr)  
// 使能vif device  
MI_VIF_EnableDev(vifDev)  
// 设置output port属性  
MI_VIF_SetChnPortAttr(VifChn, VifPort, &stChnPortAttr)  
// 使能output port  
MI_VIF_EnableChnPort(VifChn, VifPort)

2.3. VPE模块

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

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

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

VpeChannel = s32vifDev  
MI_VPE_SetChannelParam(VpeChannel, &stVpeChnParam)  
MI_VPE_CreateChannel(VpeChannel, &stChannelVpeAttr)  
MI_VPE_StartChannel(VpeChannel)  
MI_VPE_GetPortMode(VpeChannel, VpePort, &stVpeMode)  
// Change some parameter  
MI_VPE_SetPortMode(VpeChannel, VpePort, &stVpeMode)  
if(need crop)  
    MI_VPE_SetPortCrop(VpeChannel, VpePort, &stOutCropInfo)  
MI_SYS_SetChnOutputPortDepth(&stChnPort, 0, 5)  
MI_VPE_EnablePort(VpeChannel, VpePort)

2.4. DIVP模块

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

在同时开启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。

DISP模块流程框图为:

基本使用流程为:

DispDev = 0  
DispLayer = 0  
// Set disp pub attribute  
MI_DISP_SetPubAttr(DispDev,  &stPubAttr)  
MI_DISP_Enable(DispDev)  
// Set layer  
MI_DISP_BindVideoLayer(DispLayer,DispDev)  
MI_DISP_SetVideoLayerAttr(DispLayer, &stLayerAttr)  
MI_DISP_EnableVideoLayer(DispLayer)  
// Set input port attribute  
MI_DISP_SetInputPortAttr(DispLayer, u8DispInport, &stInputPortAttr)  
MI_DISP_EnableInputPort(DispLayer, u8DispInport)  
MI_DISP_SetInputPortSyncMode(DispLayer, u8DispInport, E_MI_DISP_SYNC_MODE_FREE_RUN)

2.6. PANEL模块

MI_PANEL_IntfType_e eLinkType = E_MI_PNL_INTF_TTL  
/* 如果是SPI屏需先给屏下发SPI参数! */  
MI_PANEL_Init(eLinkType)  
// 获取panel分辨率参数,给divp/disp使用  
MI_PANEL_GetPanelParam(eLinkType, &stParamCfg)

2.7. RGN模块

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

// init  
MI_RGN_Init()   // 传入调色板  
MI_RGN_Create()  
MI_RGN_AttachToChn()  
// get canvas  
MI_RGN_GetCanvasInfo()  
// Draw on canvas  
// Update canvas  
MI_RGN_UpdateCanvas()

2.8. IQSERVER

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

/* 
* width: Sensor输出分辨率宽度 
* height: Sensor输出分辨率高度 
* vpeChn: vpe通道号 
*/  
MI_IQSERVER_Open(width, height, vpeChn)

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


2.9. ISP模块

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

do  
{  
    MI_ISP_IQ_GetParaInitStatus(Vpechn,&bstatus)  
    if(bstatus.stParaAPI.bFlag != 1)  
    {  
        // 检查退出条件以免死循环  
        if(timeout)  
        {  
            break;  
        }  
        continue;  
    }  
    // pConfigPath为已调好的IQ参数文件路径  
    MI_ISP_API_CmdLoadBinFile(Vpechn, (char*)pConfigPath,  1234)  
}  
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的输出数据,基本代码流程如下:

MI_SYS_GetFd(&stChnPort, &s32Fd)  
MI_SYS_SetChnOutputPortDepth(&stDivpChnOutput, 1, 5)  
while(1)  
{  
        FD_ZERO(&read_fds);   
        FD_SET(s32Fd, &read_fds);  
        TimeoutVal.tv_sec  = 1;  
        TimeoutVal.tv_usec = 0;

        /*Waiting for frame*/  
        s32Ret = select(s32Fd + 1, &read_fds, NULL, NULL, &TimeoutVal);  
        if(s32Ret > 0 && FD_ISSET(s32Fd, &read_fds))  
        {  
            /* Get a frame from divp */  
            if(MI_SUCCESS  == MI_SYS_ChnOutputPortGetBuf(&stDivpChnOutput, &stBufInfo, &hHandle))  
            {  
            #if 0  
                if(stBufInfo.stFrameData.ePixelFormat == E_MI_SYS_PIXEL_FRAME_YUV_SEMIPLANAR_420)  
                {  
                    //memcpy(dstbuf, (char *)stBufInfo.stFrameData.pVirAddr[0], stBufInfo.stFrameData.u16Width * stBufInfo.stFrameData.u16Height * 3 >> 1);  
                }  
                else if((stBufInfo.stFrameData.ePixelFormat  == E_MI_SYS_PIXEL_FRAME_YUV422_YUYV))  
                {  
                    //memcpy(dstbuf, stBufInfo.stFrameData.pVirAddr[0], stBufInfo.stFrameData.u16Width * stBufInfo.stFrameData.u16Height * 2);  
                }

                else if((stBufInfo.stFrameData.ePixelFormat  == E_MI_SYS_PIXEL_FRAME_RGB565))  
                {  
                    //memcpy(dstbuf, (char *)stBufInfo.stFrameData.pVirAddr[0], stBufInfo.stFrameData.u16Width * stBufInfo.stFrameData.u16Height * 2);  
                }  
                else if(stBufInfo.stFrameData.ePixelFormat  == E_MI_SYS_PIXEL_FRAME_ARGB8888)  
                {  
                    //memcpy(dstbuf, (char *)stBufInfo.stFrameData.pVirAddr[0], stBufInfo.stFrameData.u16Width * stBufInfo.stFrameData.u16Height * 4);  
                }  
            #endif  
                /*Free frame*/  
                s32Ret = MI_SYS_ChnOutputPortPutBuf(hHandle);  
                if(s32Ret != MI_SUCCESS)  
                {  
                    ST_ERR("MI_SYS_ChnOutputPortPutBuf failed.s32Ret:0x%x !\n", s32Ret);  
                }

            }  
            else  
            {  
                ST_ERR("MI_SYS_ChnOutputPortGetBuf failed!\n");  
            }  
        }  
}  
MI_SYS_CloseFd(s32Fd)

3.3. RGN及FB绑定位置选择

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

比如:

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

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


4. 常用Debug信息

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

  • Sensor debug

  • Vpe debug

  • Divp debug

  • Venc debug