- 论坛徽章:
- 0
|
原文地址http://blog.ednchina.com/yuliang0321/24516/category.aspx
/* 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;
/* 下面解释上面这个数据结构中包含的数据结构,这些结构的定义都在中。 */
/* * 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 pixels */
/* 这一个数据结构是包含了摄像头的属性,name是摄像头的名字,maxwidth maxheight是摄像头所能获取的最大图像大小,用像素作单位。 */
/* 在程序中,通过ioctl函数的VIDIOCGCAP控制命令读写设备通道已获取这个结构,有关ioctl的使用,比较复杂,这里就不说了。下面列出获取这一数据结构的代码: */
int v4lgetcapability(v4ldevice *vd)
{
if(ioctl(vd->fd, VIDIOCGCAP, &(vd->capability)) fd, VIDIOCGMBUF, &(vd->mbuf))map + vd->mbuf.offsets[vd->frame]);
}
/* 2)获取影像mmap方式。 */
/* 在video4linux下获取影像有两种方式:overlay和mmap。由于我的摄像头不支持overlay方式,所以这里只谈mmap方式。 */
/*
mmap方式是通过内存映射的方式获取数据,系统调用ioctl的VIDIOCMCAPTURE后,将图像映射到内存中,然后可以通过前面的
v4lgetmbuf(vd)函数和v4lgetaddress(vd)函数获得数据的首地址,这是你可以选择是将它显示出来还是放到别的什么地方。
*/
/* 下面给出获取连续影像的最简单的方法(为了简化,将一些可去掉的属性操作都去掉了): */
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
..........................
}
/* 为了更好的理解源码,这里给出里面的函数的实现,这里为了简化,将所有的出错处理都去掉了。 */
int v4lopen(char *name, v4ldevice *vd)
{
int i;
if((vd->fd = open(name,O_RDWR)) 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)map = mmap(0, vd->mbuf.size, PROT_READ|PROT_WRITE, MAP_SHARED, vd->fd, 0)) mmap.frame = frame;
if(ioctl(vd->fd, VIDIOCMCAPTURE, &(vd->mmap)) framestat[frame] = 1;
return 0;
}
int v4lsync(v4ldevice *vd, int frame)
{
if(ioctl(vd->fd, VIDIOCSYNC, &frame) framestat[frame] = 0;
return 0;
}
int v4lcapture(v4ldevice *vd, int frame)
{
vd->mmap.frame = frame;
if(ioctl(vd->fd, VIDIOCMCAPTURE, &(vd->mmap)) framestat[frame] = 1;
return 0;
}
本文来自ChinaUnix博客,如果查看原文请点:http://blog.chinaunix.net/u/16231/showart_1745072.html |
|