王建新,张 凯,王 秀
(西安科技大学雁塔校区通信与信息工程学院,西安710054)
目前,各种视频采集以及传输的系统都是由DSP(图像处理),ARM(图像显示)以及利用FPGA搭建整个框架[1],这样会造成资源严重浪费,并且成本较大。随着嵌入式技术的迅猛发展,利用嵌入式实现远程视频采集、可视电话会议等应用已经成为可能。
本文基于 S3C2440和 Linux系统平台,采用USB摄像头捕捉视频信号,利用V4L2应用编程接口函数,实现了视频连续帧图像的采集,并利用TCP传输方式传输给服务器端,实现对嵌入式视频远程传输。开发的终端具有体积小,功耗低,适用于便携式视频采集需要。
本文以三星公司S3C2440为硬件平台,其片上64 M SDRAM可以满足视频采集软件的内存需要,256 M NAND FlLASH用于存放文件和系统,3个通道的UART等控制器和丰富的接口,使其扩展功能强大,功耗低,简单稳定符合要求。整个硬件框架如图1所示。
图1 系统硬件架构
视频采集传输系统软件架构由以下部分组成:USB(ZC301)摄像头,摄像头驱动,视频采集应用程序,视频传输,视频显示组成。如图2所示。
图2 视频采集传输系统软件构架
USB摄像头进行采集图像数据,采集图像格式为MJPE,采集应用程序通过摄像头驱动从摄像头获得采集的图像数据。利用V4L2接口函数对设备采集的数据进行操作,最后通过网络传输(TCP)将数据传输给PC机进行显示[2]。
Linu系统具有开源性,高可靠性和强大的网络功能等特点。在此基于linux2.6内核,对其进行裁剪和配置,使内核支持USB驱动和V4L2标准,建立交叉编译环境,移植编译好的内核到目标板,以构建linux文件系统,进行视频采集传输应用程序的开发。
在linux系统下,图像采集设备依赖于V4L2(Video 4 linux 2)标准支持,它针对linux内核视频设备提供了一系列API接口函数[3],视频采集流程如图3所示。
①打开视频设备
在V4L2中,视频设备被看作一个文件。使用open()函数以阻塞模式打开摄像头设备,函数格式为:
open()函数中包含两个参数,第1个参数代表打开的设备文件名,第2个参数代表设备的打开类型(读/写,阻塞或非阻塞),返回值为文件描述符fd,若返回值为大于0,则打开设备正确;若返回值为-1,则打开设备错误。
②初始化设备,包括获取设备信息,设置设备格式,函数格式为:
图3 视频采集流程
③设置视频捕获格式
当检测完视频设备支持的标准后,还需要设定视频捕获格式,函数格式如下:
④分配内存
向驱动申请帧缓冲,一般不超过5个。使用ioctl命令字VIDIOC_REQBUFS来调用struct v4l2_requestbuffers,v4l2_requestbuffers结构中定义了缓存的数量,驱动会据此申请对应数量的视频缓存。
⑤获取并记录缓存的物理空间
使用VIDIOC_REQBUFS,获取两个缓存,并通过调用VIDIOC_QUERYBUF命令来获取这些缓存的地址,再使用mmap()函数转换成应用程序中的绝对地址,最后把这段缓存放入缓存队列。使用V4L2进行图像采集时候,在一帧缓冲完成之后,都会将第二帧覆盖到另一个缓存中,req.count个缓存轮流使用,不丢数据。函数格式如下:
ioctl(fd,VIDIOC_QUERYBUF,&buf);//获取到对应index的缓存信息,此处主要利用length信息及offset信息来完成后面的mmap操作。与用户空间传递数据的一个中介,会被循环利用。
⑥图像数据采集
V4L2有三种视频图像采集方式:read()、write()方式,内存映射方式和用户指针方式。
本文采用的内存映射方式是在内核空间开辟一段地址空间,通过mmap()系统调用将其映谢到地址空间。
图像采集过程中需要使用两个ioctl的命令:即VIDIOC_DQBUF和VIDIOC_QBUF命令。函数格式为:
在配置内核时候,对USB驱动初始化,我们加上V4L2,并修改.config文件,支持ZC301摄像头,然后进行编译成内核镜像。
常用的图像传输协议有TCP协议和UDP协议。
TCP是传输控制协议,是一种面向连接(连接导向)的、可靠的、基于字节流的运输层通信协议。UDP即用户数据报协议,是一种无连接协议,传输数据之前客户端和服务器端不建立连接[4]。
在传输过程中,TCP在丢包方面比UDP严密,不容易丢包。因此本文为利用TCP协议来传输数据,首先初始化摄像头利用V4L2接口,连接到linux系统的公用协议标准,然后将数据存放至缓冲区,产生数据包,并且将数据包利用TCP传输,最后传输到 PC 机并显示出来[5]。
在linux中网络编程是通过socket接口来进行的。Socket是一种常用的进程之间的通信机制。TCP协议下的socket编程流程图,如图4所示。
Socket编程基本函数有 socket()、bind()、listen()、accept()、Send()以及 Recv()等,其中根据客户端还是服务器,这些函数的调用流程有所区别,这里对每个函数进行简明:
图4 TCP协议socket编程流程图
Socket():该函数用于建立一个socket连接,可以指定socket类型信息,对结构体sockaddr_in初始化:包含地址族,端口号,IP地址等;
Bind()该函数用于将本地IP地址绑定到端口号,若绑定其他IP地址则不成功。另外还用于TP连接;
Listen():服务端程序成功建立套接字和地址进行绑定之后,还需要准备在该套接字上接受新的连接请求;
Accept():调用accept()函数等待并且接收客户端的连接请求;
Connect():用于与服务器建立连接;
Send()与Recv():分别用于发送和接收数据。
搭建目标机linux2.6.32运行环境,并且通过宿主机使用交叉编译器连接生成可执行文件,向目标机移植后运行。
将USB摄像头同目标机连接好了之后,若成功挂载USB摄像头,则终端下会显示识别USB设备,如图5所示。
图5 USB摄像头驱动测试结果
对整个系统进行测试,该系统在传输320×240大小并以MJPEG编码的视频时,视频监控服务器端观察图像流畅并且清晰,足够满足视频监控需求,如图6所示。
图6 系统测试结果
本文提出一种基于S3C2440平台和嵌入式linux系统的C/S模型视频采集和传输方案,采用普通市面上的USB摄像头,极大的降低了成本,利用socket编程实现TCP网络传输过程,经测试,服务器端可以实时的接受到采集传输的视频,图像清晰,满足视频监控要求。
[1]周立功.ARM&WinCE实验与实践—基于S3C2410[M].北京:北京航空航天大学出版社,2007.
[2]王培珍,徐俊生.基于ARM9的嵌入式linux图像采集设计系统[J].中国制造业信息化,2007,10:85-88
[3]李新峰,何广生,赵秀文.基于ARM9的嵌入式Linux开发技术[M].北京:电子工业出版社,2008,10:118-127
[4]陈文智.嵌入式系统开发原理与实践[M].北京:清华大学出版社,2005.
[5]怯肇乾.嵌入式网络通信开发应用[M].北京:北京航空航天大学出版社,2010.
[6]吴明晖.基于ARM的嵌入式系统开发和应用[M].北京:人民邮电出版社,2005.
[7]江湖,苏详芳,刘立海,等.基于网络的数字视频监控系统[J].武汉大学学报(自然科学版),2000,46(5):608-612.
[8]Lu Yinli,Yu Hongli,Zhang Pengpeng.The Implementation of Embedded Image Acquisition Based on V4L2[C]//Electronics,Communications and Control(ICECC),2011 International Conference.Heng yang,China.2011:549-552