前言
位图的生成只是我们字符叠加的基础,具体表现就要靠对区域RGN的配置了
调试记录
现在距离移植成功osd也有一段时间了,所有所有的报错一时也想不起来太多,当时是在焦头烂额没有记录下全部,但是遇到错误一定要按照logmpp下的错误告警做出修改,再次感谢之前的转变
这部分的代码是参考手册写的,直接搬来肯定肯定肯定是跑不起来的!
报错1
HI_MPI_RGN_Create
出师不利,生成区域就开始报错,这个还是比较直接的根据提示修改画布数量
FunG irgn_check base canvas num attr lline1474 LInfoJcanvas numl1E lrvalic, not gelons O2100 Func :rgnattach to chn [Line]:4294 [Info]:region(1) is unexist! region Func :rgn set bit ap lline:3403 (Infol:rgn(1) unexist 3 rogion FunG :rgn_checkbaso_carvasnumattr[LineJ:1474[Info]:canvas num(127) invalid, not belong [1, 6]. retion. Func :rgn_attach_to_chn [Line]:4294 [Info]:region(1) is unexist rogion irgn set bit map lLine]:3403 (Info]:rgn(1) unexist! region Func :rgn_check_base_canvas_num_attr_[Line]:1474[Info]:canvas_num(127) invalid, not belong [1, 6]. region :rgn attach to chn lLine]:4294 [Infol:region(1) is unexist! recion PinC irgn set bit map lLine]:3403 [Info]:rgn(1) unexist! :rgn_checkbasecanvasnumattr[Line]:1474[Info]:canvas_nu(127) invalid, not belong [1, 6]. rekion Func :rgnattach to chn lLine]:4294 (Infol:region(1) is unexist! egion Func :rgn set bit map lLine]:3403 [Info]:rrn(1) unexist! :rgn_check_base_canas_num_attr[Line]:1474[Info]:canvas_num(127) invalid, not belong [1, 6]. Finc 98107 ren attach to chn lLinel:4294 lInfol:region(1) is unexist! 2i6n iren set bit map (Line]:3403 [Info]:rgn(1) unexist! Tegi0n IFunc :rgn_checkbase_canvas_numattr[Line]:1474[Info]:canvas_num(127) invalid, not belong [1, 6]. Fumc :rgn attach to_chn [Line]:4294 [Info]:region(1) is unexist! region Func iren set bit map [Line]:3403 [Info]:ren(i) unexist! rogion Func. :rgncheckbasecanvasnumattr[LineJ:1474 [Info]:canvas_num(127) invalid, not belong [1, 6]. region! :rgnattach to chn [Line]:4294 [Info]:region(1) is unexist! rogion tnc :rgn set_bit map [Line]:3403 [Info]:rgn(1) unexist! region :rgn_check_base_canvas_numattr[ine]:1474[Info]:canvas_num(127) invalid, not belonHfL_9024 3Drogion. Func:rgn attach to chnLine]:4294 [Infol:region(1) is unerist!
stRgnAttr.unAttr.stOverlay.u32CanvasNum = 1;
报错2
HI_MPI_RGN_AttachToChn实际上,创建通道的时候并不会对参数检查,真正的参数检查在这个函数进行
rgn_check_qp [Line]:1152 [Info]:protect_qp:127 err!
3>[region][Func]:rsn_check_op [Line]:1152 [Info]:protectap:127 enr! an
stChnAttr.unChnAttr.stOverlayChn.stQpInfo.bQpDisable = HI_FALSE;
看样子关键字就是qp(我当时也不知道qp是啥)(Qp量化参数,反应压缩效果)那就解决qp的部分错误
报错3
stChnAttr.unChnAttr.stOverlayChn.enAttachDest =ATTACH_JPEG_MAIN;
可写可不写。最开始忘记什么原因导致的HI_MPI_RGN_AttachToChn报了错,当时也是根据log的提示表示dest值不对,提示需要修改此处值。后来不知道为什么删了也没有影响,留作疑问
报错4
空指针错误
cone of nisroot found in cmdline.# cat /dev/1ogmpp <3>[region] [Func]:rgn_check_nu11 [Line]:64 [Info]:NULL pointer detectid-1024
这个错误就是没有在设置画布之前生成位图导致的
报错汇总5
一切都好像设置对了之后还是没有区域叠加怎么办?
检查编码通道是否正确?位图是否生成正确?宽高XY的值是否都设置正确了?
改进
此外,关于w和h的值,必须是偶数。但是字库导出的位图不可能每次都刚好,也是在其他博主处看到的字体大小无法调节,调节后参数错误的,非常简单,检查一下手动部位偶数即可。更不能随意设置,有可能会遇到明明水印文件字体是常规,不是倾斜的,但在视频上显示倾斜,更不用说还显示不全。
if (stBitmap.u32Width % 2 != 0) { stBitmap.u32Width += 1; } if (stBitmap.u32Height % 2 != 0) { stBitmap.u32Height += 1; } printf ("stBitmap.u32Width is %d ,stBitmap.u32Height is %d\n",stBitmap.u32Width,stBitmap.u32Height); stRgnAttr.unAttr.stOverlay.stSize.u32Width = stBitmap.u32Width;//240; /**区域宽**/ stRgnAttr.unAttr.stOverlay.stSize.u32Height = stBitmap.u32Height;//192; /**区域高**/
同样XY的值是需要16的倍数,但是XY的值相对是比较灵活的,我们自己按照心情手动配置就好了
透明度的解决办法暂时还没有思路,后续补充
代码框架如下
RGN_AddOsdToVenc(); // HI_MPI_VPSS_ReleaseChnFrame(pstPara->VpssGrp,pstPara->VpssChn,&stVideoFrame); while(1) // sleep(1); s32Ret=HI_MPI_VPSS_GetChnFrame(pstPara->VpssGrp,pstPara->VpssChn,&stVideoFrame,1000); s32Ret=HI_MPI_VENC_SendFrame(pstPara->VpssChn, &stvideoFrame,1080);// RGN_AddOsdToVenc() HI_MPI_VPSS_ReleaseChnFrame(pstPara->VpssGrp,pstPara->VpssChn,&stVideoFrame): Hx--1024
区域设置函数RGN_AddOsdToVenc
/* *描述 :用于将视频文件添加时间水印 *参数 :无 *返回值:OverlayHandle *注意 :参数在HI_MPI_RGN_Create并不做检查,只有在HI_MPI_RGN_AttachToChn的时候才会报出相应的错 */ HI_S32 RGN_AddOsdToVenc(HI_VOID) { HI_S32 s32Ret; RGN_ATTR_S stRgnAttr; RGN_CHN_ATTR_S stChnAttr; MPP_CHN_S stChn; RGN_HANDLE OverlayHandle; // RGN_CANVAS_INFO_S stCanvasInfo; OverlayHandle =0; stChn.enModId = HI_ID_VENC; /**模块号**///HI_ID_VPSS HI_ID_VENC stChn.s32DevId = 0; /**设备号**/ stChn.s32ChnId = 1; /**通道号**/ /**创建区域**/ sleep(2);//等待位图生成 stRgnAttr.unAttr.stOverlay.u32CanvasNum = 2; stRgnAttr.enType = OVERLAY_RGN; /**区域类型:叠加**/ stRgnAttr.unAttr.stOverlay.enPixelFmt = PIXEL_FORMAT_ARGB_1555; /**像素格式**///PIXEL_FORMAT_BGR_565 PIXEL_FORMAT_ARGB_1555 if (stBitmap.u32Width % 2 != 0) { stBitmap.u32Width += 1; } if (stBitmap.u32Height % 2 != 0) { stBitmap.u32Height += 1; } printf ("stBitmap.u32Width is %d ,stBitmap.u32Height is %d\n",stBitmap.u32Width,stBitmap.u32Height); stRgnAttr.unAttr.stOverlay.stSize.u32Width = stBitmap.u32Width;//240; /**区域宽**/ stRgnAttr.unAttr.stOverlay.stSize.u32Height = stBitmap.u32Height;//192; /**区域高**/ stRgnAttr.unAttr.stOverlay.u32BgColor = 0xffffff00;//0x00007c00; /**区域背景颜色**/ s32Ret = HI_MPI_RGN_Create(OverlayHandle, &stRgnAttr); if(s32Ret != HI_SUCCESS) { SAMPLE_PRT("RGN create failed: %#x\n", s32Ret); } /**将区域叠加到通道**/ /**设置叠加区域的通道显示属性**/ stChnAttr.bShow = HI_TRUE; stChnAttr.enType = OVERLAY_RGN; stChnAttr.unChnAttr.stOverlayChn.stPoint.s32X = 640;//240; stChnAttr.unChnAttr.stOverlayChn.stPoint.s32Y = 320;//192; stChnAttr.unChnAttr.stOverlayChn.u32BgAlpha = 128; stChnAttr.unChnAttr.stOverlayChn.u32FgAlpha = 80; stChnAttr.unChnAttr.stOverlayChn.u32Layer = OverlayHandle; /**设置QP属性**/ stChnAttr.unChnAttr.stOverlayChn.stQpInfo.bAbsQp = HI_FALSE; stChnAttr.unChnAttr.stOverlayChn.stQpInfo.s32Qp = 0; stChnAttr.unChnAttr.stOverlayChn.stQpInfo.bQpDisable = HI_FALSE; /**定义 OSD 反色相关属性**/ /**单元反色区域,反色处理的基本单元,[16, 64],需 16 对齐**/ stChnAttr.unChnAttr.stOverlayChn.stInvertColor.stInvColArea.u32Height = 16; stChnAttr.unChnAttr.stOverlayChn.stInvertColor.stInvColArea.u32Width = 16; /**亮度阈值,取值范围:[0, 255]**/ stChnAttr.unChnAttr.stOverlayChn.stInvertColor.u32LumThresh = 128;//128 /**OSD 反色触发模式**/ stChnAttr.unChnAttr.stOverlayChn.stInvertColor.enChgMod = LESSTHAN_LUM_THRESH; /**OSD 反色开关。overlay不支持反色**/ stChnAttr.unChnAttr.stOverlayChn.stInvertColor.bInvColEn = HI_FALSE; stChnAttr.unChnAttr.stOverlayChn.enAttachDest =ATTACH_JPEG_MAIN; OverlayHandle =0; s32Ret = HI_MPI_RGN_AttachToChn(OverlayHandle, &stChn, &stChnAttr); if(s32Ret != HI_SUCCESS) { SAMPLE_PRT("HI_MPI_RGN_AttachToChn: %#x\n", s32Ret); } stBitmap.enPixelFormat = PIXEL_FORMAT_ARGB_1555; // stBitmap.u32Height = OVERLAY_H; // stBitmap.u32Width = OVERLAY_W; s32Ret = HI_MPI_RGN_SetBitMap(OverlayHandle,&stBitmap); if(s32Ret != HI_SUCCESS) { SAMPLE_PRT("HI_MPI_RGN_SetBitMap failed with %#x!\n", s32Ret); } memset(stBitmap.pData, 0, sizeof(BITMAP_S)); // s32Ret = HI_MPI_RGN_GetCanvasInfo(OverlayHandle,&stCanvasInfo); // s32Ret = HI_MPI_RGN_DetachFromChn(OverlayHandle, &stChn);//最后用户可以将该区域从通道中撤出(非必须操作),再销毁区域。 // if(s32Ret != HI_SUCCESS) // { // SAMPLE_PRT("HI_MPI_RGN_DetachFromChn: %#x\n", s32Ret); // } // s32Ret = HI_MPI_RGN_Destroy(OverlayHandle); // if(s32Ret != HI_SUCCESS) // { // SAMPLE_PRT("RGN create failed: %#x\n", s32Ret); // } return 0; }
实时更新
开个线程每秒更新画布
/* *描述 :用于osd 字体bmp图像生成 *参数 :NULL *返回值:无 *注意 :需要加载字体ttf才能使用,否则会报段错误 */ HI_VOID *bitmap_update(HI_VOID*arg) { RGN_HANDLE OverlayHandle = 0; HI_S32 s32Ret; // time_t now; // struct tm *ptm; // char timestr[OSD_LENGTH] = {0}; while(1) { sleep(1); HI_MPI_RGN_UpdateCanvas(0); s32Ret = HI_MPI_RGN_SetBitMap(OverlayHandle,&stBitmap);//s32Ret 为RGN_HANDLE OverlayHandle if(s32Ret != HI_SUCCESS) { SAMPLE_PRT("HI_MPI_RGN_SetBitMap failed with %#x!\n", s32Ret); } memset(stBitmap.pData, 0, sizeof(BITMAP_S)); } return 0; }
每秒生成新的位图
画布结构体BITMAP_S设置成全局的,方便更新
/* *描述 :用于将想填写的内容生成位图 用于pthread osd_create_task *参数 :pu8Str u8指针,传字符串 *返回值:成功返回0 *注意 :无 */ HI_S32 string_to_bmp(char *pu8Str) { SDL_PixelFormat *fmt; TTF_Font *font; SDL_Surface *text, *temp; if (TTF_Init() < 0 ) { fprintf(stderr, "Couldn't initialize TTF: %s\n",SDL_GetError()); SDL_Quit(); } font = TTF_OpenFont(FONT_PATH, 45); if ( font == NULL ) { fprintf(stderr, "Couldn't load %d pt font from %s: %s\n",18,"ptsize", SDL_GetError()); } SDL_Color forecol = { 0xff, 0xff, 0xff, 0xff }; text = TTF_RenderUTF8_Solid(font, pu8Str, forecol); fmt = (SDL_PixelFormat*)malloc(sizeof(SDL_PixelFormat)); memset(fmt,0,sizeof(SDL_PixelFormat)); fmt->BitsPerPixel = 16; fmt->BytesPerPixel = 2; fmt->colorkey = 0xffffffff; fmt->alpha = 0xff; temp = SDL_ConvertSurface(text,fmt,0); // SDL_Surface *osd_test = SDL_ConvertSurface(text, fmt, 0); // printf ("w is %d ,h is %d\n",temp->w,temp->h); stBitmap.pData = malloc(2*(temp->w)*(temp->h)); if(stBitmap.pData == NULL) { printf("stBitmap.pData faided\r\n"); } memset(stBitmap.pData, 0, sizeof(BITMAP_S)); memcpy(stBitmap.pData, temp->pixels, (2*(temp->w)*(temp->h))); stBitmap.u32Width = temp->w; stBitmap.u32Height = temp->h; char savename[20] = {0}; snprintf(savename,20,"./osd/now_time.bmp"); // printf("savename = %s\n",savename); SDL_SaveBMP(temp, savename); free(fmt); // memset(stBitmap.pData, 0, sizeof(BITMAP_S)); SDL_FreeSurface(text); SDL_FreeSurface(temp); TTF_CloseFont(font); TTF_Quit(); return 0; } /* *描述 :用于osd 字体bmp图像生成 *参数 :NULL *返回值:无 *注意 :需要加载字体ttf才能使用,否则会报段错误 */ HI_VOID *osd_ttf_task(HI_VOID*arg) { RGN_HANDLE OverlayHandle = 0; HI_S32 s32Ret; time_t now; struct tm *ptm; char timestr[OSD_LENGTH] = {0}; while(1) { usleep(1000000); 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); string_to_bmp(timestr); HI_MPI_RGN_UpdateCanvas(OverlayHandle); s32Ret = HI_MPI_RGN_SetBitMap(OverlayHandle,&stBitmap);//s32Ret 为RGN_HANDLE OverlayHandle if(s32Ret != HI_SUCCESS) { SAMPLE_PRT("HI_MPI_RGN_SetBitMap failed with %#x!\n", s32Ret); } memset(stBitmap.pData, 0, sizeof(BITMAP_S)); memset(timestr,0,OSD_LENGTH); } return 0; }
结果