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\n",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\n");
return -1;
}

printf("%d %d\n",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\n");
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\n");
return -1;
}

printf("%d %d\n",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视频采集摄像头的更多相关文章

  1. Linux之V4L2视频采集编程详解

     V4L2(Video For Linux Two) 是内核提供给应用程序访问音.视频驱动的统一接口. Linux系统中,视频设备被当作一个设备文件来看待,设备文件存放在 /dev目录下,完整路径的设 ...

  2. V4L2视频采集原理

    一.简介 Video for Linuxtwo(Video4Linux2)简称V4L2,是V4L的改进版.V4L2是linux操作系统下用于采集图片.视频和音频数据的API接口,配合适当的视频采集设备 ...

  3. 基于Linux的v4l2视频架构驱动编写(转载)

    转自:http://www.linuxidc.com/Linux/2011-03/33022.htm 其实,我刚开始一直都不知道怎么写驱动,什么都不懂的,只知道我需要在做项目的过程中学习,所以,我就自 ...

  4. 基于Linux的v4l2视频架构驱动编写

    其实,我刚开始一直都不知道怎么写驱动,什么都不懂的,只知道我需要在做项目的过程中学习,所以,我就自己找了一个关于编写Linux下的视频采集监控项目做,然后上学期刚开学的时候听师兄说,跟院长做项目,没做 ...

  5. Android中直播视频技术探究之---采集摄像头Camera视频源数据进行推流(采用金山云SDK)

    一.前言 在之前已经详细介绍了Android中的一种视频数据源:Camera,不了解的同学可以点击进入:Android中Camera使用详解 ,在这篇文章中我们介绍了如何采集摄像头的每一帧数据,然后进 ...

  6. 如何用FFmpeg API采集摄像头视频和麦克风音频,并实现录制文件的功能

    之前一直用Directshow技术采集摄像头数据,但是觉得涉及的细节比较多,要开发者比较了解Directshow的框架知识,学习起来有一点点难度.最近发现很多人问怎么用FFmpeg采集摄像头图像,事实 ...

  7. FPGA_VIP_V101 摄像头视频采集 调试总结之SDRAM引起的水平条纹噪声问题

    FPGA_VIP_V101 摄像头视频采集 调试总结之SDRAM引起的水平条纹噪声问题 此问题困扰我很近,终于在最近的项目调整中总结了规律并解决了. 因为之前对sdram并不熟悉,用得也不是太多,于是 ...

  8. JavaCV 采集摄像头及桌面视频数据

    javacv 封装了javacpp-presets库很多native API,简化了开发,对java程序员来说比较友好. 之前使用JavaCV库都是使用ffmpeg native API开发,这种方式 ...

  9. 基于PCIe DMA的8通道视频采集&显示IP,兼容V4L2

    基于PCIe DMA的8通道视频采集&显示IP,兼容V4L2 Video Capture&Display IP for V4L2 在主机端视频设备内核驱动V4L2 的控制和调度下,Vi ...

随机推荐

  1. ajax 跨域请求资源问题

    其实相当的简单:只需要在服务端设置一下响应头: header("Access-Control-Allow-Origin: *");就可以了!! nice,有木有? 下面两句也可以带 ...

  2. Qt5:Qt文件操作类 QFile

    在QT中,操作文件一般不使用C++提供的文件操作类 , 因为操作文件的时候,要用到C++提供的 string 类,而在QT中使用的是Qt自己实现的一个string类 QString .在Qt中使用C+ ...

  3. Size Balanced Tree(SBT) 模板

    首先是从二叉搜索树开始,一棵二叉搜索树的定义是: 1.这是一棵二叉树: 2.令x为二叉树中某个结点上表示的值,那么其左子树上所有结点的值都要不大于x,其右子树上所有结点的值都要不小于x. 由二叉搜索树 ...

  4. Struts2--简单的数据校验

    action没有request, response等属性, 无法往前台传信息, 出来一个概念, valuestack: 存放action的属性, 还有各种error等... <s:propert ...

  5. spring+hibernate中的Result object returned from HibernateCallback isn't a List

    Ok the problem is that for executeFind() the return type is List....so there is no way to use unique ...

  6. extJS4.2.0 Json数据解析,嵌套及非嵌套(二)

    Ext.data.reader.Reader Readers通常用于翻译数据,使其被加载为 Model 实例或Store, 该数据一般是一个AJAX请求的响应数据. 一般情况下不需要直接创建一个Rea ...

  7. COC建筑拖动的实现

    最近在玩COC,多体验一下手游的体验,因为自己毕竟一直是做页游的,有些观念需要转变一下. 好像偏了,玩了几次之后突然想起COC那个地图拖动的自己之前实现过,那是2010年左右的时候,模拟经营类页游大行 ...

  8. oracle监听无法启动

    昨天再监听里新加了个地址,重启电脑后监听无法启动,删除新加地址就好了 # listener.ora Network Configuration File: d:\oracle\product\10.2 ...

  9. POJ 2482 Stars in Your Window

    线段树+离散化+扫描线 AC之后,又认真读了一遍题目,好文章. #include<cstdio> #include<map> #include<algorithm> ...

  10. nginx 红黑树详解

    1 介绍 这部分终于整理完了,太耗时间了,留下来备忘吧! 之前看STL源码时,只是研究了红黑树的插入部分.在stl源码剖析的书中,也没有涉及到删除操作的分析,这次对删除操作也进行了详细的研究, 并且还 ...