视频处理子系统 VPSS(Video Processing Sub System)实现视频处理功能。
由于UVC摄像头驱动是运行在Linux上的,抓取到的数据也是在Linux 端,而海思3559平台的对VPSS,VENC(编码器)的操作API都是在LiteOS端,因此需要把数据送往LiteOS之后,再通过API把数据送入VPSS。
Huawei LiteOS 和Linux两个系统之间采用DATAFIFO +IPC通信的方式进行通信。
这里通过DATAFIFO将数据传入到LiteOS中去
以下 是海思文档中的关于DATAFIFO的介绍:
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, ¶ms);
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端 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, ¶ms, 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;
}
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;
}
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;
}