v4l2摄像头驱动

环境:

硬件:radxa rock开发板,蓝色妖姬T998无驱摄像头

系统:lubuntu 3月15号固件,v4l2


其实我只是把草根老师的博客代码改了些参数:

1.摄像头的模式由O_RDWR | O_NONBLOCK改为O_RDWR,若不改,会报DQ_BUF的bug

2.视频的参数改为YUYV422

3.n_buffer中途会莫名其妙改变,所以在程序中人为赋值


程序运行后,会保存count个bin文件在选定目录下。文件内容是YUYV422的图像数据。


参考文档:

1.http://blog.chinaunix.net/uid-26833883-id-3249346.html 

2.http://wenku.baidu.com/view/2f92ce8c680203d8ce2f247f.html


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

typedef struct
{
	void *start;
	int length;
}BUFTYPE;
BUFTYPE user_buf_real;
BUFTYPE *user_buf=&user_buf_real;
int n_buffer = 0;

//鎵撳紑鎽勫儚澶磋澶?int open_camer_device()
{
	int fd;

	//if((fd = open("/dev/video0",O_RDWR | O_NONBLOCK)) < 0)
	if((fd = open("/dev/video0",O_RDWR)) < 0)
	{
		perror("Fail to open");
		exit(EXIT_FAILURE);
	} 

	printf("open camer %d \n",fd);

	return fd;
}

int init_mmap(int fd)
{
        printf("init_mmap \n");
	int i = 0;
	struct v4l2_requestbuffers reqbuf;

	bzero(&reqbuf,sizeof(reqbuf));
	reqbuf.count = 1;  //changed
	reqbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
	reqbuf.memory = V4L2_MEMORY_MMAP;
	
	//鐢宠瑙嗛缂撳啿鍖?杩欎釜缂撳啿鍖轰綅浜庡唴鏍哥┖闂达紝闇€瑕侀€氳繃mmap鏄犲皠)
	//杩欎竴姝ユ搷浣滃彲鑳戒細淇敼reqbuf.count鐨勫€硷紝淇敼涓哄疄闄呮垚鍔熺敵璇风紦鍐插尯涓暟
	if(-1 == ioctl(fd,VIDIOC_REQBUFS,&reqbuf))
	{
		perror("Fail to ioctl 'VIDIOC_REQBUFS'");
		exit(EXIT_FAILURE);
	}
	
	n_buffer = reqbuf.count; //mark reatch here
	
	printf("n_buffer = %d\n",n_buffer);

	//test_yz = calloc(reqbuf.count,sizeof(BUFTYPE));

	//test
       	//user_buf->start =(void*)calloc(reqbuf.count,sizeof(*user_buf)); //mark-err
	
        user_buf->start = calloc(reqbuf.count,sizeof(*user_buf));
       	//user_buf = (BUFTYPE*)(calloc(reqbuf.count,sizeof(*user_buf))); //mark-err
	//	printf("start \n");
	printf("start %d \n",user_buf->start);
	//

	if(user_buf == NULL){
		fprintf(stderr,"Out of memory\n");
		exit(EXIT_FAILURE);
	}

	//灏嗗唴鏍哥紦鍐插尯鏄犲皠鍒扮敤鎴疯繘绋嬬┖闂?	for(i = 0; i < reqbuf.count; i ++)
	{
		struct v4l2_buffer buf;
		
		bzero(&buf,sizeof(buf));
		buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
		buf.memory = V4L2_MEMORY_MMAP;
		buf.index = i;
		
	       	printf("index %d \n",i);
		//鏌ヨ鐢宠鍒板唴鏍哥紦鍐插尯鐨勪俊鎭?		if(-1 == ioctl(fd,VIDIOC_QUERYBUF,&buf))
		{
		  
			perror("Fail to ioctl : VIDIOC_QUERYBUF");
			exit(EXIT_FAILURE);
		}

		user_buf[i].length = buf.length;
		user_buf[i].start = 
			mmap(
					NULL,/*start anywhere*/
					buf.length,
					PROT_READ | PROT_WRITE,
					MAP_SHARED,
					fd,buf.m.offset
				);

test
			printf("user_buf: %d \t start addr:%d \n",i,user_buf->start);
	


		if(MAP_FAILED == user_buf[i].start)
		{
			perror("Fail to mmap");
			exit(EXIT_FAILURE);
		}
	}	

	return 0;
}

//鍒濆鍖栬棰戣澶?int init_camer_device(int fd)
{
 	printf("init_camer_device \n");
	struct v4l2_fmtdesc fmt;
	struct v4l2_capability cap;
	struct v4l2_format stream_fmt;
	int ret;
	
	//褰撳墠瑙嗛璁惧鏀寔鐨勮棰戞牸寮?	memset(&fmt,0,sizeof(fmt));
	fmt.index = 0;
	fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;

	while((ret = ioctl(fd,VIDIOC_ENUM_FMT,&fmt)) == 0)
	{
		fmt.index ++ ;

		printf("{pixelformat = %c%c%c%c},description = '%s'\n",
				fmt.pixelformat & 0xff,(fmt.pixelformat >> 8)&0xff,
				(fmt.pixelformat >> 16) & 0xff,(fmt.pixelformat >> 24)&0xff,
				fmt.description);
	}

	//鏌ヨ瑙嗛璁惧椹卞姩鐨勫姛鑳?	ret = ioctl(fd,VIDIOC_QUERYCAP,&cap);
	if(ret < 0){
		perror("FAIL to ioctl VIDIOC_QUERYCAP");
		exit(EXIT_FAILURE);
	}
	printf("catability : \n");
	printf("driver = %s \n",cap.driver);
	printf("card = %s \n",cap.card);
	

	//鍒ゆ柇鏄惁鏄竴涓棰戞崟鎹夎澶?	if(!(cap.capabilities & V4L2_BUF_TYPE_VIDEO_CAPTURE))
	{
		printf("The Current device is not a video capture device\n");
		exit(EXIT_FAILURE);
	
	}

	//鍒ゆ柇鏄惁鏀寔瑙嗛娴佸舰寮?	if(!(cap.capabilities & V4L2_CAP_STREAMING))
	{
		printf("The Current device does not support streaming i/o\n");
		exit(EXIT_FAILURE);
	}

	//璁剧疆鎽勫儚澶撮噰闆嗘暟鎹牸寮忥紝濡傝缃噰闆嗘暟鎹殑
	//闀?瀹斤紝鍥惧儚鏍煎紡(JPEG,YUYV,MJPEG绛夋牸寮?
	stream_fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
	stream_fmt.fmt.pix.width = 640;
	stream_fmt.fmt.pix.height = 480;
	stream_fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
	stream_fmt.fmt.pix.field = V4L2_FIELD_INTERLACED;
	
	if(-1 == ioctl(fd,VIDIOC_S_FMT,&stream_fmt))
	{
		perror("Fail to ioctl");
		exit(EXIT_FAILURE);
	}
	
	
	//鍒濆鍖栬棰戦噰闆嗘柟寮?mmap)
	init_mmap(fd);

	return 0;
}

int start_capturing(int fd)
{
        printf("start_capturing \n");
	unsigned int i;
	enum v4l2_buf_type type;
	//test
	printf("n_buffer = %d \n",n_buffer);
	//n_buffer = 1;
	//

	//灏嗙敵璇风殑鍐呮牳缂撳啿鍖烘斁鍏ヤ竴涓槦鍒椾腑
	for(i = 0;i < n_buffer;i ++)
	{
		struct v4l2_buffer buf;
		
		printf("index %d \n",i);
		bzero(&buf,sizeof(buf));
		buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
		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_VIDEO_CAPTURE;
	if(-1 == ioctl(fd,VIDIOC_STREAMON,&type))
	{
		printf("i = %d.\n",i);
		perror("Fail to ioctl 'VIDIOC_STREAMON'");
		exit(EXIT_FAILURE);
	}

	return 0;
}


//灏嗛噰闆嗗ソ鐨勬暟鎹斁鍒版枃浠朵腑
int process_image(void *addr,int length)
{
	printf("process_image \n");
	FILE *fp;
	static int num = 0;
	char picture_name[20];
	char temp;	

	sprintf(picture_name,"picture%d.bin",num ++);
	
	if((fp = fopen(picture_name,"w")) == NULL)
	{
		perror("Fail to fopen");
		exit(EXIT_FAILURE);
	}

	fwrite(addr,length,1,fp);
	usleep(500);

	fclose(fp);

	return 0;
}

int read_frame(int fd)
{
        printf("read_frame \n");
	struct v4l2_buffer buf;
	unsigned int i;

	//memset(&buf,0,sizeof(struct v4l2_buffer));
      	bzero(&buf,sizeof(buf));
       	buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
	buf.memory = V4L2_MEMORY_MMAP;
	printf("haha \n");
	//浠庨槦鍒椾腑鍙栫紦鍐插尯
	if(-1 == ioctl(fd,VIDIOC_DQBUF,&buf))
	{
		perror("Fail to ioctl 'VIDIOC_DQBUF'");
		exit(EXIT_FAILURE);
	}

	assert(buf.index < n_buffer);
	//璇诲彇杩涚▼绌洪棿鐨勬暟鎹埌涓€涓枃浠朵腑
	printf("buf.index: %d \n",buf.index);
	process_image(user_buf[buf.index].start,user_buf[buf.index].length);
	//process_image(user_buf->start,user_buf->length);	

	if(-1 == ioctl(fd,VIDIOC_QBUF,&buf))
	{
		perror("Fail to ioctl 'VIDIOC_QBUF'");
		exit(EXIT_FAILURE);
	}

	return 1;
}

int mainloop(int fd)
{ 
	int count = 20;

	while(count -- > 0)
	{
		for(;;)
		{
			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");
				exit(EXIT_FAILURE);
			}

			if(0 == r)
			{
				fprintf(stderr,"select Timeout\n");
				exit(EXIT_FAILURE);
			}

			if(read_frame(fd))
			  break;
		}
	}

	return 0;
}

void stop_capturing(int fd)
{
        printf("stop capturing \n");
	enum v4l2_buf_type type;
	
	type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
	if(-1 == ioctl(fd,VIDIOC_STREAMOFF,&type))
	{
		perror("Fail to ioctl 'VIDIOC_STREAMOFF'");
		exit(EXIT_FAILURE);
	}
	
	return;
}

void uninit_camer_device()
{
	unsigned int i;
	printf("uninit_camer_device \n");
	printf("n_buffer %d \n",n_buffer);
	for(i = 0;i < n_buffer;i ++)
	{
		if(-1 == munmap(user_buf[i].start,user_buf[i].length))
		{
			printf("munmap err: \n");
			exit(EXIT_FAILURE);
		}
	}
	
	//free(user_buf);
	printf("start addr: %d \n",user_buf->start);
	free(user_buf->start);

	return;
}

void close_camer_device(int fd)
{
	printf("close_camer_device \n");
	if(-1 == close(fd))
	{
		perror("Fail to close fd");
		exit(EXIT_FAILURE);
	}

	return;
}

int main()
{
	int fd;       
                         
	fd = open_camer_device();
	

       	init_camer_device(fd);
	
      	start_capturing(fd);
	
	mainloop(fd);
	
	stop_capturing(fd);
	
	uninit_camer_device();
	

	close_camer_device(fd);

	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值