MI IQSERVER API


REVISION HISTORY

Revision No.
Description
Date
3.0
  • Initial release
  • 12/04/2020
    3.1
  • Add note in SetDataPath
  • 04/09/2024

    1. 概述


    1.1. 模块说明

    IQSERVER(Image Quality tuning Server)图像质量调校服务,用来完成调校工具(IQTool)和开发板之间的数据通信,包括ISP参数设置,获取图像,上传/下载相关文件等功能。


    1.2. 基本结构

    • ISP

      Image Signal Processing 图像信号处理单元,负责图像降噪/颜色渲染/亮度调整等功能。

    • SCL

      Scale(缩放)。

    • VENC

      Video Encoder 视频编码器,负责将YUV序列编码成H264/H265/Jpeg等格式的视频流。


    1.3. 功能介绍

    MI_IQSERVER支持以下功能:

    • 支持IQ与ISP的参数设置。
    • 支持抓raw/yuv/jpg/raw stream。

    1.4. 应用场景

    IQSERVER可应用于以下场景:

    1. Pure linux场景

      在linux环境下,支持NetWork与IQTool连接调试。

    2. Pure rtos场景

      在rtos环境下,只支持UVC与IQTool连接调试。

    3. Dualos场景

      在dualos环境下,支持NetWork与IQTool连接调试。


    1.5. 工作原理

    IQSERVER有两种调用方式:

    • 第一种是Network的交互流程:

    • 第二种是UVC的交互流程(该流程Pcupid暂未支持):


    1.6. 开发流程

    1. 进入alkaid project根目录,make menuconfig

    2. 回车键进入Sdk Config子选项

    3. 回车键进入Interface Compile Config子选项

    4. 空格键选中iqserver子模块,并重新编译project

      编译完成将在sdk/interface/src/iqserver下生成 libmi_iqserver.a


    1.7. 实例介绍

    以vif_isp_scl串流demo为例

    • 需要在demo的makefile中导入iqserver的lib
      ifeq ($(PROG_ISPIQ_ENABLE), 1)
      INC  += ./internal/cus3a
      LIBS += -lmi_iqserver -lcus3a -lispalgo
      ifeq ($(NIR_SUPPORT), 1)
          LIBS +=  -lmi_nir
      endif
      endif
      
    void *ST_IQthread(void * args)
    {
    #if MI_ISPIQ_SUPPORT
        MI_ISP_DEV IspDevId = 0;
        MI_ISP_CHANNEL IspChnId = 0;
        char IqApiBinFilePath[ST_MAX_ISP_CHN_NUM][128];
        MI_SNR_PADID ePADId;
        ST_Sensor_Attr_t* pstSensorAttr = NULL;
        memset(IqApiBinFilePath, 0, sizeof(char)*128*ST_MAX_ISP_CHN_NUM);
        MI_IQSERVER_Open();
        while (!g_stIqResInfo.bThreadExit)
        {
            for(IspDevId=0; IspDevId<ST_MAX_ISP_DEV_NUM; IspDevId++)
            {
                ST_IspDevAttr_t *pstIspDevAttr= &gstIspModule.stIspDevAttr[IspDevId];
                if(pstIspDevAttr->bUsed == TRUE && pstIspDevAttr->bCreate == TRUE)
                {
                    for(IspChnId=0; IspChnId<ST_MAX_ISP_CHN_NUM; IspChnId++)
                    {
                        ST_IspChannelAttr_t  *pstIspChnAttr = &pstIspDevAttr->stIspChnlAttr[IspChnId];
                        if(pstIspChnAttr->bUsed == TRUE && pstIspChnAttr->bCreate == TRUE)
                        {
                            MI_ISP_IQ_Nr3dType_t stNR3D;
                            MI_ISP_IQ_ParamInitInfoType_t status;
                            //MI_ISP_ChnParam_t stIspChnParam;
                            MI_SNR_PlaneInfo_t stPlaneInfo;
                            char IqApiBinFilePath_tmp[128];
                            MI_S32 s32ret = MI_SUCCESS;
                            memset(&stNR3D,0x0,sizeof(MI_ISP_IQ_Nr3dType_t));
                            memset(&status,0x0,sizeof(MI_ISP_IQ_ParamInitInfoType_t));
                            //memset(&stIspChnParam,0x0,sizeof(MI_ISP_ChnParam_t));
                            memset(&stPlaneInfo,0x0,sizeof(MI_SNR_PlaneInfo_t));
                            memset(IqApiBinFilePath_tmp, 0, sizeof(char)*128);
                            s32ret = MI_ISP_IQ_GetParaInitStatus(IspDevId,IspChnId, &status);
                            if((s32ret == MI_SUCCESS && status.stParaAPI.bFlag != 1) || (s32ret != MI_SUCCESS))
                            {
                                continue;
                            }
                            s32ret = MI_ISP_IQ_GetNr3d(IspDevId, IspChnId, &stNR3D);
                            if(s32ret == MI_SUCCESS && stNR3D.bEnable == E_SS_IQ_FALSE)
                            {
                                stNR3D.bEnable = E_SS_IQ_TRUE;
                                printf("SET ISP dev %d, chn %d,NR3D status:%d, type:%d\n",IspDevId, IspChnId,stNR3D.bEnable, stNR3D.enOpType);
    
                                if(MI_SUCCESS != MI_ISP_IQ_SetNr3d(IspDevId, IspChnId, &stNR3D))
                                {
                                    DBG_ERR("isp dev%d chn%d set NR3D failed!! \n",IspDevId, IspChnId);
                                }
                            }
                            //MI_ISP_GetChnParam(IspDevId, IspChnId, &stIspChnParam);
                            ePADId = ST_GetFirstSensorPadId(pstIspChnAttr->u32SensorBindId);
                            pstSensorAttr = &gstSensorAttr[ePADId];
                            if(ePADId < ST_MAX_SENSOR_NUM && bUseUserSensor == FALSE && pstSensorAttr->bCreate)
                            {
                                MI_SNR_GetPlaneInfo(ePADId, 0, &stPlaneInfo);
                                sprintf(IqApiBinFilePath_tmp, "/config/iqfile/%s_api.bin", stPlaneInfo.s8SensorName);
                            }
    
                            if(pstIspChnAttr->IqCfgbin_Path[0] != '\0')
                            {
                                if(0!=strcmp(IqApiBinFilePath[IspChnId], pstIspChnAttr->IqCfgbin_Path))
                                {
                                    memcpy(IqApiBinFilePath[IspChnId], pstIspChnAttr->IqCfgbin_Path, sizeof(char)*128);
                                    printf("loading api bin...path:%s\n",IqApiBinFilePath[IspChnId]);
                                    MI_ISP_ApiCmdLoadBinFile(IspDevId, IspChnId, (char *)IqApiBinFilePath[IspChnId], 1234);
                                }
                            }
                            else
                            {
                                if(0!=strcmp(IqApiBinFilePath[IspChnId], IqApiBinFilePath_tmp))
                                {
                                    memcpy(IqApiBinFilePath[IspChnId], IqApiBinFilePath_tmp, sizeof(char)*128);
                                    printf("loading api bin...path:%s\n",IqApiBinFilePath[IspChnId]);
                                    MI_ISP_ApiCmdLoadBinFile(IspDevId, IspChnId, (char *)IqApiBinFilePath[IspChnId], 1234);
                                }
                            }
    
                        }
                    }
                }
            }
            usleep(THREAD_SLEEP_TIME_US*10);
        }
        MI_IQSERVER_Close();
    #endif
        return  NULL;
    }
    

    说明:以上实例对于使用者真正用到的部分是在串流完成之后调用MI_IQSERVER_Open()以及在串流关闭之后调用MI_IQSERVER_Close()即可,其余部分均为该MI_demo的串流流程。


    2. API 参考


    该功能模块提供以下 API:

    API名 功能
    MI_IQSERVER_Open 启动IQ server
    MI_IQSERVER_Close 关闭IQ server
    MI_IQSERVER_SetDataPath 设置IQ server数据存储路径
    MI_IQSERVER_SetCustFunc 设置IQ server的可执行自定义函数

    2.1. MI_IQSERVER_Open

    • 功能

      调用此接口启动IQ server。

    • 语法

      MI_S32 MI_IQSERVER_Open();
      
    • 返回值

      • MI_IQSERVER_OK, 启动IQ server成功。

      • 其它, 启动失败,详情参照错误码

    • 依赖

      • 头文件:mi_iqserver.h

      • 库文件:libmi_iqserver.a

    • 注意

      • IQ server只能调用一次
      • IQ server必须与ISP串流流程在同一个进程下
      • IQ server默认端口为9876
    • 举例

      /*declaration*/
      MI_S32 s32Ret = 0;
      /* open IQSERVER*/
      s32Ret = MI_IQSERVER_Open();
      if (MI_IQSERVER_OK != s32Ret)
      {
          Printf(“open iqserver error:%x\n”, s32Ret);
          return s32Ret;
      }
      
    • 相关主题

      MI_IQSERVER_Close


    2.2. MI_IQSERVER_Close

    • 功能

      调用此接口关闭IQ server。

    • 语法

      MI_ S32 MI_IQSERVER_Close();
      
    • 返回值

      • MI_IQSERVER_OK,成功关闭IQ server。

      • 其它, 关闭IQ server失败,详情参照错误码

    • 依赖

      • 头文件:mi_iqserver.h

      • 库文件:libmi_iqserver.a

    • 注意

      调用MI_IQSERVER_OpenMI_IQSERVER_Close 需要对应。

    • 举例

      /*declaration*/
      
      MI_S32 s32Ret = 0;
      
      /* close IQSERVER*/
      
      s32Ret = MI_IQSERVER_Close();
      
      if (MI_IQSERVER_OK != s32Ret)
      
      {
      
          Printf(“close iqserver error:%x\n”, s32Ret);
      
          return s32Ret;
      
      }
      
    • 相关主题

      MI_IQSERVER_Open


    2.3. MI_IQSERVER_SetDataPath

    • 功能

      设置IQ server的数据存储路径。

    • 语法

      MI_S32 MI_IQSERVER_SetDataPath(char* path);
      
    • 形参

      参数名称 描述 输入/输出
      path 路径字符串指针,末尾是\0。 输入
    • 返回值

      • MI_IQSERVER_OK,成功。

      • 其它,设置失败,详情参照错误码

    • 依赖

      • 头文件:mi_iqserver.h

      • 库文件:libmi_iqserver.a

    • 注意

      • 可以在MI_IQSERVER_Open 之前调用。

      • 调用前,请确认路径是否可访问,路径内是否有IQ server需要的数据资料。

      • IQ server通常需要读取的资料有:isp_api.xml(用于IQ Tool使用)。

      • isp_api.xml默认读取的是/config/iqfile路径,如果不是这个路径,就需要调用这个接口进行设置。

    • 举例

      /*declaration*/
      
          MI_S32 s32Ret = 0;
      
          char *data_path = “/customer/iqconfig/”;
      
      /* set IQSERVER data path*/
      
      s32Ret = MI_IQSERVER_SetDataPath(data_path);
      
      if (MI_IQSERVER_OK != s32Ret)
      
      {
      
          Printf(“set iqserver data path error:%x\n”, s32Ret);
      
          return s32Ret;
      
      }
      
    • 相关主题

      无。


    2.4. MI_IQSERVER_SetCustFunc

    • 功能

      设置IQ server的可执行的自定义函数,满足用户通过IQ Server调用自定义接口函数的目的。

    • 语法

      MI_S32 MI_IQSERVER_SetCustFunc(MI_S32(* func)(MI_U16 data_type, MI_U32     length, MI_U8 * data));
      
    • 形参

      参数名称 描述 输入/输出
      func 用户自定义的函数指针 输入
    • 返回值

      • MI_IQSERVER_OK,成功。

      • 其它,设置失败,详情参照错误码

    • 依赖

      • 头文件:mi_iqserver.h

      • 库文件:libmi_iqserver.a

    • 注意

      • 使用前,需要用户先实现自定义的func函数。函数参数如下:

        1. datatype: 表示data的类型,用户自定义,用来区分不同的data。

        2. length: 表示data的长度,IQ Tool会识别并自动填入该值。

        3. data: 表示data地址。

        在func内部可根据上述参数,做相关处理。

      • 可以添加用户自定义的函数功能实现, IQ server内部获取IQ Tool传入的数据,再调用用户传进来的函数func,这样在func里面就可以获取到IQ Tool的数据,实现客制化的功能。

        比如下面两项自定义功能:

        1. 通过IQ Tool传入固件,在func里面获取固件,然后烧写flash。

        2. 通过IQ Tool传入IR开关选项,在func里面切换IR。

      • 调用前,请确认函数指针func是否可执行。

      • Data_type和data数据通过IQ tool传入,length表示data的长度。

      • Data_type可以用来区分data的类型,这样func可以针对不同的类型实现不同的功能。

    • 举例

      /*declaration*/
      
          MI_S32 s32Ret = 0;
      
          MI_S32 sample_func(MI_U16 data_type, MI_U32 length, MI_U8 *data)
      
          {
      
              printf("call MI_IQSERVER_SetCustFunc() success\n");
      
              printf(“data_type is %d, length:%u, data addr:%p\n”, data_type, length,
              data);
      
              //do something
      
              return MI_IQSERVER_OK;
      
          }
      
      /* set IQSERVER custom function*/
      
      s32Ret = MI_IQSERVER_SetCustFunc(sample_func);
      
      if (MI_IQSERVER_OK != s32Ret)
      
      {
      
          Printf(“set iqserver cust func error:%x\n”, s32Ret);
      
          return s32Ret;
      
          }
      
    • 相关主题

      无。


    3. 错误码

    IQSERVER API 错误码如下所示。

    错误代码 宏定义 描述
    0XA02C2000 MI_ERR_IQSERVER_NOMEM 内存不足
    0XA02C2001 MI_ERR_IQSERVER_NOBUF Buffer不够
    0XA02C2002 MI_ERR_IQSERVER_CREATE_THREAD 线程创建失败
    0XA02C2003 MI_ERR_IQSERVER_INVALID_IQPATH IQ数据路径非法