前面说了MPP的几大模块及功能,但是在启动MPP业务前,还有MPP系统初始化的工作,同理,应用程序退出MPP业务后,也要完成MPP系统去初始化工作,释放资源。因此系统控制是根据 Hi35xx 芯片特性,完成硬件各个部件的复位、基本初始化工作,同时负责完成 MPP(Media Process Platform 媒体处理平台)系统各个业务模块的初始化、去初始化以及管理 MPP 系统各个业务模块的工作状态、提供当前 MPP 系统的版本信息、提供大块物理内存管理等功能。我的理解是系统控制是对硬件资源、模式的调度,大致有下面几个功能:
视频缓存池:
视频缓存池主要向媒体业务提供大块物理内存管理功能,负责内存的分配和回收,充分发挥内存缓存池的作用,让物理内存资源在各个媒体处理模块中合理使用。
视频缓存池是由一组大小相同、物理地址连续的缓存块组成,必须在系统初始化之前配置公共视频缓存池。公共缓存池的数量、缓存块的大小和数量根据业务的不同而不同。
上图为典型的公共视频缓存池数据流图,所有视频输入通道都可以从这里获取视频缓存块,用于保存采集的图像。例如图中VI从缓存池中获取缓存块Bm并发送给VPSS,VPSS处理后再释放回公共视频缓存池(下面的虚线)。假设VPSS的工作模式是USER(该模式主要用于对同一通道图像进行多路编码的场景),则 VPSS 通道 0 从公共视频缓存池 B 中获取缓存块 Bi 作为输出图像缓存 buffer 发送给 VENC,VPSS 通道 1 从公共视频缓存池 B 中获取缓存块 Bk 作为输出图像缓存 buffer 发送给 VO,Bi 经 VENC 编码完之后释放回公共视频缓存池,Bk 经 VO 显示完之后释放回公共视频缓存池。不同类型的视频缓存池大小计算参考hi_buffer.h。
系统绑定
MPP提供系统绑定接口(HI_MPI_SYS_Bind),即通过数据接收者绑定数据源来建立两者之间的关联关系(只允许数据接收者绑定数据源)。绑定后,数据源生成的数据将自动发送给接收者。目前MPP支持的绑定关系如下:
数据源VI, 数据接收者:VO、VENC、VPSS、PCIV、VI(虚拟PIPE)
数据源VPSS, 数据接收者:VO、VENC、VPSS、PCIV、VI(虚拟PIPE)、AVS
数据源VDEC, 数据接收者:VO、VENC、VPSS、PCIV、VI(虚拟PIPE)
数据源VO(WBC), 数据接收者:VO、VENC、VPSS、PCIV、VI(虚拟PIPE)
数据源AVS, 数据接收者:VO、VENC、VPSS、PCIV、VI(虚拟PIPE)
数据源AI, 数据接收者:AO、AENC
数据源ADEC, 数据接收者:AO
HI_MPI_SYS_Bind是数据源到数据接收者的绑定接口,语法为:
HI_S32 HI_MPI_SYS_Bind(const MPP_CHN_S *pstSrcChn, const MPP_CHN_S
*pstDestChn);
其中 pstSrcChn指源通道指针,pstDestChn指目的通道指针,该API需求的头文件为:hi_comm_sys.h、mpi_sys.h,需求的库文件为:libmpi.a,该API使用的注意事项为:
·系统目前支持的绑定关系见上文;
·同一个数据接收者只能绑定一个数据源;
·绑定是指数据源和数据接收者建立关联关系。绑定后,数据源生成的数据将自动发送给接收者。
·VI 和 VDEC 作为数据源,是以通道为发送者,向其他模块发送数据,用户将设备号置为0,SDK不检查输入的设备号;
·VO 作为数据源发送回写(WBC)数据时,是以设备为发送者,向其他模块发送数据,用户将通道号置为0,SDK不检查输入的通道号;
·VPSS作为数据接收者时,是以设备(GROUP)为接收者,接收其他模块发来的数据,用户将通道号置为0;
·VENC 作为数据接收者时,是以通道号为接收者,接收其他模块发过来的数据用户将设备号置为0,SDK不检查输入的设备号;
·AVS 作为数据接收者时,是以设备(GROUP)、通道(PIPE)为接收者;
·其他情况均需指定设备号和通道号。
在代码中搜了一下,关于系统绑定这块是有sample的,各种绑定都有,假如我希望VENC绑定VI为数据源,跳过VPSS处理,
HI_S32 SAMPLE_COMM_VI_UnBind_VENC(VI_PIPE ViPipe, VI_CHN ViChn, VENC_CHN VencChn)
{
MPP_CHN_S stSrcChn;
MPP_CHN_S stDestChn;
stSrcChn.enModId = HI_ID_VI;
stSrcChn.s32DevId = ViPipe;
stSrcChn.s32ChnId = ViChn;
stDestChn.enModId = HI_ID_VENC;
stDestChn.s32DevId = 0;
stDestChn.s32ChnId = VencChn;
CHECK_RET(HI_MPI_SYS_UnBind(&stSrcChn, &stDestChn), "HI_MPI_SYS_UnBind(VI-VENC)");
return HI_SUCCESS;
}
则代码为:
HI_S32 SAMPLE_COMM_VI_Bind_VENC(VI_PIPE ViPipe, VI_CHN ViChn, VENC_CHN VencChn)
{
MPP_CHN_S stSrcChn;
MPP_CHN_S stDestChn;
stSrcChn.enModId = HI_ID_VI;
stSrcChn.s32DevId = ViPipe;
stSrcChn.s32ChnId = ViChn;
stDestChn.enModId = HI_ID_VENC;
stDestChn.s32DevId = 0;
stDestChn.s32ChnId = VencChn;
CHECK_RET(HI_MPI_SYS_Bind(&stSrcChn, &stDestChn), "HI_MPI_SYS_Bind(VI-VENC)");
return HI_SUCCESS;
}
解绑的API为 HI_MPI_SYS_UnBind ,语法为:
HI_S32 HI_MPI_SYS_UnBind(const MPP_CHN_S *pstSrcChn, const MPP_CHN_S
*pstDestChn);
pstDestChn如果找不到绑定的源通道,则直接返回成功。如果找到了绑定的源通道,但是绑定的源通道和pstSrcChn不匹配,则返回失败。若需将上面的VENC和VI解绑,代码为:
HI_S32 SAMPLE_COMM_VI_UnBind_VENC(VI_PIPE ViPipe, VI_CHN ViChn, VENC_CHN VencChn)
{
MPP_CHN_S stSrcChn;
MPP_CHN_S stDestChn;
stSrcChn.enModId = HI_ID_VI;
stSrcChn.s32DevId = ViPipe;
stSrcChn.s32ChnId = ViChn;
stDestChn.enModId = HI_ID_VENC;
stDestChn.s32DevId = 0;
stDestChn.s32ChnId = VencChn;
CHECK_RET(HI_MPI_SYS_UnBind(&stSrcChn, &stDestChn), "HI_MPI_SYS_UnBind(VI-VENC)");
return HI_SUCCESS;
}
VI和VPSS的工作模式
VI和VPSS各自的工作模式分为在线、离线、并行,不同工作模式说明如下:
暂时不理解不同工作模式在实际使用过程中有什么区别,或者什么情况应该使用什么模式,后续如果要用到再回过来研究。
强制销毁VB功能
插入hi35xx_base.ko时加上模块参数vb_force_exit=1,可允许用户在程序退出时不用手动销毁VB,而由系统强制销毁VB,海思对于此功能的描述是:不是规范安全的做法,建议客户还是应该在退出程序时释放已申请的资源,禁止在使用时强制销毁资源。因此也就不再细看。
系统控制一块包括许多API,初始化、MMZ内存分配、日志管理等等,这里就不一一罗列了,毕竟没有实战过,看一遍也是没啥感觉的,要用的时候再研究。
祝大家平安健康。