1、简介
海思提供的媒体处理软件平台(Media Process Platform,简称 MPP)
VDEC用来解码的,比如磁盘里面有一个
VDA对视频内容简单的侦测
VPSS处理
VO是用于直接显示的。
2、什么是视频缓冲池
(1)视频的本质是多帧图片,图片的本质是RGB或rawRGB数据,要占用一段连续内存
(2)视频的裁剪、缩放、修正处理等各种操作,本质上就是对内存中的数据进行运算
(3)视频缓存池(VB, video buffer)就是一段很大,又被合理划分和管理的内存,用来做视频数据的暂存和运算场地
(4)公共视频缓存池的公共2字,可以理解为全局变量,也就是各个模块都能访问的一段内存
(5)看似视频缓存块在各个模块之间流转,实际上并没有内存复制,而是指针在传递
(6)视频缓存池的内存由MPP来维护,我们在系统启动时就把整个SDRAM分成了2部分:系统部分(由linux kernel来维护管理)和mpp部分(由mpp系统来维护管理)
(7)缓存池需要几个,每个中包含几个缓存块,每个缓存块多大,都是可以由用户程序设置好参数,然后调用MPP的相应API来向MPP申请分配的。
海思3518e里面有多个缓冲池,一个缓冲池里面又有很多缓冲块,大小相同地址相连,缓冲池的数量由内存大小决定(应该是自行划定的吧,还未求证)这些都是由mpp维护的。
视频处理流程大致如下,先从缓冲池取出一个缓冲块,然后放入VI中,将一帧数据填充进bm,之后传入vpss进行处理,然后将处理完是数据放入新的缓冲块中,最后将刚刚使用过的Bmijk缓冲块释放回去。
3、相关的数据结构和API
(1)VB_CONF_S:用于参数设置的,设置缓冲池有几个,缓冲块的数量大小等。
typedef struct hiVB_CONF_S
{
HI_U32 u32MaxPoolCnt; //设置申请最多缓冲池的数量,范围是0- 16/* max count of pools, (0,VB_MAX_POOLS] */
struct hiVB_CPOOL_S
{
HI_U32 u32BlkSize; //缓冲块大小
HI_U32 u32BlkCnt; //缓冲块数量
HI_CHAR acMmzName[MAX_MMZ_NAME_LEN]; //缓冲池的名字,用于调试阶段可以看到名字
}astCommPool[VB_MAX_COMM_POOLS];//最大上限16个公共缓冲池
} VB_CONF_S;
(2)HI_MPI_VB_SetConf:API,用于将缓冲池信息设置到mpp系统中
(3)HI_MPI_VB_Init :API,执行设置缓冲池的操作。
【举例】
HI_S32 s32ret;
VB_CONF_S stVbConf;
memset(&stVbConf,0,sizeof(VB_CONF_S));
stVbConf.u32MaxPoolCnt = 128; //设置缓冲池数量最大上限
stVbConf.astCommPool[0].u32BlkSize = 768*576*2; //设置第一个缓冲块大小
stVbConf.astCommPool[0].u32BlkCnt = 20; //设置第一个缓冲块数量
stVbConf.astCommPool[1].u32BlkSize = 384*288*2; //设置第二个缓冲块大小
stVbConf.astCommPool[1].u32BlkCnt = 40; //设置第二个缓冲块数量
s32ret = HI_MPI_VB_SetConf(&stVbConf); //将缓冲池信息设置到mpp系统中
if (HI_SUCCESS != s32ret)
{
printf("set vb err:0x%x\n", s32ret);
return s32ret;
}
s32ret = HI_MPI_VB_Init(); //初始化
if (HI_SUCCESS != s32ret)
{
printf("init vb err:0x%x\n", s32ret);
return s32ret;
}
SAMPLE_VENC_1080P_CLASSIC();函数主要工作流程。
程序主要是为了录像,指挥摄像头采集图像,然后将图像编码最后输出码流。
第一部分:初始化sys部分的变量,sys也就是mpp中的变量填充,列如VB结构体里面的数据
第二部分:初始化mpp系统
第三部分:启动VI部分(设备和通道),然后采集图像(和摄像头相关部分)
第四部分:启动VPSS,然后将vi处理完的数据传给vpss(使用bind函数将vi和vpss绑定在一起)
第五部分:启动编码,这部分由mpp内部完成,仅调用相关API即可。
第六部分:仅仅只是将流数据保存成文件。
3.1、第一部分详解
首先清空VB_CONF_S结构体,为了后续填充变量做准备。
然后调用SAMPLE_COMM_VI_GetSizeBySensor(PIC_SIZE_E *penSize)这个函数,传入enSize数组,在这个函数里面可以看到
SAMPLE_VI_MODE_E enMode = SENSOR_TYPE;,其中SENSOR_TYPE是在外部makefile中定义的,通过SENSOR_TYPE来确定enSize的内容,enSize是用于存放将来编码之后传输出来的码流。
s32ChnNum是设置输出多少个码流。
其中码流输出的图像是一致的,但是分辨率大小是不一样的,其中一路是主码流,其他的则是从主码流中裁剪缩放而来的。
一个缓冲池对应一个码流。
SAMPLE_COMM_SYS_CalcPicVbBlkSize(VIDEO_NORM_E enNorm, PIC_SIZE_E enPicSize, PIXEL_FORMAT_E enPixFmt, HI_U32 u32AlignWidth)
这个函数是用于计算出一个缓冲块需要多大空间。
VIDEO_NORM_E enNorm:传入视频格式,PAL制和NTSC制
PIC_SIZE_E enPicSize:图像尺寸
PIXEL_FORMAT_E enPixFmt:像素格式
HI_U32 u32AlignWidth:需要对齐排布的大小
其中这个函数的块大小=图像大小(根据长宽高和像素格式求得)+头信息。
u32VbSize = (CEILING_2_POWER(stSize.u32Width, u32AlignWidth) * \
CEILING_2_POWER(stSize.u32Height,u32AlignWidth) * \
((PIXEL_FORMAT_YUV_SEMIPLANAR_422 == enPixFmt)?2:1.5));
#define CEILING_2_POWER(x,a) ( ((x) + ((a) - 1) ) & ( ~((a) - 1) ) )//x往a上除,直到能被整除
第二部分
SAMPLE_COMM_SYS_Init(&stVbConf);
第三部分详解
学习方法:绘制调用关系图谱
(1)简单浏览VI部分的调用层次,发现很复杂
(2)有些函数是sample写的,有些是调用MPP的,数据结构也是2种都有
SAMPLE_xxx就是sample内部自己实现的
HI_MPI_xxx就是调用mmp
(3)学习重点1:全局把控熟悉整个过程全景视图。
(4)学习重点2:掌握细节数据结构元素含义,和遇到的概念。
(5)学习重点3:知道某些关键操作在哪里定义,哪里设置,将来需要改的时候能找到地方 。
main
SAMPLE_VENC_1080P_CLASSIC
SAMPLE_COMM_VI_GetSizeBySensor(step1)
SAMPLE_COMM_SYS_CalcPicVbBlkSize
SAMPLE_COMM_SYS_GetPicSize
SAMPLE_COMM_SYS_Init(step2)
HI_MPI_SYS_Exit();
HI_MPI_VB_Exit();
HI_MPI_VB_SetConf
HI_MPI_VB_Init
HI_MPI_SYS_SetConf
HI_MPI_SYS_Init
SAMPLE_COMM_VI_StartVi(step3)----------------------->
stViConfig.enViMode = SENSOR_TYPE; //sensor的类型
stViConfig.enRotate = ROTATE_NONE; //输出图像是否旋转(0、90、180°等)
stViConfig.enNorm = VIDEO_ENCODING_MODE_AUTO;//图像制式(PAL、NTSC)
stViConfig.enViChnSet = VI_CHN_SET_NORMAL; //图像加工(镜像、翻转等)
stViConfig.enWDRMode = WDR_MODE_NONE; //WDR宽动态
IsSensorInput
SAMPLE_COMM_VI_StartIspAndVi
SAMPLE_COMM_VI_StartMIPI(1)//对sensor做必要的初始化
//mipi是sensor和主芯片hi3518e之间的一种接口
//常用的接口有MIPI、LVDS、DC
SAMPLE_COMM_VI_SetMipiAttr
fd = open("/dev/hi_mipi", O_RDWR);
ioctl(fd, HI_MIPI_SET_DEV_ATTR, pstcomboDevAttr)
SAMPLE_COMM_ISP_Init(2)//isp就是image signal process,图像信号处理
//HI3518E内部的ISP硬件单元是隶属于VI模块的
sensor_register_callback //在sensor驱动中,在/component/isp/sensor
HI_MPI_AE_Register //注册3A单元:自动曝光
HI_MPI_AWB_Register //注册3A调试:自动白平衡
HI_MPI_AF_Register //注册3A调试:自动对焦
HI_MPI_ISP_MemInit //分配内存单元
HI_MPI_ISP_SetWDRMode //宽动态
HI_MPI_ISP_SetPubAttr --------------------->
根据sensor的类型进行设置,填充stPubAttr结构体。
以AR0130为例
stPubAttr.enBayer = BAYER_GRBG; //参考sensor手册得知,像素排列顺序
stPubAttr.f32FrameRate = 30; //帧率
stPubAttr.stWndRect.s32X = 0; //图像区域的起始点X
stPubAttr.stWndRect.s32Y = 0; //图像区域的起始点Y
stPubAttr.stWndRect.u32Width = 1280; //图像长
stPubAttr.stWndRect.u32Height = 720; //图像宽
HI_MPI_ISP_Init //初始化isp模块
SAMPLE_COMM_ISP_Run(3)//创建线程运行isp
pthread_create(&gs_IspPid, &attr, (void* (*)(void*))Test_ISP_Run, NULL)
Test_ISP_Run
HI_MPI_ISP_Run
SAMPLE_COMM_VI_StartDev(4)
HI_MPI_VI_SetDevAttr //在step3中设置的参数,一路传到这才被写入硬件单元
HI_MPI_ISP_GetWDRMode //在上一步isp中设置了SetWDRMode,这一步获取设置信息
HI_MPI_VI_SetWDRAttr
HI_MPI_VI_EnableDev //启动硬件单元
SAMPLE_COMM_VI_StartChn(5) //设置主通道
HI_MPI_VI_SetChnAttr //
HI_MPI_VI_SetRotate
HI_MPI_VI_EnableChn
SAMPLE_COMM_SYS_GetPicSize(step4)//得到处理图像的长和高
SAMPLE_COMM_VPSS_StartGroup //开启Group
HI_MPI_VPSS_CreateGrp //先创建一个Group
HI_MPI_VPSS_GetNRParam//获取NR的参数(降噪相关的)
HI_MPI_VPSS_SetNRParam//在写入进去(如果要做降噪相关的处理就需要在这之前对参数进行修改)
HI_MPI_VPSS_StartGrp //最后再启动
SAMPLE_COMM_VI_BindVpss //将Vpss创建出来的Group和Vi的channel绑定在一起。
HI_MPI_SYS_Bind //调用海思驱动。
SAMPLE_COMM_VPSS_EnableChn------------------------->
VpssChn = 0; //通道号
stVpssChnMode.enChnMode = VPSS_CHN_MODE_USER; //设置通道模式为用户模式
stVpssChnMode.bDouble = HI_FALSE; //现场帧率模式传输(不了解)
stVpssChnMode.enPixelFormat = PIXEL_FORMAT_YUV_SEMIPLANAR_420;
stVpssChnMode.u32Width = stSize.u32Width; //该通道输出图像的长
stVpssChnMode.u32Height = stSize.u32Height; //该通道输出图像的宽
stVpssChnMode.enCompressMode = COMPRESS_MODE_SEG;//内部压缩图像的模式
SAMPLE_COMM_VENC_Start(step5)//
SAMPLE_COMM_VENC_BindVpss//绑定Vpss和Venc的channel绑定在一起。
SAMPLE_COMM_VENC_StartGetStream(step6)//
SAMPLE_COMM_VENC_GetVencStreamProc
HI_MPI_VENC_GetChnAttr
SAMPLE_COMM_VENC_GetFilePostfix
HI_MPI_VENC_GetFd
HI_MPI_VENC_Query //返回状态信息
HI_MPI_VENC_GetStream
SAMPLE_COMM_VENC_SaveStream//保存流文件
SAMPLE_COMM_VENC_SaveH264
HI_MPI_VENC_ReleaseStream //
SAMPLE_COMM_VENC_StopGetStream(step7)
4、vpss基础知识
全称:Video Process Sub-System
支持对一幅输入图像进行统一预处理,如去噪、去隔行等,然后再对各通道分别进行缩放、锐化等处理,最后输出多种不同分辨率的图像。
概念:
GROUP:VPSS 对用户提供组(GROUP)的概念,各 GROUP 分时复用 VPSS 硬件。每个 VPSS GROUP 包含多个通道,通道数目视方案实现有所不同。
CHANNEL:VPSS 组的通道。通道分为 2 种:物理通道和扩展通道。VPSS 硬件提供多个物理通道,每个通道具有缩放、裁剪等功能。扩展通道具备缩放功能,它通过绑定物理通道,将物理通道输出作为自己的输入,把图像缩放成用户设置的目标分辨率输出。扩展通道借助物理通道的输出来进行处理。
FRC:帧率控制,分为 2 种:group 帧率控制和 chn 帧率控制。例如可变帧率的录制。
Crop:裁剪,分为 3 种:group 的裁剪和物理通道的裁剪以及扩展通道的裁剪。
− Group 的裁剪,VPSS 对输入图像进行裁剪。
− 物理通道的裁剪,VPSS 对各个物理通道的输出图像进行裁剪。
− 扩展通道的裁剪,VPSS 调用 VGS 对扩展通道的输出图像进行裁剪。
DEI:De-interlace,去隔行。将交错的隔行视频源还原成逐行视频源。
NR:去噪。通过参数配置,把图像中的高斯噪声去除,使得图像变得平滑,有助于降低编码码率。
Scale:缩放,对图像进行缩小放大。
LDC:Lens Distortion Correction,镜头畸变校正,一些低端镜头容易产生图像畸变,需要根据畸变程度对其图像进行校正。
Cover:视频遮挡区域,对 VPSS 的输出图像填充纯色块。
Overlay:视频叠加区域,在 GROUP 上进行位图的加载和背景色更新,支持 ARGB4444、ARGB1555、ARGB8888 三种格式的位图。
Border:边框,VPSS 在输出图像上加边框。
备份节点:原始图像的备份节点。每个 GROUP 都有一个备份节点,用于备份即将提交硬件处理的那帧原始图像。VPSS 在以下情况会将缓存队列队头节点的图像放入备份节点:
− 当队头节点的图像要经过 VPSS 硬件处理时,VPSS 会将其放入备份节点,并替换掉原有图像。
− 当后端绑定的接收模块要求 VPSS 将队头图像放入备份节点时,VPSS 也会替换备份节点中的图像,即使该图像不经过硬件处理。
低延时:在 VI—VPSS 的在线方案中,编码器性能足够的情况下,VPSS 支持按照,以行为单位,边采集边发送的方式,将图像发送给编码模块进行编码,用来减少 VPSS处理完整帧图像再发送给编码模块过程中,数据的延时时间。这样的方式即为低延时方案。
5、VI/VPSS 离/在线模式
VI/VPSS 离线模式是指 VI 进行时序解析后将图像数据写出到 DDR,VPSS 从DDR 中载入 VI 采集的数据进行图像处理,是传统Hi3518/Hi3520D 等芯片的VI/VPSS 的协作模式。
VI/VPSS 在线模式是指 VI 进行时序解析后直接在芯片内部将数据传递到 VPSS,中间无 DDR 写出的过程(少了一次到两次的内存复制)。在线模式可以省一定的带宽和内存,降低端到端的延时。需要注意的是,在线模式时,因为 VI 不写出数据到 DDR,无法进行CoverEx、OverlayEx、Rotate、LDC 等操作,需要在 VPSS 各通道写出后再进行Rotate/LDC 等处理,而且有些功能只在离线下能支持,比如 DIS。
通过调用HI_MPI_SYS_Bind函数可以将可与 VI 和 VO/VENC/IVE 等模块进行绑定,其中前者为 VPSS 的输入源(VO),后者为 VPSS 的接收者。每个 GROUP 仅可与一个输入源绑定。GROUP 的物理通道有两种工作模式:AUTO 和 USER,两种模式间可动态切换。默认的工作模式为 AUTO,此模式下各通道仅可与一个接收者绑定。USER 模式主要用于对同一通道图像进行多路编码的场景。
注:Hi3516A/Hi3518EV200/Hi3519V100 仅支持 USER 工作模式。
VENC 模块,即视频编码模块。本模块支持多路实时编码,且每路编码独立,编码协议和编码 profile(图像不同的清晰度标准) 可以不同。本模块支持视频编码同时,调度 Region 模块对编码图像内容进行叠加(OSD)和遮挡。
BP:基本的,清晰度不怎么样,但编码速度快。
MP:主流的,性能平衡。
HP:高清的,清晰度最好的。
视频编码的流程:典型的编码流程包括了输入图像的接收、图像内容的遮挡和覆盖、图像的编码、以及码流的输出等过程。
码率控制器:码率控制器实现对编码码率进行控制。
从信息学的角度分析,图像的压缩比越低,压缩图像的质量越高;图像压缩比例越高,压缩图像的质量越低。对于场景变化的真实场景,图像质量稳定,编码码率会波动;编码码率稳定,图像质量会波动(例如运动视频,如果压缩度过高,就会破坏视频质量)。以 H.264 编码为例,通常图像 Qp 越低,图像的质量越好,码率越高;图像 Qp (h.264编码中的一个概念)越高,图像质量越差,码率越低。
码率控制器分别提供了对 H.264\H.265\MJPEG 协议编码通道 CBR、VBR、FIXQP 等三种码率控制模式,对图像质量和码率进行调节。
CBR(Constant Bit Rate)固定比特率。即在码率统计时间内保证编码码率平稳。码率稳定主要由两个量来评估,这两个量都可以由用户在创建编码通道时指定。
VBR(Variable Bit Rate)可变比特率,即允许在码率统计时间内编码码率波动,从而保证编码图像质量平稳。以 H.264 编码为例,VENC 模块提供用户可设置 MaxQp,MinQp,MaxBitrate 和 ChangePos。MaxQp,MinQp 用于控制图像的质量范围,MaxBitrate 用于钳位码率统计时间内的最大编码码率,ChangePos 用于控制开始调整Qp 的码率基准线。
Fix Qp 固定 Qp 值。在码率统计时间内,编码图像所有宏块 Qp 值相同,采用用户设定的图像 Qp 值,I 帧和 P 帧的 QP 值可以分别设的置。