Linux下V4L2使用流程

Linux下V4L2使用流程

测试平台:vm15 ubuntu20.04
测试摄像头:小米笔记本电脑自带摄像头、优迈Q5 摄像头

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

#define V4L2_PATH "/dev/video0"
#define REQBUFFER_COUNT 4
#define PIX_WIDTH 640
#define PIX_HEIGHT 480

//用户保存数据区域
typedef struct 
{
	unsigned char *start;
	int lenth;
}UserBuffer;

/**********************************
 * VIDIOC_ENUM_FMT:
 * VIDIOC_QUERYCAP:
 * VIDIOC_S_FMT:
 * VIDIOC_G_FMT:
 * VIDIOC_REQBUFS:
 * VIDIOC_QUERYBUF:
 * VIDIOC_QBUF:
 * *******************************/

//打开设备文件
int v4l2_open(const char *pathname);
//关闭文件
int v4l2_close(const int fd);
//获取摄像头信息
int get_v4l2_info(const int fd);
//获取摄像头支持格式
int get_supported_format(const int fd);
//设置摄像头采集格式
int set_v4l2_format(const int fd);
//获取摄像头采集格式
int get_v4l2_format(const int fd);
//映射内核空间
int Mapping_kernel_space(const int fd, UserBuffer *buf);
//开始摄像头采集
int Start_cllection(const int fd);
//开始数据采集
int Data_collection(const int fd, int *Datalenth, int *index);
//停止摄像头采集
int Stop_cllection(const int fd);
//保存为jpg
int Save_data_to_JPG(const char *path, unsigned char *Data, int Datalenth);
//释放内核映射空间
int Free_kernel_mapping_space(UserBuffer *buf);
//保存至YUYV
int Save_data_to_YUYV(const char *path, unsigned char *Data, int Datalenth);


int main(int argc, char *argv[])
{
	UserBuffer Buf[4];

	int v4l2_fd = v4l2_open(V4L2_PATH);
	if(v4l2_fd == -1)return -1;

	get_v4l2_info(v4l2_fd);

	get_supported_format(v4l2_fd);

	set_v4l2_format(v4l2_fd);

	get_v4l2_format(v4l2_fd);

	Mapping_kernel_space(v4l2_fd, Buf);

	Start_cllection(v4l2_fd);

	int count = 0;
	while(1)
	{
		count ++;
		if(count > 30*10)break;
		usleep(1000000/30);

		int length = 0;
		int index = 0;

		Data_collection(v4l2_fd, &length, &index);

		Save_data_to_YUYV("test.yuv", Buf[index].start, Buf[index].lenth);

	}

	Stop_cllection(v4l2_fd);

	Free_kernel_mapping_space(Buf);

	v4l2_close(v4l2_fd);

	return 0;
}



//打开设备文件
int v4l2_open(const char *pathname)
{
	int v4l2_fd = open(pathname, O_RDWR);
	if(v4l2_fd < 0)
	{
		perror("Open v4l2");
		return -1;
	}
	return v4l2_fd;
}

//关闭文件
int v4l2_close(const int fd)
{
	int ret = close(fd);
	if(ret == -1)
	{
		perror("Close c4l2");
		return -1;
	}
	return 0;
}

//获取摄像头信息
int get_v4l2_info(const int fd)
{
	struct v4l2_capability cap;
	memset(&cap, 0, sizeof(cap));
	if(ioctl(fd, VIDIOC_QUERYCAP, &cap) == -1)
	{
		perror("get_v4l2_info");
		return -1;
	}
	puts("\n--------------------");
	printf("v4l2 info:\n");
	printf("Driver Name:%s\n", cap.driver);
	printf("Card Name:%s\n", cap.card);
	printf("Bus_info:%s\n", cap.bus_info);
	printf("Version:%u.%u.%u\n", (cap.version >> 16) & 0XFF, (cap.version >> 8) & 0XFF, cap.version & 0XFF);
	return 0;
}

//获取摄像头支持格式
int get_supported_format(const int fd)
{
	struct v4l2_fmtdesc fmt;
	memset(&fmt, 0, sizeof(fmt));
	fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
	int i = 0;
	puts("\n--------------------");
	printf("v4l2 supported format:\n");
	while(1)
	{
		fmt.index = i++;
		if(ioctl(fd, VIDIOC_ENUM_FMT, &fmt) == -1)
		{
			return 0;
		}
		printf("Description[%d]:%s\n", i, fmt.description);
		unsigned char *p = (unsigned char *)&fmt.pixelformat;
		printf("Pixelformat[%d]:%c%c%c%c\n", i, p[0], p[1],  p[2], p[3]);
	}
	return 0;
}

//设置摄像头采集格式
int set_v4l2_format(const int fd)
{
	struct v4l2_format vfmt;
	memset(&vfmt, 0, sizeof(vfmt));
	vfmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;//摄像头采集
	vfmt.fmt.pix.width = PIX_WIDTH;//设置宽
	vfmt.fmt.pix.height = PIX_HEIGHT;//设置高
	vfmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;//设置视频采集格式
	if(ioctl(fd, VIDIOC_S_FMT, &vfmt) == -1)
	{
		perror("set v4l2 format error");
		return -1;
	}
	return 0;
}

//获取摄像头采集格式
int get_v4l2_format(const int fd)
{
	struct v4l2_format vfmt;
	memset(&vfmt, 0, sizeof(vfmt));
	vfmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;//摄像头采集
	if(ioctl(fd, VIDIOC_G_FMT, &vfmt) == -1)
	{
		perror("get v4l2 format error");
		return -1;
	}
	puts("\n--------------------");
	printf("v4l2 format:\n");
	printf("Pix:%d*%d\n", vfmt.fmt.pix.width, vfmt.fmt.pix.height);
	unsigned char *p = (unsigned char *)&vfmt.fmt.pix.pixelformat;
	printf("Pixelformat:%c%c%c%c\n", p[0], p[1],  p[2], p[3]);
	return 0;
}

//映射内核空间
int Mapping_kernel_space(const int fd, UserBuffer *buf)
{
	//申请内核空间
	struct v4l2_requestbuffers reqbuffer;
	memset(&reqbuffer, 0, sizeof(reqbuffer));
	reqbuffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
	reqbuffer.count = REQBUFFER_COUNT;//申请缓冲区
	reqbuffer.memory = V4L2_MEMORY_MMAP;//映射方式
	printf("fd = %d\n", fd);
	if(ioctl(fd, VIDIOC_REQBUFS, &reqbuffer) == -1)
	{
		perror("Queue application failed");
		return -1;
	}

	//映射
	struct v4l2_buffer mapbuffer;
	mapbuffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
	int i = 0;
	for(i=0; i<4; i++)
	{
		mapbuffer.index = i;
		if(ioctl(fd, VIDIOC_QUERYBUF, &mapbuffer) == -1)
		{
			perror("Failed to query the kernel space queue. Procedure");
			return -1;
		}
		buf[i].start = (unsigned char*)mmap(NULL, mapbuffer.length, PROT_READ|PROT_WRITE, MAP_SHARED, fd, mapbuffer.m.offset);
		buf[i].lenth = mapbuffer.length;
		if(ioctl(fd, VIDIOC_QBUF, &mapbuffer) == -1)
		{
			perror("v4l2 vidioc_qbuf");
			return -1;
		}
	}
	puts("\n--------------------");
	printf("v4l2 mmap successed !!!\n");
	return 0;
}

//开始摄像头采集
int Start_cllection(const int fd)
{
	//开启采集
	enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
	if(ioctl(fd, VIDIOC_STREAMON, &type) == -1)
	{
		perror("Start Error");
		return -1;
	}
	puts("\n--------------------");
	printf("Start cllection successed !!!\n");
	return 0;
}

//数据采集
int Data_collection(const int fd, int *Datalenth, int *index)
{
	//从队列中提取一帧数据
	struct v4l2_buffer readbuffer;
	memset(&readbuffer, 0, sizeof(readbuffer));
	readbuffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
	readbuffer.memory = V4L2_MEMORY_MMAP;
	if(ioctl(fd, VIDIOC_DQBUF, &readbuffer) == -1)
	{
		perror("Collecthion Error");
		return -1;
	}


	*Datalenth = readbuffer.bytesused;
	*index = readbuffer.index;


	//通知内核使用完毕
	if(ioctl(fd, VIDIOC_QBUF, &readbuffer) == -1)
	{
		perror("VIDIOC_QBUF ERROR");
		return -1;
	}

	return 0;
}

//停止摄像头采集
int Stop_cllection(const int fd)
{
	enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
	if(ioctl(fd, VIDIOC_STREAMOFF, &type) == -1)
	{
		perror("Stop cllection");
		return -1;
	}
	puts("\n--------------------");
	printf("Stop cllection successed !!!\n");
	return 0;
}

//保存图片
int Save_data_to_JPG(const char *path, unsigned char *Data, int Datalenth)
{
	int fd = open(path, O_RDWR|O_CREAT, 0664);
	if(fd < 0)
	{
		perror("Open save path error");
		return -1;
	}
	if(write(fd, Data, Datalenth)<0)
	{

		perror("Save ERROR");
		return -1;
	}
	puts("\n--------------------");
	printf("Save successed !!!\n");
	return 0;
}

//释放内核映射空间
int Free_kernel_mapping_space(UserBuffer *buf)
{
	int i = 0;
	for(i=0; i<4; i++)
	{
		if(munmap(buf[i].start, buf[i].lenth) == -1)
		{
			perror("Free kernel");
			return -1;
		}
		buf[i].start = NULL;
	}
	puts("\n--------------------");
	printf("Free kernel successed !!!\n");

}

//保存至YUYV
int Save_data_to_YUYV(const char *path, unsigned char *Data, int Datalenth)
{
	int fd = open(path, O_RDWR|O_CREAT|O_APPEND, 0666);
	if(fd < 0)
	{
		perror("Open YUYV error");
		return -1;
	}
	if(write(fd, Data, Datalenth) < 0)
	{
		perror("Save YUYV ERROR");
		return -1;
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Reil.kun

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值