如何利用Video4Linux获取摄像头数据

本文详细介绍如何利用Video4Linux获取摄像头数据

  Video4Linux是Linux下用于获取视频和音频数据的API接口,在这篇文章中,着重阐述如何利用Video4Linux获取摄像头数据,以实现连续影像的播放。

  1. 摄像头的安装

  在Linux下常用的摄像头驱动是spca5xx, 这是一个通用驱动,读者可以在以下网站下到这个驱动 http://mxhaard.free.fr/download.html。这个网站还给出了这款驱动支持的摄像头的种类。另外,ov511芯片直接就 支持Linux,使用者款芯片的摄像头有网眼V2000。我使用的是网眼V2000的摄像头,和Z-Star 301p+现代7131R芯片的摄像头。后一种需要spca5xx的驱动。关于spca5xx的安装方法,网上有很多介绍,这里就不说了。

  2. 摄像头的调试

  安装好摄像头后,为了测试摄像头能否正常工作,可以用一下软件。比较著名的是xawtv,在网上搜以下可以下载到。安装好后,打开xawtv则可以调试摄像头。

  3. Video4Linux 编程获取数据

  现有的video4linux有两个版本,v4l和v4l2。本文主要是关于v4l的编程。利用v4l API获取视频图像一般有以下几步:

  a> 打开设备

  b> 设置设备的属性,比如图像的亮度,对比度等等

  c> 设定传输格式和传输方式

  d> 开始传输数据,一般是一个循环,用以连续的传输数据

  e> 关闭设备

  下面具体介绍v4l编程的过程。首先指出,在video4linux编程时要包含头文件,其中包含了video4linux的数据结构和函数定义。

  1)v4l的数据结构

  在video4linux API中定义了如下数据结构,详细的数据结构定义可以参考v4l API的文档,这里就编程中经常使用的数据结构作出说明。

  首先我们定义一个描述设备的数据结构,它包含了v4l中定义的所有数据结构:

typedef struct _v4ldevice

{int fd;//设备号

struct video_capability capability;

struct video_channel channel[10];

struct video_picture picture;

struct video_clip clip;

struct video_window window;

struct video_capture capture;

struct video_buffer buffer;

struct video_mmap mmap;

struct video_mbuf mbuf;

struct video_unit unit;

unsigned char *map;//mmap方式获取数据时,数据的首地址

pthread_mutex_t mutex;

int frame;

int framestat[2];

int overlay;

}v4ldevice;

 

下面解释上面这个数据结构中包含的数据结构,这些结构的定义都在中。DE>* struct video_capability
name[32] Canonical name for this interface
type Type of interface
channels Number of radio/tv channels if appropriate
audios Number of audio devices if appropriate
maxwidth Maximum capture width in pixels
maxheight Maximum capture height in pixels
minwidth Minimum capture width in pixels
minheight Minimum capture height in pixelsDE>

  这一个数据结构是包含了摄像头的属性,name是摄像头的名字,maxwidth maxheight是摄像头所能获取的最大图像大小,用像素作单位。

  在程序中,通过ioctl函数的VIDIOCGCAP控制命令读写设备通道已获取这个结构,有关ioctl的使用,比较复杂,这里就不说了。下面列出获取这一数据结构的代码:

DE>int v4lgetcapability(v4ldevice *vd)
{
if(ioctl(vd->fd, VIDIOCGCAP, &(vd->capability)) < 0) {
v4lperror("v4lopen:VIDIOCGCAP");
return -1;
}
return 0;
}
* struct video_picture
brightness Picture brightness
hue Picture hue (colour only)
colour Picture colour (colour only)
contrast Picture contrast
whiteness The whiteness (greyscale only)
depth The capture depth (may need to match the frame buffer depth)
palette Reports the palette that should be used for this imageDE>

  这个数据结构主要定义了图像的属性,诸如亮度,对比度,等等。这一结构的获取通过ioctl发出VIDIOCGPICT控制命令获取。

 

DE>* struct video_mbuf
size The number of bytes to map
frames The number of frames
offsets The offset of each frame

DE>

  这个数据结构在用mmap方式获取数据时很重要:

  size表示图像的大小,如果是640*480的彩色图像,size=640*480*3

  frames表示帧数

  offsets表示每一帧在内存中的偏移地址,通过这个值可以得到数据在图像中的地址。

  得到这个结构的数据可以用ioctl的VIDIOCGMBUF命令。源码如下:

DE>int v4lgetmbuf(v4ldevice *vd)
{
if(ioctl(vd->fd, VIDIOCGMBUF, &(vd->mbuf))<0) {
v4lperror("v4lgetmbuf:VIDIOCGMBUF");
return -1;
}
return 0;
}DE>

  而数据的地址可以有以下方式计算:

DE>unsigned char *v4lgetaddress(v4ldevice *vd)
{
return (vd->map + vd->mbuf.offsets[vd->frame]);
}DE>

  2)获取影像mmap方式。

  在video4linux下获取影像有两种方式:overlay和mmap。由于我的摄像头不支持overlay方式,所以这里只谈mmap方式。

  mmap方式是通过内存映射的方式获取数据,系统调用ioctl的VIDIOCMCAPTURE后,将图像映射到内存中,然后可以通过前面的 v4lgetmbuf(vd)函数和v4lgetaddress(vd)函数获得数据的首地址,这是李可以选择是将它显示出来还是放到别的什么地方。

  下面给出获取连续影像的最简单的方法(为了简化,将一些可去掉的属性操作都去掉了):

DE>char* devicename="/dev/video0";
char* buffer;
v4ldevice device;
int width = 640;
int height = 480;
int frame = 0;
v4lopen("/dev/video0",&device);//打开设备
v4lgrabinit(&device,width,height);//初始化设备,定义获取的影像的大小
v4lmmap(&device);//内存映射
v4lgrabstart(&device,frame);//开始获取影像
while(1){
v4lsync(&device,frame);//等待传完一帧
frame = (frame+1)%2;//下一帧的frame
v4lcapture(&device,frame);//获取下一帧
buffer = (char*)v4lgetaddress(&device);//得到这一帧的地址
//buffer给出了图像的首地址,你可以选择将图像显示或保存......
//图像的大小为 width*height*3
..........................
}DE>

为了更好的理解源码,这里给出里面的函数的实现,这里为了简化,将所有的出错处理都去掉了。DE>int v4lopen(char *name, v4ldevice *vd)
{
int i;
if((vd->fd = open(name,O_RDWR)) < 0) {
return -1;
}
if(v4lgetcapability(vd))
return -1;
}
int v4lgrabinit(v4ldevice *vd, int width, int height)
{
vd->mmap.width = width;
vd->mmap.height = height;
vd->mmap.format = vd->picture.palette;
vd->frame = 0;
vd->framestat[0] = 0;
vd->framestat[1] = 0;
return 0;
}
int v4lmmap(v4ldevice *vd)
{
if(v4lgetmbuf(vd)<0)
return -1;
if((vd->map = mmap(0, vd->mbuf.size, PROT_READ|PROT_WRITE, MAP_SHARED, vd->fd, 0)) < 0) {
return -1;
}
return 0;
}
int v4lgrabstart(v4ldevice *vd, int frame)
{
vd->mmap.frame = frame;
if(ioctl(vd->fd, VIDIOCMCAPTURE, &(vd->mmap)) < 0) {
return -1;
}
vd->framestat[frame] = 1;
return 0;
}
int v4lsync(v4ldevice *vd, int frame)
{
if(ioctl(vd->fd, VIDIOCSYNC, &frame) < 0) {
return -1;
}
vd->framestat[frame] = 0;
return 0;
}
int c4lcapture(v4ldevice *vd, int frame)
{
vd->mmap.frame = frame;
if(ioctl(vd->fd, VIDIOCMCAPTURE, &(vd->mmap)) < 0) {
return -1;
}
vd->framestat[frame] = 1;
return 0;DE>

 

关于Linux的视频编程(v4l2编程)

. 什么是video4linux
Video4linux2
(简称V4L2),linux 中关于视频设备的内核驱动。在Linux 中,视频设备是设备文件,可以像访问普通文件一样对其进行读写,摄像头在/dev/video0 下。

二、一般操作流程(视频设备):
1. 
打开设备文件。 int fd=open(”/dev/video0″,O_RDWR);
2. 
取得设备的capability ,看看设备具有什么功能,比如是否具有视频输入, 或者音频输入输出等。VIDIOC_QUERYCAP,struct v4l2_capability
3. 
选择视频输入,一个视频设备可以有多个视频输入。VIDIOC_S_INPUT,struct v4l2_input
4. 
设置视频的制式和帧格式,制式包括PALNTSC ,帧的格式个包括宽度和高度等。
VIDIOC_S_STD,VIDIOC_S_FMT,struct v4l2_std_id,struct v4l2_format
5. 
向驱动申请帧缓冲,一般不超过5 个。struct v4l2_requestbuffers
6. 
将申请到的帧缓冲映射到用户空间,这样就可以直接操作采集到的帧了,而不必去复制。mmap
7. 
将申请到的帧缓冲全部入队列,以便存放采集到的数据.VIDIOC_QBUF,struct v4l2_buffer
8. 
开始视频的采集。VIDIOC_STREAMON
9. 
出队列以取得已采集数据的帧缓冲,取得原始采集数据。VIDIOC_DQBUF
10. 
将缓冲重新入队列尾, 这样可以循环采集。VIDIOC_QBUF
11. 
停止视频的采集。VIDIOC_STREAMOFF
12. 
关闭视频设备。close(fd);
三、常用的结构体( 参见/usr/include/linux/videodev2.h)

struct v4l2_requestbuffers reqbufs;// 向驱动申请帧缓冲的请求,里面包含申请的个数
struct v4l2_capability cap;//
这个设备的功能,比如是否是视频输入设备
struct v4l2_input input; //
视频输入
struct v4l2_standard std;//
视频的制式,比如PALNTSC
struct v4l2_format fmt;//
帧的格式,比如宽度,高度等

struct v4l2_buffer buf;// 代表驱动中的一帧
v4l2_std_id stdid;//
视频制式,例如:V4L2_STD_PAL_B
struct v4l2_queryctrl query;//
查询的控制
struct v4l2_control control;//
具体控制的值

下面具体说明开发流程(网上找的啦,也在学习么)

 

打开视频设备

V4L2 中,视频设备被看做一个文件。使用open 函数打开这个设备:

//  用非阻塞模式打开摄像头设备

int  cameraFd ;

cameraFd  open (“/dev/video0″O_RDWR O_NONBLOCK , 0);

//  如果用阻塞模式打开摄像头设备,上述代码变为:

//cameraFd = open(”/dev/video0″, O_RDWR, 0);

关于阻塞模式和非阻塞模式

应用程序能够使用阻塞模式或非阻塞模式打开视频设备,如果使用非阻塞模式调用视频设备,即使尚未捕获到信息,驱动依旧会把缓存(DQBUFF )里的东西返回给应用程序。

设定属性及采集方式

打开视频设备后,可以设置该视频设备的属性,例如裁剪、缩放等。这一步是可选的。在Linux 编程中,一般使用ioctl 函数来对设备的I/O 通道进行管理:

extern int  ioctl  (int  __fdunsigned long int  __request , …) __THROW ;

__fd :设备的ID ,例如刚才用open 函数打开视频通道后返回的cameraFd

__request :具体的命令标志符。

在进行V4L2 开发中,一般会用到以下的命令标志符:

  1. VIDIOC_REQBUFS :分配内存
  2. VIDIOC_QUERYBUF :把VIDIOC_REQBUFS 中分配的数据缓存转换成物理地址
  3. VIDIOC_QUERYCAP :查询驱动功能
  4. VIDIOC_ENUM_FMT :获取当前驱动支持的视频格式
  5. VIDIOC_S_FMT :设置当前驱动的频捕获格式
  6. VIDIOC_G_FMT :读取当前驱动的频捕获格式
  7. VIDIOC_TRY_FMT :验证当前驱动的显示格式
  8. VIDIOC_CROPCAP :查询驱动的修剪能力
  9. VIDIOC_S_CROP :设置视频信号的边框
  10. VIDIOC_G_CROP :读取视频信号的边框
  11. VIDIOC_QBUF :把数据从缓存中读取出来
  12. VIDIOC_DQBUF :把数据放回缓存队列
  13. VIDIOC_STREAMON :开始视频显示函数
  14. VIDIOC_STREAMOFF :结束视频显示函数
  15. VIDIOC_QUERYSTD :检查当前视频设备支持的标准,例如PALNTSC

这些IO 调用,有些是必须的,有些是可选择的。

检查当前视频设备支持的标准

在亚洲,一般使用PAL720X576 )制式的摄像头,而欧洲一般使用NTSC720X480 ),使用VIDIOC_QUERYSTD 来检测:

v4l2_std_id std ;

do  {

ret ioctl (fdVIDIOC_QUERYSTD , &std );

while  (ret  == -1 && errno  == EAGAIN );

switch  (std ) {

case  V4L2_STD_NTSC :

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值