我是用的是罗技的QC Express, 用qt进行显示,效果不是很好,每秒只有4帧, 还需要进一步改进.当然,我做这个不光参考这一篇文章
以下为转贴: /* 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)) < 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 image */ /* 这个数据结构主要定义了图像的属性,诸如亮度,对比度,等等。这一结构的获取通过ioctl发出VIDIOCGPICT控制命令获取。 */ /* * struct video_mbuf */ /* size The number of bytes to map */ /* frames The number of frames */ /* offsets The offset of each frame */ /* 这个数据结构在用mmap方式获取数据时很重要: */ /* size表示图像的大小,如果是640*480的彩色图像,size=640*480*3 */ /* frames表示帧数 */ /* offsets表示每一帧在内存中的偏移地址,通过这个值可以得到数据在图像中的地址。 */ /* 得到这个结构的数据可以用ioctl的VIDIOCGMBUF命令。源码如下: */ int v4lgetmbuf(v4ldevice *vd) { if(ioctl(vd->fd, VIDIOCGMBUF, &(vd->mbuf))<0) { v4lperror("v4lgetmbuf:VIDIOCGMBUF"); return -1; } return 0; } /* 而数据的地址可以有以下方式计算: */ unsigned char *v4lgetaddress(v4ldevice *vd) { return (vd->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)) < 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 v4lcapture(v4ldevice *vd, int frame) { vd->mmap.frame = frame; if(ioctl(vd->fd, VIDIOCMCAPTURE, &(vd->mmap)) < 0) { return -1; } vd->framestat[frame] = 1; return 0; } |
[转] [转]v4l使用简介
最新推荐文章于 2023-06-11 12:04:39 发布