利用3156硬核实现yuv直方图数据提取
. 一 主要思路和步骤:
- 分配物理空间
HI_MPI_SYS_MmzAlloc_Cached
。 - 在一个线程中循环获取帧
(*HI_MPI_VI_GetFrame*)
- 将原始帧物理地址搬运至新开辟的地址(直接最原始帧的物理地址操作会出现问题,直方图提取可能会失败)
HI_MPI_IVE_DMA
。 - 调用ive的API函数实现直方图提取
HI_MPI_IVE_HIST
。 - 由于硬核处理函数都是对物理地址做操作,用户态想获取数据必须将其转换为虚拟地址,即调用
HI_MPI_SYS_Mmap
。
- 分配物理空间
二 实现代码如下
static HI_VOID *SAMPLE_Ive_ViToVenc(HI_VOID *pArgs)
{
HI_S32 s32Ret;
//SAMPLE_IVE_MODEL_INFO_S *pstBgModelInfo;
//SAMPLE_IVE_BG_MODEL_S *pstBgModel;
VI_FRAME_INFO_S stFrameInfo;
VI_FRAME_INFO_S stExtFrameInfo;
VI_CHN viChn = 0;
VI_CHN viIveChn = 2;
HI_BOOL bEncode =HI_TRUE;
IVE_HANDLE IveHandle;
HI_U32 *pImage = NULL;
HI_U8 *pbuf_Y;
IVE_MEM_INFO_S stDst;
HI_VOID *pVirtDst;
HI_VOID *pVirtDst2;
pbuf_Y = (HI_U8*)malloc(442368);
memset(pbuf_Y,1,442368);
pImage = (HI_U8*)malloc(256*4);
memset(pImage,1,256*4);
//创建HI_MPI_IVE_DMA需要的两个地址结构体,分别传值原地址和目的地址
IVE_SRC_INFO_S stSrc2;
IVE_MEM_INFO_S stDst2;
CYF_IVE_MD_S pstMd; //建立一个dma搬运的目的帧结构
HI_BOOL bInstant = HI_TRUE;
HI_U32 phy_addr,size;
if (HI_MPI_VI_SetFrameDepth(viIveChn, 1))
{
printf("HI_MPI_VI_SetFrameDepth err, viIveChn chn %d \n", viIveChn);
return ;
}
usleep(50000);
int sum =0;
//为dma搬运目的结构分配物理内存
s32Ret = HI_MPI_SYS_MmzAlloc_Cached(&pstMd.stSrc.u32PhyAddr[0], &pVirtDst2,NULL, HI_NULL, 442368*3/2); //D1分辨率768*576的yuv422数据
//为直方图提取操作的目的地址分配物理内存
s32Ret = HI_MPI_SYS_MmzAlloc_Cached (&stDst.u32PhyAddr, &pVirtDst,NULL, HI_NULL, 256*4*3); // 用户态分配内存, 直方图256bin的u32数据(单通道)
if(s32Ret==HI_FAILURE)
{
printf("HI_MPI_SYS_MmzAlloc_Cached failed!\n");
return HI_FAILURE;
}
usleep(50000);
while (1)
{
//获取每一帧数据
s32Ret = HI_MPI_VI_GetFrame(viIveChn, &stExtFrameInfo);
if (HI_SUCCESS != s32Ret)
{
printf("HI_MPI_VI_GetFrame fail,viIveChn(%d),Error(%#x)\n",viIveChn,s32Ret);
continue;
}
/*************************** DMA内存搬运**********/
//确定源数据地址和搬运目的地址
//stSrc2.enSrcFmt = IVE_SRC_FMT_SP422; //加入这句出错。
stSrc2.stSrcMem.u32PhyAddr= stExtFrameInfo.stVFrmInfo.stVFrame.u32PhyAddr[0];
stSrc2.stSrcMem.u32Stride = stExtFrameInfo.stVFrmInfo.stVFrame.u32Stride[0];
stSrc2.u32Width = stExtFrameInfo.stVFrmInfo.stVFrame.u32Width;
stSrc2.u32Height = stExtFrameInfo.stVFrmInfo.stVFrame.u32Height;
stDst2.u32PhyAddr = pstMd.stSrc.u32PhyAddr[0];
stDst2.u32Stride =stExtFrameInfo.stVFrmInfo.stVFrame.u32Stride[0];
bInstant = HI_FALSE;
s32Ret = HI_MPI_IVE_DMA(&IveHandle,&stSrc2,&stDst2,bInstant); ///????参数错误失败返回
if (HI_SUCCESS != s32Ret)
{
printf("HI_MPI_IVE_DMA fail,Error(%#x)\n",s32Ret);
return s32Ret;
}
pstMd.stSrc.u32Height = stExtFrameInfo.stVFrmInfo.stVFrame.u32Height;
pstMd.stSrc.u32Width = stExtFrameInfo.stVFrmInfo.stVFrame.u32Width;;
/****************************** HIST2 从内存搬运后的地方做hist*************************/
HI_BOOL bFinish, bBlock;
HI_BOOL bInstant = HI_TRUE;
IVE_SRC_INFO_S Src;
Src.enSrcFmt = IVE_SRC_FMT_SINGLE;
Src.stSrcMem.u32PhyAddr = pstMd.stSrc.u32PhyAddr[0]; //帧数据搬运后的地址
Src.stSrcMem.u32Stride = pstMd.stSrc.u32Width;
Src.u32Width = pstMd.stSrc.u32Width;
Src.u32Height = pstMd.stSrc.u32Height;
stDst.u32Stride = pstMd.stSrc.u32Width; //直方图数据目的地址
s32Ret = HI_MPI_IVE_HIST(&IveHandle, &Src,&stDst, bInstant); //操作后将结果指针指向分配好的地址上
if (HI_SUCCESS != s32Ret)
{
printf("%s: HI_MPI_IVE_HIST failed!\n", __FUNCTION__);
return HI_FAILURE;
}
s32Ret = HI_MPI_IVE_Query(IveHandle, &bFinish, bBlock); //查询是否操作成功
if(s32Ret != HI_SUCCESS)
{
printf("HI_MPI_IVE_Query fail,Error(%#x)\n",s32Ret);
return;
}
pImage = (HI_U32 *)HI_MPI_SYS_Mmap(stDst.u32PhyAddr, 256*4); //物理地址映射给用户虚拟地址
if(pImage ==NULL)
{
printf("%s: HI_MPI_SYS_Mmap failed!\n");
}
HI_U32 pix3 = (HI_U32)(*(pImage+10));
printf("pix his is %u \n",pix3);
HI_MPI_SYS_Munmap(pImage, 256*4);
/****************************** HIST2 从内存搬运后的地方做hist*************************/
s32Ret = HI_MPI_VI_ReleaseFrame(viIveChn, &stExtFrameInfo);
if (HI_SUCCESS != s32Ret)
{
printf("HI_MPI_VI_ReleaseFrame fail,viIveChn(%d),Error(%#x)\n",viIveChn,s32Ret);
}
usleep(1000);
}
return HI_NULL;
}