Linux开发板调用摄像头(V4L2编程,含YUYV解码RGB)

使用Linux的V4L2编程部分参考:

        Linux之V4L2基础编程 - emouse - 博客园

使用YUY2(YUV)与RGB之间相互转化参考:

        (转)RGB、YUY2、YUYV、YVYU、UYVY、AYUV格式详解 - 神一样的魔鬼 - 博客园

        本文是基于Linux开发板的V4L2摄像头调用程序,包括YUYV解码为RGB,以及将摄像头数据显示在开发板屏幕上。代码未封装,可直接在linux下编译使用。

        工作流程:打开设备 —> 检查和设置设备属性 —> 设置帧格式 —> 设置一种输入输出方法(缓冲区管理) —> 循环获取数据 —> 数据解码 —> 显示在lcd上 —> 关闭设备。

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

unsigned int *lcdptr = NULL;  //lcd映射内存首地址
int lcd_width;  //lcd屏幕宽
int lcd_height;   //lcd屏幕高

int camera_width = 640;  //camere屏幕宽
int camera_height = 480;   //camera屏幕高

void lcd_show_rgb(unsigned char *rgbdata,int width,int height);   //在lcd上显示
int YUV2RGB(void* pYUV, void* pRGB, int width, int height, bool alphaYUV, bool alphaRGB);  //YUYV格式转换为RGB格式

int main(void)
{
	int lcdfd = open("/dev/fb0", O_RDWR); //打开 LCD屏幕
	if(lcdfd < 0)
	{
		perror("/dev/fb0");
		exit(-1);
	}
	//获取屏幕宽高
	struct fb_var_screeninfo lcdvar;
	ioctl(lcdfd, FBIOGET_VSCREENINFO , &lcdvar);
	lcd_width = lcdvar.xres;  
	lcd_height = lcdvar.yres; 
	//4 = 透明度 + RGB
	lcdptr = (unsigned int *)mmap( NULL, lcd_width*lcd_height*4 ,    	 	//映射fb内存空间长度 	 
					PROT_READ | PROT_WRITE,	//可读可写
					MAP_SHARED,     		//进程间共享机制
					lcdfd, 				//lcd的文件描述符
					0);
					
	
	//1.打开摄像头设备
	int fd = open("/dev/video1",O_RDWR);  //video0 或 video1
	if(fd < 0)
	{
		perror("打开设备失败");
		return -1;
	}
	
	//2.获取摄像头支持的格式 ioctl(文件描述符,命令,与命令对应的结构体)
	//查询并显示所有支持的格式:VIDIOC_ENUM_FMT ,获取对应结构体
  /*struct v4l2_fmtdesc
	{
		u32 index; // 要查询的格式序号,应用程序设置
		enum v4l2_buf_type type; // 帧类型,应用程序设置
		u32 flags; // 是否为压缩格式
		u8 description[32]; // 格式名称
		u32 pixelformat; // 格式
		u32 reserved[4]; // 保留
	};
	*/
	
	
	//3.配置摄像头采集格式
	//查看或设置当前格式: VIDIOC_G_FMT, VIDIOC_S_FMT
	/* 
	struct v4l2_format
	{
		enum v4l2_buf_type type; // 帧类型,应用程序设置
		union fmt
		{
			struct v4l2_pix_format pix; // 视频设备使用
			struct v4l2_window win;
			struct v4l2_vbi_format vbi;
			struct v4l2_sliced_vbi_format sliced;
			u8 raw_data[200];
		}; 
	}; 
	
	struct v4l2_pix_format
	{
		u32 width; // 帧宽,单位像素
		u32 height; // 帧高,单位像素
		u32 pixelformat; // 帧格式
		enum v4l2_field field;
		u32 bytesperline;
		u32 sizeimage;
		enum v4l2_colorspace colorspace;
		u32 priv;
	};
	*/
	struct v4l2_format vfmt; 
	vfmt.type=V4L2_BUF_TYPE_VIDEO_CAPTURE; //设置类型摄像头采集
	vfmt.fmt.pix.width = camera_width;  //设置宽
	vfmt.fmt.pix.height = camera_height;   //设置高
	vfmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;  //根据摄像头设置格式
	int ret;
	ret = ioctl(fd, VIDIOC_S_FMT, &vfmt);
	if(ret < 0)
	{
		perror("设置格式失败");
	}	
	printf("Current data format information:\n\twidth:%d\n\theigh
  • 2
    点赞
  • 46
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
很抱歉,作为AI语言模型,我无法为您提供完整的代码。但是,我可以提供一些思路和参考: 1. 首先需要确认摄像头驱动是否已经正常安装,可以通过`ls /dev/video*`命令查看是否有/dev/video0等设备文件出现。 2. 如果摄像头已经正常安装,可以使用V4L2(Video for Linux 2)库来进行视频采集。 3. 在使用V4L2库之前,需要先打开摄像头设备文件,使用`open()`函数即可。例如: ``` int fd = open("/dev/video0", O_RDWR); if (fd == -1) { perror("open failed"); exit(EXIT_FAILURE); } ``` 4. 接下来需要设置摄像头的采集参数,包括图像格式、分辨率、帧率等。可以通过`ioctl()`函数和`struct v4l2_format`结构体来完成,例如: ``` struct v4l2_format fmt; memset(&fmt, 0, sizeof(fmt)); fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; fmt.fmt.pix.width = 640; fmt.fmt.pix.height = 480; fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV; fmt.fmt.pix.field = V4L2_FIELD_INTERLACED; if (ioctl(fd, VIDIOC_S_FMT, &fmt) == -1) { perror("ioctl VIDIOC_S_FMT failed"); exit(EXIT_FAILURE); } ``` 5. 然后需要分配视频缓冲区,并将其映射到用户空间。可以通过`struct v4l2_requestbuffers`结构体和`mmap()`函数来完成,例如: ``` struct v4l2_requestbuffers req; memset(&req, 0, sizeof(req)); req.count = 4; req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; req.memory = V4L2_MEMORY_MMAP; if (ioctl(fd, VIDIOC_REQBUFS, &req) == -1) { perror("ioctl VIDIOC_REQBUFS failed"); exit(EXIT_FAILURE); } for (int i = 0; i < req.count; i++) { struct v4l2_buffer buf; memset(&buf, 0, sizeof(buf)); buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; buf.memory = V4L2_MEMORY_MMAP; buf.index = i; if (ioctl(fd, VIDIOC_QUERYBUF, &buf) == -1) { perror("ioctl VIDIOC_QUERYBUF failed"); exit(EXIT_FAILURE); } void *ptr = mmap(NULL, buf.length, PROT_READ | PROT_WRITE, MAP_SHARED, fd, buf.m.offset); if (ptr == MAP_FAILED) { perror("mmap failed"); exit(EXIT_FAILURE); } buffers[i] = ptr; buffer_sizes[i] = buf.length; } ``` 6. 最后,需要循环读取视频数据,并进行处理。可以通过`select()`函数来检测摄像头是否有新的数据可读,然后使用`read()`函数读取数据,例如: ``` fd_set fds; FD_ZERO(&fds); FD_SET(fd, &fds); while (1) { if (select(fd + 1, &fds, NULL, NULL, NULL) == -1) { perror("select failed"); exit(EXIT_FAILURE); } if (FD_ISSET(fd, &fds)) { struct v4l2_buffer buf; memset(&buf, 0, sizeof(buf)); buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; buf.memory = V4L2_MEMORY_MMAP; if (ioctl(fd, VIDIOC_DQBUF, &buf) == -1) { perror("ioctl VIDIOC_DQBUF failed"); exit(EXIT_FAILURE); } // 处理视频数据,例如将其保存到文件中 write_video_data_to_file(buffers[buf.index], buffer_sizes[buf.index]); if (ioctl(fd, VIDIOC_QBUF, &buf) == -1) { perror("ioctl VIDIOC_QBUF failed"); exit(EXIT_FAILURE); } } } ``` 这只是一个简单的摄像头采集代码框架,具体实现还需要根据具体的需求进行调整和优化。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值