海思移植opencv直接进行图像处理

前言:

几年前基础海思,当时做了个火焰探测的项目,变使用了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(&region_cond, NULL);
	pthread_mutex_init(&normal_mutex, NULL);
    pthread_mutex_init(&region_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

 

  • 4
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值