海思3559上适配UVC摄像头(二) 数据获取

V4L2(Video For Linux Two) 是内核提供给应用程序访问音、视频驱动的统一接口。V4L2 的相关定义包含在头文件 中.
基本参照:
https://blog.csdn.net/li_wen01/article/details/53557949
大部分代码搬过来用了。
在此记录下。

流程如下:

海思3559上适配UVC摄像头(二) 数据获取_第1张图片

IOCTL使用的命令

打开视频设备后,可以设置该视频设备的属性,例如裁剪、缩放等。这一步是可选的。在Linux编程中,一般使用ioctl函数来对设备的I/O通道进行管理:
extern int ioctl (int __fd, unsigned long int __request, …) __THROW;
__fd:设备的ID,例如刚才用open函数打开视频通道后返回的cameraFd;
__request:具体的命令标志符。
在进行V4L2开发中,一般会用到以下的命令标志符:
VIDIOC_REQBUFS:分配内存
VIDIOC_QUERYBUF:把VIDIOC_REQBUFS中分配的数据缓存转换成物理地址
VIDIOC_QUERYCAP:查询驱动功能
VIDIOC_ENUM_FMT:获取当前驱动支持的视频格式
VIDIOC_S_FMT:设置当前驱动的频捕获格式
VIDIOC_G_FMT:读取当前驱动的频捕获格式
VIDIOC_TRY_FMT:验证当前驱动的显示格式
VIDIOC_CROPCAP:查询驱动的修剪能力
VIDIOC_S_CROP:设置视频信号的边框
VIDIOC_G_CROP:读取视频信号的边框
VIDIOC_QBUF:把数据从缓存中读取出来
VIDIOC_DQBUF:把数据放回缓存队列
VIDIOC_STREAMON:开始视频显示函数
VIDIOC_STREAMOFF:结束视频显示函数
VIDIOC_QUERYSTD:检查当前视频设备支持的标准,例如PAL或NTSC。
这些IO调用,有些是必须的,有些是可选择的。

我的摄像头支持的型号:

support device 1.YUV 4:2:2 (YUYV)
support device 2.MJPEG

整理代码如下:

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 


#define VIDEO_NAME				"/dev/video0"
#define TEST_STREAM_SAVE_PATH	"/app/sd"
#define BUFFER_NUM				(4)
#define V4L2_BUF_TYPE  			(V4L2_BUF_TYPE_VIDEO_CAPTURE)
static int g_video_fd;

typedef struct{
    void *start;
	int length;
}BUFTYPE;

 
BUFTYPE *usr_buf;
static unsigned int n_buffer = 0;
 

static int HI_PDT_Camera_Open(void)
{
	struct v4l2_input inp;
 	int i = 0;
	int ret = -1;
	g_video_fd = open(VIDEO_NAME, O_RDWR | O_NONBLOCK,0);
	if(g_video_fd < 0)
	{	
		printf("%s open failed ! \n", VIDEO_NAME);
		return ret;
	};

	for(i=0;i<16;i++)
	{
		inp.index = i;
		if (-1 == ioctl (g_video_fd, VIDIOC_S_INPUT, &inp))
		{
			printf("VIDIOC_S_INPUT  failed %d !\n",i);
		}
		else
		{
			printf("VIDIOC_S_INPUT  success %d !\n",i);
			ret = 0;
			break;
		}
	}
 
	return ret;
}

// close 
void HI_PDT_Camera_Close(int video_fd)
{
	unsigned int i;

	for(i = 0;i < n_buffer; i++)
	{
		if(-1 == munmap(usr_buf[i].start,usr_buf[i].length))
		{
			exit(-1);
		}
	}
	
	if(NULL != usr_buf)
	free(usr_buf);
	
 	if(video_fd >0)
		close(video_fd);
		
	return;
}
 
 
/*set video capture ways(mmap)*/
int HI_PDT_Init_mmap(int fd)
{
	/*to request frame cache, contain requested counts*/
	struct v4l2_requestbuffers reqbufs;
 
	memset(&reqbufs, 0, sizeof(reqbufs));
	reqbufs.count = BUFFER_NUM; 	 							/*the number of buffer*/
	reqbufs.type = V4L2_BUF_TYPE;    
	reqbufs.memory = V4L2_MEMORY_MMAP;				
 
	if(-1 == ioctl(fd,VIDIOC_REQBUFS,&reqbufs))
	{
		perror("Fail to ioctl 'VIDIOC_REQBUFS'");
		return -1;
	}
	
	n_buffer = reqbufs.count;
	printf("n_buffer = %d\n", n_buffer);
	usr_buf = calloc(reqbufs.count, sizeof(BUFTYPE));
	if(usr_buf == NULL)
	{
		printf("Out of memory\n");
		return -1;
	}
 
	/*map kernel cache to user process*/
	for(n_buffer = 0; n_buffer < reqbufs.count; n_buffer++)
	{
		//stand for a frame
		struct v4l2_buffer buf;
		memset(&buf, 0, sizeof(buf));
		buf.type = V4L2_BUF_TYPE;
		buf.memory = V4L2_MEMORY_MMAP;
		buf.index = n_buffer;
		
		/*check the information of the kernel cache requested*/
		if(-1 == ioctl(fd,VIDIOC_QUERYBUF,&buf))
		{
			perror("Fail to ioctl : VIDIOC_QUERYBUF");
			return -1;
		}
 
		usr_buf[n_buffer].length = buf.length;
		usr_buf[n_buffer].start = (char *)mmap(NULL,buf.length,PROT_READ | PROT_WRITE,MAP_SHARED, fd,buf.m.offset);
 
		if(MAP_FAILED == usr_buf[n_buffer].start)
		{
			perror("Fail to mmap");
			return -1;
		}
 
	}
	
	return 0;
 
}

static int HI_PDT_Set_Format(int video_fd)
{
	struct v4l2_format 		tv_fmt; /* frame format */  

 	/*set the form of camera capture data*/
	tv_fmt.type = V4L2_BUF_TYPE;      /*v4l2_buf_typea,camera must use V4L2_BUF_TYPE_VIDEO_CAPTURE*/
	tv_fmt.fmt.pix.width = 640;
	tv_fmt.fmt.pix.height = 480;
	tv_fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
	tv_fmt.fmt.pix.field = V4L2_FIELD_NONE;   		/*V4L2_FIELD_NONE*/
	if (ioctl(video_fd, VIDIOC_S_FMT, &tv_fmt)< 0) 
	{
		fprintf(stderr,"VIDIOC_S_FMT set err\n");
		return -1;
	}
	return 0;

}
static int HI_PDT_Init_Camera(int video_fd)
{
	struct v4l2_capability 	cap;	/* decive fuction, such as video input */
	struct v4l2_fmtdesc 	fmtdesc;  	/* detail control value */

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

 	return 0;
}
 
int HI_PDT_start_capture(int fd)
{
	unsigned int i;
	enum v4l2_buf_type type;
	
	/*place the kernel cache to a queue*/
	for(i = 0; i < n_buffer; i++)
	{
		struct v4l2_buffer buf;
		memset(&buf, 0, sizeof(buf));
		buf.type = V4L2_BUF_TYPE;
		buf.memory = V4L2_MEMORY_MMAP;
		buf.index = i;
 
		if(-1 == ioctl(fd, VIDIOC_QBUF, &buf))
		{
			perror("Fail to ioctl 'VIDIOC_QBUF'");
			exit(EXIT_FAILURE);
		}
	}
 
	type = V4L2_BUF_TYPE;
	if(-1 == ioctl(fd, VIDIOC_STREAMON, &type))
	{
		printf("i=%d.\n", i);
		perror("VIDIOC_STREAMON");
		close(fd);
		exit(EXIT_FAILURE);
	}
 
	return 0;
}
 
 
int HI_PDT_process_image(void *addr, int length)
{
	FILE *fp;
	static int num = 0;
	char image_name[64] = {0};
	
	sprintf(image_name, TEST_STREAM_SAVE_PATH"/%d.yuv", num++);
	if((fp = fopen(image_name, "w")) == NULL)
	{
		perror("Fail to fopen \n");
		exit(EXIT_FAILURE);
	}
	fwrite(addr, length, 1, fp);
	usleep(500);
	fclose(fp);
	
	return 0;
}
 
int HI_PDT_read_frame(int fd)
{
	struct v4l2_buffer buf;

	memset(&buf, 0, sizeof(buf));
	buf.type = V4L2_BUF_TYPE;
	buf.memory = V4L2_MEMORY_MMAP;

	//put cache from queue
	if(-1 == ioctl(fd, VIDIOC_DQBUF,&buf))
	{
		perror("Fail to ioctl 'VIDIOC_DQBUF'");
		return -1;
	}
	if(buf.index >= n_buffer)
		return -1;
 
	//read process space's data to a file
	HI_PDT_process_image(usr_buf[buf.index].start, usr_buf[buf.index].length);
	if(-1 == ioctl(fd, VIDIOC_QBUF,&buf))
	{
		perror("Fail to ioctl 'VIDIOC_QBUF'");
		return -1;
	}
	
	return 0;
}
 
 

 
static int HI_PDT_Stop_Capture(int fd)
{
	enum v4l2_buf_type type;
	type = V4L2_BUF_TYPE;
	if(-1 == ioctl(fd,VIDIOC_STREAMOFF,&type))
	{
		perror("Fail to ioctl 'VIDIOC_STREAMOFF' \n");
		return -1;
	}
	return 0;
}
 


int HI_PDT_mainloop(int fd)
{
	int count = 10;
	while(count-- > 0)
	{
		while(1)
		{
			fd_set fds;
			struct timeval tv;
			int r;
 
			FD_ZERO(&fds);
			FD_SET(fd,&fds);
 
			/*Timeout*/
			tv.tv_sec = 2;
			tv.tv_usec = 0;
			r = select(fd + 1,&fds,NULL,NULL,&tv);
			
			if(-1 == r)
			{
				 if(EINTR == errno)
					continue;
				perror("Fail to select \n");
				return -1;
			}
			if(0 == r)
			{
				fprintf(stderr,"select Timeout \n");
				return -1;
			}
 
			if(HI_PDT_read_frame(fd) == 0)
				break;
		}
	}
	return 0;
}


int HI_PDT_UVC_Init(HI_VOID)
{	
	int s32Ret =0;
	
	// 1 open device
	s32Ret = HI_PDT_Camera_Open();
	if(s32Ret <0)
	{
		printf("HI_PDT_Camera_Open failed ! \n");
		return -1;
	}

	// Check and set device properties  set frame 
	s32Ret = HI_PDT_Init_Camera(g_video_fd);
	if(s32Ret <0)
	{
		printf("HI_PDT_Camera_Open failed ! \n");
		HI_PDT_Camera_Close(g_video_fd);
		return -1;
	}
	
	HI_PDT_Set_Format(g_video_fd);

	// Apply for a video buffer 
	HI_PDT_Init_mmap(g_video_fd);

	// 
	HI_PDT_start_capture(g_video_fd);

	
	HI_PDT_mainloop(g_video_fd);

	
	HI_PDT_Stop_Capture(g_video_fd);
	
	return 0;
}


int HI_PDT_UVC_DeInit(HI_VOID)
{	
	
	HI_PDT_Camera_Close(g_video_fd);
		
	HI_PDT_Stop_Capture(g_video_fd);

	return 0;
}

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