前言
颜色空间的转换,除了闹着玩的找找定位,画画框,更具代表性的就是yuv到rgb的转化
Makefile
主要用到了sdk中ive内的算子,由于默认的是不支持ive的静态库的,需要在Makefile中将其添加进来
SENSOR_LIBS += $(REL_LIB)/libive.a
代码
还是新建专门用于转换的线程
if(yuv2rgbEnable) { stv_process_yuv2rgb.VpssGrp = VpssGrp; stv_process_yuv2rgb.VpssChn = VpssChn[1]; pthread_t video_process_yuv2rgb_id; s32Ret=pthread_create(&video_process_yuv2rgb_id, NULL, &video_process_yuv2rgb_task,(HI_VOID*)&stv_process_yuv2rgb); if(s32Ret != 0) { SAMPLE_PRT("pthread video_process_yuv2rgb create failed\n"); return -HI_FAILURE; } pthread_detach(video_process_yuv2rgb_id); }
在原先处理线程的基础上进行修改
/* *描述 :用于处理yuv2rgb颜色空间转化的线程 *参数 :arg 为自定义结构video_process_s,VPSS_GRP和VPSS_CHN用于传参给HI_MPI_VPSS_GetChnFrame *返回值: *注意 :HI_MPI_VPSS_GetChnFrame完必须释放,否则再次获取VB会报错 */ HI_VOID *video_process_yuv2rgb_task(HI_VOID *arg) { HI_S32 cnt = 0; HI_S32 s32Ret; VIDEO_FRAME_INFO_S stVideoFrame; video_process_s* pstPara; pstPara = (video_process_s*)arg; sleep(1); memset(&stVideoFrame,0,sizeof(VIDEO_FRAME_INFO_S)); while(cnt <= 10) { s32Ret = HI_MPI_VPSS_GetChnFrame(pstPara->VpssGrp, pstPara->VpssChn, &stVideoFrame,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);//不释放会导致后续vb崩溃 goto DEAL; } } goto EXIT; DEAL: // deal_myself_osd(arg); deal_myself_yuv2rgb(arg); // deal_myself(arg); EXIT: pthread_exit(0); }
HI_MPI_IVE_CSC
是核心的转换函数,位于SVP目录下HiIVE API 参考手册中,重点是对该函数参数的配置
/***************************************************************************** * Prototype : HI_MPI_IVE_CSC * Description : YUV2RGB\YUV2HSV\YUV2LAB\RGB2YUV color space conversion are supported. * Parameters : IVE_HANDLE *pIveHandle Returned handle ID of a task * IVE_SRC_IMAGE_S *pstSrc Input source data: * 1. SP420\SP422 type for YUV2RGB\YUV2HSV\YUV2LAB; * 2. U8C3_PACKAGE\U8C3_PLANAR type for RGB2YUV; * IVE_DST_IMAGE_S *pstDst Output result: * 1. U8C3_PACKAGE\U8C3_PLANAR typed for YUV2RGB\YUV2HSV\YUV2LAB; * 2. SP420\SP422 type for RGB2YUV; * IVE_CSC_CTRL_S *pstCscCtrl Control parameters for CSC * HI_BOOL bInstant For details, see HI_MPI_IVE_DMA. * Return Value : HI_SUCCESS: Success;Error codes: Failure. * Spec : The size of the input data ranges from 64x64 pixels to 1920x1080 pixels. * The physical addresses of the input data and output data must be 16-byte-aligned. * The stride must be 16-pixel-aligned. * History: * * 1. Date : 2011-05-16 * Author : * Modification : Created function * 2. Date : 2013-08-09 * Author : * Modification : Modified function * *****************************************************************************/ HI_S32 HI_MPI_IVE_CSC(IVE_HANDLE *pIveHandle, IVE_SRC_IMAGE_S *pstSrc,IVE_DST_IMAGE_S *pstDst, IVE_CSC_CTRL_S *pstCscCtrl, HI_BOOL bInstant);
注意事项要看仔细,这里对分辨率有着明确的要求,没细看的我第一次天真的又跳进自己挖好的坑里,不过在上一期思维方式转变厚,不到五分钟就成功定位到了,毕竟这个日志功能确实强大
# cat /dev/1ogmpp <3> ive] [Func] :ivecheck_image Line]:192[Info]:image->width(3840) must be in [64, 1920] 3 ive][Func]:ive_check_csc_yuv2mode [Line]:428 [Info]:check image src failed! <3> ive] [Func]:ive_check_csc_param [Line]:513[Info]:check image failed, in ctr1->mode(0)! <3> ive] [Func]:ive_csc [Line]:636[Info]:Error(0xa01d8003): check CSC parameters failed!
再然后关于函数使用的就顺利许多了,参考下面的代码配置即可
/* *描述 :线程里用于处理图像信息,完成yuv-rgb的颜色空间转换 *参数 :arg 为自定义结构video_process_s,VPSS_GRP和VPSS_CHN用于传参给HI_MPI_VPSS_GetChnFrame *返回值:无 *注意 :HI_MPI_VPSS_GetChnFrame完必须释放,否则再次获取VB会报错 HI_MPI_SYS_MmzAlloc_Cached需要搭配HI_MPI_SYS_MmzFlushCache刷新,最后需要HI_MPI_SYS_MmzFree释放 *Bug :未知原因卡顿,偶现退出后无法再次运行的问题(定位至保存问题) */ HI_S32 deal_myself_yuv2rgb(HI_VOID *arg) { HI_S32 s32Ret; IVE_SRC_IMAGE_S stSrc ; IVE_DST_IMAGE_S stDst ; IVE_HANDLE IveHandle ; IVE_CSC_CTRL_S stCscControl ; HI_BOOL bInstant = HI_TRUE; VIDEO_FRAME_INFO_S stVideoFrame; // VIDEO_FRAME_INFO_S* pstVideoFrame = &stVideoFrame; video_process_s* pstPara; pstPara = (video_process_s*)arg; memset(&stSrc,0,sizeof(IVE_SRC_IMAGE_S)); memset(&stDst,0,sizeof(IVE_DST_IMAGE_S)); memset(&stCscControl,0,sizeof(IVE_CSC_CTRL_S)); stCscControl.enMode = IVE_CSC_MODE_VIDEO_BT601_YUV2RGB; // #define RGB_SAVE #ifdef RGB_SAVE FILE *fOut; HI_CHAR *pchDstFileName = "./YUV/chn1_w1920_h1080_RGB.bgr"; #endif // ftruncate(fOut,0); while(1) { // sleep(1); s32Ret = HI_MPI_VPSS_GetChnFrame(pstPara->VpssGrp, pstPara->VpssChn, &stVideoFrame,1000); // SAMPLE_PRT("deal_myself_yuv2rgb chn is %d!\n",pstPara->VpssChn); if(s32Ret != HI_SUCCESS) { // SAMPLE_PRT("VPSS_GetChnFrame err for %#x!\n",s32Ret);//while1打印太多 continue; } else { // SAMPLE_PRT("VPSS_GetChnFrame success for %#x!\n",s32Ret); /*初始化YUV输入数据结构体stSrc*/ stSrc.enType = IVE_IMAGE_TYPE_YUV420SP ; stSrc.au64PhyAddr[0] = stVideoFrame.stVFrame.u64PhyAddr[0] ; stSrc.au64PhyAddr[1] = stVideoFrame.stVFrame.u64PhyAddr[1] ; stSrc.au64PhyAddr[2] = stVideoFrame.stVFrame.u64PhyAddr[2] ; stSrc.au64VirAddr[0] = stVideoFrame.stVFrame.u64VirAddr[0] ; stSrc.au64VirAddr[1] = stVideoFrame.stVFrame.u64VirAddr[1] ; stSrc.au64VirAddr[2] = stVideoFrame.stVFrame.u64VirAddr[2] ; stSrc.au32Stride[0] = stVideoFrame.stVFrame.u32Stride[0] ; stSrc.au32Stride[1] = stVideoFrame.stVFrame.u32Stride[1] ; stSrc.au32Stride[2] = stVideoFrame.stVFrame.u32Stride[2] ; stSrc.u32Width = stVideoFrame.stVFrame.u32Width ; stSrc.u32Height = stVideoFrame.stVFrame.u32Height ; // printf("width is %d, height is %d\n", stSrc.au32Stride[0], stSrc.u32Height); /*初始化输出RPG数据结构体并在内存中为图像数据分配空间*/ s32Ret = HI_MPI_SYS_MmzAlloc_Cached(&stDst.au64PhyAddr[0], (HI_VOID *)&stDst.au64VirAddr[0], "DstImg", HI_NULL, stSrc.au32Stride[0] * stSrc.u32Height * 3); if(HI_SUCCESS != s32Ret) { SAMPLE_PRT("Error(%#x),HI_MPI_SYS_MmzAlloc_Cached failed!\n",s32Ret) ; HI_MPI_SYS_MmzFree(stDst.au64PhyAddr[0],(HI_VOID*)stDst.au64VirAddr) ; return s32Ret; } // memset(stDst.au64VirAddr[0],0,stSrc.u32Height * stSrc.au32Stride[0] * 3) ; stDst.enType = IVE_IMAGE_TYPE_U8C3_PACKAGE ; stDst.u32Height = stSrc.u32Height ; stDst.u32Width = stSrc.u32Width ; stDst.au32Stride[0] = (((stVideoFrame.stVFrame.u32Width + 15) >> 4) << 4); // stDst.au32Stride[0] = stSrc.au32Stride[0] ; // stDst.au32Stride[1] = stDst.au32Stride[1] ; // stDst.au32Stride[2] = stDst.au32Stride[2] ; // stDst.au64VirAddr[1] = stDst.au64VirAddr[0] + stDst.u32Height * stDst.au32Stride[0] ; // stDst.au64VirAddr[2] = stDst.au64VirAddr[1] + stDst.u32Height * stDst.au32Stride[0] ; // stDst.au64PhyAddr[1] = stDst.au64PhyAddr[0] + stDst.u32Height * stDst.au32Stride[0] ; // stDst.au64PhyAddr[2] = stDst.au64PhyAddr[1] + stDst.u32Height * stDst.au32Stride[0] ; // memset(stDst.au64VirAddr,0, stSrc.au32Stride[0] * stSrc.u32Height * 3); /*将cache中的内容刷新到内存*/ // s32Ret = HI_MPI_SYS_MmzFlushCache(stDst.au64PhyAddr[0],(HI_VOID*)stDst.au64VirAddr[0],stDst.u32Height * stDst.au32Stride[0] * 3) ; // // s32Ret = HI_MPI_SYS_MmzFlushCache(0, NULL, 0) ; // if(HI_SUCCESS != s32Ret){ // SAMPLE_PRT("Error(%#x),HI_MPI_SYS_MmzFlushCache failed!\n",s32Ret) ; // // HI_MPI_SYS_MmzFree(stDst.au64PhyAddr[0],stDst.au64VirAddr) ; // // HI_MPI_SYS_MmzFree(stDst.au64PhyAddr[0],stDst.au64VirAddr) ; // // return ; // } /*将YUV数据转换到RGB planar存储,地址保存在stDst结构体中*/ s32Ret = HI_MPI_IVE_CSC(&IveHandle,&stSrc,&stDst,&stCscControl,bInstant) ; if(HI_SUCCESS != s32Ret) { SAMPLE_PRT("Error(%#x),HI_MPI_IVE_CSC failed!\n",s32Ret) ; // return ; } #ifdef RGB_SAVE printf("yuv2bgr success\r\n"); fflush(stdout); fOut = fopen(pchDstFileName,"wb"); if(HI_NULL == fOut) { printf("Open out file %s fail\n",pchDstFileName); fclose(fOut); // return; } WriteBGRPackFile(&stDst, fOut); fclose(fOut); printf("file\r\n"); #endif s32Ret = HI_MPI_SYS_MmzFree(stDst.au64PhyAddr[0],(HI_VOID*)stDst.au64VirAddr) ; if(HI_SUCCESS != s32Ret){ SAMPLE_PRT("Error(%#x),HI_MPI_SYS_MmzFree failed!\n",s32Ret) ; HI_MPI_SYS_MmzFree(stDst.au64PhyAddr[0],(HI_VOID*)stDst.au64VirAddr) ; // return ; } s32Ret = HI_MPI_VENC_SendFrame(pstPara->VpssChn, &stVideoFrame,1000); HI_MPI_VPSS_ReleaseChnFrame(pstPara->VpssGrp, pstPara->VpssChn, &stVideoFrame); } } }
将转化后的rgb文件保存下来(rgb888或者叫rgb24格式)
/* *描述 :用于保存rgb图像 *参数 :pstImg IVE_IMAGE_S 结构体,定义二维广义图像信息,用于ive_csc处理后rgb24图像的保存 pFp 文件指针,用于保存文件 *返回值:无 *注意 :无 *Bug :未知原因容易卡顿(更换打开文件的位置后解决) */ HI_VOID WriteBGRPackFile(IVE_IMAGE_S *pstImg, FILE *pFp) { HI_U16 y; HI_U8 *pU8; HI_U16 height; HI_U16 width; width = pstImg->u32Width; height = pstImg->u32Height*3; pU8 = (HI_U8*)pstImg->au64VirAddr[0]; for (y = 0; y < height; y++) { if ( 1 != fwrite(pU8,width,1,pFp)) { printf("write file error, y = %d\n", y); return ; } pU8 += pstImg->au32Stride[0]; } }
结果
小意外还是发生了,除了注释中解决的小bug,图像感觉颜色怪怪的,像加了滤镜
应该是这个算子支持的是yuv转rgb而我们默认的一直是yvu实际上,vpss处修改了图片格式后果然正常多了