摘 要: 提出了一種基于S3C2440 ARM處理器、USB攝像頭硬件平臺(tái)和嵌入式Linux操作系統(tǒng)的視頻采集系統(tǒng)方案。研究了USB攝像頭在Linux中的驅(qū)動(dòng)開發(fā),對(duì)系統(tǒng)總體結(jié)構(gòu)、基于V4L2的視頻采集以及視頻動(dòng)態(tài)顯示應(yīng)用程序等功能模塊設(shè)計(jì)做了具體介紹。試驗(yàn)結(jié)果表明,本系統(tǒng)實(shí)現(xiàn)了在LCD顯示器上動(dòng)態(tài)顯示USB攝像頭采集的圖像,且視頻采集穩(wěn)定,圖像幀過(guò)渡平穩(wěn),提供了一種成本低、體積小、功耗低的圖像采集方案,能夠很好地應(yīng)用在視頻監(jiān)控等系統(tǒng)中。
關(guān)鍵詞: 視頻采集;S3C2440;Linux;V4L2;Qtopia
隨著嵌入式系統(tǒng)、網(wǎng)絡(luò)和圖像信息技術(shù)的滲透,以及對(duì)設(shè)備體積和無(wú)線的要求越來(lái)越多,以嵌入式體系為核心的圖像采集系統(tǒng)已成為研究熱點(diǎn)。其中,嵌入式系統(tǒng)具有功耗低、體積小和集成接口豐富等優(yōu)點(diǎn)[1];嵌入式Linux系統(tǒng)具有源代碼開放、內(nèi)核穩(wěn)定、可裁減性、支持硬件廣泛及驅(qū)動(dòng)豐富等特點(diǎn),成為嵌入式系統(tǒng)領(lǐng)域不可或缺的操作系統(tǒng)之一;USB攝像頭具有性能好、價(jià)格低、使用方便、易于集成到嵌入式系統(tǒng)等特點(diǎn),在視頻監(jiān)控和網(wǎng)絡(luò)視頻會(huì)議等領(lǐng)域有廣泛應(yīng)用[2]。
本文以開發(fā)成本低、體積小、功耗低的嵌入式圖像采集系統(tǒng)為目標(biāo),采用ARM9處理器S3C2440和USB接口的攝像頭組成硬件體系,采用嵌入式Linux OS和Qtopia文件系統(tǒng)構(gòu)建應(yīng)用系統(tǒng),通過(guò)編寫USB攝像頭驅(qū)動(dòng)和Qt視頻顯示程序?qū)崿F(xiàn)視頻采集和視頻顯示程序,很好地完成了圖像采集的功能。由于本系統(tǒng)成本低、擴(kuò)展簡(jiǎn)單、體積小,能夠很好地?cái)U(kuò)展到和視頻相關(guān)的很多領(lǐng)域[3]。
1 系統(tǒng)硬件設(shè)計(jì)
系統(tǒng)硬件總體結(jié)構(gòu)如圖1所示,嵌入式處理器采用三星公司的基于ARM920T內(nèi)核的16/32位RISC嵌入式微處理器S3C2440,其主頻高達(dá)400 MHz,內(nèi)置豐富的外設(shè)資源,包括存儲(chǔ)器、LCD控制器、串口、I2C、I2S和USB等接口控制電路,主要面向高性價(jià)比、低功耗的應(yīng)用,適合于圖像和視頻處理。Flash存儲(chǔ)器采用64 MB NAND存儲(chǔ)器用于存放Linux操作系統(tǒng)啟動(dòng)引導(dǎo)程序Bootloader、Linux系統(tǒng)內(nèi)核、Qt文件系統(tǒng)及系統(tǒng)掉電后要保存的數(shù)據(jù)。SDRAM中用于存放Linux系統(tǒng)運(yùn)行時(shí)的一些臨時(shí)數(shù)據(jù)。LCD顯示器大小為4.3英寸,480×272分辨率,并帶有觸摸屏[4]。
目前用于攝像頭的控制芯片組主要有中芯微公司的ZC0301P和美國(guó)OV公司的OV511+芯片。國(guó)內(nèi)市場(chǎng)上的USB攝像頭基本上采用的是ZC0301P,并且中芯微公司的主流控制芯片都帶有硬件JPEG編碼模塊,利用這個(gè)特性可以直接從攝像頭得到經(jīng)過(guò)壓縮的圖片格式,可以簡(jiǎn)化應(yīng)用軟件的設(shè)計(jì),因此本設(shè)計(jì)采用ZC0301P芯片的130萬(wàn)像素的USB攝像頭。
在硬件系統(tǒng)中,通過(guò)USB接口將攝像頭與S3C2440相接。利用USB接口進(jìn)行通信只需要在Linux內(nèi)核中增加USB驅(qū)動(dòng)支持和加載ZC0301P硬件驅(qū)動(dòng)模塊。這樣的驅(qū)動(dòng)設(shè)計(jì)充分地利用了Linux模塊化的設(shè)計(jì)特點(diǎn),同時(shí)也有利于軟件的設(shè)計(jì)和調(diào)試。
2 嵌入式Linux系統(tǒng)設(shè)計(jì)
2.1 宿主機(jī)開發(fā)環(huán)境的建立
通常嵌入式系統(tǒng)的軟件編譯和運(yùn)行是在兩個(gè)不同平臺(tái)上進(jìn)行的,編譯是在宿主機(jī)上,通常是PC;運(yùn)行是在目標(biāo)板上,即S3C2440平臺(tái)。一般是在宿主機(jī)上通過(guò)跨平臺(tái)交叉編譯器把源文件編譯成可在目標(biāo)平臺(tái)上執(zhí)行的文件,再通過(guò)串口等方式下載到目標(biāo)平臺(tái)上的NAND或NOR存儲(chǔ)器上,然后由目標(biāo)機(jī)來(lái)運(yùn)行此軟件。本系統(tǒng)采用的交叉編譯器為arm-linux-gcc-4.3.3。
在宿主機(jī)上首先要安裝Linux操作系統(tǒng),本文使用的是Fedora10。此外,在系統(tǒng)中建立了交叉編譯環(huán)境。這樣,嵌入式Linux的開發(fā)環(huán)境就搭建完成了[5]。
2.2 搭建嵌入式Linux系統(tǒng)平臺(tái)
在目標(biāo)平臺(tái)上構(gòu)建一個(gè)完整的嵌入式Linux系統(tǒng)一般需要Bootloader引導(dǎo)程序、Linux內(nèi)核以及根文件系統(tǒng)3個(gè)內(nèi)容。
2.2.1 Bootloader引導(dǎo)程序
Bootloader引導(dǎo)程序是嵌入式開發(fā)很重要的組成部分。Boofloader引導(dǎo)程序最基本的功能是對(duì)硬件系統(tǒng)的初始化和內(nèi)核啟動(dòng)參數(shù)設(shè)置并啟動(dòng)內(nèi)核。在嵌入式系統(tǒng)開發(fā)過(guò)程中,Bootloader還與主機(jī)通信,不斷檢測(cè)從主機(jī)傳來(lái)的控制信息和數(shù)據(jù)信息,完成相應(yīng)的操作。本系統(tǒng)中使用的是U-Boot引導(dǎo)程序。下載U-Boot源碼后,在宿主機(jī)交叉編譯器中編譯出啟動(dòng)代碼的可執(zhí)行文件,下載到開發(fā)板中即可。
2.2.2 Linux操作系統(tǒng)的移植
下載linux-2.6.30內(nèi)核,并解壓Linux內(nèi)核到linux-2.6.30目錄。然后修改此目錄下的Makefile文件,需改的主要內(nèi)容是目標(biāo)代碼的類型和為編譯內(nèi)核指定一個(gè)編譯器。注釋掉以下內(nèi)容:
#ARCH?=$(SUBARCH)
#CROSS-COMPILE?=
增加如下內(nèi)容:
ARCH=arm
CROSS-COMPILE=arm-inux-
做完以上修改以后,內(nèi)核編譯以后就可在硬件板上運(yùn)行了。
2.2.3 建立根文件系統(tǒng)
根文件系統(tǒng)一直以來(lái)是所有UNIX類操作系統(tǒng)的一個(gè)核心組成部分,在內(nèi)核啟動(dòng)的最后階段,所執(zhí)行的操作之一就是掛載根文件系統(tǒng)。Linux的根文件系統(tǒng)包含內(nèi)核所需的文件和可執(zhí)行文件,還有用于系統(tǒng)管理的可執(zhí)行文件。在網(wǎng)上下載YAFFS文件系統(tǒng)代碼,并修改配置文件使之適用于本目標(biāo)平臺(tái)。配置Linux內(nèi)核,使內(nèi)核支持MTD(Memory Technology Devices)和YAFFS。重新編譯內(nèi)核并將內(nèi)核下載到開發(fā)板的Flash中,然后把編譯好的文件系統(tǒng)下載到開發(fā)板中。啟動(dòng)內(nèi)核,就可以看到在LCD中顯示Qt界面,這樣一個(gè)完整的Linux系統(tǒng)平臺(tái)就建立好了。
3 視頻采集的實(shí)現(xiàn)
3.1 攝像頭驅(qū)動(dòng)及V4L2簡(jiǎn)介
在Linux下,設(shè)備驅(qū)動(dòng)程序可以看成Linux內(nèi)核與外部設(shè)備之間的接口。設(shè)備驅(qū)動(dòng)程序向應(yīng)用程序屏蔽硬件實(shí)現(xiàn)的細(xì)節(jié),使得應(yīng)用程序可以像操作普通文件一樣來(lái)操作外部設(shè)備,可以使用和操作文件中相同的、標(biāo)準(zhǔn)的系統(tǒng)調(diào)用接口函數(shù)來(lái)完成對(duì)硬件設(shè)備的打開、關(guān)閉、讀寫和I/O控制操作,而驅(qū)動(dòng)程序的主要任務(wù)也就是要實(shí)現(xiàn)這些系統(tǒng)調(diào)用函數(shù)。
對(duì)于USB口攝像頭,其驅(qū)動(dòng)程序中提供了基本的I/O操作接口函數(shù)open、read、write、close的實(shí)現(xiàn)以及對(duì)I/O通道的控制接口函數(shù)ioctl的實(shí)現(xiàn)等,并定義在struct file_operations中。
Video4Linux2(V4L2)是Linux中關(guān)于視頻設(shè)備的內(nèi)核驅(qū)動(dòng),它為針對(duì)視頻設(shè)備的應(yīng)用程序編程提供一系列接口函數(shù),這些視頻設(shè)備包括現(xiàn)今市場(chǎng)上流行的TV卡、視頻捕捉卡和USB攝像頭等。Linux內(nèi)核提供Video4Linux2應(yīng)用程序接口,在程序開發(fā)時(shí)首先是基于Video4Linux2 API函數(shù)來(lái)設(shè)計(jì)程序[6]。
3.2 Video4Linux2下的攝像頭采集編程
在USB攝像頭被驅(qū)動(dòng)后,只需要再編寫一個(gè)對(duì)視頻采集的應(yīng)用程序就可以了,根據(jù)嵌入式系統(tǒng)開發(fā)特征,先在宿主機(jī)上編寫應(yīng)用程序,再使用交叉編譯器進(jìn)行編譯鏈接,生成在目標(biāo)平臺(tái)的可執(zhí)行文件。宿主機(jī)與目標(biāo)板通常采用打印終端的方式進(jìn)行交叉調(diào)試,成功后移植到目標(biāo)平臺(tái)。本文編寫的視頻采集程序是在安裝Linux操作系統(tǒng)的宿主機(jī)PC上進(jìn)行的,下面是具體論述[7]。
程序中定義的重要數(shù)據(jù)結(jié)構(gòu)為:
struct v4l2_capability cap;
struct v4l2_fmtdesc fmtdesc;
struct v4l2_format fmt;
struct v4l2_requestbuffers req;
struct v4l2_buffer buf;
這些數(shù)據(jù)結(jié)構(gòu)都是Video4Linux2支持的,它們的用途如下。
?。?)v4l2_capability包含攝像頭的基本信息,例如設(shè)備名稱、支持的最大及最小分辨率、信號(hào)源信息等,分別對(duì)應(yīng)著結(jié)構(gòu)體中成員變量name、maxwidth、maxheight、minwidth、minheight、channels、type等;
?。?)struct v4l2_fmtdesc獲取設(shè)備支持的視頻格式;
?。?)v4l2_format fmt設(shè)置視頻捕獲格式;
(4)v4l2_requestbuffers用于請(qǐng)求分配內(nèi)存;
?。?)v4l2_buffer代表驅(qū)動(dòng)中的一幀。
Linux下視頻圖像采集流程如圖2所示。
(1)打開視頻設(shè)備,獲得文件描述符
攝像頭在系統(tǒng)中對(duì)應(yīng)的設(shè)備文件為/dev/video0,采用系統(tǒng)調(diào)用函數(shù)video_fd=open(“/dev/video0”, O_RDWR,0),video_fd為設(shè)備打開后返回的文件描述符,以后的系統(tǒng)調(diào)用函數(shù)就可以使用它來(lái)對(duì)設(shè)備文件進(jìn)行操作了。接著用ioctl(video_fd,VIDIOC_QUERYCAP,&cap)函數(shù)讀取v4l2_capability中的有關(guān)攝像頭的信息。該函數(shù)成功返回后,這些信息從內(nèi)核空間拷貝到用戶程序空間capability各成員分量中,使用printf函數(shù)就可以得到各成員分量信息。
(2)設(shè)置圖片格式
將圖片寬設(shè)為320,高設(shè)為240,其他參數(shù)保持默認(rèn)。
struct v4l2_format fmt;
CLEAR(fmt);
fmt.type=V4L2_BUF_TYPE_VIDEO_CAPTURE;
fmt.fmt.pix.width=320;
fmt.fmt.pix.height=240;
fmt.fmt.pix.field=V4L2_FIELD_INTERLACED;
fmt.fmt.pix.pixelformat=VIDEO_FORMAT;
if(ioctl(video_fd,VIDIOC_S_FMT,&fmt)<0)
{
exit(1);
}
?。?)分配緩沖區(qū)
struct v4l2_requestbuffers req;
CLEAR(req);
req.count=4;
req.type=V4L2_BUF_TYPE_VIDEO_CAPTURE;
req.memory=V4L2_MEMORY_MMAP;
if(ioctl(video_fd,VIDIOC_REQBUFS,&req)<0)
{
exit(1);
}
然后通過(guò)調(diào)用ioctl(video_fd,VIDIOC_QUERYBUF,&buf)獲得緩沖區(qū)的長(zhǎng)度(buf.length)和偏移地址(fd,buf.m.offset),將這兩個(gè)參量作為參數(shù)傳給mmap函數(shù):
buffers[num].start=mmap(NULL,buf.length,PROT_READ|PROT_WRITE,MAP_SHARED,fd,buf.m.offset);
緩沖區(qū)分配好之后,驅(qū)動(dòng)并不會(huì)向里面寫入數(shù)據(jù),還需要將每個(gè)緩沖區(qū)放入視頻采集隊(duì)列:
ioctl(video_fd,VIDIOC_QBUF,&buf);
(4)啟動(dòng)采集過(guò)程,讀取數(shù)據(jù)
完成以上初始化設(shè)置工作后,就可以對(duì)視頻進(jìn)行采集了,有直接讀取read()和內(nèi)存映射mmap()兩種方法。read()通過(guò)內(nèi)核緩沖區(qū)來(lái)讀取數(shù)據(jù);而mmap()通過(guò)把設(shè)備文件映射到內(nèi)存中,繞過(guò)了內(nèi)核緩沖區(qū),最快的磁盤訪問(wèn)往往還是慢于最慢的內(nèi)存訪問(wèn),因此mmap()方式加速了I/O訪問(wèn)。另外,mmap()系統(tǒng)調(diào)用使得進(jìn)程之間通過(guò)映射同一文件實(shí)現(xiàn)共享內(nèi)存,各進(jìn)程可以像訪問(wèn)普通內(nèi)存一樣對(duì)文件進(jìn)行訪問(wèn),訪問(wèn)時(shí)只需要使用指針而不用調(diào)用文件操作函數(shù)。因?yàn)閙map()的以上優(yōu)點(diǎn),所以在程序?qū)崿F(xiàn)中采用內(nèi)存映射方式。
應(yīng)用程序調(diào)用VIDIOC_STREAMON來(lái)啟動(dòng)采集過(guò)程:
enum v4l2_buf_type type=
V4L2_BUF_TYPE_VIDEO_CAPTURE;
ioctl(fd,VIDIOC_STREAMON,&type);
采集過(guò)程開始以后,驅(qū)動(dòng)會(huì)不停地將數(shù)據(jù)寫入分配的緩沖區(qū)內(nèi),當(dāng)一個(gè)緩沖區(qū)的數(shù)據(jù)準(zhǔn)備就緒后,驅(qū)動(dòng)就會(huì)將其放入輸出隊(duì)列,等待應(yīng)用程序的處理。當(dāng)所有的緩沖區(qū)都進(jìn)入輸出隊(duì)列后,驅(qū)動(dòng)將停止采集,并等待緩沖區(qū)重新放入采集隊(duì)列。讀取數(shù)據(jù)時(shí),首先需要將一個(gè)緩沖區(qū)出隊(duì)列:
struct v4l2_buffer buf;
ioctl(fd,VIDIOC_DQBUF,&buf);
驅(qū)動(dòng)會(huì)從輸出隊(duì)列取出一個(gè)緩沖區(qū),并將其序號(hào)賦值給buf.index,應(yīng)用程序可以通過(guò)buffers[buf.index].start來(lái)訪問(wèn)緩沖區(qū)的數(shù)據(jù)。當(dāng)處理完成后,需要將其重新放入采集隊(duì)列:
ioctl(fd,VIDIOC_QBUF,&buf);
?。?)停止采集
首先停止采集過(guò)程ioctl(fd,VIDIOC_STREAMOFF,&type),然后使用munmap函數(shù)刪除映射,最后調(diào)用close(fd)函數(shù)關(guān)閉設(shè)備。
視頻圖像顯示模塊使用GUI軟件提供的API函數(shù)的方法進(jìn)行視頻圖像顯示。視頻顯示程序基于Qt庫(kù)來(lái)編寫,原理是將buf的內(nèi)容轉(zhuǎn)為image再轉(zhuǎn)為pixmap,然后顯示出來(lái)。按照以上編寫流程編寫視頻顯示程序后,通過(guò)交叉編譯器編譯出目標(biāo)平臺(tái)能夠執(zhí)行的代碼,下載到開發(fā)板中,即可實(shí)現(xiàn)視頻的實(shí)時(shí)采集。
4 測(cè)試結(jié)果與分析
在目標(biāo)平臺(tái)上運(yùn)行編寫的視頻采集程序,攝像頭所采集到的實(shí)時(shí)動(dòng)態(tài)圖像的截圖如圖3所示。從圖中可以看出,該系統(tǒng)所提供的視頻畫面圖像質(zhì)量較好,完全可以滿足實(shí)際應(yīng)用中對(duì)畫面質(zhì)量的要求。
采用內(nèi)嵌ARM9核的S3C2440嵌入式微控制器和ZC0301P視頻處理芯片,同時(shí)結(jié)合Linux的Video4Linux視頻接口技術(shù)和視頻流傳輸技術(shù),實(shí)現(xiàn)了快速視頻采集的應(yīng)用[8]。實(shí)踐表明,采用高性能的ARM9核的微控制器和嵌入式Linux操作系統(tǒng),使視頻采集系統(tǒng)的視頻畫面清晰流暢,其性能優(yōu)越、穩(wěn)定而且構(gòu)建成本低。該方案可以廣泛應(yīng)用于視頻通信和現(xiàn)場(chǎng)監(jiān)測(cè)等智能控制領(lǐng)域,具有廣闊的應(yīng)用前景。
參考文獻(xiàn)
[1] SAMSUNG ELECTRONICS. S3C2440 user′s manual(Revision 1.2)[Z], 2003.
[2] 杜春雷.ARM體系結(jié)構(gòu)與編程[M].北京:清華大學(xué)出版社,2003.
[3] 孫天澤,袁文菊,張海峰.嵌入式設(shè)計(jì)及Linux驅(qū)動(dòng)開發(fā)指南[M].北京:電子工業(yè)出版社,2005.
[4] RUBINI A. L INUX設(shè)備驅(qū)動(dòng)程序[M].魏永明,譯.北京:中國(guó)電力出版社,2002.
[5] 劉崢嶸,張智超,許振山.嵌入式Linux應(yīng)用開發(fā)詳解[M].北京:機(jī)械工業(yè)出版社,2004.
[6] COX A. Video 4 Linux Programming[EB/OL]. www.redhat. com.
[7] 王艷,吳旭光,趙勛峰.基于ARM的嵌入式手持掃描設(shè)備的系統(tǒng)設(shè)計(jì)[J].電子測(cè)量技術(shù),2007(3):47-49.
[8] 賈明,嚴(yán)世賢.Linux下的C編程[M].北京:人民郵電出版社,2001.