Hisilicon UVC commissioning

preface

This paper records the experience of debugging Hisilicon UVC in recent days. The chip and SDK used this time is Hisilicon 3531DV100. The final result is that two USB cameras are connected to two USB (different root hub) of Hisilicon, and HDMI outputs a quarter screen to display the pictures of the two cameras

The referenced articles are as follows:

https://blog.csdn.net/zhenglie110/article/details/89360312
https://blog.csdn.net/zhenglie110/article/details/89360423
https://blog.csdn.net/zhenglie110/article/details/89361644
http://bbs.ebaina.com/thread-37986-1-1.html

But the above articles are not all right, and everyone's needs are different, so I'll explain it again

Kernel modification

Configure menuconfig to add driver

make ARCH=arm CROSS_COMPILE=arm-hisiv500-linux- menuconfig

Device Drivers  --->
	[*] USB support  --->
		<*>   Support for Host-side USB
		[*]     Enable USB persist by default
		<*>     xHCI HCD (USB 3.0) support
		<*>       xHCI support for Hisilicon SoCs
		<*>     EHCI HCD (USB 2.0) support
		[*]       Improved Transaction Translator scheduling
		<*>     Generic EHCI driver for a platform device
		<*>     OHCI HCD (USB 1.1) support
		<*>       OHCI support for PCI-bus USB controllers
		<*>       Generic OHCI driver for a platform device
		<*>     USB Mass Storage support
		<*>   USB Gadget Support  --->
		
	<*> Multimedia support  --->
		[*]   Cameras/video grabbers support
		[*]   Media Controller API
		[*]   V4L2 sub-device userspace API
		[*]   Media USB Adapters  --->
			<*>   USB Video Class (UVC)
			[*]     UVC input events device support
			<*>   GSPCA based webcams  --->
		[*]   Media PCI Adapters  --->
		[*]   V4L platform devices  --->
			<M>   Marvell 88ALP01 (Cafe) CMOS Camera Controller support
			<*>   SoC camera support
			<*>   platform camera support 
		[*]   Autoselect ancillary drivers (tuners, sensors, i2c, frontends)

My current configuration is the above, and the driver is compiled into the kernel. Someone on the Internet has opened device drivers - > PHY subsystem - > Hisilicon inno USB2 PHY support. After my test, opening this option will lead to USB2 The interface of 0 cannot identify the device. The specific reason is unclear

Driven modification

Insert the USB camera into the board and observe the printed information

usb 1-1: USB disconnect, device number 15
usb 1-1: new high-speed USB device number 16 using xhci-hcd
uvcvideo: quirks = 512
uvcvideo: Found UVC 1.00 device USB Camera (0bda:3035)
input: USB Camera as /devices/soc/11000000.xhci/usb1/1-1/1-1:1.0/input/input15

VID and PID have been reported above, so you don't need to go to so much trouble to find VID and PID in windows

Modify the file linux-3.18 y\drivers\media\usb\uvc\uvc_ driver. c

In struct USB_ device_ id uvc_ Add your own USB device information at the end of IDS []. If it is not added, the probe will be called according to the default ID when the device is inserted_ Table to load the driver, that is, the UVC_ Generic USB Video Class at the end of IDS

/*  my test USB Camera */
{ 
    .match_flags	= USB_DEVICE_ID_MATCH_DEVICE| USB_DEVICE_ID_MATCH_INT_INFO,
    .idVendor		= 0x0bda,
    .idProduct		= 0x3035,
    .bInterfaceClass	= USB_CLASS_VIDEO,
    .bInterfaceSubClass	= 1,
    .bInterfaceProtocol	= 0,
    .driver_info		= UVC_QUIRK_RESTRICT_FRAME_RATE},
/* Generic USB Video Class */
{ USB_INTERFACE_INFO(USB_CLASS_VIDEO, 1, 0) },

Pay attention to this driver_ The assignment of info can be used to limit the frame rate, UVC_ QUIRK_ RESTRICT_ FRAME_ The rate value is 512. This setting seems to be related to the bandwidth. Without in-depth understanding, if it is set too small, it will lead to failure to plot. And USB2 The bandwidth limit of 0 is only 480Mbit/s, which is enough for even one camera.

sample_uvc

Directly upload the sample code. Originally, there was no uvc example in the SDK. I implemented this by myself. The code is uploaded to the attachment, including the following files:

  • sample_comm.h
  • sample_comm_sys.c
  • sample_comm_vdec.c
  • sample_comm_vo.c
  • sample_comm_vpss.c
  • sample_uvc.c

Download address: https://download.csdn.net/download/whitefish520/13216318

There is an error that was found after uploading: tv_fmt.fmt.pix.height = uvcParam.u32inputHeight;

Only sample is pasted below_ uvc. C here, because other contents are basically provided in the SDK, and there are basically no changes. sample_uvc.c is the hard work of these days, written from 0. The explanation of some settings in the program will be put in the next chapter. If the program doesn't understand very well, read it first and then interpret it.

/******************************************************************************
  A simple program of Hisilicon Hi35xx video input and output implementation.
  Copyright (C), 2014-2015, Hisilicon Tech. Co., Ltd.
 ******************************************************************************
    Modification:  2015-1 Created
******************************************************************************/

#ifdef __cplusplus
#if __cplusplus
extern "C"{
#endif
#endif /* End of #ifdef __cplusplus */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
#include <signal.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <sys/prctl.h>
#include <sys/ioctl.h>
#include <linux/videodev2.h>

#include "sample_comm.h"
#include "hi_comm_vb.h"
#include "mpi_vb.h"

// usb video camera number
#define     UVC_NUM     2
// save stream as file, do not store at flash
#define     SAVE_FILE   0
// video memory
typedef struct{
    void *start;
	int length;
}uvc_buf_t;

struct hiUvcParam
{
    HI_S32 fd[UVC_NUM];
	HI_CHAR cFileName[UVC_NUM][128];
    HI_CHAR cNodeName[UVC_NUM][128];
    HI_U32 u32inputWidth;
    HI_U32 u32inputHeight;
    HI_U32 u32Width;
    HI_U32 u32Height;
    HI_U32 pixelformat;
    HI_U32 V4L2_buffer_num;
    HI_U32 buffer_num[UVC_NUM];
    uvc_buf_t *uvc_buf[UVC_NUM];
    HI_U32 u32BlkSize;
    HI_U32 u32BlkCnt;
	VB_POOL VbPool;
    VB_BLK VbBlk;
    HI_U32 u32phyAddr;
    HI_U8 *pVirAddr;
    VDEC_CHN VdChn[UVC_NUM];
    VPSS_GRP VpssGrp[UVC_NUM];
    VPSS_CHN VpssChn;
    VO_DEV VoDev;
    VO_CHN VoChn[UVC_NUM];
    VO_LAYER VoLayer;
    SAMPLE_VO_MODE_E enMode;
    HI_BOOL pthRun;
    pthread_t ptuvc;
}uvcParam;

/******************************************************************************
* function : YUV422P(YUYV) To YUV422SP(NV16)
* 		YUYVYUYV  ->  YYYYUVUV          
******************************************************************************/
HI_VOID yuv422p_to_yuv422sp(HI_U8* yuv, HI_S32 width, HI_S32 height)
{
    HI_S32 i, j, k;
    HI_U8 yuv422p[width*height*2];
    memcpy(yuv422p, yuv, width*height*2);
    HI_U8* y = yuv;
    HI_U8* uv = &yuv[width*height];

    for(i=0, j=0, k=0; i<width*height*2; i+=4, j+=2, k+=2)
    {
        y[j] = yuv422p[i];
        y[j+1] = yuv422p[i+2];
        uv[k] = yuv422p[i+3];
        uv[k+1] = yuv422p[i+1];
    }
}

/******************************************************************************
* function : usb video camera parameter set
******************************************************************************/
HI_S32 HI_UVC_Param_Set(HI_VOID)
{
    HI_S32 i, j=0;
    for(i=0; i<UVC_NUM; i++)
    {
        while(j < 64)
        {
            sprintf(uvcParam.cNodeName[i], "/dev/video%d", j++);
            if(0 == access(uvcParam.cNodeName[i], F_OK))
                break;
        }
       
        sprintf(uvcParam.cFileName[i], "/app/uvc/uvcVideo%d.yuv", i);
        uvcParam.fd[i] = -1;
        uvcParam.buffer_num[i] = 0;
        uvcParam.uvc_buf[i] = NULL;
        uvcParam.pVirAddr = NULL;
        uvcParam.VdChn[i] = i;
        uvcParam.VpssGrp[i] = i;
        uvcParam.VpssChn = i;
    }
    uvcParam.u32inputWidth = HD_WIDTH;
    uvcParam.u32inputHeight = HD_HEIGHT;
    uvcParam.u32Width = HD_WIDTH;
    uvcParam.u32Height = HD_HEIGHT;
    //uvcParam.pixelformat = V4L2_PIX_FMT_YUYV;
    uvcParam.pixelformat = V4L2_PIX_FMT_MJPEG;
    uvcParam.V4L2_buffer_num = 10;
    uvcParam.u32BlkSize = uvcParam.u32Width * uvcParam.u32Height * 2;
    uvcParam.u32BlkCnt = 15;
    uvcParam.VpssChn = 0;
    uvcParam.enMode = VO_MODE_4MUX;
    uvcParam.pthRun = HI_TRUE;
    if(j >= 64)
        return HI_FAILURE;
    else
        return HI_SUCCESS;
}

/******************************************************************************
* function : open usb video camera device
******************************************************************************/
HI_S32 HI_UVC_Open(HI_VOID)
{
	struct v4l2_input inp;
 	HI_S32 i, j;
    for(i=0; i<UVC_NUM; i++)
    {
        uvcParam.fd[i] = open(uvcParam.cNodeName[i], O_RDWR, 0);
        if(uvcParam.fd[i] < 0)
        {	
            SAMPLE_PRT("camera[%d] : %s open failed ! \n", i, uvcParam.cNodeName[i]);
            return HI_FAILURE;
        }

        for(j=0;j<16;j++)
        {
            inp.index = j;
            if (-1 == ioctl (uvcParam.fd[i], VIDIOC_S_INPUT, &inp))
            {
                SAMPLE_PRT("camera[%d] : VIDIOC_S_INPUT failed %d !\n", i, j);
            }
            else
            {
                printf("camera[%d] : VIDIOC_S_INPUT success %d !\n", i, j);
                break;
            }
        }
    }
	return HI_SUCCESS;
}

/******************************************************************************
* function : close usb video camera device
******************************************************************************/
HI_S32 HI_UVC_Close(HI_VOID)
{
    HI_S32 i;
    for(i=0; i<UVC_NUM; i++)
    {
        if(uvcParam.fd[i] > 0)
            close(uvcParam.fd[i]);
    }
	return HI_SUCCESS;
}

/******************************************************************************
* function : usb video camera init
******************************************************************************/
HI_S32 HI_UVC_Init(HI_VOID)
{
    HI_S32 i;
	struct v4l2_capability 	cap;	    /* decive fuction, such as video input */
	struct v4l2_fmtdesc 	fmtdesc;  	/* detail control value */
	struct v4l2_format 		fmt; 

	HI_S32 ret = HI_FAILURE;
	
	/* get width and height*/
	fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 

    for(i=0; i<UVC_NUM; i++)
    {
        if(ret = ioctl(uvcParam.fd[i], VIDIOC_G_FMT, &fmt)<0)
        {
            SAMPLE_PRT("camera[%d] : fail to ioctl VIDIOC_G_FMT\n", i);
            return HI_FAILURE;
        }
        printf("camera[%d] : width:%d, height:%d\n", i, fmt.fmt.pix.width,fmt.fmt.pix.height);

        /* check video decive driver capability */
        if(ret=ioctl(uvcParam.fd[i], VIDIOC_QUERYCAP, &cap)<0)
        {
            SAMPLE_PRT("camera[%d] : fail to ioctl VIDEO_QUERYCAP \n", i);
            return HI_FAILURE;
        }
        
        /*judge wherher or not to be a video-get device*/
        if(!(cap.capabilities & V4L2_BUF_TYPE_VIDEO_CAPTURE))
        {
            SAMPLE_PRT("camera[%d] is not a video capture device\n", i);
            return HI_FAILURE;
        }
    
        /*judge whether or not to supply the form of video stream*/
        if(!(cap.capabilities & V4L2_CAP_STREAMING))
        {
            SAMPLE_PRT("camera[%d] does not support streaming i/o\n", i);
            return HI_FAILURE;
        }
        
        printf("camera[%d] driver name is : %s\n", i, cap.driver);
        printf("camera[%d] device name is : %s\n", i, cap.card);
        printf("camera[%d] bus information: %s\n", i, cap.bus_info);
    
        /*display the format device support*/
        /*show all the support format*/
        memset(&fmtdesc, 0, sizeof(fmtdesc));
        fmtdesc.index = 0;                 /* the number to check */
        fmtdesc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
        while(ioctl(uvcParam.fd[i], VIDIOC_ENUM_FMT, &fmtdesc) != -1)
        {	
            printf("camera[%d] : support device %d.%s\n", i, fmtdesc.index+1, fmtdesc.description);
            fmtdesc.index++;
        }
    }
 	return HI_SUCCESS;
}

/******************************************************************************
* function : set usb video camera format
******************************************************************************/
HI_S32 HI_UVC_Set_Format(HI_VOID)
{
    HI_S32 i;
	struct v4l2_format 		tv_fmt; /* frame format */  
 	/*set the form of camera capture data*/
	tv_fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;   /*v4l2_buf_typea,camera must use V4L2_BUF_TYPE_VIDEO_CAPTURE*/
	tv_fmt.fmt.pix.width = uvcParam.u32inputWidth;
	tv_fmt.fmt.pix.height = uvcParam.u32inputHeight;
	tv_fmt.fmt.pix.pixelformat = uvcParam.pixelformat;
	tv_fmt.fmt.pix.field = V4L2_FIELD_NONE;   //Field format

    for(i=0; i<UVC_NUM; i++)
    {
        if (ioctl(uvcParam.fd[i], VIDIOC_S_FMT, &tv_fmt)< 0) 
        {
            SAMPLE_PRT("camera[%d] : VIDIOC_S_FMT set err\n", i);
            return HI_FAILURE;
        }
    }
	return HI_SUCCESS;
}

/******************************************************************************
* function : mmap
******************************************************************************/
HI_S32 HI_UVC_Mmap(HI_VOID)
{
    HI_S32 i;
	/*to request frame cache, contain requested counts*/
	struct v4l2_requestbuffers reqbufs;

    for(i=0; i<UVC_NUM; i++)
    {
        memset(&reqbufs, 0, sizeof(reqbufs));
        reqbufs.count = uvcParam.V4L2_buffer_num; 	/*the number of buffer*/
        reqbufs.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;    
        reqbufs.memory = V4L2_MEMORY_MMAP;

        if(-1 == ioctl(uvcParam.fd[i], VIDIOC_REQBUFS, &reqbufs))
        {
            SAMPLE_PRT("camera[%d] : Fail to ioctl 'VIDIOC_REQBUFS'\n", i);
            return HI_FAILURE;
        }
    
        uvcParam.buffer_num[i] = reqbufs.count;
        printf("camera[%d] : buffer_num = %d\n", i, uvcParam.buffer_num[i]);
        uvcParam.uvc_buf[i] = calloc(reqbufs.count, sizeof(uvc_buf_t));
        if(uvcParam.uvc_buf[i] == NULL)
        {
            SAMPLE_PRT("camera[%d] : Out of memory\n", i);
            return HI_FAILURE;
        }
    
        /*map kernel cache to user process*/
        for(uvcParam.buffer_num[i] = 0; uvcParam.buffer_num[i] < reqbufs.count; uvcParam.buffer_num[i]++)
        {
            //stand for a frame
            struct v4l2_buffer buf;
            memset(&buf, 0, sizeof(buf));
            buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
            buf.memory = V4L2_MEMORY_MMAP;
            buf.index = uvcParam.buffer_num[i];
            
            /*check the information of the kernel cache requested*/
            if(-1 == ioctl(uvcParam.fd[i], VIDIOC_QUERYBUF, &buf))
            {
                SAMPLE_PRT("camera[%d] : Fail to ioctl : VIDIOC_QUERYBUF\n", i);
                return HI_FAILURE;
            }
    
            uvcParam.uvc_buf[i][uvcParam.buffer_num[i]].length = buf.length;
            uvcParam.uvc_buf[i][uvcParam.buffer_num[i]].start = (char *)mmap(NULL, buf.length, PROT_READ | PROT_WRITE,MAP_SHARED, uvcParam.fd[i], buf.m.offset);
    
            if(MAP_FAILED == uvcParam.uvc_buf[i][uvcParam.buffer_num[i]].start)
            {
                SAMPLE_PRT("camera[%d] : Fail to mmap\n", i);
                return HI_FAILURE;
            }
        }
    }
	return HI_SUCCESS;
}

/******************************************************************************
* function : usb video camera unmap
******************************************************************************/
HI_S32 HI_UVC_Unmap(HI_VOID)
{
	HI_U32 i, j;
    for(i=0; i<UVC_NUM; i++)
    {
        for(j = 0; j < uvcParam.buffer_num[i]; j++)
        {
            if(-1 == munmap(uvcParam.uvc_buf[i][j].start, uvcParam.uvc_buf[i][j].length))
            {
                return HI_FAILURE;
            }
        }
        if(NULL != uvcParam.uvc_buf[i])
	        free(uvcParam.uvc_buf[i]);
    }
	return HI_SUCCESS;
}

/******************************************************************************
* function : usb video camera start capture
******************************************************************************/
HI_S32 HI_UVC_Start(HI_VOID)
{
	HI_U32 i, j;
	enum v4l2_buf_type type[UVC_NUM];
	for(i=0; i<UVC_NUM; i++)
    {
        /*place the kernel cache to a queue*/
        for(j = 0; j < uvcParam.buffer_num[i]; j++)
        {
            struct v4l2_buffer buf;
            memset(&buf, 0, sizeof(buf));
            buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
            buf.memory = V4L2_MEMORY_MMAP;
            buf.index = j;
    
            if(-1 == ioctl(uvcParam.fd[i], VIDIOC_QBUF, &buf))
            {
                SAMPLE_PRT("camera[%d] : Fail to ioctl 'VIDIOC_QBUF'\n", i);
                return HI_FAILURE;
            }
        }
    
        type[i] = V4L2_BUF_TYPE_VIDEO_CAPTURE;
        if(-1 == ioctl(uvcParam.fd[i], VIDIOC_STREAMON, &type[i]))
        {
            SAMPLE_PRT("camera[%d] : VIDIOC_STREAMON\n", i);
            return HI_FAILURE;
        }
    }
	return HI_SUCCESS;
}

/******************************************************************************
* function : usb video camera stop capture
******************************************************************************/
HI_S32 HI_UVC_Stop(HI_VOID)
{
    HI_U32 i;
	enum v4l2_buf_type type;
	type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
	for(i=0; i<UVC_NUM; i++)
    {
        if(-1 == ioctl(uvcParam.fd[i], VIDIOC_STREAMOFF, &type))
        {
            SAMPLE_PRT("camera[%d] : Fail to ioctl 'VIDIOC_STREAMOFF'\n", i);
            return HI_FAILURE;
        }  
    }
	return HI_SUCCESS;
}

/******************************************************************************
* function : usb video camera capture mjpeg thread
******************************************************************************/
HI_VOID * HI_UVC_MJPEG_Thread(HI_VOID *pArgs)
{
#if SAVE_FILE
    FILE *fp[UVC_NUM];
#endif
    fd_set fds;
    HI_U8 *pu8Buf[UVC_NUM];
    HI_S32 i, j, start, len, s32Ret, fdmax = 0;
    HI_S32 s32ReadLen = 0;
    HI_U64 u64pts = 0;
    HI_BOOL bFindStart[UVC_NUM], bFindEnd[UVC_NUM];
    struct timeval tv;
    struct v4l2_buffer buf[UVC_NUM];
    VDEC_STREAM_S stStream;
    struct hiUvcParam *p = &uvcParam;

    prctl(PR_SET_NAME, "hi_SendStream2Vdec", 0, 0, 0);
    for(i=0; i<UVC_NUM; i++)
    {
        pu8Buf[i] = malloc(p->u32BlkSize);
        if(pu8Buf[i] == NULL)
        {
            printf("camera[%d] : can't alloc in send stream thread\n", i);
            return (HI_VOID *)(HI_FAILURE);
        }
    }

#if SAVE_FILE
    for(i=0; i<UVC_NUM; i++)
    {
        fp[i] = fopen(p->cFileName[i], "w+");
        if(fp[i] == NULL)
        {
            printf("camera[%d] : can't open file %s\n", i, p->cFileName[i]);
            return (HI_VOID *)(HI_FAILURE);
        }
    }
#endif

    while(p->pthRun)
    {
        FD_ZERO(&fds);
        tv.tv_sec = 1;  /*Timeout*/
        tv.tv_usec = 0;
        

        for(i=0; i<UVC_NUM; i++)
        {
            bFindStart[i] = HI_FALSE;  
            bFindEnd[i]   = HI_FALSE; 
            FD_SET(p->fd[i], &fds);
            fdmax = p->fd[i] > fdmax ? p->fd[i] : fdmax;
        }

        s32Ret = select(fdmax + 1, &fds, NULL, NULL, &tv);
        if(-1 == s32Ret)
        {
            if(EINTR == errno)
            {
                perror("select");
                continue;    
            } 
            SAMPLE_PRT("Fail to select\n");
            break;
        }
        if(0 == s32Ret)
        {
            SAMPLE_PRT("select Timeout\n");
            continue;
        }
        
        //put cache from queue
        for(i=0; i<UVC_NUM; i++)
        {
            memset(&buf[i], 0, sizeof(struct v4l2_buffer));
            buf[i].type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
            buf[i].memory = V4L2_MEMORY_MMAP;

            if(-1 == ioctl(p->fd[i], VIDIOC_DQBUF, &buf[i]))
            {
                //SAMPLE_PRT("camera[%d] : Fail to ioctl 'VIDIOC_DQBUF' \n", i);
                //There is no need to print, because mjpeg is not as big as yuv. There will be many prints here, but there is no problem with the display
                perror("VIDIOC_DQBUF");
                continue;
            }
            if(buf[i].index >= p->buffer_num[i])
            {
                SAMPLE_PRT("camera[%d] : index error \n", i);
                continue;
            }

            memcpy(pu8Buf[i], p->uvc_buf[i][buf[i].index].start, p->uvc_buf[i][buf[i].index].length);
            s32ReadLen = p->uvc_buf[i][buf[i].index].length;
#if SAVE_FILE
            fwrite(pu8Buf[i], s32ReadLen, 1, fp[i]);
#endif
            for (j=0; j<s32ReadLen-2; j++)
            {
                if (pu8Buf[i][j] == 0xFF && pu8Buf[i][j+1] == 0xD8) 
                {
                    start = j;
                    bFindStart[i] = HI_TRUE;
                    j = j + 2;
                    break;
                }  
            }

            for (; j<s32ReadLen-4; j++)
            {
                if ( (pu8Buf[i][j] == 0xFF) && (pu8Buf[i][j+1]& 0xF0) == 0xD0 )
                {
                    len = (pu8Buf[i][j+2]<<8) + pu8Buf[i][j+3];                    
                    j += 1 + len;                  
                }
                else
                {
                    break;
                }
            }

            for (; j<s32ReadLen-2; j++)
            {
                if (pu8Buf[i][j] == 0xFF && pu8Buf[i][j+1] == 0xD9)
                {
                    bFindEnd[i] = HI_TRUE;
                    break;
                } 
            }      
            s32ReadLen = j;
            if (bFindStart[i] == HI_FALSE)
            {
                printf("camera[%d] : can not find start code! s32ReadLen %d\n", i, s32ReadLen);
            }
            else if (bFindEnd[i] == HI_FALSE)
            {
                printf("camera[%d] : can not find stop code! s32ReadLen %d\n", i, s32ReadLen);
                s32ReadLen = j+2;
            }

            stStream.u64PTS  = u64pts;
            stStream.pu8Addr = pu8Buf[i] + start;
            stStream.u32Len  = s32ReadLen - start; 
            stStream.bEndOfFrame  = HI_FALSE;
            stStream.bEndOfStream = HI_FALSE;                   
            
            s32Ret=HI_MPI_VDEC_SendStream(p->VdChn[i], &stStream, 100);
            if (HI_SUCCESS != s32Ret)
            {
                SAMPLE_PRT("camera[%d] : vdec send frame fail for %#x!\n", i, s32Ret);
            }
            
            if(-1 == ioctl(p->fd[i], VIDIOC_QBUF,&buf[i]))
            {
                SAMPLE_PRT("camera[%d] : Fail to ioctl 'VIDIOC_QBUF'\n", i);
            }
        }   
    }
    printf("uvc thread exit \n");
#if SAVE_FILE
    for(i=0; i<UVC_NUM; i++)
    {
        fclose(fp[i]);
    }
#endif
	return NULL;
}

/******************************************************************************
* function : usb video camera capture yuv422 thread
******************************************************************************/
HI_VOID * HI_UVC_YUV_Thread(HI_VOID *pArgs)
{
    fd_set fds;
    HI_S32 s32Ret, fdmax = 0, i;
    SIZE_S stSize;
    HI_U32 u32LStride;
	HI_U32 u32CStride;
	HI_U32 u32LumaSize;
	HI_U32 u32ChrmSize;
    VIDEO_FRAME_INFO_S stVideoFrame;
    struct timeval tv;
    struct v4l2_buffer buf;
    struct hiUvcParam *p = (struct hiUvcParam *)&uvcParam;

    prctl(PR_SET_NAME, "hi_SendStream2Vpss", 0, 0, 0);
    p->pVirAddr = HI_MPI_SYS_Mmap(p->u32phyAddr, p->u32BlkSize);
    stSize.u32Width = p->u32inputWidth;  
    stSize.u32Height = p->u32inputHeight; 
    u32LStride = stSize.u32Width;
    u32CStride = stSize.u32Width;
	u32LumaSize = (stSize.u32Width * stSize.u32Height);
	u32ChrmSize = u32LumaSize >> 2;
    memset(&stVideoFrame.stVFrame, 0, sizeof(VIDEO_FRAME_S));
    stVideoFrame.u32PoolId = HI_MPI_VB_Handle2PoolId(p->VbBlk);
    stVideoFrame.stVFrame.u32Width = stSize.u32Width;
	stVideoFrame.stVFrame.u32Height = stSize.u32Height;
    stVideoFrame.stVFrame.u32Field = VIDEO_FIELD_FRAME;
    stVideoFrame.stVFrame.enPixelFormat = SAMPLE_PIXEL_FORMAT;
    stVideoFrame.stVFrame.u32Stride[0] = u32LStride;
	stVideoFrame.stVFrame.u32Stride[1] = u32CStride;
	stVideoFrame.stVFrame.u32Stride[2] = u32CStride;
	stVideoFrame.stVFrame.u32PhyAddr[0] = p->u32phyAddr;
	stVideoFrame.stVFrame.u32PhyAddr[1] = stVideoFrame.stVFrame.u32PhyAddr[0] + u32LumaSize;
	stVideoFrame.stVFrame.u32PhyAddr[2] = stVideoFrame.stVFrame.u32PhyAddr[1] + u32ChrmSize;
	stVideoFrame.stVFrame.pVirAddr[0] = p->pVirAddr;
	stVideoFrame.stVFrame.pVirAddr[1] = stVideoFrame.stVFrame.pVirAddr[0] + u32LumaSize;
	stVideoFrame.stVFrame.pVirAddr[2] = stVideoFrame.stVFrame.pVirAddr[1] + u32ChrmSize;
    
    while(p->pthRun)
    {
        FD_ZERO(&fds);
        for(i=0; i<UVC_NUM; i++)
        {
            FD_SET(p->fd[i], &fds);
            fdmax = p->fd[i] > fdmax ? p->fd[i] : fdmax;
        }
        tv.tv_sec = 1;  /*Timeout*/
        tv.tv_usec = 0;
        s32Ret = select(fdmax + 1, &fds, NULL, NULL, &tv);
        
        if(-1 == s32Ret)
        {
            if(EINTR == errno)
            {
                perror("select");
                continue;
            }  
            SAMPLE_PRT("Fail to select \n");
            break;
        }
        if(0 == s32Ret)
        {
            SAMPLE_PRT("select Timeout \n");
            continue;
        }
        
        for(i=0; i<UVC_NUM; i++)
        {
            if(FD_ISSET(p->fd[i], &fds))
            {
                 memset(&buf, 0, sizeof(buf));
                buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
                buf.memory = V4L2_MEMORY_MMAP;

                //put cache from queue
                if(-1 == ioctl(p->fd[i], VIDIOC_DQBUF, &buf))
                {
                    SAMPLE_PRT("Fail to ioctl 'VIDIOC_DQBUF'\n");
                    continue;
                }
                if(buf.index >= p->buffer_num[i])
                {
                    SAMPLE_PRT("index error \n");
                    continue;
                }
                memcpy(p->pVirAddr, p->uvc_buf[i][buf.index].start, p->uvc_buf[i][buf.index].length);
                yuv422p_to_yuv422sp(p->pVirAddr, stSize.u32Width, stSize.u32Height);
                s32Ret =HI_MPI_VPSS_SendFrame(p->VpssGrp[i], &stVideoFrame, 100);
                if(s32Ret != HI_SUCCESS)
                {               
                    SAMPLE_PRT("vpss  send frame fail for %#x!\n", s32Ret);
                }

                if(-1 == ioctl(p->fd[i], VIDIOC_QBUF,&buf))
                {
                    SAMPLE_PRT("Fail to ioctl 'VIDIOC_QBUF'\n");
                }  
            }    
        }
    }
    printf("uvc thread exit \n");
	return NULL;
}

/******************************************************************************
* function : usb(1080p) -> VPSS -> VO HD1(1080p60)         
******************************************************************************/
HI_S32 SAMPLE_UVC(HI_VOID)
{
    HI_CHAR ch;
	HI_S32 s32Ret, i;
    SIZE_S stSize;
    VB_CONF_S stVbConf, stModVbConf;
    VDEC_CHN_ATTR_S stVdecChnAttr[UVC_NUM];
    VPSS_GRP_ATTR_S stVpssGrpAttr;
    VO_PUB_ATTR_S stVoPubAttr;
    VO_VIDEO_LAYER_ATTR_S stVoLayerAttr;
    
    // step0 : init uvc
    s32Ret = HI_UVC_Param_Set();
    if(s32Ret < 0)
        goto UVC_EXIT;

    s32Ret = HI_UVC_Open();
    if(s32Ret < 0)
        goto UVC_EXIT;

    s32Ret = HI_UVC_Init();
    if(s32Ret < 0)
        goto UVC_CLOSE;

    s32Ret = HI_UVC_Set_Format();
    if(s32Ret < 0)
        goto UVC_CLOSE;

    s32Ret = HI_UVC_Mmap();
    if(s32Ret < 0)
        goto UVC_CLOSE;

    s32Ret = HI_UVC_Start();
    if(s32Ret < 0)
        goto UVC_UNMAP;

    stSize.u32Width = uvcParam.u32Width;
    stSize.u32Height = uvcParam.u32Height;
  
    // step1 : init SYS and common VB
    memset(&stVbConf, 0, sizeof(VB_CONF_S));
    memset(&stVbConf.astCommPool[0].acMmzName, 0, sizeof(stVbConf.astCommPool[0].acMmzName));
    stVbConf.u32MaxPoolCnt = 128;	
    stVbConf.astCommPool[0].u32BlkSize = uvcParam.u32BlkSize;
    stVbConf.astCommPool[0].u32BlkCnt = uvcParam.u32BlkCnt;
    s32Ret = SAMPLE_COMM_SYS_Init(&stVbConf);
    if(s32Ret != HI_SUCCESS)
    {
        SAMPLE_PRT("init sys fail for %#x!\n", s32Ret);
        goto HI_SYS_EXIT;
    }

    // step2:  init mod common VB for mjpeg
    if(uvcParam.pixelformat == V4L2_PIX_FMT_MJPEG)
    {
        SAMPLE_COMM_VDEC_ModCommPoolConf(&stModVbConf, PT_MJPEG, &stSize, UVC_NUM, HI_FALSE);
        s32Ret = SAMPLE_COMM_VDEC_InitModCommVb(&stModVbConf);
        if(s32Ret != HI_SUCCESS)
        {
            SAMPLE_PRT("init mod common vb fail for %#x!\n", s32Ret);
            goto HI_SYS_EXIT;
        }
    }
    
    // step3 : create pool for stream for yuv
    if(uvcParam.pixelformat == V4L2_PIX_FMT_YUYV)
    {
        uvcParam.VbPool = HI_MPI_VB_CreatePool(uvcParam.u32BlkSize, uvcParam.u32BlkCnt, NULL);
        if ( VB_INVALID_POOLID == uvcParam.VbPool ) 
        {
            SAMPLE_PRT("create vb err\n");
            goto HI_SYS_EXIT;
        }
        uvcParam.VbBlk = HI_MPI_VB_GetBlock(uvcParam.VbPool, uvcParam.u32BlkSize, NULL);
        if (VB_INVALID_HANDLE == uvcParam.VbBlk ) 
        {
            SAMPLE_PRT("get vb block err\n");
            goto HI_POOL;
        }
        uvcParam.u32phyAddr = HI_MPI_VB_Handle2PhysAddr(uvcParam.VbBlk);
        if (HI_NULL == uvcParam.u32phyAddr)
        {
            SAMPLE_PRT("blk to physaddr err\n");
            goto HI_BLOCK;
        }
    }

    // step4:  start VDEC
    if(uvcParam.pixelformat == V4L2_PIX_FMT_MJPEG)
    {
        SAMPLE_COMM_VDEC_ChnAttr(UVC_NUM, stVdecChnAttr, PT_MJPEG, &stSize);
        s32Ret = SAMPLE_COMM_VDEC_Start(UVC_NUM, stVdecChnAttr);
        if(s32Ret != HI_SUCCESS)
        {
            SAMPLE_PRT("start VDEC fail for %#x!\n", s32Ret);
            goto HI_VDEC;
        }
    }

    // step5 : start VPSS
    stVpssGrpAttr.enDieMode = VPSS_DIE_MODE_NODIE;  //Don't interlace
    stVpssGrpAttr.bIeEn     = HI_TRUE;             //image enhancement 
    stVpssGrpAttr.bDciEn    = HI_TRUE;             //Dynamic contrast adjustment
    stVpssGrpAttr.bNrEn     = HI_TRUE;             //noise reduction
    stVpssGrpAttr.bHistEn   = HI_FALSE;             //Must be 0
    stVpssGrpAttr.bEsEn	    = HI_FALSE;             //Edge smoothing must be preserved for 0
    stVpssGrpAttr.enPixFmt  = SAMPLE_PIXEL_FORMAT;
    stVpssGrpAttr.u32MaxW   = ALIGN_UP(stSize.u32Width,  16);
    stVpssGrpAttr.u32MaxH   = ALIGN_UP(stSize.u32Height, 16);
    // N-channel video corresponds to n VPSs groups. How many outputs can each vpss group have, corresponding to multiple VPSs channels
    // There is only one HDMI output in this sample, so there is only one vpss channel
    s32Ret = SAMPLE_COMM_VPSS_Start(UVC_NUM, &stSize, 1, &stVpssGrpAttr);
    if(s32Ret != HI_SUCCESS)
    {
        SAMPLE_PRT("start VPSS fail for %#x!\n", s32Ret);
        goto HI_VPSS;
    }

    // step6 : start vo
    uvcParam.VoDev = SAMPLE_VO_DEV_DHD1;
 	uvcParam.VoLayer = SAMPLE_VO_LAYER_VHD1;
    stVoPubAttr.enIntfSync = VO_OUTPUT_1080P60;
    stVoPubAttr.enIntfType = VO_INTF_HDMI;
    stVoPubAttr.u32BgColor = 0x0000ffff;
    s32Ret = SAMPLE_COMM_VO_StartDev(uvcParam.VoDev, &stVoPubAttr);
    if(s32Ret != HI_SUCCESS)
    {
        SAMPLE_PRT("vdec bind vpss fail for %#x!\n", s32Ret);
        goto HI_VO_DEV; 
    }
    if (HI_SUCCESS != SAMPLE_COMM_VO_HdmiStart(stVoPubAttr.enIntfSync))
    {
        SAMPLE_PRT("Start SAMPLE_COMM_VO_HdmiStart failed!\n");
        goto HI_VO_HDMI; 
    }
    s32Ret = SAMPLE_COMM_VO_GetWH(stVoPubAttr.enIntfSync, \
        &stVoLayerAttr.stDispRect.u32Width, &stVoLayerAttr.stDispRect.u32Height, &stVoLayerAttr.u32DispFrmRt);
    if (s32Ret != HI_SUCCESS)
    {
        SAMPLE_PRT("failed with %#x!\n", s32Ret);
        goto HI_VO_HDMI; 
    }
    stVoLayerAttr.stImageSize.u32Width = stVoLayerAttr.stDispRect.u32Width;
    stVoLayerAttr.stImageSize.u32Height = stVoLayerAttr.stDispRect.u32Height;
    stVoLayerAttr.bClusterMode = HI_FALSE;
    stVoLayerAttr.bDoubleFrame = HI_FALSE;
    stVoLayerAttr.enPixFormat = SAMPLE_PIXEL_FORMAT;
    s32Ret = SAMPLE_COMM_VO_StartLayer(uvcParam.VoLayer, &stVoLayerAttr);
    if(s32Ret != HI_SUCCESS)
    {
        SAMPLE_PRT("vdec bind vpss fail for %#x!\n", s32Ret);
        goto HI_VO_LAYER; 
    }

    s32Ret = SAMPLE_COMM_VO_StartChn(uvcParam.VoLayer, uvcParam.enMode);
    if(s32Ret != HI_SUCCESS)
    {
        SAMPLE_PRT("vdec bind vpss fail for %#x!\n", s32Ret);
        goto HI_VO_CHN; 
    }

    // step7:  VDEC bind VPSS
    if(uvcParam.pixelformat == V4L2_PIX_FMT_MJPEG)
    {
        for(i=0; i<UVC_NUM; i++)
        {
            s32Ret = SAMPLE_COMM_VDEC_BindVpss(i, i);
            if(s32Ret != HI_SUCCESS)
            {
                SAMPLE_PRT("vdec bind vpss fail for %#x!\n", s32Ret);
                goto HI_VDEC_UNBIND_VPSS;
            }
        }
        
    }

    // step8 : VPSS bind VO
    for(i=0; i<UVC_NUM; i++)
    {
        s32Ret = SAMPLE_COMM_VO_BindVpss(uvcParam.VoLayer, i, i, VPSS_CHN0);
        if(s32Ret != HI_SUCCESS)
        {
            SAMPLE_PRT("vpss bind vo fail for %#x!\n", s32Ret);
            goto HI_VO_UNBIND_VPSS; 
        }
    }

    // step9 : thread send data
    if(uvcParam.pixelformat == V4L2_PIX_FMT_MJPEG)
    {
        pthread_create(&uvcParam.ptuvc, 0, HI_UVC_MJPEG_Thread, NULL);
    }
    else if(uvcParam.pixelformat == V4L2_PIX_FMT_YUYV)
    {
        pthread_create(&uvcParam.ptuvc, 0, HI_UVC_YUV_Thread, NULL);
    }
    else
    {
        SAMPLE_PRT("wrong video format!\n");
    }
    

    while(1)
	{
		SAMPLE_PRT("input 'q' to exit sample\n");
		ch = getchar();
        if (10 == ch)
            continue;
		getchar();
		if ('q' == ch)
			break;
		else
		{
			SAMPLE_PRT("input 'q' to quit sample\n");
			continue;
		}
	}
    uvcParam.pthRun = HI_FALSE;
    pthread_join(uvcParam.ptuvc, NULL);

HI_VO_UNBIND_VPSS:
    for(i=0; i<UVC_NUM; i++)
    {
        SAMPLE_COMM_VO_UnBindVpss(uvcParam.VoLayer, i, i, VPSS_CHN0);
    }
HI_VDEC_UNBIND_VPSS:
    if(uvcParam.pixelformat == V4L2_PIX_FMT_MJPEG)
    {
        for(i=0; i<UVC_NUM; i++)
        {
            SAMPLE_COMM_VDEC_UnBindVpss(i, i);
        }
    }
HI_VO_CHN:
    SAMPLE_COMM_VO_StopChn(uvcParam.VoLayer, uvcParam.enMode);
HI_VO_LAYER:
    SAMPLE_COMM_VO_StopLayer(uvcParam.VoLayer);
HI_VO_HDMI:
    SAMPLE_COMM_VO_HdmiStop();
HI_VO_DEV:
    SAMPLE_COMM_VO_StopDev(uvcParam.VoDev);  
HI_VPSS:
    SAMPLE_COMM_VPSS_Stop(UVC_NUM, 1);
HI_VDEC:
    if(uvcParam.pixelformat == V4L2_PIX_FMT_MJPEG)
    {
        SAMPLE_COMM_VDEC_Stop(UVC_NUM);
    }
HI_BLOCK:
    if(uvcParam.pixelformat == V4L2_PIX_FMT_YUYV)
    {
        HI_MPI_VB_ReleaseBlock(uvcParam.VbBlk);
    }
HI_POOL:
    if(uvcParam.pixelformat == V4L2_PIX_FMT_YUYV)
    {
        HI_MPI_VB_DestroyPool(uvcParam.VbPool);
    }
HI_SYS_EXIT:
    SAMPLE_COMM_SYS_Exit();
    HI_UVC_Stop();
UVC_UNMAP:
    HI_UVC_Unmap();
UVC_CLOSE:
    HI_UVC_Close();
UVC_EXIT:
	return s32Ret;
}

/******************************************************************************
* function : to process abnormal case
******************************************************************************/
void SAMPLE_UVC_HandleSig(HI_S32 signo)
{
    HI_U32 i;
    if (SIGINT == signo || SIGTERM == signo)
    {   
        for(i=0; i<UVC_NUM; i++)
        {
            SAMPLE_COMM_VO_UnBindVpss(uvcParam.VoLayer, i, i, VPSS_CHN0);
        }
        if(uvcParam.pixelformat == V4L2_PIX_FMT_MJPEG)
        {
            for(i=0; i<UVC_NUM; i++)
            {
                SAMPLE_COMM_VDEC_UnBindVpss(i, i);
            }
        }
        SAMPLE_COMM_VO_StopChn(uvcParam.VoLayer, uvcParam.enMode);
        SAMPLE_COMM_VO_StopLayer(uvcParam.VoLayer);
        SAMPLE_COMM_VO_HdmiStop();
        SAMPLE_COMM_VO_StopDev(uvcParam.VoDev);  
        SAMPLE_COMM_VPSS_Stop(UVC_NUM, 1);
        if(uvcParam.pixelformat == V4L2_PIX_FMT_MJPEG)
        {
            SAMPLE_COMM_VDEC_Stop(UVC_NUM);
        }
        if(uvcParam.pixelformat == V4L2_PIX_FMT_YUYV)
        {
            HI_MPI_VB_ReleaseBlock(uvcParam.VbBlk);
        }
        if(uvcParam.pixelformat == V4L2_PIX_FMT_YUYV)
        {
            HI_MPI_VB_DestroyPool(uvcParam.VbPool);
        }
        SAMPLE_COMM_SYS_Exit();
        HI_UVC_Stop();
        HI_UVC_Unmap();
        HI_UVC_Close();
        SAMPLE_PRT("\033[0;31mprogram termination abnormally!\033[0;39m\n");
    }
    exit(-1);
}

/******************************************************************************
* function    : main()
******************************************************************************/
int main(int argc, char *argv[])
{
    HI_S32 s32Ret = HI_FAILURE;
    signal(SIGINT, SAMPLE_UVC_HandleSig);
    signal(SIGTERM, SAMPLE_UVC_HandleSig);
	s32Ret = SAMPLE_UVC();
			
    if (HI_SUCCESS == s32Ret)
        SAMPLE_PRT("program exit normally!\n");
    else
        SAMPLE_PRT("program exit abnormally!\n");
    exit(s32Ret);
}

#ifdef __cplusplus
#if __cplusplus
}
#endif
#endif /* End of #ifdef __cplusplus */

Program interpretation

These two macros, UVC_NUM specifies the number of USB cameras. When opening the corresponding device node in the thread, you must be able to find two / dev/video *, otherwise the program will end abnormally

SAVE_ If the file is 1, the video file will be saved locally. This is only for testing, because the file is saved greatly. First, it is easy to fill FLASH, and second, the VO output will get stuck

#define     UVC_NUM     2
#define     SAVE_FILE   0

Parameter structure

  • fd is the file pointer after / dev/video * is opened
  • cFileName is the macro save_ Save path when file takes effect
  • cNodeName is the file name of the device node. / dev/video*
  • u32inputWidth/u32inputHeight is used to set the resolution of USB camera and calculate the parameters of vpss when inputting in yuv422p format
  • u32Width/u32Height is used to specify HDMI output parameters and to calculate and allocate MPP memory space
  • pixelformat is used to specify the video format of USB camera. Generally, it only supports YUV422 and MJPEG
  • V4L2_buffer_num is used to specify the number of v4l2 caches
  • buffer_num is the same as above, indicating the number of caches actually allocated
  • uvc_buf points to the cache space allocated by V4L2
  • u32BlkSize/u32BlkCnt is used to assign VB
  • Parameters of data in mpp memory when VbPool/VbBlk/u32phyAddr/pVirAddr is used in YUV422 format
  • VdChn/VpssGrp/VpssChn/VoDev/VoChn/VoLayer, in MJEPG format, VDEC needs to be used. N channels of VDEC are required. Each channel of video corresponds to a VPSS group, so there are n VPSS groups. The number of VPSS channels corresponds to the number of VPSS channels. There is only one HMDI output here. Therefore, the number of VPSS channels is 1, the number of VoDev is 1, and the number of VoLayer is 1. There are N channels of video that need to be output, so VoChn is n
  • enMode specifies the number of split screen output. The program will determine the value of VoChn according to this parameter and open the corresponding vo channel
  • If pthRun is false, the thread used to send data stops running and the program exits
  • ptuvc is used to identify the thread sending data
struct hiUvcParam
{
    HI_S32 fd[UVC_NUM];
	HI_CHAR cFileName[UVC_NUM][128];
    HI_CHAR cNodeName[UVC_NUM][128];
    HI_U32 u32inputWidth;
    HI_U32 u32inputHeight;
    HI_U32 u32Width;
    HI_U32 u32Height;
    HI_U32 pixelformat;
    HI_U32 V4L2_buffer_num;
    HI_U32 buffer_num[UVC_NUM];
    uvc_buf_t *uvc_buf[UVC_NUM];
    HI_U32 u32BlkSize;
    HI_U32 u32BlkCnt;
	VB_POOL VbPool;
    VB_BLK VbBlk;
    HI_U32 u32phyAddr;
    HI_U8 *pVirAddr;
    VDEC_CHN VdChn[UVC_NUM];
    VPSS_GRP VpssGrp[UVC_NUM];
    VPSS_CHN VpssChn;
    VO_DEV VoDev;
    VO_CHN VoChn[UVC_NUM];
    VO_LAYER VoLayer;
    SAMPLE_VO_MODE_E enMode;
    HI_BOOL pthRun;
    pthread_t ptuvc;
}uvcParam;

The following is the initialization of V4L2 uvc. The code found on the Internet has been changed for my use. There is nothing to explain. It is basically ioctl. It should be noted that,

  • VIDIOC_STREAMON may report an error. In general, it uses a hub to connect two UVCS on a usb, resulting in insufficient bandwidth (Resource temporarily unavailable). There are many online solutions. If you are interested, you can try, but it may not work
  • When opening the device node, it is not recommended to open it in a non blocking way, because when reading data in MJEPG format, the underlying data may not be ready every time, so an error will be returned, and there will be a lot of error printing on the serial port. The suggestion is to open the blocking mode and use select to listen to all fd
s32Ret = HI_UVC_Param_Set();	//Complete parameter initialization
s32Ret = HI_UVC_Open();			//Open device node
s32Ret = HI_UVC_Init();			//Initialize UVC and obtain the parameters supported by UVC
s32Ret = HI_UVC_Set_Format();	//Set UVC video format and resolution
s32Ret = HI_UVC_Mmap();			//Map memory space
s32Ret = HI_UVC_Start();		//Start video streaming

The subsequent initialization parts are quite common. There's nothing to say. Let's talk about the thread part

The YUV thread part involves a conversion from yuv422p to yuv422sp, because the YUV output sequence of the camera is YUYVYUYV, which is yuv422 in the form of packet, while the VPSs can only receive yuv422 (YYYYUVUV) or yuv420 (yyyyyuv) from semiplannar. Therefore, it is necessary to transcode the data and then call hi_ MPI_ VPSS_ Send frame to VPSs, otherwise the position and color on the picture are wrong, but it can definitely distinguish the picture

mjepg thread part involves the detection of key position data such as frame header and frame tail. Each frame should meet the requirements of jpeg. However, the key data given by the uvc camera does not necessarily conform to the standard jpeg format. This part of knowledge can be read This article For supplementary courses, it is mentioned that the file header is FF D8 FF E0, but what I actually collected here is FF D8 FF DB, so I need to deal with it flexibly

Finally, it is recommended to use MJPEG format, because in YUV format, 1080P only supports 5 frames, which is very card, while MJPEG format does not have this problem.

Tags: UVC

Posted by cyberdesi on Thu, 05 May 2022 00:18:16 +0300