劉 澤,陳 洋,陳 林
(重慶郵電大學(xué),重慶400065)
嵌入式視頻采集系統(tǒng)軟件平臺大多用的是Linux 系統(tǒng),V4L2 是Linux 內(nèi)核采用的視頻采集基本框架,相比于V4L,V4L2 更靈活,擴(kuò)展性也更好一些,由于V4L2 對V4L 的改動較大,兩者并不兼容[1]。V4L2 支持多種設(shè)備,并且支持視頻采集接口、視頻輸出接口等。視頻采集采用的流水線方式使得V4L2 的操作極其簡單方便。V4L2 中還提供大量API 來對攝像頭進(jìn)行基本操作,這些操作主要通過調(diào)用ioctl 來實(shí)現(xiàn)設(shè)備打開、關(guān)閉,以及圖像格式、曝光、增益等操作[2],一般V4L2 驅(qū)動是讓CPU 通過I2C 總線對圖像傳感器進(jìn)行讀寫操作,I2C 總線包括數(shù)據(jù)總線和時鐘總線,主要由三部分構(gòu)成:I2C 總線驅(qū)動、I2C 設(shè)備驅(qū)動和I2C 核心[3]。
本文采用MT9M001 圖像傳感器,開發(fā)出支持曝光、增益以及圖片尺寸大小等參數(shù)設(shè)置的驅(qū)動程序,CPU 采用TI 公司的AM3354,由于該芯片并沒有標(biāo)準(zhǔn)的攝像頭接口,硬件方案采用CPLD+SRAM 方式對CMOS 傳感器采集數(shù)據(jù)進(jìn)行預(yù)處理和緩存,并參照Linux 自帶虛擬攝像頭ViVi,設(shè)計出具有兩個線程的驅(qū)動程序,詳細(xì)給出了非標(biāo)準(zhǔn)攝像頭接口的V4L2驅(qū)動程序的設(shè)計過程,最后調(diào)用動態(tài)庫API 來實(shí)現(xiàn)抓圖。
Linux 提供了虛擬攝像頭驅(qū)動程序ViVi,其框架也是基于V4L2 標(biāo)準(zhǔn),V4L2 主要包括V4L2 驅(qū)動核心、字符設(shè)備驅(qū)動核心、平臺V4L2 驅(qū)動以及具體傳感器驅(qū)動,見圖1。
圖1 V4L2 驅(qū)動框架
V4L2 作為兩層驅(qū)動系統(tǒng),在videodev 頂層模塊,初始化時會被注冊為主設(shè)備號為81 的字符設(shè)備,底層則是以videodevice 為核心的V4L2 驅(qū)動,該結(jié)構(gòu)主要包含了功能函數(shù)以及視頻設(shè)備的屬性。此外videodev 模塊還提供video_device_register 函數(shù)API 來注冊V4L2 驅(qū)動,生成視頻設(shè)備節(jié)點(diǎn),比如/dev/video1 等。V4L2 驅(qū)動源碼位于內(nèi)核目錄/driver/media/video 下面,主要核心代碼文件有[4]:
1)v4l2-dev.c 視頻捕捉接口,主要數(shù)據(jù)結(jié)構(gòu)為:struct video-device,主要用于射頻設(shè)備的注冊。
2)v4l2-device.c v4l2 提供設(shè)備描述,主要用于注冊v4l2設(shè)備。
3)v4l2-ioctl.c 為ioctl 提供了通用框架,主要是為了實(shí)現(xiàn)結(jié)構(gòu)體v4l2_ioctl_ops 視頻操作相關(guān)聯(lián)下的API。
4)v4l2-mem2mem.c 內(nèi)存之間的操作函數(shù),是內(nèi)核和視頻設(shè)備緩沖之間的框架。
5)v4l2-common.c 通用視頻的設(shè)備接口,此文件替換videodevice.c 文件配備常規(guī)內(nèi)核分配。
在V4L2 核心中,提供了一套標(biāo)準(zhǔn)API 來用于視頻處理緩沖器,這些API 允許驅(qū)動程序用自己的方式實(shí)現(xiàn)read()、mmap()等[5]。
目前設(shè)備上的視頻緩沖器,支持線性存取DMA 的方式。Videobuf 層實(shí)現(xiàn)了用戶空間與驅(qū)動程序之間數(shù)據(jù)傳輸?shù)恼澈闲?,主要用于幀緩沖管理和分配。Videobuf 層的更多相關(guān)信息,在內(nèi)核目錄的Documentation/video4linux/videobuf 中有詳細(xì)說明。
圖像傳感器采用的是micron 公司的MT9M001 CMOS 圖像傳感器,該傳感器幀率最大為30 f/s(幀/秒),即1 s 最大可以采集30 幀圖像數(shù)據(jù),最大支持130 萬像素。性能優(yōu)異,由于圖像傳感器采集的數(shù)據(jù)是10 位的灰度值,實(shí)際采集使用時舍去兩位,保存為8 位位圖格式來降低存儲空間。
主控芯片采用的是cortex A8 系列的ARM 處理器AM3354,工作時鐘最大為800 MHz,具有抗高溫、抗干擾等特點(diǎn),完全可以滿足高清工業(yè)相機(jī)對CPU 的要求。
在主線程中,會注冊I2C 設(shè)備,通過檢查設(shè)備的名字,若有相同名字的設(shè)備probe 函數(shù)便會被調(diào)用,在驅(qū)動探測函數(shù)中需要使能圖像傳感器。通過傳感器的ID 號0x8431 來完成初始化。
reg_write(cmos_mt9m001_client,MT9M001_CHIP_ENABLE,1);
mid=reg_read(cmos_mt9m001_client,MT9M001_CHIP_VERSION);
if(mid!=0x8431)return ENXIO;
若能識別傳感器ID 號,說明傳感器被正確連接。應(yīng)用程序調(diào)用open 打開注冊的視頻設(shè)備節(jié)點(diǎn)時,驅(qū)動中的open 函數(shù)會被執(zhí)行,在open 函數(shù)中會創(chuàng)建一個負(fù)責(zé)讀取傳感器數(shù)據(jù)的子線程,在子線程被創(chuàng)建后會一直休眠。
kthread_run(cmos_buffer,dev,dev->v4l2_dev.name);
set_current_state(TASK_INTERRUPTIBLE);
wait_for_completion(&thread_completion);
此處采用CPLD 來預(yù)處理一幀的圖像數(shù)據(jù),當(dāng)CPLD 完成一幀數(shù)據(jù)的預(yù)處理后,通過CPLD 產(chǎn)生邊沿觸發(fā)信號來對視頻數(shù)據(jù)進(jìn)行讀取,同時在open 函數(shù)中會申請cpld_int 內(nèi)核中斷函數(shù):
ret =request_irq(CPLD_IRQ,cpld_int,IRQF_TRIGGER_FALLING,"frame_interrupt",NULL);
CPLD 完成預(yù)處理后會向CPU 發(fā)出中斷,中斷函數(shù)會被調(diào)用,在中斷處理函數(shù)中會調(diào)用完成量喚醒創(chuàng)建的子線程。
子線程會對緩沖區(qū)隊(duì)列數(shù)據(jù)進(jìn)行處理,其運(yùn)行結(jié)束后會喚醒應(yīng)用程序采集,一幀圖像數(shù)據(jù)處理完成,總結(jié)主次線程流程見圖2。
圖2 主次線程執(zhí)行流程
在內(nèi)核下的video_buf.c 中提供了V4L2 視頻緩沖區(qū)內(nèi)存管理的函數(shù),視頻的數(shù)據(jù)隊(duì)列通過videobuf_queue 結(jié)構(gòu)體來管理,在此結(jié)構(gòu)體中通過videobuf_queue_ops 結(jié)構(gòu)體來進(jìn)行相關(guān)視頻緩沖區(qū)操作,數(shù)據(jù)結(jié)構(gòu)里主要提供API 來進(jìn)行緩存區(qū)的具體操作。buffer_prepare 用來準(zhǔn)備好隊(duì)列中的幀緩沖,buffer_queue 用來將buffer 加入對列,buffer_cleanup 則用來清除對列[6]。
視頻采集主要基于ioctl 操作集來實(shí)現(xiàn),Linux 內(nèi)核專門提供v4l2_ioctl_ops 結(jié)構(gòu)體來管理緩沖區(qū)數(shù)據(jù)。常用函數(shù)說明如表1。
表1 v4l2_ioctl_ops 操作集
表中每一個ioctl 對應(yīng)一個API 接口,這些API 需要手動實(shí)現(xiàn)[7]。視頻采集一幀數(shù)據(jù)流程如圖3 所示。
圖3 視頻采集基本流程
在對圖像數(shù)據(jù)進(jìn)行采集時,在沒有DMA 情況下,直接read 和write 方式從內(nèi)核空間拷貝大量數(shù)據(jù)到用戶空間的方式,不僅耗費(fèi)大量內(nèi)存,效率也十分低下[8]。本驅(qū)動采用內(nèi)存映射的方式,向內(nèi)和空間申請2 ~4 個緩沖區(qū),當(dāng)應(yīng)用程序調(diào)用mmap 函數(shù)時,驅(qū)動程序不再是直接拷貝數(shù)據(jù)到用戶空間,而是利用mmap 來建立緩沖區(qū)和用戶空間的映射,即直接對用戶空間進(jìn)行操作,效率大大提高。驅(qū)動程序建立映射只需對數(shù)據(jù)結(jié)構(gòu)v4l2_file_operations 成員函數(shù)mmap 填充即可。
本驅(qū)動中還支持設(shè)置采集圖片尺寸大小以及曝光、增益等的設(shè)置。其中v4l2_ctrl_ops 結(jié)構(gòu)體中的成員函數(shù)s_ctrl 用來設(shè)置曝光增益值,而g_volatile_ctrl 用來獲取曝光值。
硬件環(huán)境搭載好后,通過makefile 將驅(qū)動程序生成.ko 文件,將.ko 文件用insmod 命令安裝驅(qū)動。會在文件目錄/dev下自動生成video1 文件,此文件就是V4L2 驅(qū)動掛載點(diǎn),對驅(qū)動程序進(jìn)行測試時,將測試程序封裝為動態(tài)庫,動態(tài)庫中各個API 說明如表2。
表2 動態(tài)庫API 功能說明
上述API 中,CameraImageProcess 比較關(guān)鍵,因?yàn)槠漕A(yù)留出圖像數(shù)據(jù)數(shù)組指針,實(shí)際需要對圖像進(jìn)行分析處理時,只需獲得該API 參數(shù)指針進(jìn)行操作即可,圖4 和圖5 為調(diào)用封裝動態(tài)庫采集圖片。
本文針對cortexA8 硬件平臺以及cmos 圖像傳感器mt9m001,實(shí)現(xiàn)一款針對非標(biāo)準(zhǔn)攝像頭接口的V4L2 驅(qū)動,詳細(xì)闡述了程序的設(shè)計思路以及實(shí)現(xiàn)應(yīng)用程序動態(tài)庫的封裝,并在驅(qū)動程序中實(shí)現(xiàn)了對曝光、增益值得設(shè)置。最后通過調(diào)用應(yīng)用程序封裝的動態(tài)庫采集圖片來驗(yàn)證驅(qū)動的正確性,對沒有標(biāo)準(zhǔn)攝像頭接口的平臺開發(fā)具有一定借鑒意義。
圖4 未設(shè)置曝光增益采集的圖片
圖5 加入曝光增益設(shè)置采集的圖片
[1]王飛,孔聰. 基于V4L2 的Linux 攝像頭驅(qū)動的實(shí)現(xiàn)[J]. 電子科技,2012,25(2):86-87.
[2]黃俊偉,巴義. 基于V4L2 移動視頻監(jiān)控系統(tǒng)的研究與設(shè)計[J]. 電視技術(shù),2012,36(17):159-162.
[3]宋寶華.Linux 設(shè)備驅(qū)動開發(fā)詳解[M].北京:人民郵電出版社,2008.
[4]蔡小偉.基于ARM cortex A8 的嵌入式視頻監(jiān)控系統(tǒng)設(shè)計[D].南昌:南昌大學(xué),2013.
[5]廖夢云,趙利,莫金旺.基于CMOS 圖像傳感器的嵌入式視頻采集系統(tǒng)設(shè)計[J].計算機(jī)系統(tǒng)應(yīng)用,2009(5):194-197.
[6]余臣.高分辨率高速CMOS 相機(jī)的硬件設(shè)計[D].成都:電子科技大學(xué),2011.
[7]劉登誠,沈蘇彬,李莉. 基于V4L2 的視頻驅(qū)動程序設(shè)計與實(shí)現(xiàn)[J].微計算機(jī)信息,2011,27(10):56-58.
[8]叢培超.高幀高清CMOS 工業(yè)攝像機(jī)設(shè)計與實(shí)現(xiàn)[D].大連:大連理工大學(xué),2013.