基于Video for Linux内核的USB摄像头视频信号采集实现

时间:2022-06-27 06:36:05

基于Video for Linux内核的USB摄像头视频信号采集实现

摘要:Video for Linux是Linux中关于视频设备的内核驱动,本文介绍了在Video for Linux内

>> 基于ARM9和USB摄像头的网络视频采集系统设计 基于嵌入式video4linux的USB视频信号采集 基于USB摄像头的嵌入式视频监控系统 基于USB摄像头的局域网 基于摄像头的路径信息采集系统的简易设计与实现 基于Linux系统的USB摄像头视频播放实现 Linux 下 USB摄像头驱动的实现 基于PTZ摄像头的视频人脸识别 基于FPGA的多路高清视频信号叠加系统的设计 基于FPGA的DVI视频信号发生器设计 基于USB摄像头的实验报告成绩录入系统 基于MPEG-2 TS流的数字视频信号可变延时器 基于多摄像头的行人视频运动目标检测算法研究 基于ARM的多摄像头无线视频报警系统 基于VB 6.0下的对网络摄像头视频捕捉 基于OpenCV的摄像头实时人脸检测系统的设计与实现 基于摄像头的赛道信息处理和控制策略实现 基于STM32的双摄像头图像采集自主避障机器鱼设计 亚马逊推出Video Direct视频自助服务 基于摄像头导航的智能车系统 常见问题解答 当前所在位置:l文件,程序里调用ioctl()。主要调用的函数有:open()函数,用来打开视频设备,get_capability()函数和get_picture()函数用来获取视频设备的信息,初始化设备调用v4l set norm()函数,对视频信号的采集需要调用v4l grab frame()函数,最后关闭视频设备用到close()函数。接下来介绍设备初始化和视频的截取。

2.2.1 设备的初始化首先打开视频设备,摄像头在系统中对应的设备文件为/dev/video0,采用系统调用函数camera_fd=open(“/dev/video0”,O_RDWR)(注:camera_fd是设备打开后返回的文件描述符)。以下是open函数的具体实现:

int camera-open(char *dev,camera device *vd)

{

if(!dev)

dev=dev/video0;

if((vd->fd=open(dev,O_RDWR))

perror(“camera_open:”);retum-1;

}

if(camera-cap(vd))

retum -1;

if(camera-pic(vd))

return -1;

return 0;

}

接着,利用ioctl WIDIOCGCAP读取struct video_cability中有关摄像头的信息。

int camera_cap(camera_device *vd)

{

if(ioctl(vd->fd,VIDIOCGCAP,&(vd->capability))

{

perror(“camera_cap:”);

return -1;

}

return 0;

}

该函数成功返回后,从内核空间将这些信息拷贝到用户程序空间camera_cap各成员分量中,使printf函数就可得到各成员分量信息。然后通过调用ioctl VIDIOCSFBUF设置内存缓冲区的相关信息,缓冲区的信息也可通过printf函数输出;通过调用ioctl VIDIOCSWIN完成对视频窗口的设置;如窗口的宽度,高度等;通过调用ioctl VIDIOCSPICT来设置所采集图像的属性,如亮度,对比度等。

2.2.2 视频截取初始化设备后,就可以开始视频图像的截取,有两种方法:一种是read()直接读取;另外一种mmap()内存映射。Read()通过内核缓冲区来读取数据;而mmap()通过把设备文件映射到内存中,绕过了内核缓冲区。显而易见,内存访问速度是远高于磁盘访问的,所以mmap方式优于I/O访问方式。不过,采用mmap()方式的前提是拥有带内存管理单元(MMU)的CPU,本课题采用的S3C2410是具有MMU的CPU。用mmap(内存映射)方式截取视频;mmap()系统调用使得进程之间通过映射同一个普通文件实现共享内存。普通文件被映射到进程地址空间后,进程可以向访问普通内存一样对文件进行访问,不必再调用read(),write()等操作。两个不同进程A、B共享内存的意思是,同一块物理内存被映射到进程A、B各自的进程地址空间。进程A可以即时看到进程B对共享内存中数据的更新,反之亦然。采用共享内存通信的一个明显的好处是效率高,因为进程可以直接读写内存,而不需要任何数据的拷贝。基于以上优点,所以在程序实现中采用了内存映射方式,即mmap()方式。

①实现摄像头设备文件到内存区的映射:调用buf=void *mmap(void *addr,size_t len,int prot,int flags,int fd,off_toffset)。以下是个函数各参数的注释:len:映射到调用进程地址空间的字节数,它从被映射文件开头offset个字开始算起;prot:指定共享内存的访问权限PROT_READ(可读),PROT-WRITE(可写),PROT_EXEC(可执行);flags:MAP_SHARED MAP_PRIVATE中必选一个,MAP_FIXED不推荐使用;addr:共享内存的起始地址,一般设0,表示由系统分配;mmap():返回值是系统实际分配的起始地址;

下面是该函数的程序实现:

int camera_mmap_init(camera_device *vd)

{

if(camera_mbuf(vd)

return -1;

if((vd->map=mmap(0,vd->mbuf.size,PROT_READ|PROT_WRITE,

MAP_SHARED,vd->fd,0))

{

perror(“camera_mmap_init:mmap”);

return -1;

}

return 0;

}

通过调用该函数,可以将设备文件的内容就映射到内存区,该映射内存区可读可写并且不同进程间可共享。该函数成功时返回映像内存区的指针,失败时返回值为-1。

②数据采集。调用ioctl(fd,VIDIOCMCAPTURE,&camera_buf截取图像,然后调用ioctl(fd,VIDIOCSYNC,&frame)函数,该函数成功返回则表示采集完毕。在此基础上同样可实现连续帧的采集,即一次采集连续多帧图像的数据,Video4Linux最多支持一次采集32帧,此时首先要设置camera_buf.frame为要采集的帧数,而每一帧的数据在内存中的起始位置为data+camera_mbuf.offsets[frame],其中camera_mbuf为video_buf结构体变量的一个声明,利用ioctl(fd,VDIOCGMBUF,&camera_mbuf便可获得camera--mbuf的信息。除此之外还要设置数据缓冲区的大小,然后利用ioctl VDIOCMCAPTURE操作进行数据的连续采集,直到缓冲区中的剩余空间无法保存一个完整的数据帧,此时缓冲区中没有剩余的空间供数据采集进程使用。以下是控制连续采集的循环语句:

for(frame=0;frame

{

mapbuf.frame=frame;

if(ioct1(cam,VIDIOCMCAITURE,&camer_mbuf

perror(“VIDIOCMCAPTURE”);

exit(-1);

}

}

当缓冲区中没有可利用的空间时,系统调用ioctl VIDIOCSYNC操作来检查当前的视频采集过程是否完成,如果完成,应用程序就通过buf=bigbuf+vidbuf.offsets[frame]为数据帧分配地址,这样缓冲区中的数据帧就可被安全的保存下来供其他进程使用。

3结语

Video for Linux作为Linux中关于视频设备的内核驱动,其为视频设备编程提供一系列接口函数,数据结构为用户编写视频设备驱动提供极大的便利,本文基于Video for Linux内核开发,编写usb摄像头驱动程序,实现了USB摄像头对视频信号采集实现,并在移动目标自动跟踪系统中应用效果良好。

参考文献:

[1]蔡婧璇,潘银松.基于嵌入式Video4Linux的USB视频信号采集[J].电子设计应用,2009,2:40-42.

[2]戴丽.基于Video4Linux的USB摄像头图像采集实现[D].合肥工业大学,2008.

[3]毛德操,胡希明.Linux内核情景分析(下)[M].杭州:浙江大学出版社,2001.

[4]李善平等.Linux与嵌入式系统[M].北京:清华大学出版社,2002:236-418.

[5]孙天泽,袁文菊,张海峰.嵌入式设计及Linux驱动开发指南[M].北京:电子工业出版社,2006,1.

[6]黄智伟,邓月明,王彦.ARM9嵌入式系统设计基础教程[M].北京:北京航空航天大学出版社,2008.

上一篇:全民健身活动中群众体育意识形成的理论研究 下一篇:浅谈龙栖湾新区城市电网规划