海思3559万能平台搭建:OSD功能的优化
前言:
??功能測試的OSD使用還是比較簡單的,隨便找個位置做個時間戳,背景還是黑色,且只能顯示一行,很明顯效果并不是那么理想,這里做一個升級,對海思區域疊加的配置以及osd窗口的創建等都在本文一并寫了。
OSD多行文字
??我們的位圖需要20ms之內作一次更新,有了性能要求之后,就不能像之前一樣隨意的把創建位圖并疊加籠統的放進循環,頻繁的打開創建銷毀了,雖然文件很小也不必每次都進行保存了。一個合適的做法是在最開始做個初始化,根據需要隨時獲得待更新的數據,最后退出的時候銷毀
??那么多行文字怎么解決呢?最直接的想法肯定是生成好幾個位圖,拼成一整個,把整個的數據copy到region進行更新(更簡單粗暴的就是多個region但是很明顯沒必要),那么怎么拼呢?是生成一個個位圖后分別粘貼到全局的bitmap拼成大的,還是根源處解決呢…bitmap處需要大量計算,而且寫起來也比較復雜,而根源處沒有相應的庫函數啊(SDL2更新了可以在字符串中加空格進行換行)
SDL_ConvertSurface和SDL_CreateRGBSurface
??我們之前一直在剛好生成大小合適的圖像,因為SDL_ConvertSurface是庫函數也沒有深究以為沒有暴露對應的函數接口給用戶,實際上并不是的,我們可以參考該函數的更底層是怎么進行轉換的
/* * Convert a surface into the specified pixel format.*/ SDL_Surface * SDL_ConvertSurface (SDL_Surface *surface,SDL_PixelFormat *format, Uint32 flags) {SDL_Surface *convert;Uint32 colorkey = 0;Uint8 alpha = 0;Uint32 surface_flags;SDL_Rect bounds;/* Check for empty destination palette! (results in empty image) */if ( format->palette != NULL ) {int i;for ( i=0; i<format->palette->ncolors; ++i ) {if ( (format->palette->colors[i].r != 0) ||(format->palette->colors[i].g != 0) ||(format->palette->colors[i].b != 0) )break;}if ( i == format->palette->ncolors ) {SDL_SetError("Empty destination palette");return(NULL);}}/* Only create hw surfaces with alpha channel if hw alpha blitsare supported */if(format->Amask != 0 && (flags & SDL_HWSURFACE)) {const SDL_VideoInfo *vi = SDL_GetVideoInfo();if(!vi || !vi->blit_hw_A)flags &= ~SDL_HWSURFACE;}/* Create a new surface with the desired format */convert = SDL_CreateRGBSurface(flags,surface->w, surface->h, format->BitsPerPixel,format->Rmask, format->Gmask, format->Bmask, format->Amask);if ( convert == NULL ) {return(NULL);}/* Copy the palette if any */if ( format->palette && convert->format->palette ) {SDL_memcpy(convert->format->palette->colors,format->palette->colors,format->palette->ncolors*sizeof(SDL_Color));convert->format->palette->ncolors = format->palette->ncolors;}/* Save the original surface color key and alpha */surface_flags = surface->flags;if ( (surface_flags & SDL_SRCCOLORKEY) == SDL_SRCCOLORKEY ) {/* Convert colourkeyed surfaces to RGBA if requested */if((flags & SDL_SRCCOLORKEY) != SDL_SRCCOLORKEY&& format->Amask) {surface_flags &= ~SDL_SRCCOLORKEY;} else {colorkey = surface->format->colorkey;SDL_SetColorKey(surface, 0, 0);}}if ( (surface_flags & SDL_SRCALPHA) == SDL_SRCALPHA ) {/* Copy over the alpha channel to RGBA if requested */if ( format->Amask ) {surface->flags &= ~SDL_SRCALPHA;} else {alpha = surface->format->alpha;SDL_SetAlpha(surface, 0, 0);}}/* Copy over the image data */bounds.x = 0;bounds.y = 0;bounds.w = surface->w;bounds.h = surface->h;SDL_LowerBlit(surface, &bounds, convert, &bounds);/* Clean up the original surface, and update converted surface */if ( convert != NULL ) {SDL_SetClipRect(convert, &surface->clip_rect);}if ( (surface_flags & SDL_SRCCOLORKEY) == SDL_SRCCOLORKEY ) {Uint32 cflags = surface_flags&(SDL_SRCCOLORKEY|SDL_RLEACCELOK);if ( convert != NULL ) {Uint8 keyR, keyG, keyB;SDL_GetRGB(colorkey,surface->format,&keyR,&keyG,&keyB);SDL_SetColorKey(convert, cflags|(flags&SDL_RLEACCELOK),SDL_MapRGB(convert->format, keyR, keyG, keyB));}SDL_SetColorKey(surface, cflags, colorkey);}if ( (surface_flags & SDL_SRCALPHA) == SDL_SRCALPHA ) {Uint32 aflags = surface_flags&(SDL_SRCALPHA|SDL_RLEACCELOK);if ( convert != NULL ) {SDL_SetAlpha(convert, aflags|(flags&SDL_RLEACCELOK),alpha);}if ( format->Amask ) {surface->flags |= SDL_SRCALPHA;} else {SDL_SetAlpha(surface, aflags, alpha);}}/* We're ready to go! */return(convert); }??不難看到,除去了大量的判斷后關鍵的操作是SDL_CreateRGBSurface創建窗口(位圖)和疊加SDL_LowerBlit,SDL_LowerBlit是可以指定位置的啊,
/* * Set up a blit between two surfaces -- split into three parts:* The upper part, SDL_UpperBlit(), performs clipping and rectangle * verification. The lower part is a pointer to a low level* accelerated blitting function.** These parts are separated out and each used internally by this * library in the optimimum places. They are exported so that if* you know exactly what you are doing, you can optimize your code* by calling the one(s) you need.*/ int SDL_LowerBlit (SDL_Surface *src, SDL_Rect *srcrect,SDL_Surface *dst, SDL_Rect *dstrect) {SDL_blit do_blit;SDL_Rect hw_srcrect;SDL_Rect hw_dstrect;/* Check to make sure the blit mapping is valid */if ( (src->map->dst != dst) ||(src->map->dst->format_version != src->map->format_version) ) {if ( SDL_MapSurface(src, dst) < 0 ) {return(-1);}}/* Figure out which blitter to use */if ( (src->flags & SDL_HWACCEL) == SDL_HWACCEL ) {if ( src == SDL_VideoSurface ) {hw_srcrect = *srcrect;hw_srcrect.x += current_video->offset_x;hw_srcrect.y += current_video->offset_y;srcrect = &hw_srcrect;}if ( dst == SDL_VideoSurface ) {hw_dstrect = *dstrect;hw_dstrect.x += current_video->offset_x;hw_dstrect.y += current_video->offset_y;dstrect = &hw_dstrect;}do_blit = src->map->hw_blit;} else {do_blit = src->map->sw_blit;}return(do_blit(src, srcrect, dst, dstrect)); }??那么我們就可以將TTF_RenderUTF8_Solid轉位圖格式后的surface按照不同的寬高疊進來,把時間信息osd_time_text,脫靶信息osd_losttarget_info_text,其他信息osd_other_info_text經過TTF_RenderUTF8_Solid轉位圖后設置不同的寬高SDL_LowerBlit到整個osd_bottom_left 中,在hi_memcpy到海思的結構體bitmap中用于更新
/* *描述 :用于將想填寫的內容生成位圖左下角 用于pthread osd_create_task*參數 :pu8Str_losttargrt_inf 傳字符串脫靶信息* pu8Str_other_info 傳字符串視場角信息和焦距* pu8Str_time u8指針,傳字符串時間*返回值:成功返回0*注意 :無*/HI_S32 string_to_bmp_bottom_left(char *pu8Str_losttargrt_info,char *pu8Str_other_info,char *pu8Str_time) {SDL_Rect bounddst,boundsrc;// printf("before TTF_RenderUTF8_Solid\n");osd_time_text = TTF_RenderUTF8_Solid(font, pu8Str_time, forecol);osd_losttarget_info_text = TTF_RenderUTF8_Solid(font, pu8Str_losttargrt_info, forecol);osd_other_info_text = TTF_RenderUTF8_Solid(font, pu8Str_other_info, forecol);// osd_bottom_left = SDL_ConvertSurface(osd_time_text,osd_fmt,0);osd_bottom_left = SDL_CreateRGBSurface(SDL_SWSURFACE, osd_time_text->w, osd_time_text->h*3, osd_fmt->BitsPerPixel,osd_fmt->Rmask, osd_fmt->Gmask, osd_fmt->Bmask, osd_fmt->Amask);// printf ("w is %d ,h is %d\n",osd_time_text->w,osd_time_text->h);// hi_memset(osd_bottom_left, sizeof(SDL_Surface),0, sizeof(SDL_Surface));boundsrc.x = 0;boundsrc.y = 0;boundsrc.w = osd_losttarget_info_text->w;boundsrc.h = osd_losttarget_info_text->h;bounddst.x = 0;bounddst.y = 0;bounddst.w = osd_losttarget_info_text->w;bounddst.h = osd_losttarget_info_text->h;SDL_LowerBlit(osd_losttarget_info_text, &boundsrc, osd_bottom_left, &bounddst);boundsrc.x = 0;boundsrc.y = 0;boundsrc.w = osd_other_info_text->w;boundsrc.h = osd_other_info_text->h;bounddst.x = 0;bounddst.y = osd_losttarget_info_text->h;bounddst.w = osd_other_info_text->w;bounddst.h = osd_other_info_text->h;SDL_LowerBlit(osd_other_info_text, &boundsrc, osd_bottom_left, &bounddst);boundsrc.x = 0;boundsrc.y = 0;boundsrc.w = osd_time_text->w;boundsrc.h = osd_time_text->h;bounddst.x = 0;bounddst.y = osd_losttarget_info_text->h+osd_other_info_text->h;bounddst.w = osd_time_text->w;bounddst.h = osd_time_text->h;SDL_LowerBlit(osd_time_text, &boundsrc, osd_bottom_left, &bounddst);// printf ("w is %d ,h is %d\n",osd_bottom_left->w,osd_bottom_left->h);// 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");// }// pthread_mutex_lock(&mutex);hi_memset(stBitmap_bottom_left.pData, (2*(osd_bottom_left->w)*(osd_bottom_left->h)),0, (2*(osd_bottom_left->w)*(osd_bottom_left->h)));hi_memcpy(stBitmap_bottom_left.pData, (2*(osd_bottom_left->w)*(osd_bottom_left->h)),osd_bottom_left->pixels, (2*(osd_bottom_left->w)*(osd_bottom_left->h)));// pthread_mutex_unlock(&mutex);stBitmap_bottom_left.u32Width = osd_bottom_left->w;stBitmap_bottom_left.u32Height = osd_bottom_left->h; // printf ("stBitmap_bottom_left is %d ,h is %d\n",osd_bottom_left->w,osd_bottom_left->h);//446,90// char savename[20] = {0};// snprintf(savename,20,"./osd/now_time.bmp");// printf("before SDL_SaveBMP\n");// SDL_SaveBMP(osd_bottom_left, savename); // memset(stBitmap.pData, 0, sizeof(BITMAP_S));SDL_FreeSurface(osd_time_text); SDL_FreeSurface(osd_losttarget_info_text); SDL_FreeSurface(osd_other_info_text); SDL_FreeSurface(osd_bottom_left);// TTF_CloseFont(font); // TTF_Quit(); return 0; } /* *描述 :用于將想填寫的內容生成位圖左上角 用于pthread osd_create_task*參數 :pu8Str_angle_info 跟蹤器狀態(檢測/識別/跟蹤)* pu8Str_other_info 幀號*返回值:成功返回0*注意 :無*/ HI_S32 string_to_bmp_top_left(char *pu8Str_trk_info,char *pu8Str_frame_info) {// SDL_Color forecol = { 0xff, 0xff, 0xff, 0xff };SDL_Rect bounddst,boundsrc;// printf("before TTF_RenderUTF8_Solid\n");osd_trk_info_text = TTF_RenderUTF8_Solid(font, pu8Str_trk_info, forecol);osd_frame_info_text = TTF_RenderUTF8_Solid(font, pu8Str_frame_info, forecol);// osd_top_left = SDL_ConvertSurface(osd_time_text,osd_fmt,0);osd_top_left = SDL_CreateRGBSurface(SDL_SWSURFACE, osd_trk_info_text->w, osd_trk_info_text->h*2, osd_fmt->BitsPerPixel,osd_fmt->Rmask, osd_fmt->Gmask, osd_fmt->Bmask, osd_fmt->Amask);//// hi_memset(osd_top_left, sizeof(SDL_Surface),0, sizeof(SDL_Surface));//也可以選擇初始化的時候建一次,每次memset,最后釋放,但是直接memset無法調用SDL_LowerBlitboundsrc.x = 0;boundsrc.y = 0;boundsrc.w = osd_trk_info_text->w;boundsrc.h = osd_trk_info_text->h;bounddst.x = 0;bounddst.y = 0;bounddst.w = osd_trk_info_text->w;bounddst.h = osd_trk_info_text->h;SDL_LowerBlit(osd_trk_info_text, &boundsrc, osd_top_left, &bounddst);boundsrc.x = 0;boundsrc.y = 0;boundsrc.w = osd_frame_info_text->w;boundsrc.h = osd_frame_info_text->h;bounddst.x = 0;bounddst.y = osd_trk_info_text->h;bounddst.w = osd_frame_info_text->w;bounddst.h = osd_frame_info_text->h;SDL_LowerBlit(osd_frame_info_text, &boundsrc, osd_top_left, &bounddst);// 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");// }// printf ("osd_top_left is %d ,h is %d\n",osd_top_left->w,osd_top_left->h);// pthread_mutex_lock(&mutex );hi_memset(stBitmap_top_left.pData, (2*(osd_top_left->w)*(osd_top_left->h)),0, (2*(osd_top_left->w)*(osd_top_left->h)));hi_memcpy(stBitmap_top_left.pData, (2*(osd_top_left->w)*(osd_top_left->h)),osd_top_left->pixels, (2*(osd_top_left->w)*(osd_top_left->h)));// pthread_mutex_unlock(&mutex );// memcpy(stBitmap.pData+(2*(osd_top_left->w)*(osd_top_left->h)), osd_top_left->pixels, (2*(osd_top_left->w)*(osd_top_left->h)));stBitmap_top_left.u32Width = osd_top_left->w;stBitmap_top_left.u32Height = osd_top_left->h; // char savename[20] = {0};// snprintf(savename,20,"./osd/now_time.bmp");// printf("before SDL_SaveBMP\n");// SDL_SaveBMP(osd_top_left, savename); // memset(stBitmap_top_left.pData, 0, sizeof(BITMAP_S));SDL_FreeSurface(osd_trk_info_text); SDL_FreeSurface(osd_frame_info_text); SDL_FreeSurface(osd_top_left);// TTF_CloseFont(font); // TTF_Quit(); return 0; }??有需要的話可以吧保存放開
補充
??循環內我們每次都創建了新的SDL_CreateRGBSurface,必須對應的SDL_FreeSurface,不然過一會內存就會占滿,卡在這里不往下進行,之后段錯誤啊,buserror(可能是memset bitmap數據時填錯了長度,出現概率低,修改后暫未出現)out of memory之類的都出現過,不易排查。至于這個為什么不創建一次,最后free的原因是沒有往下深入研究,不知道memset這個surface的結構體那部分,在長時間系統測試穩定和性能完全達標(不到5ms)后,暫時先這樣處理
區域疊加的多行
在哪部分疊加
??之前的RGN疊加在venc通道,且只能疊加一個通道,一旦需要多路碼流疊加,來回切通道會造成不必要的麻煩。mentor建議直接疊加到vpss上,之前沒有選擇疊加在vpss因為 stRgnAttr.enType選擇了OVERLAY_RGN,這個模式不能在vpss疊加,選擇COVEREX_RGN就可以解決
透明度
??選擇了COVEREX_RGN后發現還沒有做改動我們的背景色就由純黑變成了淺黑,說明alpha值在這里生效了,那就更簡單了,stChnAttr.unChnAttr.stOverlayChn.u32BgAlpha值改為0,我們的背景就變成透明的啦!
多個區域疊加
??這個也比較簡單OverlayHandle選擇不同值即可取值范圍[0, RGN_HANDLE_MAX),創建不同區域分別疊加即可
疊加部分代碼
/* *描述 :用于將視頻文件添加時間水印左下角*參數 :無*返回值:OverlayHandle_bottom_leftle*注意 :參數在HI_MPI_RGN_Create并不做檢查,只有在HI_MPI_RGN_AttachToChn的時候才會報出相應的錯*/ HI_S32 RGN_AddOsdToVpss_bottom_left(HI_S32 s32ChnId) {HI_S32 s32Ret;RGN_ATTR_S stRgnAttr;RGN_CHN_ATTR_S stChnAttr;MPP_CHN_S stChn;// RGN_CANVAS_INFO_S stCanvasInfo;stChn.enModId = HI_ID_VPSS; /**模塊號**///HI_ID_VPSS HI_ID_VENCstChn.s32DevId = 0; /**設備號**/stChn.s32ChnId = s32ChnId; /**通道號**//**創建區域**/sleep(2);//等待位圖生成stRgnAttr.unAttr.stOverlay.u32CanvasNum = 1; stRgnAttr.enType = OVERLAYEX_RGN; /**區域類型:疊加**/stRgnAttr.unAttr.stOverlay.enPixelFmt = PIXEL_FORMAT_ARGB_1555; /**像素格式**///PIXEL_FORMAT_BGR_565 PIXEL_FORMAT_ARGB_1555if (stBitmap_bottom_left.u32Width % 2 != 0){stBitmap_bottom_left.u32Width += 1;}if (stBitmap_bottom_left.u32Height % 2 != 0){stBitmap_bottom_left.u32Height += 1;}printf ("stBitmap_bottom_left.u32Width is %d ,stBitmap_bottom_left.u32Height is %d\n",stBitmap_bottom_left.u32Width,stBitmap_bottom_left.u32Height);stRgnAttr.unAttr.stOverlay.stSize.u32Width = stBitmap_bottom_left.u32Width;//240; /**區域寬**/stRgnAttr.unAttr.stOverlay.stSize.u32Height = stBitmap_bottom_left.u32Height;//192; /**區域高**/stRgnAttr.unAttr.stOverlay.u32BgColor = 0xffffff00;//0x00007c00; /**區域背景顏色**/s32Ret = HI_MPI_RGN_Create(OverlayHandle_bottom_left, &stRgnAttr);if(s32Ret != HI_SUCCESS){SAMPLE_PRT("RGN create failed: %#x\n", s32Ret);} /**將區域疊加到通道**//**設置疊加區域的通道顯示屬性**/stChnAttr.bShow = HI_TRUE;stChnAttr.enType = OVERLAYEX_RGN;stChnAttr.unChnAttr.stOverlayChn.stPoint.s32X = 20;//240;stChnAttr.unChnAttr.stOverlayChn.stPoint.s32Y = 980;//192;stChnAttr.unChnAttr.stOverlayChn.u32BgAlpha = 0;//128;stChnAttr.unChnAttr.stOverlayChn.u32FgAlpha = 128;//80;stChnAttr.unChnAttr.stOverlayChn.u32Layer = OverlayHandle_bottom_left;/**設置QP屬性Qp(量化參數,反應壓縮效果)以 H.264 編碼為例,通常圖像 Qp(量化參數,反應壓縮效果) 越低,圖像的質量越好,碼率越高;圖像 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_TRUE;stChnAttr.unChnAttr.stOverlayChn.enAttachDest =ATTACH_JPEG_MAIN;// OverlayHandle =0;s32Ret = HI_MPI_RGN_AttachToChn(OverlayHandle_bottom_left, &stChn, &stChnAttr);if(s32Ret != HI_SUCCESS){SAMPLE_PRT("HI_MPI_RGN_AttachToChn: %#x\n", s32Ret);} stBitmap_bottom_left.enPixelFormat = PIXEL_FORMAT_ARGB_1555;// stBitmap.u32Height = OVERLAY_H;// stBitmap.u32Width = OVERLAY_W;s32Ret = HI_MPI_RGN_SetBitMap(OverlayHandle_bottom_left,&stBitmap_bottom_left);if(s32Ret != HI_SUCCESS){SAMPLE_PRT("HI_MPI_RGN_SetBitMap failed with %#x!\n", s32Ret);}// hi_memset(stBitmap_bottom_left.pData, sizeof(BITMAP_S),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; } HI_S32 RGN_AddOsdToVpss_top_left(HI_S32 s32ChnId) {HI_S32 s32Ret;RGN_ATTR_S stRgnAttr;RGN_CHN_ATTR_S stChnAttr;MPP_CHN_S stChn;// OverlayHandle_top_left =1;stChn.enModId = HI_ID_VPSS; /**模塊號**///HI_ID_VPSS HI_ID_VENCstChn.s32DevId = 0; /**設備號**/stChn.s32ChnId = s32ChnId; /**通道號**//**創建區域**/sleep(2);//等待位圖生成stRgnAttr.unAttr.stOverlay.u32CanvasNum = 2; stRgnAttr.enType = OVERLAYEX_RGN; /**區域類型:疊加**/stRgnAttr.unAttr.stOverlay.enPixelFmt = PIXEL_FORMAT_ARGB_1555; /**像素格式**///PIXEL_FORMAT_BGR_565 PIXEL_FORMAT_ARGB_1555if (stBitmap_top_left.u32Width % 2 != 0){stBitmap_top_left.u32Width += 1;}if (stBitmap_top_left.u32Height % 2 != 0){stBitmap_top_left.u32Height += 1;}// printf ("stBitmap_top_left.u32Width is %d ,stBitmap_top_left.u32Height is %d\n",stBitmap_top_left.u32Width,stBitmap_top_left.u32Height);394,60stRgnAttr.unAttr.stOverlay.stSize.u32Width = stBitmap_top_left.u32Width;//240; /**區域寬**/stRgnAttr.unAttr.stOverlay.stSize.u32Height = stBitmap_top_left.u32Height;//192; /**區域高**/stRgnAttr.unAttr.stOverlay.u32BgColor = 0xffffff00;//0x00007c00; /**區域背景顏色**/s32Ret = HI_MPI_RGN_Create(OverlayHandle_top_left, &stRgnAttr);if(s32Ret != HI_SUCCESS){SAMPLE_PRT("RGN create failed: %#x\n", s32Ret);}/**將區域疊加到通道**//**設置疊加區域的通道顯示屬性**/stChnAttr.bShow = HI_TRUE;stChnAttr.enType = OVERLAYEX_RGN;stChnAttr.unChnAttr.stOverlayChn.stPoint.s32X = 20;//240;stChnAttr.unChnAttr.stOverlayChn.stPoint.s32Y = 20;//192;stChnAttr.unChnAttr.stOverlayChn.u32BgAlpha = 0;//128;stChnAttr.unChnAttr.stOverlayChn.u32FgAlpha = 128;stChnAttr.unChnAttr.stOverlayChn.u32Layer = OverlayHandle_top_left;/**設置QP屬性Qp(量化參數,反應壓縮效果)以 H.264 編碼為例,通常圖像 Qp(量化參數,反應壓縮效果) 越低,圖像的質量越好,碼率越高;圖像 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_top_left, &stChn, &stChnAttr);if(s32Ret != HI_SUCCESS){SAMPLE_PRT("HI_MPI_RGN_AttachToChn: %#x\n", s32Ret);} stBitmap_top_left.enPixelFormat = PIXEL_FORMAT_ARGB_1555;s32Ret = HI_MPI_RGN_SetBitMap(OverlayHandle_top_left,&stBitmap_top_left);if(s32Ret != HI_SUCCESS){SAMPLE_PRT("HI_MPI_RGN_SetBitMap failed with %#x!\n", s32Ret);}// hi_memset(stBitmap_top_left.pData, sizeof(BITMAP_S),0, sizeof(BITMAP_S));return 0; }初始化和退出
??都配置完了就可以初始化了,初始化打開osd字體,在創建疊加通道前生成位圖,區域初始化就是我們整個osd功能初始化的內容了,退出相應的關閉字體,釋放打開的結構體就好
/* *描述 :用于OSD 初始化,打開字體,生成位圖后區域初始化*參數 :arg 為自定義結構video_process_s,VPSS_GRP和VPSS_CHN用于傳參給HI_MPI_VPSS_GetChnFrame*返回值:*注意 : */ HI_VOID osd_init(HI_VOID *arg) {if (TTF_Init() < 0 ) { fprintf(stderr, "Couldn't initialize TTF: %s\n",SDL_GetError()); SDL_Quit();} font = TTF_OpenFont(FONT_PATH, 29); if ( font == NULL ) { fprintf(stderr, "Couldn't load %d pt font from %s: %s\n",18,"ptsize", SDL_GetError()); // return -1;} video_process_s* pstPara;pstPara = (video_process_s*)arg;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};osd_fmt = (SDL_PixelFormat*)malloc(sizeof(SDL_PixelFormat));hi_memset(osd_fmt,sizeof(SDL_PixelFormat),0,sizeof(SDL_PixelFormat));osd_fmt->BitsPerPixel = 16;osd_fmt->BytesPerPixel = 2;osd_fmt->colorkey = 0xffffffff;osd_fmt->alpha = 0xff;// osd_bottom_left = SDL_CreateRGBSurface(SDL_SWSURFACE, OSD_BOTTOM_LEFT_W, OSD_BOTTOM_LEFT_H, // osd_fmt->BitsPerPixel,osd_fmt->Rmask, osd_fmt->Gmask, osd_fmt->Bmask, osd_fmt->Amask);// osd_top_left = SDL_CreateRGBSurface(SDL_SWSURFACE, OSD_TOP_LEFT_W, OSD_TOP_LEFT_H, // osd_fmt->BitsPerPixel,osd_fmt->Rmask, osd_fmt->Gmask, osd_fmt->Bmask, osd_fmt->Amask);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",osd_fmt->BitsPerPixel,osd_fmt->BytesPerPixel);snprintf(other_info_str,100,"視場角信息:X:%02d,Y:%02d,焦距:%02d",osd_fmt->BitsPerPixel,osd_fmt->BytesPerPixel,osd_fmt->BytesPerPixel);snprintf(trk_str,100,"跟蹤器狀態:檢測?識別?跟蹤? ");snprintf(frame_str,100,"幀率:%02d",osd_fmt->BytesPerPixel);string_to_bmp_bottom_left(lost_target_info_str,other_info_str,timestr);string_to_bmp_top_left(trk_str,frame_str);RGN_AddOsdToVpss_bottom_left(pstPara->VpssChn);RGN_AddOsdToVpss_top_left(pstPara->VpssChn); } /* *描述 :用于OSD 退出,關閉字體,釋放配置結構體*參數 :無*注意 : */ HI_VOID osd_exit() {// SDL_FreeSurface(osd_time_text); // SDL_FreeSurface(osd_losttarget_info_text); // SDL_FreeSurface(osd_other_info_text); // SDL_FreeSurface(osd_bottom_left);// SDL_FreeSurface(osd_trk_info_text); // SDL_FreeSurface(osd_frame_info_text); // SDL_FreeSurface(osd_top_left);free(osd_fmt);TTF_CloseFont(font); TTF_Quit(); }字符疊加線程
??當然,這里除了時間戳,其他要更新的消息都是隨便填的哈哈
* *描述 :線程里用于字符疊加*參數 :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;//獲取在集合中的cpuint 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){// tmp = clockGetTime(CLOCK_MONOTONIC); //單位us// timeOffset = tmp.tv_sec*1000*1000 + tmp.tv_usec;/* 測試代碼執行時間 */// printf("osd queue not empty\n");stVideoFrame_process_osd = q_stVideoFrame_process_osd.front();q_stVideoFrame_process_osd.pop();// printf("osd%d\n", q_stVideoFrame_process_osd.size());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_year,ptm->tm_year,ptm->tm_year);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 OverlayHandleHI_MPI_RGN_SetBitMap(OverlayHandle_top_left,&stBitmap_top_left);//s32Ret 為RGN_HANDLE OverlayHandle// pthread_mutex_unlock(&mutex);// usleep(15000);// memset(&tmp,0,sizeof(tmp));// tmp = clockGetTime(CLOCK_MONOTONIC);// timeOffset1 = tmp.tv_sec*1000*1000 + tmp.tv_usec;// printf("timeOffset:%d\n",(timeOffset1 - timeOffset));/* 測試代碼執行時間 */// hi_memset(stBitmap_bottom_left.pData, sizeof(BITMAP_S),0, sizeof(BITMAP_S));// hi_memset(stBitmap_top_left.pData, sizeof(BITMAP_S),0, sizeof(BITMAP_S));// hi_memset(timestr,OSD_LENGTH,0,OSD_LENGTH);// q_stVideoFrame_venc.push(stVideoFrame_process_osd);// printf("osd ok\n");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; }效果
??擺出最后疊加后的效果圖
后續改進
??這樣的OSD已經滿足大多數需求了,但是還是沒有考慮到如果過亮或者過暗的情況,對于亮度的采集和反色處理將在下一篇更新
總結
以上是生活随笔為你收集整理的海思3559万能平台搭建:OSD功能的优化的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: ElasticSearch(十一)Jav
- 下一篇: 安卓开发者的历程