前言:
几年前基础海思,当时做了个火焰探测的项目,变使用了opencv,苦于网上没有资料,都是编译这块的资料;
后先后把Opencv移植到hi35183v200/hi3516dv100/hi3516dv300/hi359av100/rv1126/寒武纪
目前到了在做自己的Sigmastar SSC33X 38板开始预售,希望有个好彩头
Copy
海思移植opencv步骤
交叉编译opencv,网上资料很多,再次不多说;
1.版本选择,海思官方SDK已经说明,很多的图像接口都是参考了2.x的版本;
因此个人在最初移植时也同样使用了2.4版本,后期有使用过3.5版本,但是接口还是用的2.4,几乎没有变动过接口;
2.编译重点
Opencv组件繁杂,在嵌入式使用没必要勾选不必要的组件;少勾选,之勾选基础的组件,才能尽可能保证
Copy
海思端准备工作
1.运算速度
测试过2818ev200/d1516dv300的速度,经过一系列处理后,640*480图片,前置速度400ms后者320ms,
2款芯片主频一个600一个好像900,速度差别不大;
2.色彩空间转换
opencv在海思运行,本身没有多大难度.问题在于运行的速度;opencv使用BGR数据;海思接口出的是yuv12(也能是21忘了)数据;
因此需要吧yuv转到bgr;
3.转换方式
opencv有自己的接口cvColor,但是在嵌入式端转换效率非常的低,耗费CPU,因此需借助硬件的DSP加速;
海思有IVE协处理器,有IVE的色彩转换接口;使用海思的接口速度相当的快;从yu12转换到rgb888,
在opencv3.x中可以用Mat test = cv::Mat(xx,xx,xx,xx,转换后的rgb地址),方式直接开始opencv的操作;
Copy
海思色彩空间转换工作
23230319:
HI_S8 SAMPLE_MISC_VpssDump_Opencv(VPSS_GRP Grp, VPSS_CHN Chn, VENC_CHN VencChn)
{
HI_S32 i = 0;
HI_S32 s32Ret; //返回值
HI_U64 u64pts = 0;
HI_U32 u32Size = 0;
/*VPSS相关参数*/
HI_U32 u32Depth = 2;
HI_S32 s32Times = 10;
HI_S32 s32GetFrameMilliSec = 200;
HI_S32 s32SetFrameMilliSec = 200;
HI_U32 u32OrigDepth = 0;
VIDEO_FRAME_INFO_S srcFrame;
/*CSC_IVE输入输出参数定义*/
HI_S32 hIveHandle;
HI_BOOL bFinish = HI_FALSE;
HI_BOOL bBlock = HI_FALSE;
IVE_SRC_IMAGE_S stSrc; //输入空间--yuv-->osc
IVE_DST_IMAGE_S stDst; //输出空间--osc-->rgb ----opencv直接在这里处理...直接填充彩色的框
IVE_CSC_CTRL_S stCtrl; //yub_to_rgb rgb_to_yuv
/*VB相关参数*/
VB_BLK handleY = VB_INVALID_HANDLE;
HI_U32 phyYaddr,*pVirYaddr;
VB_POOL hPool = VB_INVALID_POOLID;
/*venc相关参数*/
fd_set read_fds;
VENC_CHN_STAT_S stStat;
struct timeval TimeoutVal;
VIDEO_FRAME_INFO_S pstFrame; //用来发送frame给venc编码....
VENC_STREAM_S stStream; //接受venc的输出流...
/*文件配置*/
FILE* opencv_fp;
FILE* opencv_mem_fp;
/*REGION/NAMAL/DEBUG切换*/
pthread_cond_init(&normal_cond, NULL);
pthread_cond_init(®ion_cond, NULL);
pthread_mutex_init(&normal_mutex, NULL);
pthread_mutex_init(®ion_mutex, NULL);
//***********************************************************************************************
if (HI_MPI_VPSS_GetDepth(Grp, Chn, &u32OrigDepth) != HI_SUCCESS)
{
debug("get depth error!!!\n");
return HI_FAILURE;
}
if (HI_MPI_VPSS_SetDepth(Grp, Chn, u32Depth) != HI_SUCCESS)
{
debug("set depth error!!!\n");
VPSS_Restore(Grp, Chn);
return HI_FAILURE;
}
memset(&srcFrame, 0, sizeof(srcFrame));
srcFrame.u32PoolId = VB_INVALID_POOLID;
while (HI_MPI_VPSS_GetChnFrame(Grp, Chn, &srcFrame, s32GetFrameMilliSec) != HI_SUCCESS)
{
s32Times--;
if(0 >= s32Times)
{
debug("get frame error for 10 times,now exit !!!\n");
VPSS_Restore(Grp, Chn);
return HI_FAILURE;
}
usleep(40000);
}
//*****************根据第1次得到的frame开辟空间--第1次CSC <输出参数> 初始化****************************************************************
//开辟CSC色彩空间--YUV-->RGB--------------opencv<输入参数>:原始RGB存储的空间......
stDst.u16Width = srcFrame.stVFrame.u32Width;
stDst.u16Height = srcFrame.stVFrame.u32Height;
stDst.u16Stride[0] = srcFrame.stVFrame.u32Stride[0];
stDst.u16Stride[1] = srcFrame.stVFrame.u32Stride[1]; //*****************************
stDst.enType = IVE_IMAGE_TYPE_U8C3_PACKAGE; //RGB_PACKAGE图像-以B0G0R0B1G1R1形式存储,B在最前面
u32Size = stDst.u16Stride[0] * stDst.u16Height * 3; //RGB的大小....
s32Ret = HI_MPI_SYS_MmzAlloc(&stDst.u32PhyAddr[0], (void**)&stDst.pu8VirAddr[0],"Output_RGB_Image", HI_NULL, u32Size);
if(s32Ret != HI_SUCCESS){
debug("can't alloc Output_RGB_Image memory for %x\n",s32Ret);
}
//************** 第2次CSC <输入参数> 初始化********************************************************************************************
//开辟CSC空间---用来存储RGB---用于存储WORK_DEBUG模式:opencv处理后的binary_rgb---也是第2次CSC的输入空间--BGR
stDst_opencv_binary_rgb.u16Height = srcFrame.stVFrame.u32Height;
stDst_opencv_binary_rgb.u16Width = srcFrame.stVFrame.u32Width;
stDst_opencv_binary_rgb.u16Stride[0] = srcFrame.stVFrame.u32Stride[0];
stDst_opencv_binary_rgb.u16Stride[1] = srcFrame.stVFrame.u32Stride[1]; //**************************
stDst_opencv_binary_rgb.enType = IVE_IMAGE_TYPE_U8C3_PACKAGE;
u32Size = stDst_opencv_binary_rgb.u16Stride[0] * stDst_opencv_binary_rgb.u16Height * 3; //BGR的大小....
s32Ret = HI_MPI_SYS_MmzAlloc(&stDst_opencv_binary_rgb.u32PhyAddr[0], (void**)&stDst_opencv_binary_rgb.pu8VirAddr[0],"OutputOpencvBinaryRgb", HI_NULL, u32Size);
if(s32Ret != HI_SUCCESS){
debug("can't alloc OutputImage memory for %x\n",s32Ret);
}
//*************** 第2次CSC <输出参数> 初始化,*******************************************************************************************
//创建一个视频缓存池。 有2个缓存快,用来存储最终sendframe需要的的YUV
hPool = HI_MPI_VB_CreatePool(srcFrame.stVFrame.u32Stride[0] * srcFrame.stVFrame.u32Height * 3 / 2, 2 , NULL); //之前是NULL/HI_NULL //******1个块也可以....
if (hPool == VB_INVALID_POOLID)
{
debug("HI_MPI_VB_CreatePool failed!.. %s %s %d \n",__FILE__,__func__,__LINE__);
return HI_FAILURE;
}
//**********************************************************************************************************
//开辟CSC空间---RGB---用于存储opencv处理后的白底的contours,用于REGION BMP叠加
stDst_opencv_contours.u16Width = srcFrame.stVFrame.u32Width;
stDst_opencv_contours.u16Height = srcFrame.stVFrame.u32Height;
stDst_opencv_contours.u16Stride[0] = srcFrame.stVFrame.u32Stride[0];
stDst_opencv_contours.u16Stride[1] = srcFrame.stVFrame.u32Stride[1];
stDst_opencv_contours.enType = IVE_IMAGE_TYPE_U8C3_PACKAGE;
u32Size = stDst_opencv_contours.u16Stride[0] * stDst_opencv_contours.u16Height * 3; //BGR的大小....
s32Ret = HI_MPI_SYS_MmzAlloc(&stDst_opencv_contours.u32PhyAddr[0], (void**)&stDst_opencv_contours.pu8VirAddr[0],"OutputOpencvBinaryRgb", HI_NULL, u32Size);
if(s32Ret != HI_SUCCESS){
debug("can't alloc OutputImage memory for %x\n",s32Ret);
}
//*****根据第一次获得的frame部分参数对opencv中的图形空间申请*****调用c++代码*************************************************
opencv_alloc(&opencv_img,&srcFrame);
//4_1_opencv <输入参数>---RGB 初始化 --- 使用上面CSC的<输出参数>--stDst 初始化opencv<输入>参数
opencv_img.frame->imageData = (char*)stDst.pu8VirAddr[0];
opencv_img.frame->imageDataOrigin = (char*)stDst.pu8VirAddr[0];
//4_2_opencv <输出参数> 初始化 输出得到Binary_RGB,使用opencv <输出参数> 作为第2次CSC <输入参数> 用于 WORK_DEBUG模式
opencv_img.out_RGB_bin->imageData = (char*)stDst_opencv_binary_rgb.pu8VirAddr[0];
opencv_img.out_RGB_bin->imageDataOrigin = (char*)stDst_opencv_binary_rgb.pu8VirAddr[0];
//4_3_opencv <输出参数>---out_contours初始化 ---得到白底countours用于REGION_BMP
opencv_img.out_contours->imageData = (char*)stDst_opencv_contours.pu8VirAddr[0];
opencv_img.out_contours->imageDataOrigin = (char*)stDst_opencv_contours.pu8VirAddr[0];
//countor初始化白底
opencv_init(&opencv_img);
//********释放第一次获得的frame******************************************************************************************
HI_MPI_VPSS_ReleaseChnFrame(Grp, Chn, &srcFrame);
srcFrame.u32PoolId = VB_INVALID_POOLID;
HI_S32 VencFd = HI_MPI_VENC_GetFd(VencChn);
if (VencFd < 0)
{
debug("HI_MPI_VENC_GetFd failed with %d.. %s %s %d\n",VencFd,__FILE__,__func__,__LINE__);
return HI_FAILURE;
}
//***********************************************************************************************************************
opencv_fp = fopen("opencv_crtl.conf","r");
if(NULL==opencv_fp)
{
perror("fail to fopen");
return HI_FAILURE;
}
fseek(opencv_fp,0,SEEK_SET);
fread(opencv_ctrl_buffer,sizeof(char)*100,1,opencv_fp);
opencv_mem_fp = fopen("/tmp/opencv_crtl_mem.conf","w+");
if(NULL==opencv_mem_fp)
{
perror("create oepncv_bgr configure file fail...\n");
return HI_FAILURE;
}
fwrite(opencv_ctrl_buffer,sizeof(char)*100,1,opencv_mem_fp);
fclose(opencv_mem_fp);
Interval_Ms();
/* get frame & opencv_fire process */
while (1)
{
//1--获取YUV数据源....
s32Ret = HI_MPI_VPSS_GetChnFrame(Grp, Chn, &srcFrame, s32GetFrameMilliSec);
if (s32Ret!= HI_SUCCESS)
{
debug("Get frame fail %#X %s %s %d\n",s32Ret,__FILE__,__func__,__LINE__);
usleep(1000);
continue;
}
if((srcFrame.stVFrame.enCompressMode > 0) || (srcFrame.stVFrame.enVideoFormat > 0))
{
debug("enCompressMode is not COMPRESS_MODE_NONE && VIDEO_FORMAT_LINEAR ,code is not support......\n");
return HI_FAILURE;
}
// debug("HI_MPI_VPSS_GetChnFrame ms: %s %s %d\n",__FILE__,__func__,__LINE__);
// Interval_Ms();
//2--CSC <输入参数> 初始化------填充YUV数据源到CSC输入端口......
stSrc.u16Width = srcFrame.stVFrame.u32Width;
stSrc.u16Height = srcFrame.stVFrame.u32Height;
stSrc.u16Stride[0] = srcFrame.stVFrame.u32Stride[0];
stSrc.u16Stride[1] = srcFrame.stVFrame.u32Stride[1];
stSrc.pu8VirAddr[0] = (HI_U8*)srcFrame.stVFrame.pVirAddr[0];
stSrc.pu8VirAddr[1] = (HI_U8*)srcFrame.stVFrame.pVirAddr[1]; //YU起始地址...
stSrc.u32PhyAddr[0] = srcFrame.stVFrame.u32PhyAddr[0];
stSrc.u32PhyAddr[1] = srcFrame.stVFrame.u32PhyAddr[1];
stSrc.enType = IVE_IMAGE_TYPE_YUV420SP;
//##################################第1次_CSC色彩空间转换###################################################################################
//#########################################################################################################################################
//3--CSC: YUV--> RGB
stCtrl.enMode = IVE_CSC_MODE_PIC_BT601_YUV2RGB;
HI_MPI_IVE_CSC(&hIveHandle, &stSrc, &stDst, &stCtrl, HI_TRUE);
do{
s32Ret = HI_MPI_IVE_Query(hIveHandle,&bFinish,bBlock); //bBlockwei
if(0 != s32Ret)
debug("HI_MPI_IVE_Query failed %#X,%s %s %d\n",s32Ret,__FILE__,__func__,__LINE__);
}while(0 != s32Ret);
// debug("convert yuv to rgb ok_ms: <%s %s %d>\n",__FILE__,__func__,__LINE__);
// Interval_Ms();
//########################################################################################################################################
//4--使用opencv对得到的RGB原始数据进行处理###################################################################################################
//4_4--打开opencv配置文件..
opencv_mem_fp = fopen("/tmp/opencv_crtl_mem.conf","r");
if(NULL==opencv_mem_fp)
{
perror("fail to fopen oepncv configure file\n");
return HI_FAILURE;
}
fseek(opencv_mem_fp,0,SEEK_SET);
fread(opencv_ctrl_buffer,sizeof(char)*100,1,opencv_mem_fp);
fclose(opencv_mem_fp);
//先备份取到的控制到本地 下边在读
memcpy(&opencv_ctrl_temp,&opencv_ctrl,sizeof(OPENCV_CTRL));
//从新从本地buuffer中读数据到opencv_ctrl
for(i=0;i<120;i++){
if('B'==opencv_ctrl_buffer[i])
opencv_ctrl.B = (opencv_ctrl_buffer[i+1]-48)*100 + (opencv_ctrl_buffer[i+2]-48)*10 + (opencv_ctrl_buffer[i+3]-48);
if('G'==opencv_ctrl_buffer[i])
opencv_ctrl.G = (opencv_ctrl_buffer[i+1]-48)*100 + (opencv_ctrl_buffer[i+2]-48)*10 + (opencv_ctrl_buffer[i+3]-48);
if('R'==opencv_ctrl_buffer[i])
opencv_ctrl.R = (opencv_ctrl_buffer[i+1]-48)*100 + (opencv_ctrl_buffer[i+2]-48)*10 + (opencv_ctrl_buffer[i+3]-48);
//RGB_Bin_Count--第几次的rgb_bin 有效果前 和效果后
if('C'==opencv_ctrl_buffer[i])
opencv_ctrl.RGB_Bin_Count = (opencv_ctrl_buffer[i+1]-48)*100 + (opencv_ctrl_buffer[i+2]-48)*10 + (opencv_ctrl_buffer[i+3]-48);
//-------------------------------------------------------------------------------------------------------------------------------
//cvSmooth_Num平滑滤波次数
if('S'==opencv_ctrl_buffer[i])
opencv_ctrl.cvSmooth_Num = (opencv_ctrl_buffer[i+1]-48)*100 + (opencv_ctrl_buffer[i+2]-48)*10 + (opencv_ctrl_buffer[i+3]-48);
//-------------------------------------------------------------------------------------------------------------------------------
//ConvKernel_Default--自定义核心
if('K'==opencv_ctrl_buffer[i])
opencv_ctrl.ConvKernel_Default = (opencv_ctrl_buffer[i+1]-48)*100 + (opencv_ctrl_buffer[i+2]-48)*10 + (opencv_ctrl_buffer[i+3]-48);
//腐蚀次数
if('E'==opencv_ctrl_buffer[i])
opencv_ctrl.cvErode_Num = (opencv_ctrl_buffer[i+1]-48)*100 + (opencv_ctrl_buffer[i+2]-48)*10 + (opencv_ctrl_buffer[i+3]-48);
//膨胀次数
if('D'==opencv_ctrl_buffer[i])
opencv_ctrl.cvDilate_Num = (opencv_ctrl_buffer[i+1]-48)*100 + (opencv_ctrl_buffer[i+2]-48)*10 + (opencv_ctrl_buffer[i+3]-48);
//开合运算次数
if('M'==opencv_ctrl_buffer[i])
opencv_ctrl.cvMorphologyEx_Num = (opencv_ctrl_buffer[i+1]-48)*100 + (opencv_ctrl_buffer[i+2]-48)*10 + (opencv_ctrl_buffer[i+3]-48);
//-------------------------------------------------------------------------------------------------------------------------------
//面积
if('A'==opencv_ctrl_buffer[i])
opencv_ctrl.AREA = (opencv_ctrl_buffer[i+1]-48)*100 + (opencv_ctrl_buffer[i+2]-48)*10 + (opencv_ctrl_buffer[i+3]-48);
//周长
if('P'==opencv_ctrl_buffer[i])
opencv_ctrl.PERIMETER = (opencv_ctrl_buffer[i+1]-48)*100 + (opencv_ctrl_buffer[i+2]-48)*10 + (opencv_ctrl_buffer[i+3]-48);
//高
if('H'==opencv_ctrl_buffer[i])
opencv_ctrl.HEIGHT = (opencv_ctrl_buffer[i+1]-48)*100 + (opencv_ctrl_buffer[i+2]-48)*10 + (opencv_ctrl_buffer[i+3]-48);
//宽
if('W'==opencv_ctrl_buffer[i])
opencv_ctrl.WIDTH = (opencv_ctrl_buffer[i+1]-48)*100 + (opencv_ctrl_buffer[i+2]-48)*10 + (opencv_ctrl_buffer[i+3]-48);
//环境状态亮度变化阀值
if('L'==opencv_ctrl_buffer[i])
opencv_ctrl.ENV_LIGHT_AREA = (opencv_ctrl_buffer[i+1]-48)*1000 + (opencv_ctrl_buffer[i+2]-48)*100 + (opencv_ctrl_buffer[i+3]-48)*10 + (opencv_ctrl_buffer[i+3]-48);
//环境状态活火点数目变化阀值
if('F'==opencv_ctrl_buffer[i])
opencv_ctrl.ENV_FIRE_NUM = (opencv_ctrl_buffer[i+1]-48)*100 + (opencv_ctrl_buffer[i+2]-48)*10 + (opencv_ctrl_buffer[i+3]-48);
}
debug("B=%d\n",opencv_ctrl.B);
debug("G=%d\n",opencv_ctrl.G);
debug("R=%d\n\n",opencv_ctrl.R);
debug("opencv_ctrl.RGB_Bin_Count=%d\n\n",opencv_ctrl.RGB_Bin_Count);
debug("opencv_ctrl.cvSmooth_Num=%d\n\n",opencv_ctrl.cvSmooth_Num);
debug("opencv_ctrl.ConvKernel_Default=%d\n",opencv_ctrl.ConvKernel_Default);
debug("opencv_ctrl.cvErode_Num=%d\n",opencv_ctrl.cvErode_Num);
debug("opencv_ctrl.cvDilate_Num=%d\n",opencv_ctrl.cvDilate_Num);
debug("opencv_ctrl.cvMorphologyEx_Num=%d\n\n",opencv_ctrl.cvMorphologyEx_Num);
debug("opencv_ctrl.AREA=%d\n",opencv_ctrl.AREA);
debug("opencv_ctrl.PERIMETER=%d\n",opencv_ctrl.PERIMETER);
debug("opencv_ctrl.HEIGHT=%d\n",opencv_ctrl.HEIGHT);
debug("opencv_ctrl.WIDTH=%d\n\n",opencv_ctrl.WIDTH);
debug("opencv_ctrl.ENV_LIGHT_AREA=%d\n\n",opencv_ctrl.ENV_LIGHT_AREA);
debug("opencv_ctrl.ENV_FIRE_NUM=%d\n\n",opencv_ctrl.ENV_FIRE_NUM);
//配置改变后保存配置到本地...
//if(opencv_ctrl_temp.R_Temp != opencv_ctrl.R || opencv_ctrl_temp.G_Temp != opencv_ctrl.G || opencv_ctrl_temp.B_Temp!= opencv_ctrl.B )
//如果两个不等 说明配置跟新了,然后写到本地....
HI_U8* ctrl_temp = (HI_U8*)&opencv_ctrl_temp;
HI_U8* ctrl = (HI_U8*)&opencv_ctrl;
for(i=0; i<sizeof(OPENCV_CTRL_TEMP)/sizeof(HI_U8); i++)
{
if(ctrl_temp[i]!=ctrl[i]) //如果两个不等 说明配置跟新了
{
debug("preparing update opencv_crtl.conf\n");
opencv_fp = fopen("opencv_crtl.conf","w+");
if(NULL==opencv_fp)
{
perror("fail to fopen home_oepncv configure file\n");
return HI_FAILURE;
}
fseek(opencv_fp,0,SEEK_SET); //移动到开头
fwrite(opencv_ctrl_buffer,sizeof(char)*100,1,opencv_fp); //把所有的便跟配置写到本地.conf
fclose(opencv_fp);
}
}
//4 _5---opencv处理火点....
//1--画框-->RGB----------------------------------调试模式---RGB
//2--画框-->Binary_RGB---------------------------调试模式---Binary_RGB
//3--画框-->contours--白底色红框------------------叠加GEGION--工作流畅模式
//4--得到输出的Binary_RGB/grey/contours-----------CSC输入参数
opencv_main(&opencv_img,&opencv_ctrl);
debug("opencv process over, ms:\n");
debug("opencvPrecess time:\n");
Interval_Ms();
//暂停REGION线程
//暂停WORK_NARMAL线程的数据发送
// if(1==WORK_STATUS) //如果上次是NORMAL
// WORK_STATUS = 0; //现在为DEBUG
//################--opencv处理后_叠加countor到REGION--#############################--叠加countor到REGION--##########################
//################--opencv处理后_叠加countor到REGION--#############################--叠加countor到REGION--##########################
//****************CSC <输出参数> 初始化********************************************************************************************
//为了CSC第2个输出参数获取缓冲块...数据源头 必须要用缓冲池........
do{
handleY = HI_MPI_VB_GetBlock(hPool, srcFrame.stVFrame.u32Stride[0] * srcFrame.stVFrame.u32Height * 3 / 2, NULL);
if(handleY != VB_INVALID_HANDLE) break;
else debug("get vb_clock failed..\n");
}while (VB_INVALID_HANDLE == handleY); //成功调处
//debug("get vb_clock success \n");
//获取缓冲快的地址..
phyYaddr = HI_MPI_VB_Handle2PhysAddr(handleY);
if(0==phyYaddr)
{
debug("HI_MPI_VB_Handle2PhysAddr for handleY failed..\n");
return HI_FAILURE;
}
//存储映射接口。得到虚拟地址..
pVirYaddr = (HI_U32*) HI_MPI_SYS_Mmap(phyYaddr, srcFrame.stVFrame.u32Stride[0] * srcFrame.stVFrame.u32Height * 3/2);
//CSC输出参数初始化(每次都需要获取缓冲块;因此每次都需要初始化CSC输出信息)-----从存有Binary_BGR的缓冲块信息提取信息到CSC色彩空间所需要的输出参数--YUV
stDst_opencv_YUV.u16Width = srcFrame.stVFrame.u32Width;
stDst_opencv_YUV.u16Height = srcFrame.stVFrame.u32Height;
stDst_opencv_YUV.u16Stride[0] = srcFrame.stVFrame.u32Stride[0];
stDst_opencv_YUV.u16Stride[1] = srcFrame.stVFrame.u32Stride[1];
stDst_opencv_YUV.pu8VirAddr[0] = (HI_U8*)pVirYaddr;
stDst_opencv_YUV.pu8VirAddr[1] = (HI_U8*)pVirYaddr + srcFrame.stVFrame.u32Stride[0] * srcFrame.stVFrame.u32Height;
stDst_opencv_YUV.u32PhyAddr[0] = phyYaddr;
stDst_opencv_YUV.u32PhyAddr[1] = phyYaddr + srcFrame.stVFrame.u32Stride[0] * srcFrame.stVFrame.u32Height;
stDst_opencv_YUV.enType = IVE_IMAGE_TYPE_YUV420SP;
//############################第2次_色彩空间转换######################################################################################
//############################第2次_色彩空间转换######################################################################################
//CSC转换: Opencv_Binary_BGR --> YUV-------用于DEBUG模式
stCtrl.enMode = IVE_CSC_MODE_PIC_BT601_RGB2YUV;
HI_MPI_IVE_CSC(&hIveHandle, &stDst_opencv_binary_rgb, &stDst_opencv_YUV, &stCtrl, HI_TRUE);
do{
s32Ret = HI_MPI_IVE_Query(hIveHandle,&bFinish,bBlock); //bBlockwei
if(0 != s32Ret)
debug("HI_MPI_IVE_Query failed %#X\n",s32Ret);
}while(0 != s32Ret);
// debug("convert rgb to yuv is ok, ms:\n");
// Interval_Ms();
//#####################################################################################################################################
//6--YUV--SendFrameVenc===###########################################################################
//使用CSC转换得到的stDst_opencv_YUV中部分参数: phyYaddr/pVirYadd,对send_Venc<输入参数>初始化
memset(&pstFrame,0,sizeof(VIDEO_FRAME_INFO_S));
pstFrame.u32PoolId = hPool;
pstFrame.stVFrame.u32Width = srcFrame.stVFrame.u32Width;
pstFrame.stVFrame.u32Height = srcFrame.stVFrame.u32Height;
pstFrame.stVFrame.enPixelFormat = PIXEL_FORMAT_YUV_SEMIPLANAR_420;
pstFrame.stVFrame.enCompressMode = COMPRESS_MODE_NONE;
pstFrame.stVFrame.enVideoFormat = VIDEO_FORMAT_LINEAR;
pstFrame.stVFrame.u32Field = VIDEO_FIELD_FRAME;
pstFrame.stVFrame.u32Width = srcFrame.stVFrame.u32Width;
pstFrame.stVFrame.u32Height = srcFrame.stVFrame.u32Height;
pstFrame.stVFrame.u32Stride[0] = srcFrame.stVFrame.u32Stride[0];
pstFrame.stVFrame.u32Stride[1] = srcFrame.stVFrame.u32Stride[1];
//新加的,没啥用
pstFrame.stVFrame.u32HeaderPhyAddr[0] = 0;
pstFrame.stVFrame.u32HeaderPhyAddr[1] = 0;
pstFrame.stVFrame.u32PhyAddr[0] = phyYaddr; //缓冲池的物理地址
pstFrame.stVFrame.u32PhyAddr[1] = phyYaddr + srcFrame.stVFrame.u32Stride[0] * srcFrame.stVFrame.u32Height;
pstFrame.stVFrame.pVirAddr[0] = pVirYaddr; //缓冲池的虚拟地址
pstFrame.stVFrame.pVirAddr[1] = pVirYaddr + srcFrame.stVFrame.u32Stride[0] * srcFrame.stVFrame.u32Height;
pstFrame.stVFrame.u64pts = srcFrame.stVFrame.u64pts;
// pstFrame.stVFrame.u64pts = u64pts;
// u64pts += 1000000;
pstFrame.stVFrame.u32TimeRef = srcFrame.stVFrame.u32TimeRef;
// debug("srcFrame.stVFrame.u32TimeRef = %d\n",srcFrame.stVFrame.u32TimeRef);
// debug("srcFrame.stVFrame.u64pts = %d\n",srcFrame.stVFrame.u64pts);
// debug("pstFrame.stVFrame.u32TimeRef = %llu\n",pstFrame.stVFrame.u32TimeRef);
// debug("pstFrame.stVFrame.u64pts = %llu\n",pstFrame.stVFrame.u64pts);
//发送的是_BRG_bin
s32Ret = HI_MPI_VENC_SendFrame(VencChn, &pstFrame, s32SetFrameMilliSec); //超时时间 = 50 ********************sendFrame*******sendFrame********sendFrame****
if(s32Ret != 0)
{
debug("HI_MPI_VENC_SendFrame to VencChn = %d failed %#X\n",VencChn,s32Ret);
return HI_FAILURE;
}//else debug("HI_MPI_VENC_SendFrame is ok %s %s %d\n\n");
//使用select循环读取编码后的数据
FD_ZERO(&read_fds);
FD_SET(VencFd, &read_fds);
TimeoutVal.tv_sec = 2;
TimeoutVal.tv_usec = 0;
//通过查看编码通道设备文件句柄得知编码通道是否准备好.
s32Ret = select(VencFd + 1, &read_fds, NULL, NULL, &TimeoutVal);
if (s32Ret < 0)
{
debug("venc select failed!.. %s %s %d\n",__FILE__,__func__,__LINE__);
break;
}
else if (s32Ret == 0)
{
debug("get venc stream time out, exit thread.. %s %s %d\n",__FILE__,__func__,__LINE__);
continue;
}
else
{
//debug("select_while is ok %s %s %d\n",__FILE__,__func__,__LINE__);
if (FD_ISSET(VencFd, &read_fds))
{
//debug("select has data can read....%s %s %d\n",__FILE__,__func__,__LINE__);
/*******************************************************
step 2.1 : query how many packs in one-frame stream.
*******************************************************/
memset(&stStream, 0, sizeof(stStream));
//查询编码通道,编码器状态状态--stStat,
//获得: 编码的帧个数,剩余的byte数目。
//中剩余的帧数目。
s32Ret = HI_MPI_VENC_Query(VencChn, &stStat);
if (HI_SUCCESS != s32Ret)
{
debug("HI_MPI_VENC_Query VencChn_%d failed with %#X!\n", VencChn, s32Ret);
break;
}
/*******************************************************
step 2.2 :suggest to check both u32CurPacks and u32LeftStreamFrames at the same time,for example:
if(0 == stStat.u32CurPacks || 0 == stStat.u32LeftStreamFrames)
{
SAMPLE_PRT("NOTE: Current frame is NULL!\n");
continue;
}
*******************************************************/
if(0 == stStat.u32CurPacks)
{
debug("NOTE: Current frame is NULL!\n");
continue;
}
/*******************************************************
step 2.3 : malloc corresponding number of pack nodes.
分配buffer准备读取Pack
*******************************************************/
//申请获取当前要传输-<包>-的空间大小....
//获取VENC_STREAM_S stStream---帧码流类型结构体
stStream.pstPack = (VENC_PACK_S*)malloc(sizeof(VENC_PACK_S) * stStat.u32CurPacks);
if (NULL == stStream.pstPack)
{
debug("malloc stream pack failed!\n");
break;
}
/*******************************************************
step 2.4 : call mpi to get one-frame stream
读取编码好的数据
*******************************************************/
stStream.u32PackCount = stStat.u32CurPacks;
//获取编码的码流。
s32Ret = HI_MPI_VENC_GetStream(VencChn, &stStream, -1); //原来 -1 是 HI_TRUE
if (HI_SUCCESS != s32Ret)
{
free(stStream.pstPack);
stStream.pstPack = NULL;
debug("HI_MPI_VENC_GetStream failed with %#X!\n", s32Ret);
break;
}
//debug("HI_MPI_VENC_GetStream ok %s %s %d\n",__FILE__,__func__,__LINE__);
/*******************************************************
step 2.5 : rtsp....
推流....
*******************************************************/
Sent_H264_Stream_RTP(&stStream,VencChn);
//debug("Sent_H264_Stream_RTP is ok %s %s %d\n",__FILE__,__func__,__LINE__);
/*******************************************************
step 2.6 : release stream
释放buffer给编码通道
*******************************************************/
s32Ret = HI_MPI_VENC_ReleaseStream(VencChn, &stStream);
if(0 != s32Ret)
{
debug("vb_Munmap error.. %#X ,%s %s %d\n",s32Ret,__FILE__,__func__,__LINE__);
free(stStream.pstPack);
stStream.pstPack = NULL;
break;
}
/*******************************************************
step 2.7 : free pack nodes
*******************************************************/
free(stStream.pstPack);
stStream.pstPack = NULL;
}
//解除映射 <缓存块> 的 <虚拟地址> 和 <物理地址>..
s32Ret =HI_MPI_SYS_Munmap(pVirYaddr, srcFrame.stVFrame.u32Stride[0] * srcFrame.stVFrame.u32Height * 3 / 2);
if(0 != s32Ret) debug("vb_Munmap error.. %#X ,%s %s %d\n",s32Ret,__FILE__,__func__,__LINE__);
/* 释放掉获取的 <缓存块> 物理地址和虚拟地址 */
s32Ret = HI_MPI_VB_ReleaseBlock(handleY);
if(0 != s32Ret) debug("ReleaseBlock error.. %#X,%s %s %d\n",s32Ret,__FILE__,__func__,__LINE__);
handleY = VB_INVALID_HANDLE;
/* 清除已经处理完的<VPSS_CHN>得到的frame> */
HI_MPI_VPSS_ReleaseChnFrame(Grp, Chn, &srcFrame);
srcFrame.u32PoolId = VB_INVALID_POOLID;
}
/* 清除已经处理完的<VPSS_CHN>得到的frame> */
HI_MPI_VPSS_ReleaseChnFrame(Grp, Chn, &srcFrame);
srcFrame.u32PoolId = VB_INVALID_POOLID;
}
VPSS_Restore(Grp, Chn);
//销毁 缓存池
// s32Ret = HI_MPI_VB_DestroyPool(hPool);
// if(0 != s32Ret) debug("vb_pool error.. %#X ,%s %s %d\n",s32Ret,__FILE__,__func__,__LINE__);
return HI_SUCCESS;
}
本来想把海思各个平台代码传到csdn资源,没想到竟然传不上去,需要的找我w=linlin591440293