前言
海思的OSD功能除了之前提到的第三方库,自己的VGS也可以做到一些简单的诸如画线之类的操作,这里介绍下假如类似识别时需要画矩形框的时候可以的一种做法
海思VGS简介
海思的VGS 是视频图形子系统,全称为 Video Graphics Sub-System。支持对一幅输入图像进行处理,如进行缩放、像素格式转换、视频存储格式转换、压缩/解压、打 COVER、打 OSD、画线、旋转、动态范围转换等处理。
海思VGS基本概念
HANDLE
任务句柄,标识一个 job。
job
VGS 管理 task 的结构,一个 job 里可以包含多个 task,VGS 保证 task 按照添加到job 的顺序执行,并且保证一个 job 里的所有 task 一次性提交硬件执行。用户可以在加载 VGS ko 时设置模块参数(max_vgs_job)来设置 VGS 支持的最大 job 数。
job 数取值范围为[20, 400],Linux 默认为 128, Huawei LiteOS 默认值为 64。
task
对一幅图像完成具体的一个或多个操作,比如打 OSD、缩放或像素格式转换等。
用户可以在加载 VGS ko 时设置模块参数(max_vgs_task)来设置 VGS 支持的最大 task 数。task 数取值范围为[20, 800],Linux 默认为 200, Huawei LiteOS 默认值为 100。
node
VGS 硬件的最小执行单位,一个 task 对应一个或多个 node。node 中包含硬件工作需要的信息,比如源图像地址,目标图像地址,操作类型等,并按照硬件要求的形式组织。用户可以在加载 VGS ko 时设置模块参数(max_vgs_node)来设置VGS 支持的最大 node 数。node 数取值范围为[20, 800],Linux 默认为 200, Huawei LiteOS 默认值为 100。
bVgsHdrSupport
HDR 模块参数,取值范围[0, 1],0 为关闭(默认关闭 HDR),HDR 关闭时 VGS只支持 SDR8 和 SDR10。用户可以在加载 VGS ko 时设置模块参数(bVgsHdrSupport)来设置 VGS 是否支持 HDR。此模块参数仅用于Hi3559AV100。
vgs_en[VGS_IP_NUM]
VGS 硬件开关,用户可以在加载 VGS ko 时设置模块参数(vgs_en)来设置 VGSIP 开启或关闭。默认所有 IP 都开启。当 VGS_IP_NUM 为 2 时,只支持开启或关闭 VGS1,插 ko 后 VGS0 始终打开;当 VGS_IP_NUM 为 1 时,该参数无效,插ko 后 VGS0 始终打开。
bVgsExitInSys
VGS 模块参数,用于指定用户在调用 HI_MPI_SYS_Exit 接口时是否退出 VGS,取值范围[HI_FALSE, HI_TRUE]。用户可以在加载 VGS ko 时设置模块参数(bVgsExitInSys)来指定在 HI_MPI_SYS_Exit 时是否退出 VGS,bVgsExitInSys=0表示不退出,bVgsExitInSys=1 表示退出(默认值是 1)。
注意:
如果不退出 VGS,VGS 分配的内存是没有释放的(包括 MMZ 内存),若需要释放 VGS 内存,需要卸载 ko。此模块参数仅用于 Hi3516EV200。
功能描述
VGS 的功能主要有缩放、打 OSD、打 COVER、画线、像素格式转换、视频存储格式转换、压缩/解压、旋转、低功耗策略、动态范围转换。
缩放
VGS 支持对一幅图像进行缩放,最大支持图像宽高均放大 16 倍,最大支持图像宽高均缩小 30 倍。支持单分量(Y)缩放。
打 OSD
VGS 支持在一幅图像上叠加一张位图,可设置位图是否反色,支持批量打 OSD。
注意:VGS 每个 task 只支持打一个 OSD;需要打多个 OSD 时,需要通过提交多个 task 来实现,每个 task 使用上一个 task 打完 OSD 的图像作为当前 task 的源图像进行打 OSD 处理(批量打 OSD)。VGS 打 OSD 操作只支持非压缩图像输入,非压缩图像输出,或者是压缩图像输入,压缩图像输出。VGS 离线打 OSD 操作时,输入输出图像使用的是同一块内存。Hi3516EV200 不支持反色。
打 COVER
VGS 支持对一幅图像进行遮挡操作,遮挡区域形状可以是矩形或者任意四边形,遮挡区域颜色为纯色,支持批量打 COVER。
注意:VGS 每个 task 只支持打一个 COVER;需要打多个 COVER 时,需要通过提交多个 task 来实现,每个 task 使用上一个 task 打完 COVER 的图像作为当前task 的源图像进行打 COVER 处理(批量打 COVER)。VGS 打 COVER 操作只支持非压缩图像输入,非压缩图像输出,或者是压缩图像输入,压缩图像输出。
VGS 离线打 COVER 操作时,输入输出图像使用的是同一块内存。
画线
VGS 支持对一幅图像进行画线操作。画线通过打 COVER 实现,支持批量画线。注意:使用画线功能时,
画线操作时,如果起始坐标和结束坐标的 X 坐标相同,则起始坐标和结束坐标的Y 坐标不变,X 坐标分别向右增加线的宽度。
画线操作时,如果起始坐标和结束坐标的 X 坐标不相同,则 X 坐标不变,起始坐标与结束坐标的 Y 坐标分别向下方延伸线的宽度(即 X 坐标不变,Y 坐标向下增加线宽)。
像素格式转换
VGS 支持的输入输出像素格式包括 semi-planar 420、semi-planar 422 和单分量(Y)。支持 semi-planar 420 与 semi-planar 422 之间的格式转换,支持 semi-planar420、semi-planar 422 到单分量(Y)格式的转换,Hi3516EV200 支持 semi-planar420/semi-planar 422 转为 packed 422 格式,具体格式见表 10-2 至表 10-8。做像素格式转换时,支持 UV 先后顺序可调整。
视频存储格式转换
− Hi3559AV100 VGS 支持 linear、TILE 和 semi-planar 420 16x8 tile 格式转为 GPU格式。
− Hi3559AV100 支持 TILE 和 semi-planar 420 16x8 tile 格式转为 linear 格式。
− Hi3559AV100 VGS 支持 linear 格式下 semi-planar 422、semi-planar 420 和单分量(Y)格式的压缩/解压。
− Hi3559AV100 支持 TILE 格式下 semi-planar 420 格式的解压缩。
− Hi3559AV100 支持 16x8 tile 格式下 semi-planar 420 格式的解压缩。
旋转
VGS 支持 0、90、180 和 270 度的旋转。
低功耗策略
VGS 模块使用低功耗策略,在 VGS 没有工作时 VGS 时钟是关闭的,这时候手动读写 VGS 模块的寄存器可能会有读写错误或者卡死的现象。
动态范围转换
VGS 支持视频的动态范围转换,具体为:
− Hi3559AV100 支持 HLG/HDR10 转 SDR10/SDR8。
VGS 支持 OSD 的动态范围转换,具体为:
− Hi3559AV100 支持 SDR 转 HDR10/HLG。
注意:
叠加 OSD 时,用于叠加的图像为标准动态范围图像。仅 Hi3559AV100ES、Hi3559AV100 支持动态范围转换。HDR 转换时需要设置 bVgsHdrSupport=1。仅缩放接口支持 YUV 的动态范围转换。
API 参考
该功能模块为用户提供以下 MPI:
HI_MPI_VGS_BeginJob:启动一个 job。
HI_MPI_VGS_AddScaleTask:往一个已经启动的 job 添加缩放 task。
HI_MPI_VGS_AddDrawLineTask:往一个已经启动的 job 添加画线 task。
HI_MPI_VGS_AddDrawLineTaskArray:往一个已经启动的 job 中添加批量划线task。
HI_MPI_VGS_AddCoverTask:往一个已经启动的 job 添加打 COVER task。
HI_MPI_VGS_AddCoverTaskArray:往一个已经启动的 job 中添加打批量 COVERtask。
HI_MPI_VGS_AddOsdTask:往一个已经启动的 job 添加打 OSD task。
HI_MPI_VGS_AddOsdTaskArray:往一个已经启动的 job 添加打批量 OSD task。
HI_MPI_VGS_AddRotationTask:往一个已经启动的 job 里添加旋转任务。
HI_MPI_VGS_AddLumaTaskArray:往一个已经启动的 job 里添加获取亮度和任务。
HI_MPI_VGS_EndJob:提交一个 job。
HI_MPI_VGS_CancelJob:取消一个 job。
示例代码
vgs.cpp
#include "vgs.h" #define SAMPLE_VGS_ARRAYNUM 4 static VGS_HANDLE g_hHandle[2]={0,1}; HI_S32 g_DefaultWGPos_visible[2]={0,0}; // static track_See_Info g_seetrk; // static VGS_ADD_OSD_S g_stVgsAddOsd[SAMPLE_VGS_ARRAYNUM]; /* *描述 :封装海思VGS画线函数 结果为矩形框 *参数 :VIDEO_FRAME_INFO_S *pvfrm 输入 getchnframe获得的图像 * trackResult* pvgsres 输入 从算法库获得的xyhw信息,如果移植可以单独设置位置信息 * HI_U8 grp 输入 用于判断是哪路输入(默认第一路vi对应grp0,以此类推) * HI_U32 lcolor 输入 画线颜色 *返回值:无 *注意 :无 */ void PLATFORM_VGS_RectLine(VIDEO_FRAME_INFO_S *pvfrm, trackResult* pvgsres, HI_U8 grp, HI_U32 lcolor) { HI_S32 s32Ret=-1; VGS_TASK_ATTR_S stVgsTaskAttr; VGS_DRAW_LINE_S stVgsLine[12]={0}; HI_U8 VgslineNum=0; track_See_Info g_seetrk; g_seetrk.trk_x=(int)pvgsres->_x; g_seetrk.trk_y=(int)pvgsres->_y; g_seetrk.trk_w=(int)pvgsres->_w; g_seetrk.trk_h=(int)pvgsres->_h; // if((g_seetrk.trk_x<0) || (g_seetrk.trk_y<0) || (g_seetrk.trk_w<2) ||(g_seetrk.trk_h<2)) // { // return ; // } //step 0 before vgs job,variables initialization if(pvfrm==HI_NULL) { return; } memcpy(&stVgsTaskAttr.stImgOut, pvfrm, sizeof(VIDEO_FRAME_INFO_S)); memcpy(&stVgsTaskAttr.stImgIn, pvfrm, sizeof(VIDEO_FRAME_INFO_S)); //ARGB1555 // for(int ii=0;ii<SAMPLE_VGS_ARRAYNUM;ii++) // { // g_stVgsAddOsd[ii].stRect.s32X = 8; // g_stVgsAddOsd[ii].stRect.s32Y = 96+ii*128; // g_stVgsAddOsd[ii].stRect.u32Width = 180; // g_stVgsAddOsd[ii].stRect.u32Height = 144; // // g_stVgsAddOsd[ii].u32BgColor = 0xFFFFFF; // // g_stVgsAddOsd[ii].enPixelFmt = PIXEL_FORMAT_ARGB_8888; // g_stVgsAddOsd[ii].u32BgColor = 0x7FFF; // g_stVgsAddOsd[ii].enPixelFmt = PIXEL_FORMAT_ARGB_1555; // g_stVgsAddOsd[ii].u64PhyAddr = 0; // g_stVgsAddOsd[ii].u32Stride = 0; // g_stVgsAddOsd[ii].u32BgAlpha = 0x0; // g_stVgsAddOsd[ii].u32FgAlpha = 0xff; // //notice this is very important! // g_stVgsAddOsd[ii].bOsdRevert = HI_FALSE;//HI_TRUE // g_stVgsAddOsd[ii].stOsdRevert.stSrcRect = g_stVgsAddOsd[ii].stRect; // g_stVgsAddOsd[ii].stOsdRevert.enColorRevertMode = VGS_COLOR_REVERT_RGB; // } if(grp==0) { //可见光 if(!((g_seetrk.trk_w==0) || (g_seetrk.trk_h==0))) { stVgsLine[0].stStartPoint.s32X=g_seetrk.trk_x/2*2; stVgsLine[0].stStartPoint.s32Y=g_seetrk.trk_y/2*2; stVgsLine[0].stEndPoint.s32X=stVgsLine[0].stStartPoint.s32X; stVgsLine[0].stEndPoint.s32Y=(g_seetrk.trk_y+24)/2*2; stVgsLine[0].u32Thick=2; stVgsLine[0].u32Color=lcolor; stVgsLine[1].stStartPoint.s32X=g_seetrk.trk_x/2*2; stVgsLine[1].stStartPoint.s32Y=g_seetrk.trk_y/2*2; stVgsLine[1].stEndPoint.s32X=(g_seetrk.trk_x+24)/2*2; stVgsLine[1].stEndPoint.s32Y=stVgsLine[1].stStartPoint.s32Y; stVgsLine[1].u32Thick=2; stVgsLine[1].u32Color=lcolor; stVgsLine[2].stStartPoint.s32X=g_seetrk.trk_x/2*2; stVgsLine[2].stStartPoint.s32Y=(g_seetrk.trk_y+g_seetrk.trk_h)/2*2; stVgsLine[2].stEndPoint.s32X=stVgsLine[2].stStartPoint.s32X; stVgsLine[2].stEndPoint.s32Y=(g_seetrk.trk_y+g_seetrk.trk_h-24)/2*2; stVgsLine[2].u32Thick=2; stVgsLine[2].u32Color=lcolor; stVgsLine[3].stStartPoint.s32X=g_seetrk.trk_x/2*2; stVgsLine[3].stStartPoint.s32Y=(g_seetrk.trk_y+g_seetrk.trk_h)/2*2; stVgsLine[3].stEndPoint.s32X=(g_seetrk.trk_x+24)/2*2; stVgsLine[3].stEndPoint.s32Y=stVgsLine[3].stStartPoint.s32Y; stVgsLine[3].u32Thick=2; stVgsLine[3].u32Color=lcolor; stVgsLine[4].stStartPoint.s32X=(g_seetrk.trk_x+g_seetrk.trk_w)/2*2; stVgsLine[4].stStartPoint.s32Y=(g_seetrk.trk_y+g_seetrk.trk_h)/2*2; stVgsLine[4].stEndPoint.s32X=(g_seetrk.trk_x+g_seetrk.trk_w-24)/2*2; stVgsLine[4].stEndPoint.s32Y=stVgsLine[4].stStartPoint.s32Y; stVgsLine[4].u32Thick=2; stVgsLine[4].u32Color=lcolor; stVgsLine[5].stStartPoint.s32X=(g_seetrk.trk_x+g_seetrk.trk_w)/2*2; stVgsLine[5].stStartPoint.s32Y=(g_seetrk.trk_y+g_seetrk.trk_h)/2*2; stVgsLine[5].stEndPoint.s32X=stVgsLine[5].stStartPoint.s32X; stVgsLine[5].stEndPoint.s32Y=(g_seetrk.trk_y+g_seetrk.trk_h-24)/2*2; stVgsLine[5].u32Thick=2; stVgsLine[5].u32Color=lcolor; stVgsLine[6].stStartPoint.s32X=(g_seetrk.trk_x+g_seetrk.trk_w)/2*2; stVgsLine[6].stStartPoint.s32Y=g_seetrk.trk_y/2*2; stVgsLine[6].stEndPoint.s32X=stVgsLine[6].stStartPoint.s32X; stVgsLine[6].stEndPoint.s32Y=(g_seetrk.trk_y+24)/2*2; stVgsLine[6].u32Thick=2; stVgsLine[6].u32Color=lcolor; stVgsLine[7].stStartPoint.s32X=(g_seetrk.trk_x+g_seetrk.trk_w)/2*2; stVgsLine[7].stStartPoint.s32Y=g_seetrk.trk_y/2*2; stVgsLine[7].stEndPoint.s32X=(g_seetrk.trk_x+g_seetrk.trk_w-24)/2*2; stVgsLine[7].stEndPoint.s32Y=stVgsLine[7].stStartPoint.s32Y; stVgsLine[7].u32Thick=2; stVgsLine[7].u32Color=lcolor; VgslineNum+=8; } // stVgsLine[8].stStartPoint.s32X=(960+g_DefaultWGPos_visible[0])/2*2; // stVgsLine[8].stStartPoint.s32Y=(540-18-g_DefaultWGPos_visible[1])/2*2; // stVgsLine[8].stEndPoint.s32X=(960+g_DefaultWGPos_visible[0])/2*2; // stVgsLine[8].stEndPoint.s32Y=(540+18-g_DefaultWGPos_visible[1])/2*2; // stVgsLine[8].u32Thick=2; // stVgsLine[8].u32Color=lcolor; // stVgsLine[9].stStartPoint.s32X=(960-32+g_DefaultWGPos_visible[0])/2*2; // stVgsLine[9].stStartPoint.s32Y=(540-g_DefaultWGPos_visible[1])/2*2; // stVgsLine[9].stEndPoint.s32X=(960+32+g_DefaultWGPos_visible[0])/2*2; // stVgsLine[9].stEndPoint.s32Y=(540-g_DefaultWGPos_visible[1])/2*2; // stVgsLine[9].u32Thick=2; // stVgsLine[9].u32Color=lcolor; // VgslineNum+=2; } else if(grp==1) { //红外 if(!((g_seetrk.trk_w==0) || (g_seetrk.trk_h==0))) { stVgsLine[0].stStartPoint.s32X=g_seetrk.trk_x/2*2; stVgsLine[0].stStartPoint.s32Y=g_seetrk.trk_y/2*2; stVgsLine[0].stEndPoint.s32X=stVgsLine[0].stStartPoint.s32X; stVgsLine[0].stEndPoint.s32Y=(g_seetrk.trk_y+12)/2*2; stVgsLine[0].u32Thick=2; stVgsLine[0].u32Color=lcolor; stVgsLine[1].stStartPoint.s32X=g_seetrk.trk_x/2*2; stVgsLine[1].stStartPoint.s32Y=g_seetrk.trk_y/2*2; stVgsLine[1].stEndPoint.s32X=(g_seetrk.trk_x+12)/2*2; stVgsLine[1].stEndPoint.s32Y=stVgsLine[1].stStartPoint.s32Y; stVgsLine[1].u32Thick=2; stVgsLine[1].u32Color=lcolor; stVgsLine[2].stStartPoint.s32X=g_seetrk.trk_x/2*2; stVgsLine[2].stStartPoint.s32Y=(g_seetrk.trk_y+g_seetrk.trk_h)/2*2; stVgsLine[2].stEndPoint.s32X=stVgsLine[2].stStartPoint.s32X; stVgsLine[2].stEndPoint.s32Y=(g_seetrk.trk_y+g_seetrk.trk_h-12)/2*2; stVgsLine[2].u32Thick=2; stVgsLine[2].u32Color=lcolor; stVgsLine[3].stStartPoint.s32X=g_seetrk.trk_x/2*2; stVgsLine[3].stStartPoint.s32Y=(g_seetrk.trk_y+g_seetrk.trk_h)/2*2; stVgsLine[3].stEndPoint.s32X=(g_seetrk.trk_x+12)/2*2; stVgsLine[3].stEndPoint.s32Y=stVgsLine[3].stStartPoint.s32Y; stVgsLine[3].u32Thick=2; stVgsLine[3].u32Color=lcolor; stVgsLine[4].stStartPoint.s32X=(g_seetrk.trk_x+g_seetrk.trk_w)/2*2; stVgsLine[4].stStartPoint.s32Y=(g_seetrk.trk_y+g_seetrk.trk_h)/2*2; stVgsLine[4].stEndPoint.s32X=(g_seetrk.trk_x+g_seetrk.trk_w-12)/2*2; stVgsLine[4].stEndPoint.s32Y=stVgsLine[4].stStartPoint.s32Y; stVgsLine[4].u32Thick=2; stVgsLine[4].u32Color=lcolor; stVgsLine[5].stStartPoint.s32X=(g_seetrk.trk_x+g_seetrk.trk_w)/2*2; stVgsLine[5].stStartPoint.s32Y=(g_seetrk.trk_y+g_seetrk.trk_h)/2*2; stVgsLine[5].stEndPoint.s32X=stVgsLine[5].stStartPoint.s32X; stVgsLine[5].stEndPoint.s32Y=(g_seetrk.trk_y+g_seetrk.trk_h-12)/2*2; stVgsLine[5].u32Thick=2; stVgsLine[5].u32Color=lcolor; stVgsLine[6].stStartPoint.s32X=(g_seetrk.trk_x+g_seetrk.trk_w)/2*2; stVgsLine[6].stStartPoint.s32Y=g_seetrk.trk_y/2*2; stVgsLine[6].stEndPoint.s32X=stVgsLine[6].stStartPoint.s32X; stVgsLine[6].stEndPoint.s32Y=(g_seetrk.trk_y+12)/2*2; stVgsLine[6].u32Thick=2; stVgsLine[6].u32Color=lcolor; stVgsLine[7].stStartPoint.s32X=(g_seetrk.trk_x+g_seetrk.trk_w)/2*2; stVgsLine[7].stStartPoint.s32Y=g_seetrk.trk_y/2*2; stVgsLine[7].stEndPoint.s32X=(g_seetrk.trk_x+g_seetrk.trk_w-12)/2*2; stVgsLine[7].stEndPoint.s32Y=stVgsLine[7].stStartPoint.s32Y; stVgsLine[7].u32Thick=2; stVgsLine[7].u32Color=lcolor; VgslineNum+=8; } // stVgsLine[8].stStartPoint.s32X=(360+g_DefaultWGPos_infrared[0])/2*2; // stVgsLine[8].stStartPoint.s32Y=(288-10-g_DefaultWGPos_infrared[1])/2*2; // stVgsLine[8].stEndPoint.s32X=(360+g_DefaultWGPos_infrared[0])/2*2; // stVgsLine[8].stEndPoint.s32Y=(288+10-g_DefaultWGPos_infrared[1])/2*2; // stVgsLine[8].u32Thick=2; // stVgsLine[8].u32Color=lcolor; // stVgsLine[9].stStartPoint.s32X=(360-12+g_DefaultWGPos_infrared[0])/2*2; // stVgsLine[9].stStartPoint.s32Y=(288-g_DefaultWGPos_infrared[1])/2*2; // stVgsLine[9].stEndPoint.s32X=(360+12+g_DefaultWGPos_infrared[0])/2*2; // stVgsLine[9].stEndPoint.s32Y=(288-g_DefaultWGPos_infrared[1])/2*2; // stVgsLine[9].u32Thick=2; // stVgsLine[9].u32Color=lcolor; // VgslineNum+=2; } else { VgslineNum=0; } /************************************************ step3: Create VGS job *************************************************/ s32Ret = HI_MPI_VGS_BeginJob(&g_hHandle[0]); if (s32Ret != HI_SUCCESS) { SAMPLE_PRT("HI_MPI_VGS_BeginJob failed, s32Ret:0x%x", s32Ret); } /************************************************ step4: Add VGS task *************************************************/ s32Ret = HI_MPI_VGS_AddDrawLineTaskArray(g_hHandle[0], &stVgsTaskAttr, stVgsLine,VgslineNum); if (s32Ret != HI_SUCCESS) { HI_MPI_VGS_CancelJob(g_hHandle[0]); SAMPLE_PRT("HI_MPI_VGS_AddDrawLineTaskArray failed, s32Ret:0x%x\n", s32Ret); } /************************************************ step5: Start VGS work *************************************************/ s32Ret = HI_MPI_VGS_EndJob(g_hHandle[0]); if (s32Ret != HI_SUCCESS) { HI_MPI_VGS_CancelJob(g_hHandle[0]); SAMPLE_PRT("HI_MPI_VGS_EndJob failed, s32Ret:0x%x\n", s32Ret); } #if 0 //创建第二个job,不要删掉,用于以后参考 //************************************************************************/ s32Ret = HI_MPI_VGS_BeginJob(&g_hHandle[1]); if (s32Ret != HI_SUCCESS) { SAMPLE_PRT("HI_MPI_VGS_BeginJob failed, s32Ret:0x%x", s32Ret); } s32Ret = HI_MPI_VGS_AddDrawLineTaskArray(g_hHandle[1], &stVgsTaskAttr, &stVgsLine[4],2); if (s32Ret != HI_SUCCESS) { HI_MPI_VGS_CancelJob(g_hHandle[1]); SAMPLE_PRT("HI_MPI_VGS_AddDrawLineTask failed, s32Ret:0x%x", s32Ret); } /************************************************ step5: end VGS work *************************************************/ s32Ret = HI_MPI_VGS_EndJob(g_hHandle[1]); if (s32Ret != HI_SUCCESS) { HI_MPI_VGS_CancelJob(g_hHandle[1]); SAMPLE_PRT("HI_MPI_VGS_EndJob failed, s32Ret:0x%x", s32Ret); } #endif }
vgs.h
/****************************************************************************** Copyright (C), 2022, Sunwise Space. Co., Ltd. ****************************************************************************** File Name : yvu.h Version : Author : xin.han Created : 2022.10.27 Description : ******************************************************************************/ #ifndef __VGS_H__ #define __VGS_H__ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <pthread.h> #include <signal.h> #include <pthread.h> #include <fcntl.h> #include <time.h> #include <stdint.h> #include <sys/prctl.h> #include "sample_comm.h" #include "hi_comm_vgs.h" #include "hi_comm_video.h" #include "hi_ive.h" #include "mpi_ive.h" #include "hi_common.h"//IVE库 #include "comm.h" #include "GZQtracker.h" /* VGS临时位置信息 */ typedef struct stVgs_See { int trk_x; int trk_y; int trk_w; int trk_h; }track_See_Info; /* *描述 :封装海思VGS画线函数 结果为矩形框 *参数 :VIDEO_FRAME_INFO_S *pvfrm 输入 getchnframe获得的图像 * trackResult* pvgsres 输入 从算法库获得的xyhw信息,如果移植可以单独设置位置信息 * HI_U8 grp 输入 用于判断是哪路输入(默认第一路vi对应grp0,以此类推) * HI_U32 lcolor 输入 画线颜色 *返回值:无 *注意 :无 */ void PLATFORM_VGS_RectLine(VIDEO_FRAME_INFO_S *pvfrm, trackResult* pvgsres, HI_U8 grp, HI_U32 lcolor); #endif /* End of #ifndef __VGS_H__ */
主函数内相关线程:
/****************************************************************************** Copyright (C), 2017, Hisilicon Tech. Co., Ltd. ****************************************************************************** File Name : sample_venc.c Version : Initial Draft Author : Hisilicon multimedia software group Created : 2017 Description : ******************************************************************************/ // #ifdef __cplusplus // #if __cplusplus extern "C" { // #endif // #endif /* End of #ifdef __cplusplus */ #include "platform.h" } #include "savestream.h" #include "vgs.h" #include "datatype.h" // #include "GZQdetector.h" #include "GZQtracker.h" #include <bits/stdc++.h>//包含了大量C++头文件不需要再一个个查找,缺点是编译会变慢 #include <queue> using namespace std; // sem_t sem_frm_recv; // sem_t sem_frm_process; // sem_t sem_frm_enc; // VIDEO_FRAME_INFO_S stVideoFrame_process; video_process_s stv_process_test ; video_process_s stv_process_osd ;//全局,用于给图像处理线程传参 video_process_s stv_process_yuvdump ; video_process_s stv_process_yuv2rgb ; BITMAP_S stBitmap_bottom_left;//全局 用于更新位图 BITMAP_S stBitmap_top_left;//全局 用于更新位图 HI_S64 rtsp_ts;//全局 RTSP 与实时误差时间,us HI_S32 rtsp_playchl;//全局 rtsp播放通道 HI_BOOL saveEnable,rtspEnable;//全局,用于控制是否保存视频文件 // TTF_Font *font; //全局,用于打开字体文件 // SDL_PixelFormat *osd_fmt;//全局,用于配置OSD文件格式 // BITMAP_S *pstBitmap =&stBitmap; extern HI_U32 luma_value;//亮度值,有ini配置文件传入 extern FILE* pFd_h264test;//保存h264文件名 extern rtsp_demo_handle demo;//端口号 extern rtsp_session_handle session[MAX_SESSION_NUM];//端口会话 extern sem_t sem_saveflg;//信号量,传递保存缓冲池 extern sem_t sem_rtspflg;//信号量,传递rtsp缓冲池 RGN_HANDLE OverlayHandle_bottom_left = 0;//区域叠加句柄(实际为层数layer) RGN_HANDLE OverlayHandle_top_left = 1 ;//区域叠加句柄(实际为层数layer) queue<VIDEO_FRAME_INFO_S> q_stVideoFrame_process;//std:queue队列,用于多线程同步传递消息是否需要处理 queue<VIDEO_FRAME_INFO_S> q_stVideoFrame_process_osd;//std:queue队列,用于多线程同步传递消息是否需要叠加 char FLIRName[255]="./trk/yolov5s_relu_FLIR_yuv420_inst.wk"; char UAVName[255]="./trk/yolov5s_relu_uav_yuv420sp_inst.wk"; float posf[4];//runGzqTracker入参yxhw trackResult g_trk_result;//trackResult追踪结果 extern IVE_HANDLE hIveHandless_visible; extern IVE_HANDLE hIveHandless_infrared; extern IVE_CSC_CTRL_S stCscCtrl; extern IVE_SRC_IMAGE_S ive_yuvImagess_visible; extern IVE_DST_IMAGE_S ive_RGB888Imagess_visible; // extern SDL_Surface *osd_bottom_left,*osd_top_left; // extern pthread_mutex_t mutex; // queue<VIDEO_FRAME_INFO_S> q_stVideoFrame_venc; /*描述 :用于获得us时间,用于计算代码运行时间 *参数 :clockid_t _tclock_id *返回值:us时间 *注意 :tmp = clockGetTime(CLOCK_MONOTONIC); //单位us timeOffset = tmp.tv_sec*1000*1000 + tmp.tv_usec;// 测试代码执行时间 * memset(&tmp,0,sizeof(tmp)); * tmp = clockGetTime(CLOCK_MONOTONIC); * timeOffset1 = tmp.tv_sec*1000*1000 + tmp.tv_usec;//相减即是运行时间 */ timeval clockGetTime(clockid_t _tclock_id) { struct timespec stTime; //该函数的时间精确到纳秒级别 clock_gettime(_tclock_id, &stTime); timeval stRet; stRet.tv_sec = stTime.tv_sec; stRet.tv_usec = stTime.tv_nsec/1000; return stRet; } int tracker_func(unsigned char* img, void* ptcf, trackResult* pres,int choice,detectResult* pdt) { if(choice==4) { g_trk_result = runGzqTracker(img, NULL,pdt,4); } else { // 初始化 if((choice == 1) || (choice ==2 ) ||(choice ==3)) { // posf[0] = (((struct TrkCmdFrm_trk*)ptcf)->yoffset-540)*(-1); posf[0] = ((struct TrkCmdFrm_trk*)ptcf)->yoffset; // posf[1] = ((struct TrkCmdFrm_trk*)ptcf)->xoffset+960; posf[1] = ((struct TrkCmdFrm_trk*)ptcf)->xoffset; posf[2] = ((struct TrkCmdFrm_trk*)ptcf)->height; posf[3] = ((struct TrkCmdFrm_trk*)ptcf)->width; //printf("trk init %f %f %f %f\n", posf[1],posf[0],posf[3],posf[2]); // 初始化跟踪器 g_trk_result=runGzqTracker(img, posf,pdt,choice); } else { g_trk_result = runGzqTracker(img, NULL,pdt,0); } } memcpy(pres,&g_trk_result,sizeof(trackResult)); return 0; } /* *描述 :线程里用于检查是否有图像 *参数 :arg 为自定义结构video_process_s,VPSS_GRP和VPSS_CHN用于传参给HI_MPI_VPSS_GetChnFrame *返回值:无 *注意 :HI_MPI_VPSS_GetChnFrame完必须释放,否则再次获取VB会报错 VIDEO_FRAME_INFO_S里的虚拟地址不可以直接使用,必须通过物理地址HI_MPI_SYS_Mmap映射后才可以作为数据存放地址用 用完同样需要HI_MPI_SYS_Munmap解映射 */ HI_VOID *frame_check_task(HI_VOID *arg) { cpu_set_t mask;//cpu核的集合 cpu_set_t get;//获取在集合中的cpu int num = sysconf(_SC_NPROCESSORS_CONF); printf("frame_check_task:system has %d processor(s)\n", num); CPU_ZERO(&mask);//置空 CPU_SET(0, &mask);//设置亲和力值 if (pthread_setaffinity_np(pthread_self(), sizeof(mask), &mask) < 0)//设置线程CPU亲和力 { fprintf(stderr, "set thread affinity failed\n"); } if (pthread_getaffinity_np(pthread_self(), sizeof(get), &get) < 0)//获取线程CPU亲和力 { fprintf(stderr, "get thread affinity failed\n"); } HI_S32 s32Ret; // VIDEO_FRAME_INFO_S* pstVideoFrame = &stVideoFrame_process; VIDEO_FRAME_INFO_S stVideoFrame_check; video_process_s* pstPara; pstPara = (video_process_s*)arg; // sleep(1); hi_memset(&stVideoFrame_check,sizeof(VIDEO_FRAME_INFO_S),0,sizeof(VIDEO_FRAME_INFO_S)); // queue<int> q; // for(int i = 0; i < 5; i++){ // q.push(i); // } // cout<<q.front()<<' '<<q.back(); while(1) { // sleep(1); s32Ret = HI_MPI_VPSS_GetChnFrame(pstPara->VpssGrp, pstPara->VpssChn, &stVideoFrame_check,1000); // SAMPLE_PRT("pstPara->VpssGrp is %dpstPara->VpssChnis %d!\n",pstPara->VpssGrp, pstPara->VpssChn);//while1打印太多 if(s32Ret != HI_SUCCESS) { usleep(1000); // SAMPLE_PRT("VPSS_GetChnFrame err for %#x!\n",s32Ret);//while1打印太多 } // printf("u32TimeRef is %d\r\n",pstVideoFrame->stVFrame.u32TimeRef); else { // SAMPLE_PRT("frame_check_task:VPSS_GetChnFrame success\n");//while1打印太多 // frm_recv_flag = 1; // sem_post(&sem_frm_recv); q_stVideoFrame_process.push(stVideoFrame_check); // HI_MPI_VPSS_ReleaseChnFrame(pstPara->VpssGrp, pstPara->VpssChn, &stVideoFrame_check); // printf("check%d\n", q_stVideoFrame_process.size()); // printf("check ok\n"); } } return NULL; } /* *描述 :线程里用于处理图像图像 *参数 :arg 为自定义结构video_process_s,VPSS_GRP和VPSS_CHN用于传参给HI_MPI_VPSS_GetChnFrame *返回值:无 *注意 : */ HI_VOID *frame_process_task(HI_VOID *arg) { HI_S32 s32Ret; cpu_set_t mask;//cpu核的集合 cpu_set_t get;//获取在集合中的cpu int num = sysconf(_SC_NPROCESSORS_CONF); printf("frame_process_task:system has %d processor(s)\n", num); CPU_ZERO(&mask);//置空 CPU_SET(3, &mask);//设置亲和力值 if (pthread_setaffinity_np(pthread_self(), sizeof(mask), &mask) < 0)//设置线程CPU亲和力 { fprintf(stderr, "set thread affinity failed\n"); } if (pthread_getaffinity_np(pthread_self(), sizeof(get), &get) < 0)//获取线程CPU亲和力 { fprintf(stderr, "get thread affinity failed\n"); } VIDEO_FRAME_INFO_S stVideoFrame_process; video_process_s* pstPara; pstPara = (video_process_s*)arg; // HI_CHAR *pcModelName = UAVName; // printf("before createGzqDetector\n"); // createGzqDetector(pcModelName);//跟踪器初始化 // printf("after createGzqDetector\n"); createGzqTracker(1920, 1080,1);//bool is color,1 = color yuv2rgb_init();//yuv2rgb 初始化,开辟mmz内存 int choice = 3; while(1) { // sleep(1); // sem_wait(&sem_frm_recv); if(q_stVideoFrame_process.empty() != true) { // printf("queue not empty\n"); stVideoFrame_process = q_stVideoFrame_process.front(); ive_yuvImagess_visible.au64PhyAddr[0] = stVideoFrame_process.stVFrame.u64PhyAddr[0]; ive_yuvImagess_visible.au64PhyAddr[1] = stVideoFrame_process.stVFrame.u64PhyAddr[1]; ive_yuvImagess_visible.au64PhyAddr[2] = stVideoFrame_process.stVFrame.u64PhyAddr[2]; ive_yuvImagess_visible.au64VirAddr[0] = stVideoFrame_process.stVFrame.u64VirAddr[0]; ive_yuvImagess_visible.au64VirAddr[1] = stVideoFrame_process.stVFrame.u64VirAddr[1]; ive_yuvImagess_visible.au64VirAddr[2] = stVideoFrame_process.stVFrame.u64VirAddr[2]; ive_yuvImagess_visible.au32Stride[0] = stVideoFrame_process.stVFrame.u32Stride[0]; ive_yuvImagess_visible.au32Stride[1] = stVideoFrame_process.stVFrame.u32Stride[1]; ive_yuvImagess_visible.au32Stride[2] = stVideoFrame_process.stVFrame.u32Stride[2]; s32Ret=HI_MPI_IVE_CSC(&hIveHandless_visible,&ive_yuvImagess_visible,&ive_RGB888Imagess_visible,&stCscCtrl,HI_TRUE); if(s32Ret!=HI_SUCCESS) { printf("HI_MPI_IVE_CSC failed with error %x\n",s32Ret); } else { // printf("HI_MPI_IVE_CSC OK %d\n",ConvCnt++); } HI_MPI_SYS_MmzFlushCache(ive_RGB888Imagess_visible.au64PhyAddr[0],(HI_VOID*)ive_RGB888Imagess_visible.au64VirAddr[0], ive_RGB888Imagess_visible.au32Stride[0]*ive_RGB888Imagess_visible.u32Height); HI_U8 *pImgInput=(HI_U8*)ive_RGB888Imagess_visible.au64VirAddr[0]; #if 0 //save rgb FILE * prgbfile=fopen("rgb888save","wb+"); if(prgbfile!=NULL) { fwrite((HI_U8*)ive_RGB888Imagess_visible.au64VirAddr[0], ive_RGB888Imagess_visible.u32Width*ive_RGB888Imagess_visible.u32Height*3,1,prgbfile); fflush(prgbfile); fclose(prgbfile); } #endif posf[0] = 200; posf[1] = 500; posf[2] = 700; posf[3] = 800; if(choice == 3) { g_trk_result = runGzqTracker(pImgInput, posf,NULL,3); choice = 0; } else { g_trk_result = runGzqTracker(pImgInput, posf,NULL,0); } g_trk_result._x = 200; g_trk_result._y = 500; g_trk_result._h = 80; g_trk_result._w = 350; PLATFORM_VGS_RectLine(&stVideoFrame_process,&g_trk_result,pstPara->VpssChn,0xffffff); // tracker_func(pImgInput,&g_trkcmdFrm,gpres,2,NULL); q_stVideoFrame_process.pop(); // printf("process%d\n", q_stVideoFrame_process.size()); /* 图像处理 */ usleep(5000); q_stVideoFrame_process_osd.push(stVideoFrame_process); // printf("process ok\n"); // sem_post(&sem_frm_process); } else { usleep(1000); } } return NULL; } /* *描述 :线程里用于字符叠加 *参数 :arg 为自定义结构video_process_s,VPSS_GRP和VPSS_CHN用于传参给HI_MPI_VPSS_GetChnFrame *返回值:无 *注意 : */ HI_VOID *frame_osd_task(HI_VOID *arg) { cpu_set_t mask;//cpu核的集合 cpu_set_t get;//获取在集合中的cpu int num = sysconf(_SC_NPROCESSORS_CONF); printf("frame_osd_task:system has %d processor(s)\n", num); CPU_ZERO(&mask);//置空 CPU_SET(0, &mask);//设置亲和力值 if (pthread_setaffinity_np(pthread_self(), sizeof(mask), &mask) < 0)//设置线程CPU亲和力 { fprintf(stderr, "set thread affinity failed\n"); } if (pthread_getaffinity_np(pthread_self(), sizeof(get), &get) < 0)//获取线程CPU亲和力 { fprintf(stderr, "get thread affinity failed\n"); } VIDEO_FRAME_INFO_S stVideoFrame_process_osd; video_process_s* pstPara; pstPara = (video_process_s*)arg; // HI_S32 s32Ret; time_t now; struct tm *ptm; char timestr[OSD_LENGTH] = {0}; char lost_target_info_str[OSD_LENGTH] = {0}; char other_info_str[OSD_LENGTH] = {0}; char trk_str[OSD_LENGTH] = {0}; char frame_str[OSD_LENGTH] = {0}; stBitmap_bottom_left.pData = malloc(2*OSD_BOTTOM_LEFT_W*OSD_BOTTOM_LEFT_H); if(stBitmap_bottom_left.pData == NULL) { printf("stBitmap.pData faided\r\n"); } stBitmap_top_left.pData = malloc(2*OSD_TOP_LEFT_W*OSD_TOP_LEFT_H); if(stBitmap_top_left.pData == NULL) { printf("stBitmap_top_left.pData faided\r\n"); } osd_init(arg); // int timeOffset = 0; // int timeOffset1 = 0; while(1) { // sleep(1); // sem_wait(&sem_frm_process); if(q_stVideoFrame_process_osd.empty() != true) { rocess_osd.front(); q_stVideoFrame_process_osd.pop(); time(&now); ptm = localtime(&now); snprintf(timestr,100,"当前时间:%d-%02d-%02d %02d:%02d:%02d ",ptm->tm_year+1900,ptm->tm_mon+1,ptm->tm_mday,ptm->tm_hour,ptm->tm_min,ptm->tm_sec); snprintf(lost_target_info_str,100,"脱靶信息:X:%02d,Y:%02d",ptm->tm_year,ptm->tm_year); snprintf(other_info_str,100,"视场角信息:X:%02d,Y:%02d,焦距:%02d",ptm->tm_hour,ptm->tm_hour,ptm->tm_hour); snprintf(trk_str,100,"跟踪器状态:检测?识别?跟踪? "); snprintf(frame_str,100,"帧率:%02d",ptm->tm_year); string_to_bmp_bottom_left(lost_target_info_str,other_info_str,timestr); string_to_bmp_top_left(trk_str,frame_str); HI_MPI_RGN_UpdateCanvas(OverlayHandle_top_left); HI_MPI_RGN_UpdateCanvas(OverlayHandle_bottom_left); // pthread_mutex_lock(&mutex); HI_MPI_RGN_SetBitMap(OverlayHandle_bottom_left,&stBitmap_bottom_left);//s32Ret 为RGN_HANDLE OverlayHandle HI_MPI_RGN_SetBitMap(OverlayHandle_top_left,&stBitmap_top_left);//s32Ret 为RGN_HANDLE OverlayHandle HI_MPI_VENC_SendFrame(pstPara->VpssChn, &stVideoFrame_process_osd,1000); HI_MPI_VPSS_ReleaseChnFrame(pstPara->VpssGrp, pstPara->VpssChn, &stVideoFrame_process_osd); } else { usleep(1000); } } return NULL; } // HI_VOID *frame_venc_task(HI_VOID *arg) // { // cpu_set_t mask;//cpu核的集合 // cpu_set_t get;//获取在集合中的cpu // int num = sysconf(_SC_NPROCESSORS_CONF); // printf("frame_process_task:system has %d processor(s)\n", num); // CPU_ZERO(&mask);//置空 // CPU_SET(0, &mask);//设置亲和力值 // if (pthread_setaffinity_np(pthread_self(), sizeof(mask), &mask) < 0)//设置线程CPU亲和力 // { // fprintf(stderr, "set thread affinity failed\n"); // } // if (pthread_getaffinity_np(pthread_self(), sizeof(get), &get) < 0)//获取线程CPU亲和力 // { // fprintf(stderr, "get thread affinity failed\n"); // } // VIDEO_FRAME_INFO_S stVideoFrame_venc; // video_process_s* pstPara; // pstPara = (video_process_s*)arg; // while(1) // { // // sleep(1); // // printf("process start\n"); // // sem_wait(&sem_frm_recv); // if(q_stVideoFrame_venc.empty() != true) // { // // printf("queue not empty\n"); // stVideoFrame_venc = q_stVideoFrame_venc.front(); // q_stVideoFrame_venc.pop(); // // printf("process%d\n", q_stVideoFrame_venc.size()); // /* 图像处理 */ // HI_MPI_VENC_SendFrame(pstPara->VpssChn, &stVideoFrame_venc,1000); // HI_MPI_VPSS_ReleaseChnFrame(pstPara->VpssGrp, pstPara->VpssChn, &stVideoFrame_venc); // // sem_post(&sem_frm_process); // } // else // { // usleep(1000); // } // } // return NULL; // } /* *描述 :用于处理图像信息的线程 *参数 :arg 为自定义结构video_process_s,VPSS_GRP和VPSS_CHN用于传参给HI_MPI_VPSS_GetChnFrame *返回值: *注意 :HI_MPI_VPSS_GetChnFrame完必须释放,否则再次获取VB会报错 */ HI_VOID *video_process_test_task(HI_VOID *arg) { HI_S32 cnt = 0; HI_S32 s32Ret; VIDEO_FRAME_INFO_S stVideoFrame_process; video_process_s* pstPara; pstPara = (video_process_s*)arg; // sem_init(&sem_frm_recv,0,0); // sem_init(&sem_frm_process,0,0); // sem_init(&sem_frm_enc,0,0); sleep(1); hi_memset(&stVideoFrame_process,sizeof(VIDEO_FRAME_INFO_S),0,sizeof(VIDEO_FRAME_INFO_S)); // sleep(1); // memset(&stVideoFrame,0,sizeof(VIDEO_FRAME_INFO_S)); pthread_t frame_check_id; s32Ret=pthread_create(&frame_check_id, NULL, &frame_check_task,arg); if(s32Ret != 0) { SAMPLE_PRT("pthread video_process_osd create failed\n"); // return -HI_FAILURE; } pthread_detach(frame_check_id); pthread_t frame_process_id; s32Ret=pthread_create(&frame_process_id, NULL, &frame_process_task,arg); if(s32Ret != 0) { SAMPLE_PRT("pthread video_process_osd create failed\n"); // return -HI_FAILURE; } pthread_detach(frame_process_id); pthread_t frame_osd_id; s32Ret=pthread_create(&frame_osd_id, NULL, &frame_osd_task,arg); if(s32Ret != 0) { SAMPLE_PRT("pthread video_process_osd create failed\n"); // return -HI_FAILURE; } pthread_detach(frame_osd_id); // pthread_t frame_venc_id; // s32Ret=pthread_create(&frame_venc_id, NULL, &frame_venc_task,arg); // if(s32Ret != 0) // { // SAMPLE_PRT("pthread video_process_osd create failed\n"); // // return -HI_FAILURE; // } // pthread_detach(frame_venc_id); SAMPLE_PRT("BEFORE WHILE\n"); while(cnt <= 10) { // printf("test come %d\n",cnt); s32Ret = HI_MPI_VPSS_GetChnFrame(pstPara->VpssGrp, pstPara->VpssChn, &stVideoFrame_process,1000); if(s32Ret != HI_SUCCESS) { SAMPLE_PRT("%dVPSS_GetChnFrame err for %#x!\n", cnt,s32Ret); cnt++; } else { HI_MPI_VPSS_ReleaseChnFrame(pstPara->VpssGrp, pstPara->VpssChn, &stVideoFrame_process);//不释放会导致后续vb崩溃 goto EXIT; } } goto EXIT; EXIT: pthread_exit(0); }
预期结果