v4l2视频采集摄像头

摘要:
V4l2-是Linux内核中视频设备的内核驱动程序框架,为上层访问底层视频设备提供了统一的接口。fd_set*writefds,//0fd_set*exceptfds,//0structtimeval*超时);10.从队列中删除缓冲区ioctl;11.过程图像_图像;12.再次停止/收集ioctl/ioctl;13.资源回收地图;关闭;#include#include#include#包含#include#包括#include#contain#include#defineCLEARmemsetintfd_fb;char*pfb;charyuyv[640*480*2];炭化物[640*480*3];结构缓冲区{void*start;unsignedtlength;};voidprocess_图像{inti,j;inty0,u0,y1,v0;intr,g,b;memcpy;//保存原始yuyv数据//将yuyv转换为rgb数据,用于{y0=yuyv[i*4];y1=yuyv[i*4+2];u0=yuyv[i*4+1];v0=yuyv[i*4+3];//i*2点b=;如果b=255;如果(b˂0)b=0;g=1.16483*-0.391762*-0.81 2968*;如果g=255;如果(g˂0)g=0;r=1.164383*+1.596027*;ifr=255;若(r˂0)r=0;rgb[i*3*2+0]=b;rgb[i*3*2+1]=克;rgb[i*3*2+2]=r//i*2+1点b=;如果b=255;如果(b<0)b=0;g=1.164383*-0.391762*-0.812968*;如果g=255;如果(g<0)g=0;r=1.164383*+1.596027*;ifr=255;如果(r<0)r=0;rgb[i*3*2+3]=b;rgb[i*3*2+4]=g;rgb[i*3*2+5]=r;}对于{对于{*=0x0;*=0x00;*=00x00;}对于//????????

v4l2 --是Linux内核中关于视频设备的内核驱动框架,为上层访问底层的视频设备提供了统一的接口。
/dev/vidioX

1.打开设备文件
fd=open("/dev/video3",O_RDWR);
/dev/video3:视频设备文件名
O_RDWR:可读可写
fd: open成功反返回文件描述符

jpeg


yuv


2.查询设备支持哪种格式
struct v4l2_fmtdesc fmt; //查询设备格式所用结构体
fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
fmt.index = 0;
int ret;
//通过ioctl(文件描述符,命令,补充参数(依赖于命令))函数发送命令,成功返回0
ret = ioctl(fd,VIDIOC_ENUM_FMT,&fmt);
printf("format:%s ",fmt.description);//成功可显示视频所支持的格式
3.设置视频格式
struct v4l2_format s_fmt;
s_fmt.fmt.pix.width = 650;
s_fmt.fmt.pix.height = 480;
s_fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_JPEG;
s_fmt.fmt.pix.field = V4L2_FIELD_INTERLACED;//4
s_fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
ret = ioctl(fd,VIDIOC_S_FMT,&s_fmt);

4.申请内核态缓冲
struct v4l2_requestbuffers reqbuf;
//memset(&reqbuf,0,sizeof(reqbuf));
reqbuf.count = 1;
reqbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
reqbuf.memory = V4L2_MEMORY_MMAP;

ret = ioctl(fd,VIDIOC_REQBUFS,&reqbuf);

5.查询内核缓冲
struct v4l2_buffer buf;
//memset(&buf,0,sizeof(buf));
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf.memory = V4L2_MEMORY_MMAP;
buf.index = 0;
ret = ioctl(fd,VIDIOC_QUERYBUF,&buf);

6.把内核空间分配好的缓冲映射到用户空间
ub.len = buf.length;
ub.start = mmap(NULL,buf.length,
PROT_READ|PROT_WRITE,
MAP_SHARED,
fd,buf.m.offset);
if(ub.start == MAP_FAILED)
{
perror("mmap");
return -1;
}

7.添加到采集队列
ret = ioctl(fd,VIDIOC_QBUF,&buf);

8.启动视频采集
enum v4l2_buf_type type;
type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
ioctl(fd,VIDIOC_STREAMON,&type);

9. 监测视频采集是否完成
int select(int nfds, //最大文件描述符加1
fd_set *readfds,//?
fd_set *writefds, //0
fd_set *exceptfds, //0
struct timeval *timeout);
10.从队列中取出缓冲
ioctl(fd,VIDIOC_DQBUF,&buf);
11.处理图像
process_image(ub.start,ub.len);
12.停止/再次采集
ioctl(fd,VIDIOC_STREAMOFF,&type);/ioctl(fd,VIDIOC_QBUF,&buf);

13.资源回收
munmap(ub.start,ub.len);
close(fd);

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

#define CLEAR(x) memset(&(x), 0, sizeof(x))

int fd_fb;
char* pfb;
char yuyv[640*480*2];
char rgb[640*480*3];

struct buffer
{
void* start;
unsigned int length;
};

void process_image(struct buffer bb)
{
int i, j;
int y0, u0, y1, v0;
int r, g, b;
memcpy(yuyv, bb.start, bb.length);
//保存原始yuyv数据

//把yuyv转为rgb数据
for (i = 0; i < 640*480/2 ; i++)
{
y0 = yuyv[i*4];
y1 = yuyv[i*4+2];
u0 = yuyv[i*4+1];
v0 = yuyv[i*4+3];

//第i*2个点
b = (1.164383 * (y0 - 16) + 2.017232*(u0 - 128));
if (b > 255) b = 255;
if (b < 0) b = 0;
g= 1.164383 * (y0 - 16) - 0.391762*(u0 - 128) - 0.812968*(v0 - 128);
if (g > 255) g = 255;
if (g < 0) g = 0;
r= 1.164383 * (y0 - 16) + 1.596027*(v0 - 128);
if (r > 255) r = 255;
if (r < 0) r = 0;
rgb[i*3*2 + 0] = b;
rgb[i*3*2 + 1] = g;
rgb[i*3*2 + 2] = r;

//第i*2+1个点
b = (1.164383 * (y1 - 16) + 2.017232*(u0 - 128));
if (b > 255) b = 255;
if (b < 0) b = 0;
g= 1.164383 * (y1 - 16) - 0.391762*(u0 - 128) - 0.812968*(v0 - 128);
if (g > 255) g = 255;
if (g < 0) g = 0;
r= 1.164383 * (y1 - 16) + 1.596027*(v0 - 128);
if (r > 255) r = 255;
if (r < 0) r = 0;
rgb[i*3*2 + 3] = b;
rgb[i*3*2 + 4] = g;
rgb[i*3*2 + 5] = r;
}

for ( i = 0; i < 480; i++)
{
for(j=0; j<80; j++)
{
*(pfb+(i*800+j)*4 + 0) = 0x00;
*(pfb+(i*800+j)*4 + 1) = 0x00;
*(pfb+(i*800+j)*4 + 2) = 0x00;
}
for (j = 80; j < 720; j++)//????????640
{
*(pfb+(i*800+j)*4 + 0) = rgb[(i*640+j-80)*3 + 0];
*(pfb+(i*800+j)*4 + 1) = rgb[(i*640+j-80)*3 + 1];
*(pfb+(i*800+j)*4 + 2) = rgb[(i*640+j-80)*3 + 2];
}
for(j=720; j<800; j++)
{
*(pfb+(i*800+j)*4 + 0) = 0x00;
*(pfb+(i*800+j)*4 + 1) = 0x00;
*(pfb+(i*800+j)*4 + 2) = 0x00;
}
}
}

int main()
{
int fd_video;
//打开摄像头设备
fd_video = open("/dev/video3", O_RDWR);
if (fd_video < 0)
{
perror("video3 open");
return fd_video;
}
//打开屏幕设备
fd_fb = open("/dev/fb0", O_RDWR);
if (fd_fb < 0)
{
perror("fb open");
return fd_fb;
}
//设置视频的格式
struct v4l2_format s_fmt;
s_fmt.fmt.pix.width = 800;
s_fmt.fmt.pix.height = 480;
s_fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
//s_fmt.fmt.pix.field = V4L2_FIELD_INTERLACED;//4
s_fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
int flag= ioctl(fd_video,VIDIOC_S_FMT,&s_fmt);
if(flag != 0)
{
printf("set format error ");
return -1;
}

printf("%d %d ",s_fmt.fmt.pix.width,s_fmt.fmt.pix.height);

//映射
pfb = (char *)mmap(NULL, 800*480*4, PROT_WRITE|PROT_READ,MAP_SHARED, fd_fb, 0);
if (pfb == NULL)
{
perror ("mmap");
return -1;
}
//此处作用为申请缓冲区
struct v4l2_requestbuffers req;
req.count=4;
req.type=V4L2_BUF_TYPE_VIDEO_CAPTURE;
req.memory=V4L2_MEMORY_MMAP;
ioctl(fd_video,VIDIOC_REQBUFS,&req);
//缓冲区与应用程序关联
struct buffer *buffers;//start, length
//申请4个struct buffer空间
buffers = (struct buffer*)calloc (req.count, sizeof (struct buffer));
if (!buffers)
{
perror ("Out of memory");
exit (EXIT_FAILURE);
}
unsigned int n_buffers;
for (n_buffers = 0; n_buffers < req.count; n_buffers++)
{
struct v4l2_buffer buf;
memset(&buf,0,sizeof(buf));
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf.memory = V4L2_MEMORY_MMAP;
buf.index = n_buffers;
if (-1 == ioctl (fd_video, VIDIOC_QUERYBUF, &buf))
exit(-1);
buffers[n_buffers].length = buf.length;
buffers[n_buffers].start = mmap (NULL,
buf.length,PROT_READ | PROT_WRITE ,MAP_SHARED,fd_video, buf.m.offset);
if (MAP_FAILED == buffers[n_buffers].start)
exit(-1);
}

enum v4l2_buf_type type;
int i;
for (i = 0; i < 4; ++i)
{
struct v4l2_buffer buf;
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf.memory = V4L2_MEMORY_MMAP;
buf.index = i;
ioctl (fd_video, VIDIOC_QBUF, &buf);
}
while(1)
{
//开始捕获图像
type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
ioctl (fd_video, VIDIOC_STREAMON, &type);


struct v4l2_buffer buf;
CLEAR (buf);
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf.memory = V4L2_MEMORY_MMAP;
//取出图像数据
ioctl (fd_video, VIDIOC_DQBUF, &buf);
//在LCD屏幕上显示图像
process_image (buffers[buf.index]); //YUYV
//告知buf可以使用
ioctl (fd_video,VIDIOC_QBUF,&buf);
}

for (i = 0; i < 4; i++)
munmap(buffers[i].start, buffers[i].length);
free(buffers);
munmap(pfb, 800*480*4);


close(fd_video);
close(fd_fb);

}

代码不够完善,因为要结束摄像头按CTRL + C 最后面6行不会执行,这样的话不会执行munmap释放映射,free内存,close文件操作,

可以用信号signal函数SIGINT (ctrl +c)写个信号函数当按下CTRL + C 时处理最后面6行;

看代码

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

#define CLEAR(x) memset(&(x), 0, sizeof(x))

int fd_fb;
char* pfb;
int fd_video;
char yuyv[640*480*2];
char rgb[640*480*3];
struct buffer *buffers;//start, length

struct buffer
{
void* start;
unsigned int length;
};

void mysignal(int signo)
{
printf("success ");
int i;
for (i = 0; i < 4; i++)
{
munmap(buffers[i].start, buffers[i].length);
}
free(buffers);
munmap(pfb, 800*480*4);
close(fd_video);
close(fd_fb);
exit(0);
}

void process_image(struct buffer bb)
{
int i, j;
int y0, u0, y1, v0;
int r, g, b;
memcpy(yuyv, bb.start, bb.length);
//保存原始yuyv数据

//把yuyv转为rgb数据
for (i = 0; i < 640*480/2 ; i++)
{
y0 = yuyv[i*4];
y1 = yuyv[i*4+2];
u0 = yuyv[i*4+1];
v0 = yuyv[i*4+3];

//第i*2个点
b = (1.164383 * (y0 - 16) + 2.017232*(u0 - 128));
if (b > 255) b = 255;
if (b < 0) b = 0;
g= 1.164383 * (y0 - 16) - 0.391762*(u0 - 128) - 0.812968*(v0 - 128);
if (g > 255) g = 255;
if (g < 0) g = 0;
r= 1.164383 * (y0 - 16) + 1.596027*(v0 - 128);
if (r > 255) r = 255;
if (r < 0) r = 0;
rgb[i*3*2 + 0] = b;
rgb[i*3*2 + 1] = g;
rgb[i*3*2 + 2] = r;

//第i*2+1个点
b = (1.164383 * (y1 - 16) + 2.017232*(u0 - 128));
if (b > 255) b = 255;
if (b < 0) b = 0;
g= 1.164383 * (y1 - 16) - 0.391762*(u0 - 128) - 0.812968*(v0 - 128);
if (g > 255) g = 255;
if (g < 0) g = 0;
r= 1.164383 * (y1 - 16) + 1.596027*(v0 - 128);
if (r > 255) r = 255;
if (r < 0) r = 0;
rgb[i*3*2 + 3] = b;
rgb[i*3*2 + 4] = g;
rgb[i*3*2 + 5] = r;
}

for ( i = 0; i < 480; i++)
{
for(j=0; j<80; j++)
{
*(pfb+(i*800+j)*4 + 0) = 0x00;
*(pfb+(i*800+j)*4 + 1) = 0x00;
*(pfb+(i*800+j)*4 + 2) = 0x00;
}
for (j = 80; j < 720; j++)//????????640
{
*(pfb+(i*800+j)*4 + 0) = rgb[(i*640+j-80)*3 + 0];
*(pfb+(i*800+j)*4 + 1) = rgb[(i*640+j-80)*3 + 1];
*(pfb+(i*800+j)*4 + 2) = rgb[(i*640+j-80)*3 + 2];
}
for(j=720; j<800; j++)
{
*(pfb+(i*800+j)*4 + 0) = 0x00;
*(pfb+(i*800+j)*4 + 1) = 0x00;
*(pfb+(i*800+j)*4 + 2) = 0x00;
}
}
}

int main()
{
//打开摄像头设备
fd_video = open("/dev/video3", O_RDWR);
if (fd_video < 0)
{
perror("video3 open");
return fd_video;
}
//打开屏幕设备
fd_fb = open("/dev/fb0", O_RDWR);
if (fd_fb < 0)
{
perror("fb open");
return fd_fb;
}
//设置视频的格式
struct v4l2_format s_fmt;
s_fmt.fmt.pix.width = 800;
s_fmt.fmt.pix.height = 480;
s_fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
//s_fmt.fmt.pix.field = V4L2_FIELD_INTERLACED;//4
s_fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
int flag= ioctl(fd_video,VIDIOC_S_FMT,&s_fmt);
if(flag != 0)
{
printf("set format error ");
return -1;
}

printf("%d %d ",s_fmt.fmt.pix.width,s_fmt.fmt.pix.height);

//映射
pfb = (char *)mmap(NULL, 800*480*4, PROT_WRITE|PROT_READ,MAP_SHARED, fd_fb, 0);
if (pfb == NULL)
{
perror ("mmap");
return -1;
}
//此处作用为申请缓冲区
struct v4l2_requestbuffers req;
req.count=4;
req.type=V4L2_BUF_TYPE_VIDEO_CAPTURE;
req.memory=V4L2_MEMORY_MMAP;
ioctl(fd_video,VIDIOC_REQBUFS,&req);
//缓冲区与应用程序关联

//申请4个struct buffer空间
buffers = (struct buffer*)calloc (req.count, sizeof (struct buffer));
if (!buffers)
{
perror ("Out of memory");
exit (EXIT_FAILURE);
}
unsigned int n_buffers;
for (n_buffers = 0; n_buffers < req.count; n_buffers++)
{
struct v4l2_buffer buf;
memset(&buf,0,sizeof(buf));
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf.memory = V4L2_MEMORY_MMAP;
buf.index = n_buffers;
if (-1 == ioctl (fd_video, VIDIOC_QUERYBUF, &buf))
exit(-1);
buffers[n_buffers].length = buf.length;
buffers[n_buffers].start = mmap (NULL,
buf.length,PROT_READ | PROT_WRITE ,MAP_SHARED,fd_video, buf.m.offset);
if (MAP_FAILED == buffers[n_buffers].start)
exit(-1);
}

enum v4l2_buf_type type;
int i;
for (i = 0; i < 4; ++i)
{
struct v4l2_buffer buf;
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf.memory = V4L2_MEMORY_MMAP;
buf.index = i;
ioctl (fd_video, VIDIOC_QBUF, &buf);
}
signal(SIGINT,mysignal);
while(1)
{
//开始捕获图像
type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
ioctl (fd_video, VIDIOC_STREAMON, &type);


struct v4l2_buffer buf;
CLEAR (buf);
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf.memory = V4L2_MEMORY_MMAP;
//取出图像数据
ioctl (fd_video, VIDIOC_DQBUF, &buf);
//在LCD屏幕上显示图像
process_image (buffers[buf.index]); //YUYV
//告知buf可以使用
ioctl (fd_video,VIDIOC_QBUF,&buf);
}
}

免责声明:文章转载自《v4l2视频采集摄像头》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇使用vs2010自带的数据库的方法生成唯一标识符 ,通用唯一标识符 UUID下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

Swoole从入门到入土(17)——WebSocket服务器[成员函数与配置选项]

这一节,我们重点了解websocket server的成员函数以及相关的配置选项。 1、成员函数 push:向 WebSocket 客户端连接推送数据,长度最大不得超过 2M。 SwooleWebSocketServer->push(int $fd, string $data, int $opcode = WEBSOCKET_OPCODE_TEXT,...

【转】CUDA程序优化要点

CUDA程序优化应该考虑的点:精度:只在关键步骤使用双精度,其他部分仍然使用单精度浮点以获得指令吞吐量和精度的平衡;    目前 GPU 的单精度性能要远远超过双精度性能,整数乘法、求模、求余等运算的指令吞吐量也较为有限。在科学计算中,由于需要处理的数据量巨大,往往采用双精度或者四精度才能获得可靠的结果,目前的 Tesla 架构还不能很好的满足高精度计算的...

nginx 部署web页面问题

nginx 部署web页面的时候,路径都是对的,但是css文件就是不起作用,控制台提示如下,原来是格式的问题,截图如下: css 被转成了application/octet-stream,这个是nginx的默认格式,所以需要在nginx的配置文件上配置type,配置文件截图为: mime.types 内容为: types { text/html...

vue下实现WebRTC

1.1 WebRTC简介 WebRTC,名称源自网页即时通信(英语:Web Real-Time Communication)的缩写,是一个支持网页浏览器进行实时语音对话或视频对话的实时通信框架,提供了一系列页面可调用API。 参考定义: 谷歌开放实时通信框架 在上一篇博客Vue +WebSocket + WaveSurferJS 实现H5聊天对话交互 中...

从网络I/O模型到Netty,先深入了解下I/O多路复用

微信搜索【阿丸笔记】,关注Java/MySQL/中间件各系列原创实战笔记,干货满满。 本文是Netty系列第3篇 上一篇文章我们了解了Unix标准的5种网络I/O模型,知道了它们的核心区别与各自的优缺点。尤其是I/O多路复用模型,在高并发场景下,有着非常好的优势。而Netty也采用了I/O多路复用模型。 那Netty是如何实现I/O多路复用的呢? Nett...

[从源码学设计] Flume 之 memory channel

[从源码学设计] Flume 之 memory channel 目录 [从源码学设计] Flume 之 memory channel 0x00 摘要 0x01 业务范畴 1.1 用途和特点 1.2 Channel 1.3 研究重点 1.4 实际能够学到什么 1.5 总述 0x02 定义 2.1 接口 2.2 配置参数2.2.1 channe...