7.camera驱动07-写一个v4l2应用程序

该代码示例展示了如何在Linux环境下,通过V4L2(Video for Linux Two)API打开设备文件/dev/video0,查询设备功能,枚举并设置像素格式,申请和映射内存缓冲区,开始视频捕获,接收并处理原始RGB565数据,最终将数据写入文件test.data中。整个过程涵盖了视频捕获的基础流程。
摘要由CSDN通过智能技术生成

直接贴代码:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <malloc.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/mman.h>
#include <sys/ioctl.h>
#include <poll.h>

#include <linux/videodev2.h>

struct map_info {
	int			index;
    void		*addr;
    int			length;
    int			offset;
};

#define DEV_NAME "/dev/video0"
#define NUM_BUFS 4

static struct map_info minfo[NUM_BUFS];

int main(void) {
	int fd,i,ret;
	
	fd = open(DEV_NAME, O_RDWR | O_NONBLOCK, 0);
	if (fd < 0) {
		printf("open falied\n");
		return -1;
	}
	printf("open %s fd = %d\n", DEV_NAME, fd);
	
	//1.查询设备功能
	struct v4l2_capability cap;
	if (ioctl(fd, VIDIOC_QUERYCAP, &cap) < 0){
		printf("VIDIOC_QUERYCAP failed\n");
		return -1;
	}
	if(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE)
		printf("dev support capture\n");
	
	//2.枚举支持的像素格式
	struct v4l2_fmtdesc fmtdesc;
	fmtdesc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
	fmtdesc.index = 0;
	while (!ioctl(fd, VIDIOC_ENUM_FMT, &fmtdesc))
	{
		printf("fmt:%s\n", fmtdesc.description);
		fmtdesc.index++;
	}
	
	//3.设置像素格式
	struct v4l2_format v4l2_fmt;
	memset(&v4l2_fmt, 0, sizeof(struct v4l2_format));
	v4l2_fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 
	v4l2_fmt.fmt.pix.width = 240; 					//宽度
	v4l2_fmt.fmt.pix.height = 240; 					//高度
	v4l2_fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_RGB565; //像素格式
	v4l2_fmt.fmt.pix.field = V4L2_FIELD_ANY;

	if (ioctl(fd, VIDIOC_S_FMT, &v4l2_fmt) < 0)
	{
		printf("VIDIOC_S_FMT failed\n");
		return -1;
	}

	//4.申请缓存
	struct v4l2_requestbuffers req;
    req.count = NUM_BUFS;
    req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    req.memory = V4L2_MEMORY_MMAP;
    if (ioctl(fd, VIDIOC_REQBUFS, &req) < 0)
    {
        printf("VIDIOC_REQBUFS failed\n");
		return -1;
    }

	//5.查询缓存信息
	struct v4l2_buffer v4l2_buf;
	for(i=0;i<NUM_BUFS;i++) {
		memset(&v4l2_buf, 0, sizeof(struct v4l2_buffer));
		v4l2_buf.index = i; //想要查询的缓存
		v4l2_buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
		v4l2_buf.memory = V4L2_MEMORY_MMAP;
		
		ret = ioctl(fd, VIDIOC_QUERYBUF, &v4l2_buf);
		if(ret < 0)
		{
			printf("Unable to query buffer.\n");
			return -1;
		}
		
		//6.映射
		void *addr;
		addr = mmap(NULL,
				v4l2_buf.length, PROT_READ | PROT_WRITE, MAP_SHARED,
				fd, v4l2_buf.m.offset);
		if(addr < 0) {
			printf("map %d v4l2_buffer error!!!\n",i);
			close(fd);
			return -1;
		}
		
		minfo[i].index = i;
		minfo[i].addr = addr;
		minfo[i].length = v4l2_buf.length;
		minfo[i].offset = v4l2_buf.m.offset;
	}
	
	//7.将所有的缓存放入队列
	for(i = 0; i < NUM_BUFS; i++)
	{
		memset(&v4l2_buf, 0, sizeof(struct v4l2_buffer));
		v4l2_buf.index = i; //想要放入队列的缓存
		v4l2_buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
		v4l2_buf.memory = V4L2_MEMORY_MMAP;	

		ret = ioctl(fd, VIDIOC_QBUF, &v4l2_buf);
		if(ret < 0)
		{
			printf("Unable to queue buffer.\n");
			close(fd);
			return -1;
		}
	}
	
	//8.开始捕获
	enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
	ret = ioctl(fd, VIDIOC_STREAMON, &type);
	if (ret < 0){
		printf("VIDIOC_STREAMON failed\n");
		return -1;
	}

	//9.等待数据的到来
	struct pollfd poll_fds[1];
	poll_fds[0].fd = fd;
	poll_fds[0].events = POLLIN; //等待可读
	poll(poll_fds, 1, 10000);
	
	//10.出队列
	memset(&v4l2_buf, 0, sizeof(struct v4l2_buffer));
	v4l2_buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
	v4l2_buf.memory = V4L2_MEMORY_MMAP;	
	ret = ioctl(fd, VIDIOC_DQBUF, &v4l2_buf);
	if (ret < 0)
	{
		printf("VIDIOC_DQBUF failed, dropped frame\n");
		return -1;
	}

	//11.处理数据
	FILE *fp;
	fp = fopen("test.data", "w");
    if(!fp)
    {
        printf("failed to open picture\n");
    } else {
		fwrite(minfo[v4l2_buf.index].addr, 1, minfo[v4l2_buf.index].length, fp);
		fclose(fp);
	}
	
	//12.入队列
	if (ioctl(fd, VIDIOC_QBUF, &v4l2_buf) < 0) {
		printf("VIDIOC_QBUF failed\n");
		return -1;
	}
	
	//13.关闭设备
	ret = ioctl(fd, VIDIOC_STREAMOFF, &type);
	if (ret < 0){
		printf("VIDIOC_STREAMOFF failed\n");
		return -1;
	}
	
	//14.取消映射
	for(i = 0; i < NUM_BUFS; i++)
		munmap(minfo[i].addr, minfo[i].length);
	
	close(fd);
	
	return 0;
}

$ gcc test.c -o test
$./test
生成test.data,是RGB565的原始数据。

在ubuntu下可以用gimg看图像的原始数据。
$ sudo apt-get install gimp
$ gimp test.data
设置好格式和宽高,显示效果如下:

在这里插入图片描述

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值