MI VDISP API

version 2.07


1. 概述


1.1. 模块说明

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

一个典型的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


1.3. 约束

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

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

    1. E_MI_SYS_PIXEL_FRAME_YUV_SEMIPLANAR_420

    2. E_MI_SYS_PIXEL_FRAME_YUV_SEMIPLANAR_422

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

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

  5. 参见更多的规格参数


2. API 参考


2.1. 功能模块API

表2-1

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.2. 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.3. 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.4. MI_VDISP_OpenDevice

  • 描述

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

  • 语法

    MI_S32 MI_VDISP_OpenDevice(MI_VDISP_DEV DevId)
    
  • 参数

    表2-2

    参数名称 描述 输入/输出
    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.5. MI_VDISP_CloseDevice

  • 描述

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

  • 语法

    MI_S32 MI_VDISP_CloseDevice(MI_VDISP_DEV DevId);
    
  • 参数

    表2-3

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

    • 0 成功。

    • 非0 失败,参照错误码

  • 依赖

    • 头文件:mi_vdisp.h mi_vdisp_datatype.h

    • 库文件:libmi_vdisp.a(so)

  • 注意

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


2.6. MI_VDISP_SetOutputPortAttr

  • 描述

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

  • 语法

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

    表2-4

    参数名称 描述 输入/输出
    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_GetOutputPortAttr

  • 描述

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

  • 语法

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

    表2-5

    参数名称 描述 输入/输出
    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.8. MI_VDISP_SetInputChannelAttr

  • 描述

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

  • 语法

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

    表2-6

    参数名称 描述 输入/输出
    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.9. MI_VDISP_GetInputChannelAttr

  • 描述

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

  • 语法

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

    表2-7

    参数名称 描述 输入/输出
    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). 输入
    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.10. 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);
    
  • 参数

    表2-8

    参数名称 描述 输入/输出
    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_DisableInputChannel

  • 描述

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

  • 语法

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

    表2-9

    参数名称 描述 输入/输出
    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.12. MI_VDISP_StartDev

  • 描述

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

  • 语法

    MI_S32 MI_VDISP_StartDev(MI_VDISP_DEV DevId);
    
  • 参数

    表2-10

    参数名称 描述 输入/输出
    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.13. MI_VDISP_StopDev

  • 描述

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

  • 语法

    MI_S32 MI_VDISP_StopDev(MI_VDISP_DEV DevId);
    
  • 参数

    表2-11

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

    • 0 成功。

    • 非0 失败,参照错误码

  • 依赖

    • 头文件:mi_vdisp.h mi_vdisp_datatype.h

    • 库文件:libmi_vdisp.a(so)

  • 注意

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


2.14. 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.15. 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. 数据类型


3.1. 数据类型定义

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

表3-1

数据结构 说明
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.2. MI_VDISP_DEV

  • 说明

    定义device id类型。

  • 定义

    typedef MI_S32 MI_VDISP_DEV;
    
  • 注意事项

    小于0为无效值


3.3. MI_VDISP_PORT

  • 说明

    定义port id类型。

  • 定义

    typedef MI_S32 MI_VDISP_PORT;
    
  • 注意事项

    小于0为无效值。


3.4. MI_VDISP_CHN

  • 说明

    定义channel id类型。

  • 定义

    typedef MI_S32 MI_VDISP_CHN;
    
  • 注意事项

    小于0为无效值。


3.5. MI_VDISP_OutputPortAttr_t

  • 说明

    定义输出端口属性。

  • 成员

    表3-2

    成员名称 描述
    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.6. MI_VDISP_InputChnAttr_t

  • 说明

    vdisp的input channel属性。

  • 成员

    表3-3

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

3.7. MI_VDISP_InitParam_t

  • 说明

    VDISP设备初始化参数。

  • 定义

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

    表3-4

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

    MI_VDISP_InitDev


4. 错误码

表4-1 API错误码

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

5. 规格参数

表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

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;