海思3559上适配UVC摄像头(三) 数据送入VPSS

一、海思 VPSS介绍:

视频处理子系统 VPSS(Video Processing Sub System)实现视频处理功能。

由于UVC摄像头驱动是运行在Linux上的,抓取到的数据也是在Linux 端,而海思3559平台的对VPSS,VENC(编码器)的操作API都是在LiteOS端,因此需要把数据送往LiteOS之后,再通过API把数据送入VPSS。

二、DATAFIFO

Huawei LiteOS 和Linux两个系统之间采用DATAFIFO +IPC通信的方式进行通信。
这里通过DATAFIFO将数据传入到LiteOS中去
以下 是海思文档中的关于DATAFIFO的介绍:
DATAFIFO

整体设计如下:
海思3559上适配UVC摄像头(三) 数据送入VPSS_第1张图片

三 LiteOS DATAFIFO

3.1、LiteOS DATAFIFO 初始化

HI_U32 UsbCamera_DataFifo_Create(HI_VOID)
{
	HI_S32 s32Ret = 0;
    HI_DATAFIFO_Params_S params = {2, BLOCK_LEN, HI_TRUE, READER};
	s32Ret= HI_DATAFIFO_Open(&hDataFifo, &params);
    if (s32Ret == HI_FAILURE)
    {
        fprintf(stderr, "open fail\n");
		return s32Ret;
    }
	
	HI_DATAFIFO_Ioctl(hDataFifo, GET_DATAFIFO_PHY_ADDR, &DATAFIFO_phyAddr);

	return HI_SUCCESS;
}

3.2 LiteOS DATAFIFO 读取函数:

void* UsbCamera_DataFifo_read_more(void *arg)
{
    HI_U32 readLen = 0;
    HI_CHAR *pBuf = NULL;
    HI_CHAR *VPSSBuf = NULL;
	
	VPSSBuf = (HI_CHAR *)malloc(BLOCK_LEN);
	
    prctl(PR_SET_NAME, (unsigned long) "Hi_pTReadMore1", 0, 0, 0);
    while(HI_TRUE == s_DataFifoStart)
    {
        readLen = 0;
        HI_DATAFIFO_Ioctl(hDataFifo, GET_AVAIL_READ_LEN, &readLen);
        if (readLen > 0)
        {
            if (HI_SUCCESS == HI_DATAFIFO_Read(hDataFifo, (HI_VOID**)&pBuf))
            {				
            	memcpy(VPSSBuf,pBuf,BLOCK_LEN);
				
                HI_DATAFIFO_Ioctl(hDataFifo, NOTIFY_READ_DONE, pBuf);
				UsbCamera_VPSS_SendFrame(VPSSBuf);
            }
			usleep(30*1000);
            continue;
        }
    }
    return NULL;
}

四 Linux DATAFIFO

Linux DATAFIFO 初始化
Linux端 DATAFIO的物理地址 通过IPC通信 从LiteOS端获取

void  HI_PDT_DataFifo_Init(HI_U32 phyAddr)
{
    HI_DATAFIFO_Params_S params = {2, BLOCK_LEN, HI_TRUE, WRITER};
    if (HI_FAILURE == HI_DATAFIFO_OpenByAddr(&hDataFifo, &params, phyAddr))
    {
        printf("HI_DATAFIFO_OpenByAddr fail ! \n");
    }
		
    printf("HI_PDT_DataFifo_Init finish \n");
	
	return;
}

Linux DATAFIFO 写入函数

static int HI_PDT_DataFifo_send_frame(void *addr, int length)
{
    HI_U32 availWriteLen = 0;
	
    // call write NULL to flush
    HI_DATAFIFO_Write(hDataFifo, NULL);
    HI_DATAFIFO_Ioctl(hDataFifo, GET_AVAIL_WRITE_LEN, &availWriteLen);
    if (availWriteLen >= BLOCK_LEN)
    {
        HI_DATAFIFO_Write(hDataFifo, addr);
        HI_DATAFIFO_Ioctl(hDataFifo, NOTIFY_WRITE_DONE, NULL); 
    } else
    {
        printf("no free space: %d\n", availWriteLen);
		usleep(30*1000);
    }

    return HI_SUCCESS;
}

五、YUV422(YUYV) 转 YUV422SP

static HI_U32 UsbCamera_Frame_YUYVtoYUV422SP(HI_CHAR *YUV422buff,HI_S32 buf_index)
{
	HI_U8 *phy_buffer = NULL;
	HI_U32 u32BlkSize = USBCAMERA_WIDTH*USBCAMERA_HEIGHT*2;
	HI_U32 i =0;
	HI_U32 j =0;
	HI_U8 *phy_buffer_UV = NULL;

	phy_buffer = (HI_U8 *)UVC_VB_u32Addr[buf_index];       
	phy_buffer_UV = phy_buffer +USBCAMERA_WIDTH*USBCAMERA_HEIGHT;


	for(i=0;i<u32BlkSize;i+=4)
	{
		*(phy_buffer+j) = *(YUV422buff+i);
		*(phy_buffer_UV+j) = *(YUV422buff+i+3);

		j++;
		*(phy_buffer+j) = *(YUV422buff+i+2);
		*(phy_buffer_UV+j) = *(YUV422buff+i+1); 
		j++;
	}
	return 0;
}

六、VPSS 帧发送

6.1 初始化VPSS 帧参数

 // 初始化VPSS 帧参数
static HI_U32 UsbCamera_VPSS_Frame_Init()
{
	int  i=0;
	HI_U32 u32LumaSize;
	HI_U32 u32ChrmSize;
	HI_U32 u32LStride;
	HI_U32 u32CStride;
	
	u32LStride = USBCAMERA_WIDTH;
	u32CStride = USBCAMERA_WIDTH;
	u32LumaSize = (USBCAMERA_WIDTH * USBCAMERA_HEIGHT);
	u32ChrmSize = u32LumaSize;	/* 422*/
	
	for(i=0;i<UVC_BUFFER_NUM;i++)
	{
		stVideoFrame[i].u32PoolId = UVC_VbPool;
		
		stVideoFrame[i].stVFrame.u32Width = USBCAMERA_WIDTH;
		stVideoFrame[i].stVFrame.u32Height = USBCAMERA_HEIGHT;
		
		stVideoFrame[i].stVFrame.u32Field = VIDEO_FIELD_FRAME;
		stVideoFrame[i].stVFrame.enPixelFormat = PIXEL_FORMAT_YUV_SEMIPLANAR_422;
		
		stVideoFrame[i].stVFrame.enVideoFormat = VIDEO_FORMAT_LINEAR;
		stVideoFrame[i].stVFrame.enCompressMode = COMPRESS_MODE_NONE;

		
		stVideoFrame[i].stVFrame.s16OffsetTop = 0;
		stVideoFrame[i].stVFrame.s16OffsetBottom = 0;
		stVideoFrame[i].stVFrame.s16OffsetLeft = 0;
		stVideoFrame[i].stVFrame.s16OffsetRight = 0; 
		
		stVideoFrame[i].stVFrame.u32Stride[0] = u32LStride;
		stVideoFrame[i].stVFrame.u32Stride[1] = u32CStride;
		stVideoFrame[i].stVFrame.u32Stride[2] = u32CStride;
		stVideoFrame[i].stVFrame.u32PhyAddr[0] = UVC_VB_u32Addr[i];
		stVideoFrame[i].stVFrame.u32PhyAddr[1] = stVideoFrame[i].stVFrame.u32PhyAddr[0] + u32LumaSize;
		stVideoFrame[i].stVFrame.u32PhyAddr[2] = stVideoFrame[i].stVFrame.u32PhyAddr[1] + u32ChrmSize;
		stVideoFrame[i].stVFrame.u32PrivateData = 0;
	}

	return 0;
}

6.2 发送函数

// 发送一帧数据到VPSS 
static HI_U32 UsbCamera_VPSS_SendFrame(HI_CHAR *Vpssbuffer)
{
	HI_U64 u64pts;
	VPSS_GRP VpssGrp = VPROC_HANDLE;
	HI_S32 s32MilliSec = 100;
	HI_S32 s32Ret = 0;
	struct timespec tp;
	g_u32TimeRef +=2;
	
	if(g_buf_index >= UVC_BUFFER_NUM)
		g_buf_index = 0;
	
	clock_gettime(CLOCK_REALTIME, &tp);
	
	u64pts = (HI_U64)((tp.tv_sec-time_start)*1000000 + tp.tv_nsec/1000);

	stVideoFrame[g_buf_index].stVFrame.u64pts = u64pts;
	stVideoFrame[g_buf_index].stVFrame.u32TimeRef = g_u32TimeRef;
 
	UsbCamera_Frame_YUYVtoYUV422SP(Vpssbuffer,g_buf_index);
 
	s32Ret =  HI_MPI_VPSS_SendFrame(VpssGrp, &stVideoFrame[g_buf_index],  s32MilliSec);
	if(s32Ret != HI_SUCCESS)
	{
		printf("HI_MPI_VPSS_SendFrame failed s32Ret: %#x \n",s32Ret);
	}	
	g_buf_index++;
	return HI_SUCCESS;
}

你可能感兴趣的:(海思平台(hisi))