v4l2视频采集摄像头
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视频采集摄像头的更多相关文章
- Linux之V4L2视频采集编程详解
V4L2(Video For Linux Two) 是内核提供给应用程序访问音.视频驱动的统一接口. Linux系统中,视频设备被当作一个设备文件来看待,设备文件存放在 /dev目录下,完整路径的设 ...
- V4L2视频采集原理
一.简介 Video for Linuxtwo(Video4Linux2)简称V4L2,是V4L的改进版.V4L2是linux操作系统下用于采集图片.视频和音频数据的API接口,配合适当的视频采集设备 ...
- 基于Linux的v4l2视频架构驱动编写(转载)
转自:http://www.linuxidc.com/Linux/2011-03/33022.htm 其实,我刚开始一直都不知道怎么写驱动,什么都不懂的,只知道我需要在做项目的过程中学习,所以,我就自 ...
- 基于Linux的v4l2视频架构驱动编写
其实,我刚开始一直都不知道怎么写驱动,什么都不懂的,只知道我需要在做项目的过程中学习,所以,我就自己找了一个关于编写Linux下的视频采集监控项目做,然后上学期刚开学的时候听师兄说,跟院长做项目,没做 ...
- Android中直播视频技术探究之---采集摄像头Camera视频源数据进行推流(采用金山云SDK)
一.前言 在之前已经详细介绍了Android中的一种视频数据源:Camera,不了解的同学可以点击进入:Android中Camera使用详解 ,在这篇文章中我们介绍了如何采集摄像头的每一帧数据,然后进 ...
- 如何用FFmpeg API采集摄像头视频和麦克风音频,并实现录制文件的功能
之前一直用Directshow技术采集摄像头数据,但是觉得涉及的细节比较多,要开发者比较了解Directshow的框架知识,学习起来有一点点难度.最近发现很多人问怎么用FFmpeg采集摄像头图像,事实 ...
- FPGA_VIP_V101 摄像头视频采集 调试总结之SDRAM引起的水平条纹噪声问题
FPGA_VIP_V101 摄像头视频采集 调试总结之SDRAM引起的水平条纹噪声问题 此问题困扰我很近,终于在最近的项目调整中总结了规律并解决了. 因为之前对sdram并不熟悉,用得也不是太多,于是 ...
- JavaCV 采集摄像头及桌面视频数据
javacv 封装了javacpp-presets库很多native API,简化了开发,对java程序员来说比较友好. 之前使用JavaCV库都是使用ffmpeg native API开发,这种方式 ...
- 基于PCIe DMA的8通道视频采集&显示IP,兼容V4L2
基于PCIe DMA的8通道视频采集&显示IP,兼容V4L2 Video Capture&Display IP for V4L2 在主机端视频设备内核驱动V4L2 的控制和调度下,Vi ...
随机推荐
- 何查询SQL Server数据库没有主键的表并增加主键
SQL Server数据库中,如果一个表没有主键,我们该如何查询呢?本文我们主要就介绍了如何查询数据库中没有主键的表名并为其增加主键的方法,希望能够对您有所帮助. 该功能的实现代码如下: declar ...
- struts1.x中web.xml文件的配置
1.配置欢迎文件清单 当客户访问Web应用时,如果仅仅给出Web应用的Root URL,没有指定具体的文件名.Web容器会自动调用Web应用的欢迎文件.<welcome-file-li ...
- webView进度条
self.progress = [[NJKWebViewProgress alloc] init]; self.webView.delegate = self.progress; __weak typ ...
- ARM汇编指令的一些总结-转
ARM汇编指令的一些总结ARM汇编指令很多,但是真正常用的不是很多,而且需要认真琢磨的又更少了.比较有用的是MOV B BL LDR STR还是通过具体汇编代码来学习吧.@ disable watch ...
- [算法] aov图拓扑算法
#include <stdio.h> #include <string.h> #include <stdlib.h> #include <queue> ...
- Gradle依赖项学习总结,dependencies、transitive、force、exclude的使用与依赖冲突解决
http://www.paincker.com/gradle-dependencies https://docs.gradle.org/current/userguide/dependency_man ...
- 试水 Egret :TouchEvent与EnterFrame相关
由于Egret是照着ActionScript的api去做的,且TS就是JS,JS和AS都是兄弟语法,同属于ECMAScript语法系的,所以我就直接测试了的. 如下: var sp:egret.Spr ...
- 彻底领悟javascript中的this
this是Javascript语言的一个关键字. 它代表函数运行时,自动生成的一个内部对象,只能在函数内部使用.比如, function test() { this.x = 1; } 随着函数使用场合 ...
- iOS 旋转
实现一张图片的旋转部分角度显示: [cpp] view plaincopy UIImageView image = [[UIImageView alloc]init]; image.frame = C ...
- 如何成为一名优秀的UI设计师
zccst整理 因为我自己就是一个 0 美术基础.非计算机.非艺术类科班出身,但从事视觉设计工作的同学,所以很多和题主一样大学里学着不喜欢的专业,想要转设计但又不知从何开始的朋友都来问过我类似的问题, ...