随着 AI 技术的不断发展,从 Sensor 采集数据,经过处理之后给 AI 模型做图像分析已经变成一个很典型的应用。因此,在嵌入式应用行业,无论是汽车,安防,手机等应用中,对 Sensor 采集的数据做图像处理变得非常重要。针对以上需求,Cambricon CE3226 内部集成了多个复杂的硬件组件,并实现了对应的中间层软件库,能够满足客户对视频处理的各种要求。
本系列博文会对 CNMPS(Cambricon Media Process System,寒武纪媒体处理系统)各个组件功能,工作原理作详细介绍,并对中间层软件作系统分析,方便客户编写自己的应用程序。
本文是该系列博文的第三篇,介绍视频输出系统的组成,工作原理以及软件架构。
一、基本概念
VO(Video Output,视频输出)模块从内存读取视频数据和图形数据进行叠加,并进行图像后处理,最
终通过相应的显示设备输出。CE3226V100 支持的显示/回写设备、视频层、图形层情况参见图(1)。
图(1)
- DHD0(Device High Definition 0):HD0 设备,高清显示设备 0。
- VHD0(Video layer of HD 0):高清视频层 0,属于 DHD0。
- VHD1:高清视频层 1,属于 DHD0。
- WD(Write Back Device):回写设备。
- 高清显示设备
CE3226V100 支持 1 个高清显示设备 DHD0 。支持显示设备的详细情况请参见 CE3226V100 支持的显
示 / 回写设备、视频层、图形层 。HD 设备功能属性参见 CE3226V100 设备规格 。设备的视频输出接口
只支持逐行扫描,不支持隔行扫描,设备支持的最大输出时序参见 CE3226V100 视频输出接口时序 。
- 回写设备
对设备级的视频数据进行捕获,可用于显示和编码。回写设备和显示设备不可同时使用。回写设备只
可以回写设备级,即视频层与图形层进行叠加后的视频数据。
- 虚拟设备
虚拟设备是软件上的概念,没有与之对应的实际物理设备。
– 内部处理流程:虚拟设备通过 VGU 实现缩放,并将多个视频图像拼接为一整幅图像。
– 发送虚拟设备图像:虚拟设备支持通过用户态调 cnvoGetScreenFrame 接口获取虚拟设备对应视频
层的图像,再发送给其他模块;也支持系统绑定模式下在内核态向其他模块发送虚拟设备图像。
CE3226V100 支持 2 个虚拟设备,设备号为 1~2,对应的虚拟视频层为 2~3 ,虚拟视频层 2 最多支持
16 个通道,虚拟视频层 3 最多支持 4 个通道。
- 视频层
表示固定在显示设备上的视频层。CE3226 的视频层功能规格请参见 CE3226V100 视频层规格 。
- 通道
通道是指一个视频的显示区域,通道由视频层进行管理,一个视频层上可包含单个或多个通道,视频
区域必须在通道区域内,通道区域必须在视频层内。通道与通道之间都是独立的,每一个视频层上的
通道的单独进行排号。
使用系统绑定方案时,应该使用视频层号和通道号来进行绑定配置。
- 通道优先级
高清显示设备支持视频层上多个通道同时输出显示,叠加顺序按照优先级进行排序,当各个通道重叠
时,通道优先级高的显示在上层,如果通道优先级相等,则通道号越大的默认优先级越高。
- 缩放和显示
对于 CE3226V100 VHD0 最大支持 16 个通道,VHD1 最大支持 4 个通道。通道支持通过 VGU 对图像进
行缩放,再将多个通道的视频图像拼接为一整幅图像,并将这一整幅图像的数据送给设备显示。可支
持的缩放和显示情况参见 CE3226V100 视频层规格 。
视频层不支持缩放,允许对视频层进行裁剪。视频层在显示视频图像时均不进行缩放,只支持裁剪显
示。
- 旋转
VO 支持对通道的图像进行旋转操作。旋转功能只支持非压缩数据格式。
- 单画面直通模式
此模式下,VO 通道中的图像可直接显示,不需要 VGU 模块进行缩放和拼接处理,节省一次 VGU 搬移
数据过程,VO 也无需申请私有内存,直通模式需要满足以下条件:
– VO 通道使能,且只有一个通道显示;
– VO 没有使能边框;
– VO 通道图像像素格式和设置的一致;
– VO 通道图像视频格式为 LINEAR;
– VO 通道图像大小(stVFrame.Size)= 通道大小(stRect)= 画布大小(stImageSize);
- 图形层绑定
CE3226V100 支持 2 个图形层 G0 和 G1、G0 以及 G1 固定绑定在 DHD0 上。
- 解压和压缩
– 视频数据解压。
CE3226V100 支持输入源图像是压缩数据(格式为段压缩,256Bytes 为一段)。视频层、通道均支
持解压功能,通道使用解压功能时不支持旋转功能。非单通道直通模式,不支持解压功能。
– 视频数据压缩。
CE3226V100 回写设备支持输出压缩数据图像(格式为段压缩,256Bytes 为一段)。
- 输入和输出数据格式
VO 支持输入和输出指定格式的数据,这里的输出是指回写数据到 DDR 。可支持的输入输出数据格
式参见 CE3226V100 支持的输入输出数据格式 。其中 PIXEL FORMAT、VIDEO FORMAT、COMPRESS
MODE 和 DYNAMIC RANGE 项分别列出了芯片支持的输入输出像素格式、视频格式、压缩模式和视频
动态范围。
- 像素格式转换
VO 工作于非直通模式时支持像素格式转换,如果输入通道的图像像素格式和视频层设置的像素格式
不同,可通过 VGU 进行像素格式转换。
- 分辨率
分辨率主要有以下 4 种概念:
– 设备分辨率指显示设备的输出有效像素点数,由设备输出时序决定。
– 显示分辨率指视频层画面在设备上的有效区域,由视频层属性中的 stDispRect 成员决定。
– 画布分辨率指一块用来存放 VGU 拼接后输出视频数据的内存区域,由视频层属性中的 stImageSize
决定。单画面直通时无此定义。
– 图像分辨率指图像的有效像素点数,由实际的图像决定。
- 低功耗策略
VO 模块使用低功耗策略,在模块加载后或用例退出后,VO 时钟是关闭的,此时手动读写 VO 模块的
寄存器可能导致读写错误或系统卡死。
二、软硬件限制
三、API & 关键代码
1.驱动交互 API
如图(5),/mps/out/include/cn_vo.h 头文件中分别针对 Layer、channel 导出了 api 函数,具体实现封装在/mps/out/lib/libcn_vi.so 动态库文件中。这些 API函数直接与驱动程序交互。
针对 VO 设备,实现了如下 API 函数
cnS32_t cnvoSetPubAttr(cnS32_t s32Dev, const cnvoPubAttr_t *pstPubAttr);//设置 VO 属性
cnS32_t cnvoGetPubAttr(cnS32_t s32Dev, cnvoPubAttr_t *pstPubAttr);//获取 VO 属性
cnS32_t cnvoEnable (cnS32_t s32Dev);//启动 VO
cnS32_t cnvoDisable(cnS32_t s32Dev);//关闭 VO
针对 layer,实现了以下主要 API 函数
cnS32_t cnvoSetVideoLayerAttr(cnS32_t s32Layer, const cnvoVideoLayerAttr_t *pstLayerAttr);//设置 layer 属性
cnS32_t cnvoSetVideoLayerPriority(cnS32_t s32Layer, cnU32_t u32Priority);//设置视频层优先级
cnS32_t cnvoSetVideoLayerBoundary(cnS32_t s32Layer, const cnvoLayerBoundary_t *pstLayerBoundary);//设置视频层区域边框的宽高和颜色
通道相关的 API 如下:
cnS32_t cnvoSetChnAttr(cnS32_t s32Layer, cnS32_t s32Chn, const cnvoChnAttr_t *pstChnAttr); //设置 VO 通道属性
cnS32_t cnvoEnableChn (cnS32_t s32Layer, cnS32_t s32Chn);//启动视频输出通道
cnS32_t cnvoSendFrame(cnS32_t s32Layer, cnS32_t s32Chn, cnVideoFrameInfo_t *pstVFrame, cnS32_t s32MilliSec); //将视频图像送入指定的输出通道
cnS32_t cnvoGetChnFrame(cnS32_t s32Layer, cnS32_t s32Chn, cnVideoFrameInfo_t *pstVFrame, cnS32_t s32MilliSec); //获取显示帧率
cnS32_t cnvoReleaseChnFrame(cnS32_t s32Layer, cnS32_t s32Chn, const cnVideoFrameInfo_t *pstVFrame);//释放输出通道图像数据
cnS32_t cnvoSetChnFrameRate(cnS32_t s32Layer, cnS32_t s32Chn, cnS32_t s32ChnFrmRate); //设置通道帧率
cnS32_t cnvoShowChn(cnS32_t s32Layer, cnS32_t s32Chn); //显示视频输出通道的图像
cnS32_t cnvoHideChn(cnS32_t s32Layer, cnS32_t s32Chn); //隐藏视频输出通道的图像
cnS32_t cnvoSetChnRotation(cnS32_t s32Layer, cnS32_t s32Chn, cnEnRotation_t enRotation);//设置旋转
2.用户 API
为了方便客户应用开发,MPS 在以上 API 基础上,继续封装了一层 API,供开发人员间接对 VO 模块进行设置、初始化、启动等操作。相关函数通过 /mps/sample/common/cnsample_comm.h 导出。具体函数实现在/mps/sample/common/cnsample_comm_vo.cpp 文件中实现。
cnsample_comm_vo.cpp 中实现了2 个类似的函数供用户 APP 直接使用,分别是 cnsampleCommVoStartVo()和 cnsampleCommVoStartLayerChn()。下面分别介绍这两个函数。
2.1
cnsampleCommVoStartVo()函数调用层级如下:
|--cnsampleCommVoStartVo(cnsampleVoConfig_t *pstVoConfig)
|--cnsampleCommVoStartDev(voDev_t VoDev, cnvoPubAttr_t *pstPubAttr)
|--cnvoSetPubAttr(cnS32_t s32Dev, const cnvoPubAttr_t *pstPubAttr)
|--cnvoEnable (cnS32_t s32Dev)
|--cnsampleCommVoGetWH(cnvoEnIntfSync_t enIntfSync, cnU32_t* pu32W, …)
|--cnvoSetDisplayBufLen(cnS32_t s32Layer, cnU32_t u32BufLen)
|--cnsampleCommVoStartLayer(voLayer_t VoLayer, const cnvoVideoLayerAttr_t* pstLayerAttr)
|--cnvoSetVideoLayerAttr(cnS32_t s32Layer, const cnvoVideoLayerAttr_t *pstLayerAttr)
|--cnvoEnableVideoLayer (cnS32_t s32Layer)
|--cnsampleCommVoStartChn(voLayer_t VoLayer, cnsampleVoMode_t enMode)
|--cnvoGetVideoLayerAttr(cnS32_t s32Layer, cnvoVideoLayerAttr_t *pstLayerAttr)
|--cnvoSetChnAttr(cnS32_t s32Layer, cnS32_t s32Chn, const cnvoChnAttr_t *pstChnAttr)
|--cnvoEnableChn (cnS32_t s32Layer, cnS32_t s32Chn)
图(7)
cnsampleCommVoStartVo()函数体首先定义一系列设置 VO,Layer,channel 的参数变量,首先根据输入参数
pstvoconfig 结构体指针中的成员值去填充 VO 的属性,然后调用 cnsampleCommVoStartDev() 启动 VO 设备。
VO 启动之后,调用 cnsampleCommVoGetWH()获取 VO 设备的宽度、高度、帧率。填充 Layer 属性后启动 Layer
其中 s32x,s32y 为 x,y轴起点位置,u32Width,u32Height 为宽度和高度。i为窗口个数。
宏ALIGN_DOWN(addr, size) ((addr)&(~((size)-1))) 用于计算上述四个参数,并作偶数(行数和列数)对齐。
下图(9)所示为窗口个数为 2、4、8、9 的情况下显示布局。
2.2 cnsampleCommVoStartLayerChn()函数与 cnsampleCommVoStartVo()类似,不同之处在于不启动 VO 设备,
一般用于在 VO 设备启动后改变 Layer 和 channel 的属性参数。
参考资料:
寒武纪媒体处理系统开发者手册-CN-v0.8.0.pdf
评论