MI VDISP API


REVISION HISTORY

Revision No.
Description
Date
2.03
  • Initial release
  • 04/12/2018
    2.04
  • Update statement
  • 2.05
  • Update base on new architecture
  • 10/29/2019
    2.06
  • Fix errors and format
  • 01/13/2020
    2.07
  • Add API: MI_VDISP_InitDev and MI_VDISP_DeInitDev
  • 04/26/2020
  • Add PROCFS Introduction
  • 08/25/2021
    2.08
  • Add figure title
  • Fix hyperlinks
  • Add error code value
  • 10/26/2021

    1. 概述

    1.1. 模块说明

    VDISP(virtual display)模块设计用来组合多份YUV/RGB等颜色空间的数据成一张全幅输出,并为每一个数据输入指定一个缩略图形式的显示窗口。特定缩略图窗口支持区域重叠。

    一个典型的VDISP应用场景:

    图1-1 VDISP典型应用场景

    如图1-1所示:

    • vdec采用3路channel输出3路数据给VDISP做拼图,绿色通道、黄色通道和蓝色通道,普通通道预览窗口不支持叠加,绿色通道为overlay 通道,overlay通道会叠加到所有普通通道之上。

    • vdisp接收3路vdec数据,2路普通通道(黄色,蓝色),一路overlay通道(绿色),做拼图,完成之后给disp输出到VGA。

    • disp接收vdisp的数据,用VGA信号输出。

    1.2. 模块框图

    VDISP特别之处在于Input/Output Buffer是同一块,前一级模块通过Stride Write的方式直接写入Output Buffer的对应位置来实现最终的拼接效果,理论上可以实现零内存拷贝。

    图1-2 VDISP buffer queue流程图

    1.3. 约束

    • 输入通道的起始横坐标(u32OutX)有对齐的需求,但是对齐的具体值取决于接入VDISP的前端模块,因为硬件元件读写内存通常有地址的对齐需求,否则会引起最终输出花边等异常。通常情况下至少需要8对齐,推荐16。

    • 目前支持2种输入数据格式:

      E_MI_SYS_PIXEL_FRAME_YUV_SEMIPLANAR_420

      E_MI_SYS_PIXEL_FRAME_YUV_SEMIPLANAR_422

    • 目前只支持固定帧率输出:参见MI_VDISP_OutputPortAttr_t的参数u32FrmRate。

    • VDISP 模块目前不支持:**格式转换/裁剪/缩放**等功能。

    • 参见更多的规格参数


    2. API 参考

    该功能模块提供以下API:

    API名 功能
    MI_VDISP_Init 模块初始化
    MI_VDISP_Exit 模块去初始化
    MI_VDISP_OpenDevice 打开一个VDISP虚拟设备
    MI_VDISP_CloseDevice 关闭一个VDISP虚拟设备
    MI_VDISP_SetOutputPortAttr 设置输出port属性
    MI_VDISP_GetOutputPortAttr 获取输出port属性
    MI_VDISP_SetInputChannelAttr 设置输入通道属性
    MI_VDISP_GetInputChannelAttr 获取输入通道属性
    MI_VDISP_EnableInputChannel 使能一个输入通道
    MI_VDISP_DisableInputChannel 关闭一个输入通道
    MI_VDISP_StartDev 开始VDISP设备的工作
    MI_VDISP_StopDev 停止VDISP设备工作
    MI_VDISP_InitDev 初始化VDISP设备
    MI_VDISP_DeInitDev 反初始化VDISP设备

    2.1. MI_VDISP_Init

    • 描述

      初始化vdisp模块,打开vdisp模块依赖模块,申请并初始模块内部的全局数据。

    • 语法

      MI_S32 MI_VDISP_Init (void);
      
    • 返回值

      • 0:成功。

      • 非0:失败,参照错误码

    • 依赖

      • 头文件:mi_vdisp.h, mi_vdisp_datatype.h

      • 库文件:libmi_vdisp.a(so)

    • 注意

      对vdisp执行任何操作之前,先调用本函数初始化vdisp模块。

    • 相关主题

      MI_VDISP_Exit

    2.2. MI_VDISP_Exit

    • 描述

      退出vdisp模块,关闭vdisp模块依赖模块,析构模块内部的全局数据。

    • 语法

      MI_S32 MI_VDISP_Exit (void);
      
    • 返回值

      • 0:成功。

      • 非0:失败,参照错误码

    • 依赖

      • 头文件:mi_vdisp.h, mi_vdisp_datatype.h

      • 库文件:libmi_vdisp.a(so)

    • 相关主题

      MI_VDISP_Init

    2.3. MI_VDISP_OpenDevice

    • 描述

      初始化vdisp虚拟设备,向sys注册本虚拟设备,用以和其它模块绑定。

    • 语法

      MI_S32 MI_VDISP_OpenDevice(MI_VDISP_DEV DevId)
      
    • 参数

      参数名称 描述 输入/输出
      DevId 本参数指定要打开的虚拟设备ID。
      [0, VDISP_MAX_DEVICE_NUM),见规格参数
      输入
    • 返回值

      • 0:成功。

      • 非0:失败,参照错误码

    • 依赖

      • 头文件:mi_vdisp.h, mi_vdisp_datatype.h

      • 库文件:libmi_vdisp.a(so)

    • 注意

      调用本函数前,先使用MI_VDISP_Init初始化vdisp模块。

    2.4. MI_VDISP_CloseDevice

    • 描述

      关闭vdisp虚拟设备,向sys解注册本虚拟设备,不能绑定其它模块。

    • 语法

      MI_S32 MI_VDISP_CloseDevice(MI_VDISP_DEV DevId);
      
    • 参数

      参数名称 描述 输入/输出
      DevId 本参数指定要关闭的虚拟设备ID。
      [0, VDISP_MAX_DEVICE_NUM),见规格参数
      输入
    • 返回值

      • 0:成功。

      • 非0:失败,参照错误码

    • 依赖

      • 头文件:mi_vdisp.h, mi_vdisp_datatype.h

      • 库文件:libmi_vdisp.a(so)

    • 注意

      调用本函数前,先使用MI_VDISP_StopDev停止对应的设备。

    2.5. MI_VDISP_SetOutputPortAttr

    • 描述

      设置该vdisp虚拟设备output port的参数。

    • 语法

      MI_S32 MI_VDISP_SetOutputPortAttr(MI_VDISP_DEV DevId, MI_VDISP_PORT PortId,MI_VDISP_OutputPortAttr_t *pstOutputPortAttr);
      
    • 参数

      参数名称 描述 输入/输出
      DevId 目标output port所属vdisp虚拟设备的ID。
      [0, VDISP_MAX_DEVICE_NUM),见规格参数
      输入
      PortId 目标output port的port ID。
      [0, VDISP_MAX_INPUTPORT_NUM),见规格参数
      输入
      pstOutputPortAttr 目标outputport的配置参数指针。
      MI_VDISP_OutputPortAttr_t
      输入
    • 返回值

      • 0:成功。

      • 非0:失败,参照错误码

    • 依赖

      • 头文件:mi_vdisp.h, mi_vdisp_datatype.h

      • 库文件:libmi_vdisp.a(so)

    • 注意

      调用本函数前,先使用MI_VDISP_OpenDevice打开对应的vdisp设备。

    2.6. MI_VDISP_GetOutputPortAttr

    • 描述

      获取该vdisp虚拟设备output port的参数。

    • 语法

      MI_S32 MI_VDISP_GetOutputPortAttr(MI_VDISP_DEV DevId, MI_VDISP_PORT PortId,MI_VDISP_OutputPortAttr_t *pstOutputPortAttr);
      
    • 参数

      参数名称 描述 输入/输出
      DevId 目标output port所属vdisp虚拟设备的ID。
      [0, VDISP_MAX_DEVICE_NUM),见规格参数
      输入
      PortId 目标output port的port ID。
      [0, VDISP_MAX_INPUTPORT_NUM),见规格参数
      输入
      pstOutputPortAttr 目标outputport的配置参数指针。
      MI_VDISP_OutputPortAttr_t
      输出
    • 返回值

      • 0:成功。

      • 非0:失败,参照错误码

    • 依赖

      • 头文件:mi_vdisp.h, mi_vdisp_datatype.h

      • 库文件:libmi_vdisp.a(so)

    • 注意

      调用本函数前,先使用MI_VDISP_OpenDevice打开对应的vdisp设备。

    2.7. MI_VDISP_SetInputChannelAttr

    • 描述

      设置该vdisp虚拟设备input channel的参数。

    • 语法

      MI_S32 MI_VDISP_SetInputChannelAttr(MI_VDISP_DEV DevId, MI_VDISP_CHN ChnId,MI_VDISP_InputChnAttr_t *pstInputChnAttr);
      
    • 参数

      参数名称 描述 输入/输出
      DevId 目标output port所属vdisp虚拟设备的ID。
      [0, VDISP_MAX_DEVICE_NUM),见规格参数
      输入
      ChnId 目标input channel的channel ID。
      [0,VDISP_MAX_CHN_NUM_PER_DEV+VDISP_MAX_OVERLAYINPUTCHN_NUM),见规格参数
      输入
      pstInputChntAttr 目标input channel的配置参数指针。
      MI_VDISP_InputChnAttr_t
      输入
    • 返回值

      • 0:成功。

      • 非0:失败,参照错误码

    • 依赖

      • 头文件:mi_vdisp.h, mi_vdisp_datatype.h

      • 库文件:libmi_vdisp.a(so)

    • 注意

      调用本函数前,先使用MI_VDISP_OpenDevice打开对应的vdisp设备。

    2.8. MI_VDISP_GetInputChannelAttr

    • 描述

      获取该vdisp虚拟设备input channel的参数。

    • 语法

      MI_S32 MI_VDISP_GetInputChannelAttr(MI_VDISP_DEV DevId, MI_VDISP_CHN ChnId,MI_VDISP_InputChnAttr_t *pstInputChnAttr);
      
    • 参数

      参数名称 描述 输入/输出
      DevId 目标output port所属vdisp虚拟设备的ID。
      [0, VDISP_MAX_DEVICE_NUM),见规格参数
      输入
      ChnId 目标input channel的channel ID。
      [0, VDISP_MAX_CHN_NUM_PER_DEV+VDISP_MAX_OVERLAYINPUTCHN_NUM),见规格参数
      输入
      pstInputChnAttr 目标input channel的配置参数指针。
      MI_VDISP_InputChnAttr_t
      输出
    • 返回值

      • 0:成功。

      • 非0:失败,参照错误码

    • 依赖

      • 头文件:mi_vdisp.h, mi_vdisp_datatype.h

      • 库文件:libmi_vdisp.a(so)

    • 注意

      调用本函数前,先使用MI_VDISP_OpenDevice打开对应的vdisp设备。

    2.9. MI_VDISP_EnableInputChannel

    • 描述

      使能该input channel,vdisp模块开始接收deviceID=DevId,channelID=ChnId的输入通道的数据。标记该channel状态为enbale。

    • 语法

      MI_S32 MI_VDISP_EnableInputChannel(MI_VDISP_DEV DevId, MI_VDISP_CHN ChnId);
      
    • 参数

      参数名称 描述 输入/输出
      DevId 目标input channel所属vdisp虚拟设备的ID。
      [0, VDISP_MAX_DEVICE_NUM),见规格参数
      输入
      ChnId 目标input channel的channel ID。
      [0, VDISP_MAX_CHN_NUM_PER_DEV+VDISP_MAX_OVERLAYINPUTCHN_NUM),见规格参数
      输入
    • 返回值

      • 0:成功。

      • 非0:失败,参照错误码

    • 依赖

      • 头文件:mi_vdisp.h, mi_vdisp_datatype.h

      • 库文件:libmi_vdisp.a(so)

    • 注意

      调用本函数前,先使用MI_VDISP_SetInputChannelAttr设置对应input channel的参数。

    2.10. MI_VDISP_DisableInputChannel

    • 描述

      用该input channel,vdisp模块停止接收deviceID=DevId, channelID=ChnId的输入通道的数据。标记该channel状态为disable。

    • 语法

      MI_S32 MI_VDISP_DisableInputChannel(MI_VDISP_DEV DevId, MI_VDISP_CHN ChnId);
      
    • 参数

      参数名称 描述 输入/输出
      DevId 目标input channel所属vdisp虚拟设备的ID。
      [0, VDISP_MAX_DEVICE_NUM), 见规格参数
      输入
      ChnId 目标input channel的channel ID。
      [0, VDISP_MAX_CHN_NUM_PER_DEV+VDISP_MAX_OVERLAYINPUTCHN_NUM), 见规格参数
      输入
    • 返回值

      • 0:成功。

      • 非0:失败,参照错误码

    • 依赖

      • 头文件:mi_vdisp.h, mi_vdisp_datatype.h

      • 库文件:libmi_vdisp.a(so)

    • 注意

      调用本函数前,先使用MI_VDISP_SetInputChannelAttr设置对应input channel的参数。

    2.11. MI_VDISP_StartDev

    • 描述

      使能该虚拟设备,vdisp output port开始尝试输出input channels数据拼图之后的数据帧。使能input channel状态为enbale的所有input channel,使能output port。

    • 语法

      MI_S32 MI_VDISP_StartDev(MI_VDISP_DEV DevId);
      
    • 参数

      参数名称 描述 输入/输出
      DevId 本参数指定要启动的虚拟设备ID。
      [0, VDISP_MAX_DEVICE_NUM), 见规格参数
      输入
    • 返回值

      • 0:成功。

      • 非0:失败,参照错误码

    • 依赖

      • 头文件:mi_vdisp.h, mi_vdisp_datatype.h

      • 库文件:libmi_vdisp.a(so)

    • 注意

      调用本函数前,先使用MI_VDISP_OpenDevice打开对应的vdisp虚拟设备。

    2.12. MI_VDISP_StopDev

    • 描述

      停止该虚拟设备,vdisp output port停止输出数据帧。禁用input channel状态为enbale的所有input channel以及output port,但是不修改其状态。

    • 语法

      MI_S32 MI_VDISP_StopDev(MI_VDISP_DEV DevId);
      
    • 参数

      参数名称 描述 输入/输出
      DevId 本参数指定要停止的虚拟设备ID。
      [0, VDISP_MAX_DEVICE_NUM),见规格参数
      输入
    • 返回值

      • 0:成功。

      • 非0:失败,参照错误码

    • 依赖

      • 头文件:mi_vdisp.h, mi_vdisp_datatype.h

      • 库文件:libmi_vdisp.a(so)

    • 注意

      本函数会disable所有enable的输入通道/输出端口,同时清空vdisp缓存的数据帧。

    2.13. MI_VDISP_InitDev

    • 描述

      初始化vdisp设备。

    • 语法

      MI_S32 MI_VDISP_InitDev (MI_VDISP_InitParam_t *pstInitParam);
      
    • 参数

      参数名称 描述 输入/输出
      pstInitParam 设备初始化参数。 输入
    • 返回值

      • 0:成功。

      • 非0:失败,参照错误码

    • 依赖

      • 头文件:mi_vdisp.h, mi_vdisp_datatype.h

      • 库文件:libmi_vdisp.a(so)

    • 注意

      • pstInitParam暂未使用,空值传入即可。

      • 此接口在Version 2.07以上版本推荐使用,用于替换原有MI_VDISP_Init接口。

    2.14. MI_VDISP_DeInitDev

    • 描述

      反初始化vdisp设备。

    • 语法

      MI_S32 MI_VDISP_DeInitDev (void);
      
    • 返回值

      • 0:成功。

      • 非0:失败,参照错误码

    • 依赖

      • 头文件:mi_vdisp.h, mi_vdisp_datatype.h

      • 库文件:libmi_vdisp.a(so)

    • 注意

      此接口在Version 2.07以上版本推荐使用,用于替换原有MI_VDISP_Exit接口。


    3. 数据类型

    MI VDISP相关数据类型、数据结构定义如下:

    数据类型 定义
    MI_VDISP_DEV 定义device id类型
    MI_VDISP_PORT 定义port id类型
    MI_VDISP_CHN 定义channel id 类型
    MI_VDISP_OutputPortAttr_t 定义输出端口属性
    MI_VDISP_InputChnAttr_t 定义输入端口属性
    MI_VDISP_InitParam_t 定义VDISP设备初始化参数

    3.1. MI_VDISP_DEV

    • 说明

      定义device id类型。

    • 定义

      typedef MI_S32 MI_VDISP_DEV;
      
    • 注意事项

      小于0为无效值。

    3.2. MI_VDISP_PORT

    • 说明

      定义port id类型。

    • 定义

      typedef MI_S32 MI_VDISP_PORT;
      
    • 注意事项

      小于0为无效值。

    3.3. MI_VDISP_CHN

    • 说明

      定义channel id类型。

    • 定义

      typedef MI_S32 MI_VDISP_CHN;
      
    • 注意事项

      小于0为无效值。

    3.4. MI_VDISP_OutputPortAttr_t

    • 说明

      定义输出端口属性。

    • 定义

      typedef struct MI_VDISP_OutputPortAttr_s
      {
          MI_U32 u32BgColor; /* Background color of a output port, in YUV > format.
          [23:16]:v, [15:8]:y, [7:0]:u*/
          MI_SYS_PixelFormat_e ePixelFormat; /* pixel format of a output port */
          MI_U64 u64pts; /* current PTS */
          MI_U32 u32FrmRate; /* the frame rate of output port */
          MI_U32 u32Width; /* the frame width of a output port */
          MI_U32 u32Height; /* the frame height of a output port */
      } MI_VDISP_OutputPortAttr_t;
      
    • 成员

      成员名称 描述
      u32BgColor vdisp用来设置给未使用的预览窗口区域填充的颜色(yuv颜色空间)。很多情况下vdisp的整张frame并不是所有的区域都会有预览窗口被使用,这些区域需要被填充默认值,否则会输出杂讯。
      ePixelFormat 输出frame的像素格式
      u64pts vdisp输出frame的合法最早PTS,当前输入数据的PTS小于这个PTS,不会被会vidsp输出。
      u32FrmRate vdisp输出frame的帧率,vdisp采用固定帧率输出,如果输入数据的帧率不足这个帧率,VDISP会使用上一次收到的frame插帧。
      u32Width vdisp输出frame的宽。
      u32Height vdisp输出frame的高。

    3.5. MI_VDISP_InputChnAttr_t

    • 说明

      vdisp的input channel属性。

    • 定义

      typedef struct MI_VDISP_InputPortAttr_s
      {
          MI_U32 u32OutX; /* the output frame X position of this input port */
          MI_U32 u32OutY; /* the output frame Y position of this input port */
          MI_U32 u32OutWidth; /* the output frame width of this input port */
          MI_U32 u32OutHeight; /* the output frame height of this input port */
          MI_S32 s32IsFreeRun; /* is this port free run */
      } MI_VDISP_InputChnAttr_t;
      
    • 成员

      成员名称 描述
      u32OutX vdisp输入通道在输出的frame的预览窗口的起始横坐标
      u32OutY vdisp输入通道在输出的frame的预览窗口的起始纵坐标
      u32OutWidth vdisp输入通道在输出的frame的预览窗口的宽
      u32OutHeight vdisp输入通道在输出的frame的预览窗口的高
      s32IsFreeRun vdisp输入通道frame数据的PTS是否被检查
      TRUE: 不被检查,始终能够输出
      FALSE: 被检查,小于output port 的pts则不被输出

    3.6. MI_VDISP_InitParam_t

    • 说明

      VDISP设备初始化参数。

    • 定义

      typedef struct MI_DIVP_InitParam_s
      {
          MI_U32 u32DevId;
          MI_U8 *u8Data;
      } MI_DIVP_InitParam_t;
      
    • 成员

      成员名称 描述
      u32DevId 设备ID
      u8Data 数据指针buffer
    • 相关数据类型及接口

      MI_VDISP_InitDev


    4. 错误码

    错误码如表4-1所示:

    表4-1 API错误码

    错误代码 宏定义 描述
    0XA0142000 MI_SUCCESS 操作成功
    0XA0142031 MI_VDISP_ERR_FAIL vdisp 函数执行失败,参见系统log
    0XA0142001 MI_VDISP_ERR_INVALID_DEVID 函数的dev参数非法
    0XA0142003 MI_VDISP_ERR_ILLEGAL_PARAM 函数的某个参数非法,参见系统log
    0XA0142008 MI_VDISP_ERR_NOT_SUPPORT 函数不支持当前参数设定
    0XA0142022 MI_VDISP_ERR_MOD_INITED vdisp已经初始化过
    0XA0142021 MI_VDISP_ERR_MOD_NOT_INIT vdisp还没有初始化
    0XA0142240 MI_VDISP_ERR_DEV_OPENED vdisp dev已经open过
    0XA0142241 MI_VDISP_ERR_DEV_NOT_OPEN 在调用该函数前,需要先open vdisp设备
    0XA0142027 MI_VDISP_ERR_DEV_NOT_STOP 在调用该函数前,需要先stop vdisp设备
    0XA0142242 MI_VDISP_ERR_DEV_NOT_CLOSE 在调用该函数前,需要先close vdisp设备
    0XA0142007 MI_VDISP_ERR_NOT_CONFIG vdisp 的input/output 没有配置
    0XA0142024 MI_VDISP_ERR_PORT_NOT_DISABLE 在调用该函数,需要先disable该 channel/port
    0XA0142243 MI_VDISP_ERR_PORT_NOT_UNBIND 参数指定port,未绑定前后端

    5. 规格

    规格参数如表5-1所示:

    表5-1 vdisp模块规格参数

    宏定义 参数 描述
    VDISP_MAX_DEVICE_NUM 4 VDISP模块支持的虚拟设备个数
    VDISP_MAX_CHN_NUM_PER_DEV 16 单个虚拟设备,支持的最大非叠加输入通道的个数
    VDISP_MAX_INPUTPORT_NUM 1 单个虚拟设备的单个非叠加输入通道的入口数。
    VDISP_MAX_OVERLAYINPUTCHN_NUM 4 单个虚拟设备可叠加通道的个数, 该参数为built-in的常数,可以增加以支持更多的可叠加窗口
    VDISP_OVERLAYINPUTCHNID VDISP_MAX_CHN_NUM_PER_DEV 可叠加输入通道的起始ID
    VDISP_MAX_OUTPUTPORT_NUM 1 单个虚拟设备的最大出口数

    6. 示例代码

    本节示例代码实现了模块说明中的场景。

    6.1. 示例程序流程图

    绿色部分为vdisp模块相关流程。

    图6-1 VDISP示例流程图

    6.2. vdisp相关代码

    6.2.1. 构建vdisp模块

    /*
    * 初始化vdisp模块
    *      v
    * 打开vdisp设备
    *      v
    * 设置vdisp input channel/output port 参数
    *      v
    * 激活input channel
    *      v
    * 开始vdisp设备
    */
    void construct_vdisp_module(void)
    {
    #define MAKE_YUYV_VALUE(y,u,v)    ((y) << 24) | ((u) << 16) | ((y) << 8) | (v)
    #define YUYV_BLACK                MAKE_YUYV_VALUE(0,128,128)
    #define ALIGN16_DOWN(x) (x&0xFFF0)
    
        typedef struct RECT
        {
            /*
            (x,y)_ _ _ _ _
            |             |
            |            (h)
            |_ _ _(w)_ _ _|
            */
            short x;
            short y;
            short w;
            short h;
        } RECT;
    
        /*
        *初始化vdisp模块
        */
        MI_VDISP_Init();
    
        MI_VDISP_InputChnAttr_t stInputChnAttr;
        MI_VDISP_OutputPortAttr_t stOutputPortAttr;
        MI_VDISP_DEV DevId = 0;
        RECT rect_0, rect_1, rect_2;
        MI_VDISP_CHN Chn_0_Id = VDISP_OVERLAYINPUTCHNID;
        MI_VDISP_CHN Chn_1_Id = 1;
        MI_VDISP_CHN Chn_2_Id = 2;
    
        /*
        *打开一个vdisp虚拟设备,以便开始对这个设备进行配置
        */
        MI_VDISP_OpenDevice(DevId);
    
        /*
        *为了满足vdisp缩略图窗口的对齐要求,对x坐标做16向下对齐
        *设置input channel 参数
        */
        rect_0.x = ALIGN16_DOWN(960);
        rect_0.y = 0;
        rect_0.w = 960;
        rect_0.h = 960;
        stInputChnAttr.s32IsFreeRun = TRUE;
        stInputChnAttr.u32OutHeight = rect_0.h;
        stInputChnAttr.u32OutWidth = rect_0.w;
        stInputChnAttr.u32OutX = rect_0.x;
        stInputChnAttr.u32OutY = rect_0.y;
        /*
        *为input channel VDISP_OVERLAYINPUTCHNID 设置参数
        */
        MI_VDISP_SetInputChannelAttr(DevId, Chn_0_Id, &stInputChnAttr);
    
        /*
        *为了满足vdisp缩略图窗口的对齐要求,对x坐标做16向下对齐
        *设置input channel 参数
        */
        rect_1.x = ALIGN16_DOWN(0);
        rect_1.y = 1080 - 300;
        rect_1.w = ALIGN16_DOWN(300);
        rect_1.h = 300;
        stInputChnAttr.s32IsFreeRun = TRUE;
        stInputChnAttr.u32OutHeight = rect_1.h;
        stInputChnAttr.u32OutWidth = rect_1.w;
        stInputChnAttr.u32OutX = rect_1.x;
        stInputChnAttr.u32OutY = rect_1.y;
        /*
        *为input channel 1 设置参数
        */
        MI_VDISP_SetInputChannelAttr(DevId, Chn_1_Id, &stInputChnAttr);
    
        /*
        *为了满足vdisp缩略图窗口的对齐要求,对x坐标做16向下对齐
        *设置input channel 参数
        */
        rect_2.x = ALIGN16_DOWN(300);
        rect_2.y = 1080 - 700;
        rect_2.w = 700;
        rect_2.h = 700;
        stInputChnAttr.s32IsFreeRun = TRUE;
        stInputChnAttr.u32OutHeight = rect_2.h;
        stInputChnAttr.u32OutWidth = rect_2.w;
        stInputChnAttr.u32OutX = rect_2.x;
        stInputChnAttr.u32OutY = rect_2.y;
    
        /*
        *为input channel 2 设置参数
        */
        MI_VDISP_SetInputChannelAttr(DevId, Chn_2_Id, &stInputChnAttr);
    
        //设置输出的颜色格式
        stOutputPortAttr.ePixelFormat = E_MI_SYS_PIXEL_FRAME_YUV_SEMIPLANAR_420;
        //设置vdisp输出帧中未使用区域的涂黑颜色,YUV 颜色空间
        stOutputPortAttr.u32BgColor = YUYV_BLACK;
        //设置vdisp输出帧率
        stOutputPortAttr.u32FrmRate = 30;
        //设置vdisp输出帧的高
        stOutputPortAttr.u32Height = 1080;
        //设置vdisp输出帧的宽
        stOutputPortAttr.u32Width = 1920;
        //设置vdisp输出帧的最低PTS
        stOutputPortAttr.u64pts = 0;
    
        /*
        *为output port 0 设置参数
        */
        MI_VDISP_SetOutputPortAttr(DevId,0,&stOutputPortAttr);
    
        /*
        *在设置完input channel 参数之后,
        *激活对应的channel,以供使用
        */
        MI_VDISP_EnableInputChannel(DevId, Chn_0_Id);
        MI_VDISP_EnableInputChannel(DevId, Chn_1_Id);
        MI_VDISP_EnableInputChannel(DevId, Chn_2_Id);
    
        /*
        *在vdisp 的input channel&output port 都配置完参数之后,
        *让vdisp的这个设备开始工作
        */
        MI_VDISP_StartDev(DevId);
    }
    

    6.2.2. 绑定vdisp上下游模块

    /*
    * 绑定 vdec out0 -> vdisp inOverlay---\
    * 绑定 vdec out1 -> vdisp in1 --------->--> disp in0
    * 绑定 vdec out2 -> vdisp in2---------/
    */
    void bind_disp_vdisp_vdec(void)
    {
        MI_SYS_ChnPort_t stSrcChnPort;
        MI_SYS_ChnPort_t stDstChnPort;
    
        /*
        * 绑定vdisp out0-> disp in0
        * <chn,dev,port> : (0,0,0) -> (0,0,0)
        */
        stSrcChnPort.eModId = E_MI_MODULE_ID_VDISP;
        stSrcChnPort.u32ChnId = 0;
        stSrcChnPort.u32DevId = 0;
        stSrcChnPort.u32PortId = 0;
    
        stDstChnPort.eModId = E_MI_MODULE_ID_DISP;
        stDstChnPort.u32ChnId = 0;
        stDstChnPort.u32DevId = 0;
        stDstChnPort.u32PortId = 0;
        MI_SYS_BindChnPort(&stSrcChnPort, &stDstChnPort, 30, 30);
    
        /*
        * 绑定vdec out0-> vdisp inOverlay
        * <chn,dev,port> : (0,0,0) -> (VDISP_OVERLAYINPUTCHNID,0,0)
        */
        stSrcChnPort.eModId = E_MI_MODULE_ID_VDEC;
        stSrcChnPort.u32ChnId = 0;
        stSrcChnPort.u32DevId = 0;
        stSrcChnPort.u32PortId = 0;
    
        stDstChnPort.eModId = E_MI_MODULE_ID_VDISP;
        stDstChnPort.u32ChnId = VDISP_OVERLAYINPUTCHNID;
        stDstChnPort.u32DevId = 0;
        stDstChnPort.u32PortId = 0;
        MI_SYS_BindChnPort(&stSrcChnPort, &stDstChnPort, 30, 30);
    
        /*
        * 绑定vdec out0-> vdisp in1
        * <chn,dev,port> : (1,0,0) -> (1,0,0)
        */
        stSrcChnPort.eModId = E_MI_MODULE_ID_VDEC;
        stSrcChnPort.u32ChnId = 1;
        stSrcChnPort.u32DevId = 0;
        stSrcChnPort.u32PortId = 0;
    
        stDstChnPort.eModId = E_MI_MODULE_ID_VDISP;
        stDstChnPort.u32ChnId = 1;
        stDstChnPort.u32DevId = 0;
        stDstChnPort.u32PortId = 0;
        MI_SYS_BindChnPort(&stSrcChnPort, &stDstChnPort, 30, 30);
    
        /*
        * 绑定vdec out2-> vdisp in2
        * <chn,dev,port> : (2,0,0) -> (2,0,0)
        */
        stSrcChnPort.eModId = E_MI_MODULE_ID_VDEC;
        stSrcChnPort.u32ChnId = 2;
        stSrcChnPort.u32DevId = 0;
        stSrcChnPort.u32PortId = 0;
    
        stDstChnPort.eModId = E_MI_MODULE_ID_VDISP;
        stDstChnPort.u32ChnId = 2;
        stDstChnPort.u32DevId = 0;
        stDstChnPort.u32PortId = 0;
        MI_SYS_BindChnPort(&stSrcChnPort, &stDstChnPort, 30, 30);
    
    }
    

    6.2.3. 解绑vdisp上下游模块

    与绑定过程区别很小,参见完整代码实现。

    6.2.4. 析构vdisp模块

    /*
    * 禁用所有channel
    *      v
    * 停止vdisp设备
    *      v
    * 关闭vdisp设备
    *      v
    * 退出vdisp模块
    */
    void destruct_vdisp_module(void)
    {
        MI_VDISP_DEV DevId = 0;
        MI_VDISP_CHN Chn_0_Id = VDISP_OVERLAYINPUTCHNID;
        MI_VDISP_CHN Chn_1_Id = 1;
        MI_VDISP_CHN Chn_2_Id = 2;
        /*
        * 先禁用已经打开vdisp channel
        * <VDISP_OVERLAYINPUTCHNID,1,2>
        */
        MI_VDISP_DisableInputChannel(DevId, Chn_0_Id);
        MI_VDISP_DisableInputChannel(DevId, Chn_1_Id);
        MI_VDISP_DisableInputChannel(DevId, Chn_2_Id);
    
        /*
        *停止已经打开的vdisp设备
        */
        MI_VDISP_StopDev(DevId);
        /*
        *关闭已经打开的vdisp设备
        */
        MI_VDISP_CloseDevice(DevId);
        /*
        *退出vdisp模块
        */
        MI_VDISP_Exit();
    }
    

    6.3. 完整代码

    #include <threads.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <unistd.h>
    #include <assert.h>
    #include <signal.h>
    
    #include <mi_sys_datatype.h>
    #include <mi_sys.h>
    #include <mi_vdec_datatype.h>
    #include <mi_vdec.h>
    #include <mi_disp_datatype.h>
    #include <mi_disp.h>
    #include <mi_vdisp_datatype.h>
    #include <mi_vdisp.h>
    
    
    static volatile int keepRunning = 1;
    
    static void intHandler(int dummy)
    {
        keepRunning = 0;
    }
    
    void construct_disp_module(void)
    {
    
        MI_DISP_PubAttr_t stDispPubAttr;
        stDispPubAttr.eIntfSync = E_MI_DISP_OUTPUT_1080P60;
        stDispPubAttr.eIntfType = E_MI_DISP_INTF_VGA;
        MI_DISP_SetPubAttr(0, &stDispPubAttr);
    
        MI_DISP_InputPortAttr_t stInputPortAttr;
        stInputPortAttr.u16SrcWidth = 1920;
        stInputPortAttr.u16SrcHeight = 1080;
        stInputPortAttr.stDispWin.u16X = 0;
        stInputPortAttr.stDispWin.u16Y = 0;
        stInputPortAttr.stDispWin.u16Width = 1920;
        stInputPortAttr.stDispWin.u16Height = 1080;
        MI_DISP_SetInputPortAttr(0, 0, &stInputPortAttr);
    
        MI_DISP_Enable(0);
        MI_DISP_EnableVideoLayer(0);
        MI_DISP_EnableInputPort(0, 0);
    }
    void destruct_disp_module(void)
    {
        MI_DISP_DisableInputPort(0, 0);
        MI_DISP_DisableVideoLayer(0);
        MI_DISP_UnBindVideoLayer(0, 0);
        MI_DISP_Disable(0);
    }
    typedef struct vdecStream
    {
        FILE *fp;
        MI_VDEC_CHN VdecChn;
        int frameRate;
    } vdecStream;
    
    MI_U64 get_pts(MI_U32 u32FrameRate)
    {
        if(0 == u32FrameRate)
        {
            return (MI_U64)(-1);
        }
    
        return (MI_U64)(1000 / u32FrameRate);
    }
    
    int push_stream(void *args)
    {
    
    #define MI_U32VALUE(pu8Data, index) (pu8Data[index]<<24)|(pu8Data[index+1]<<16)|(pu8Data[index+2]<<8)|(pu8Data[index+3])
    #define VESFILE_READER_BATCH (128 * 1024)
    
        MI_S32 s32Ret = MI_SUCCESS;
        MI_VDEC_CHN VdecChn;
        MI_U32 u32FrmRate = 0;
        MI_U8 *pu8Buf = NULL;
        MI_U32 u32Len = 0;
        MI_U32 u32FrameLen = 0;
        MI_U64 u64Pts = 0;
        MI_U8 au8Header[16] = {0};
        MI_U32 u32Pos = 0;
        MI_VDEC_ChnStat_t stChnStat;
        vdecStream *vdecS = (vdecStream *)args;
        MI_VDEC_VideoStream_t stVdecStream;
        MI_S32 s32TimeOutMs = 20;
    
        MI_U32 u32FpBackLen = 0; // if send stream failed, file pointer back length
    
        VdecChn    = vdecS->VdecChn;
        u32FrmRate = vdecS->frameRate;
    
        pu8Buf = malloc(VESFILE_READER_BATCH);
    
        while(keepRunning)
        {
            ///frame mode, read one frame lenght every time
    
            memset(au8Header, 0, 16);
            u32Pos = fseek(vdecS->fp, 0L, SEEK_CUR);
            u32Len = fread(au8Header, 16, 1, vdecS->fp);
    
            if(u32Len <= 0)
            {
                fseek(vdecS->fp, 0, SEEK_SET);
                continue;
            }
    
            u32FrameLen = MI_U32VALUE(au8Header, 4);
            if(u32FrameLen > VESFILE_READER_BATCH)
            {
                fseek(vdecS->fp, 0, SEEK_SET);
                continue;
            }
    
            u32Len = fread(pu8Buf, u32FrameLen, 1, vdecS->fp);
    
            if(u32Len <= 0)
            {
                fseek(vdecS->fp, 0, SEEK_SET);
                continue;
            }
    
            stVdecStream.pu8Addr = pu8Buf;
            stVdecStream.u32Len = u32FrameLen;
            stVdecStream.u64PTS = u64Pts;
            stVdecStream.bEndOfFrame = 1;
            stVdecStream.bEndOfStream = 0;
    
            u32FpBackLen = stVdecStream.u32Len + 16; //back length
    
            if(MI_SUCCESS != (s32Ret = MI_VDEC_SendStream(VdecChn, &stVdecStream, s32TimeOutMs)))
            {
                fseek(vdecS->fp, - u32FpBackLen, SEEK_CUR);
            }
    
            u64Pts = u64Pts + get_pts(1000 / u32FrmRate);
    
            memset(&stChnStat, 0x0, sizeof(stChnStat));
            MI_VDEC_GetChnStat(VdecChn, &stChnStat);
            usleep(20 * 1000);
    
        }
    
        free(pu8Buf);
        return NULL;
    }
    
    thrd_t thr0, thr1, thr2;
    vdecStream vS0, vS1, vS2;
    
    void construct_vdec_module(void)
    {
        MI_VDEC_ChnAttr_t stChnAttr;
        MI_VDEC_CHN Chn_0_Id = 0;
        MI_VDEC_CHN Chn_1_Id = 1;
        MI_VDEC_CHN Chn_2_Id = 2;
    
        memset(&stChnAttr, 0, sizeof(MI_VDEC_ChnAttr_t));
    
        MI_VDEC_InitParam_t stVdecInitParam;
        MI_VDEC_ChnParam_t stChnParam;
        MI_VDEC_OutputPortAttr_t stOutputPortAttr;
        stVdecInitParam.bDisableLowLatency = FALSE;
        MI_VDEC_InitDev(&stVdecInitParam);
    
        stChnAttr.eCodecType    = E_MI_VDEC_CODEC_TYPE_H264;
        stChnAttr.u32PicWidth   = 1920;
        stChnAttr.u32PicHeight  = 1080;
        stChnAttr.eVideoMode    = E_MI_VDEC_VIDEO_MODE_FRAME;
        stChnAttr.u32BufSize    = 1024 * 1024;
        stChnAttr.eDpbBufMode  = E_MI_VDEC_DPB_MODE_NORMAL;
        stChnAttr.stVdecVideoAttr.u32RefFrameNum = 2;
        stChnAttr.u32Priority = 0;
    
        MI_VDEC_CreateChn(Chn_0_Id, &stChnAttr);
        stOutputPortAttr.u16Width = 960;
        stOutputPortAttr.u16Height = 960;
        MI_VDEC_SetOutputPortAttr(Chn_0_Id, &stOutputPortAttr);
    
        MI_VDEC_CreateChn(Chn_1_Id, &stChnAttr);
        stOutputPortAttr.u16Width = 300;
        stOutputPortAttr.u16Height = 300;
        MI_VDEC_SetOutputPortAttr(Chn_1_Id, &stOutputPortAttr);
    
        MI_VDEC_CreateChn(Chn_2_Id, &stChnAttr);
        stOutputPortAttr.u16Width = 700;
        stOutputPortAttr.u16Height = 700;
        MI_VDEC_SetOutputPortAttr(Chn_2_Id, &stOutputPortAttr);
    
        MI_VDEC_StartChn(Chn_0_Id);
        MI_VDEC_StartChn(Chn_1_Id);
        MI_VDEC_StartChn(Chn_2_Id);
    
    #define VDEC_FILE0 "./vdisp_demo0.h264"
    #define VDEC_FILE1 "./vdisp_demo1.h264"
    #define VDEC_FILE2 "./vdisp_demo2.h264"
    
        vS0.fp = fopen(VDEC_FILE0, "rb");
        vS0.frameRate = 30;
        vS0.VdecChn = Chn_0_Id;
        assert(vS0.fp);
        thrd_create(&thr0, push_stream, &vS0);
        vS1.fp = fopen(VDEC_FILE1, "rb");
        vS1.frameRate = 30;
        vS1.VdecChn = Chn_1_Id;
        assert(vS1.fp);
        thrd_create(&thr1, push_stream, &vS1);
        vS2.fp = fopen(VDEC_FILE2, "rb");
        vS2.frameRate = 30;
        vS2.VdecChn = Chn_2_Id;
        assert(vS2.fp);
        thrd_create(&thr2, push_stream, &vS2);
    }
    void destruct_vdec_module(void)
    {
        thrd_join(thr0,NULL);
        thrd_join(thr1,NULL);
        thrd_join(thr2,NULL);
        MI_VDEC_StopChn(vS0.VdecChn);
        MI_VDEC_StopChn(vS1.VdecChn);
        MI_VDEC_StopChn(vS2.VdecChn);
        MI_VDEC_DestroyChn(vS0.VdecChn);
        MI_VDEC_DestroyChn(vS1.VdecChn);
        MI_VDEC_DestroyChn(vS2.VdecChn);
        MI_VDEC_DeInitDev();
    }
    
    /*
    * 初始化vdisp模块
    *      v
    * 打开vdisp设备
    *      v
    * 设置vdisp input channel/output port 参数
    *      v
    * 激活input channel
    *      v
    * 开始vdisp设备
    */
    void construct_vdisp_module(void)
    {
    #define MAKE_YUYV_VALUE(y,u,v)    ((y) << 24) | ((u) << 16) | ((y) << 8) | (v)
    #define YUYV_BLACK                MAKE_YUYV_VALUE(0,128,128)
    #define ALIGN16_DOWN(x) (x&0xFFF0)
    
        typedef struct RECT
        {
            /*
            (x,y)_ _ _ _ _
            |             |
            |            (h)
            |_ _ _(w)_ _ _|
            */
            short x;
            short y;
            short w;
            short h;
        } RECT;
    
        /*
        *初始化vdisp模块
        */
        MI_VDISP_Init();
    
        MI_VDISP_InputChnAttr_t stInputChnAttr;
        MI_VDISP_OutputPortAttr_t stOutputPortAttr;
        MI_VDISP_DEV DevId = 0;
        RECT rect_0, rect_1, rect_2;
        MI_VDISP_CHN Chn_0_Id = VDISP_OVERLAYINPUTCHNID;
        MI_VDISP_CHN Chn_1_Id = 1;
        MI_VDISP_CHN Chn_2_Id = 2;
    
        /*
        *打开一个vdisp虚拟设备,以便开始对这个设备进行配置
        */
        MI_VDISP_OpenDevice(DevId);
    
        /*
        *为了满足vdisp缩略图窗口的对齐要求,对x坐标做16向下对齐
        *设置input channel 参数
        */
        rect_0.x = ALIGN16_DOWN(960);
        rect_0.y = 0;
        rect_0.w = 960;
        rect_0.h = 960;
        stInputChnAttr.s32IsFreeRun = TRUE;
        stInputChnAttr.u32OutHeight = rect_0.h;
        stInputChnAttr.u32OutWidth = rect_0.w;
        stInputChnAttr.u32OutX = rect_0.x;
        stInputChnAttr.u32OutY = rect_0.y;
        /*
        *为input channel VDISP_OVERLAYINPUTCHNID 设置参数
        */
        MI_VDISP_SetInputChannelAttr(DevId, Chn_0_Id, &stInputChnAttr);
    
        /*
        *为了满足vdisp缩略图窗口的对齐要求,对x坐标做16向下对齐
        *设置input channel 参数
        */
        rect_1.x = ALIGN16_DOWN(0);
        rect_1.y = 1080 - 300;
        rect_1.w = ALIGN16_DOWN(300);
        rect_1.h = 300;
        stInputChnAttr.s32IsFreeRun = TRUE;
        stInputChnAttr.u32OutHeight = rect_1.h;
        stInputChnAttr.u32OutWidth = rect_1.w;
        stInputChnAttr.u32OutX = rect_1.x;
        stInputChnAttr.u32OutY = rect_1.y;
        /*
        *为input channel 1 设置参数
        */
        MI_VDISP_SetInputChannelAttr(DevId, Chn_1_Id, &stInputChnAttr);
    
        /*
        *为了满足vdisp缩略图窗口的对齐要求,对x坐标做16向下对齐
        *设置input channel 参数
        */
        rect_2.x = ALIGN16_DOWN(300);
        rect_2.y = 1080 - 700;
        rect_2.w = 700;
        rect_2.h = 700;
        stInputChnAttr.s32IsFreeRun = TRUE;
        stInputChnAttr.u32OutHeight = rect_2.h;
        stInputChnAttr.u32OutWidth = rect_2.w;
        stInputChnAttr.u32OutX = rect_2.x;
        stInputChnAttr.u32OutY = rect_2.y;
    
        /*
        *为input channel 2 设置参数
        */
        MI_VDISP_SetInputChannelAttr(DevId, Chn_2_Id, &stInputChnAttr);
    
        //设置输出的颜色格式
        stOutputPortAttr.ePixelFormat = E_MI_SYS_PIXEL_FRAME_YUV_SEMIPLANAR_420;
        //设置vdisp输出帧中未使用区域的涂黑颜色,YUV 颜色空间
        stOutputPortAttr.u32BgColor = YUYV_BLACK;
        //设置vdisp输出帧率
        stOutputPortAttr.u32FrmRate = 30;
        //设置vdisp输出帧的高
        stOutputPortAttr.u32Height = 1080;
        //设置vdisp输出帧的宽
        stOutputPortAttr.u32Width = 1920;
        //设置vdisp输出帧的最低PTS
        stOutputPortAttr.u64pts = 0;
    
        /*
        *为output port 0 设置参数
        */
        MI_VDISP_SetOutputPortAttr(DevId,0,&stOutputPortAttr);
    
        /*
        *在设置完input channel 参数之后,
        *激活对应的channel,以供使用
        */
        MI_VDISP_EnableInputChannel(DevId, Chn_0_Id);
        MI_VDISP_EnableInputChannel(DevId, Chn_1_Id);
        MI_VDISP_EnableInputChannel(DevId, Chn_2_Id);
    
        /*
        *在vdisp 的input channel&output port 都配置完参数之后,
        *让vdisp的这个设备开始工作
        */
        MI_VDISP_StartDev(DevId);
    }
    
    /*
    * 禁用所有channel
    *      v
    * 停止vdisp设备
    *      v
    * 关闭vdisp设备
    *      v
    * 退出vdisp模块
    */
    void destruct_vdisp_module(void)
    {
        MI_VDISP_DEV DevId = 0;
        MI_VDISP_CHN Chn_0_Id = VDISP_OVERLAYINPUTCHNID;
        MI_VDISP_CHN Chn_1_Id = 1;
        MI_VDISP_CHN Chn_2_Id = 2;
    /*
        * 先禁用已经打开vdisp channel
        * <VDISP_OVERLAYINPUTCHNID,1,2>
        */
        MI_VDISP_DisableInputChannel(DevId, Chn_0_Id);
        MI_VDISP_DisableInputChannel(DevId, Chn_1_Id);
        MI_VDISP_DisableInputChannel(DevId, Chn_2_Id);
    
    /*
        *停止已经打开的vdisp设备
        */
        MI_VDISP_StopDev(DevId);
    /*
        *关闭已经打开的vdisp设备
        */
        MI_VDISP_CloseDevice(DevId);
    /*
        *退出vdisp模块
        */
        MI_VDISP_Exit();
    }
    
    /*
    * 绑定 vdec out0 -> vdisp inOverlay---\
    * 绑定 vdec out1 -> vdisp in1 --------->--> disp in0
    * 绑定 vdec out2 -> vdisp in2---------/
    */
    void bind_disp_vdisp_vdec(void)
    {
        MI_SYS_ChnPort_t stSrcChnPort;
        MI_SYS_ChnPort_t stDstChnPort;
    
        /*
        * 绑定vdisp out0-> disp in0
        * <chn,dev,port> : (0,0,0) -> (0,0,0)
        */
        stSrcChnPort.eModId = E_MI_MODULE_ID_VDISP;
        stSrcChnPort.u32ChnId = 0;
        stSrcChnPort.u32DevId = 0;
        stSrcChnPort.u32PortId = 0;
    
        stDstChnPort.eModId = E_MI_MODULE_ID_DISP;
        stDstChnPort.u32ChnId = 0;
        stDstChnPort.u32DevId = 0;
        stDstChnPort.u32PortId = 0;
        MI_SYS_BindChnPort(&stSrcChnPort, &stDstChnPort, 30, 30);
    
        /*
        * 绑定vdec out0-> vdisp inOverlay
        * <chn,dev,port> : (0,0,0) -> (VDISP_OVERLAYINPUTCHNID,0,0)
        */
        stSrcChnPort.eModId = E_MI_MODULE_ID_VDEC;
        stSrcChnPort.u32ChnId = 0;
        stSrcChnPort.u32DevId = 0;
        stSrcChnPort.u32PortId = 0;
    
        stDstChnPort.eModId = E_MI_MODULE_ID_VDISP;
        stDstChnPort.u32ChnId = VDISP_OVERLAYINPUTCHNID;
        stDstChnPort.u32DevId = 0;
        stDstChnPort.u32PortId = 0;
        MI_SYS_BindChnPort(&stSrcChnPort, &stDstChnPort, 30, 30);
    
        /*
        * 绑定vdec out0-> vdisp in1
        * <chn,dev,port> : (1,0,0) -> (1,0,0)
        */
        stSrcChnPort.eModId = E_MI_MODULE_ID_VDEC;
        stSrcChnPort.u32ChnId = 1;
        stSrcChnPort.u32DevId = 0;
        stSrcChnPort.u32PortId = 0;
    
        stDstChnPort.eModId = E_MI_MODULE_ID_VDISP;
        stDstChnPort.u32ChnId = 1;
        stDstChnPort.u32DevId = 0;
        stDstChnPort.u32PortId = 0;
        MI_SYS_BindChnPort(&stSrcChnPort, &stDstChnPort, 30, 30);
    
        /*
        * 绑定vdec out2-> vdisp in2
        * <chn,dev,port> : (2,0,0) -> (2,0,0)
        */
        stSrcChnPort.eModId = E_MI_MODULE_ID_VDEC;
        stSrcChnPort.u32ChnId = 2;
        stSrcChnPort.u32DevId = 0;
        stSrcChnPort.u32PortId = 0;
    
        stDstChnPort.eModId = E_MI_MODULE_ID_VDISP;
        stDstChnPort.u32ChnId = 2;
        stDstChnPort.u32DevId = 0;
        stDstChnPort.u32PortId = 0;
        MI_SYS_BindChnPort(&stSrcChnPort, &stDstChnPort, 30, 30);
    
    }
    
    void unbind_disp_vdisp_vdec(void)
    {
        MI_SYS_ChnPort_t stSrcChnPort;
        MI_SYS_ChnPort_t stDstChnPort;
    
        stSrcChnPort.eModId = E_MI_MODULE_ID_VDISP;
        stSrcChnPort.u32ChnId = 0;
        stSrcChnPort.u32DevId = 0;
        stSrcChnPort.u32PortId = 0;
    
        stDstChnPort.eModId = E_MI_MODULE_ID_DISP;
        stDstChnPort.u32ChnId = 0;
        stDstChnPort.u32DevId = 0;
        stDstChnPort.u32PortId = 0;
        MI_SYS_UnBindChnPort(&stSrcChnPort, &stDstChnPort);
    
        stSrcChnPort.eModId = E_MI_MODULE_ID_VDEC;
        stSrcChnPort.u32ChnId = 0;
        stSrcChnPort.u32DevId = 0;
        stSrcChnPort.u32PortId = 0;
    
        stDstChnPort.eModId = E_MI_MODULE_ID_VDISP;
        stDstChnPort.u32ChnId = VDISP_OVERLAYINPUTCHNID;
        stDstChnPort.u32DevId = 0;
        stDstChnPort.u32PortId = 0;
        MI_SYS_UnBindChnPort(&stSrcChnPort, &stDstChnPort);
    
        stSrcChnPort.eModId = E_MI_MODULE_ID_VDEC;
        stSrcChnPort.u32ChnId = 1;
        stSrcChnPort.u32DevId = 0;
        stSrcChnPort.u32PortId = 0;
    
        stDstChnPort.eModId = E_MI_MODULE_ID_VDISP;
        stDstChnPort.u32ChnId = 1;
        stDstChnPort.u32DevId = 0;
        stDstChnPort.u32PortId = 0;
        MI_SYS_UnBindChnPort(&stSrcChnPort, &stDstChnPort);
    
        stSrcChnPort.eModId = E_MI_MODULE_ID_VDEC;
        stSrcChnPort.u32ChnId = 2;
        stSrcChnPort.u32DevId = 0;
        stSrcChnPort.u32PortId = 0;
    
        stDstChnPort.eModId = E_MI_MODULE_ID_VDISP;
        stDstChnPort.u32ChnId = 2;
        stDstChnPort.u32DevId = 0;
        stDstChnPort.u32PortId = 0;
        MI_SYS_UnBindChnPort(&stSrcChnPort, &stDstChnPort);
    
    }
    
    int main(void)
    {
        signal(SIGINT, intHandler);
    
        MI_SYS_Init();
        construct_disp_module();
        construct_vdisp_module();
        construct_vdec_module();
        bind_disp_vdisp_vdec();
        while(keepRunning)
        {
            sleep(1);
        }
        unbind_disp_vdisp_vdec();
        destruct_disp_module();
        destruct_vdisp_module();
        destruct_vdec_module();
        MI_SYS_Exit();
        return 0;
    }
    

    7. PROCFS介绍

    7.1. cat

    • 调试信息

      ​# cat proc/mi_modules/mi_vdisp/mi_vdisp0
      
      ============================Private Vdisp0 Info ===============================
      DevStatus
          Start
      ------------------------------------------------------- Input Port Info ---------------------------------------------
      PortID  PortStatus  ChnX  ChnY  ChnW  ChnH  IsFreeRun    TryOk      RecvOk
          0   Enabled      0     0      960     540    1      245356299     313332
          1   Enabled      960   0      960     540    1      355670297     313332
          2   Enabled      0     540    960     540    1      578760014     313331
          3   Enabled      960   540    960     540    1      757579130     313330
      ------------------------------------------------------ Output Port Info -------------------------------------------------
      Inited  FrmInterval  BgColor  PixelFmt  FrmRate  Width  Height    SendOk
          1      33333     8388736     0        30     1920    1080     471418
      
    • 调试信息分析

      记录当前VDISP的使用状况以及device属性、Input port属性、Output port属性,可以动态地获取到这些信息,方便调试和测试。

    • 参数说明

      参数 描述
      device info DevStatus Vdisp设备的工作状态
      Uninit:未初始化
      Init:初始化
      Start:运行状态
      Stop:停止状态
      layer info PortID Inport ID
      取值范围:[0~16],16为overlay通道,即PIP通道。
      PortStatus Port口状态
      Uninit:inport未初始化
      Init:inport已初始化
      Enabled:inport已经使能
      Disabled:inport已经禁用
      ChnX 输入inport的起始坐标X地址
      取值范围:[0~4094],需要根据chip的align对齐
      ChnY 输入inport的起始坐标Y地址
      取值范围:[0~2159]
      ChnW 输入inport的图像宽度,需要根据chip的align对齐
      取值范围:[0~4096]
      ChnH 输入inport的图像高度
      取值范围:[0~4096]
      IsFreeRun 是否不做帧率控制
      0:按pts控制播放
      1:自由播放
      TryOk 尝试取前级绑定端口的数据次数
      RecvOk 从前级绑定端口成功拿到数据的次数
      Output port info Inited 是否有初始化Output Port
      0:未初始化
      1:已初始化
      FrmInterval 出帧时间间隔,单位US
      BgColor 背景色,此处打印的是10进制
      PixelFmt 色彩空间
      取值范围[0~E_MI_SYS_PIXEL_FRAME_FORMAT_MAX-1] 0-YUYV422,9-YUVSP420
      FrmRate 输出帧率
      Width 图像输出宽度
      取值范围:[0~4096],需要根据chip的align对齐
      Height 图像输出高度
      取值范围:[0~2160],需要根据chip的align对齐
      SendOk 成功推往后级的帧数统计