必威电竞|足球世界杯竞猜平台

Video4Linux
來源:互聯網

Video4Linux(簡V4L)是Linux中關于視頻設備的內核驅動,它為針對視頻設備的應用程序編 程提供一系列接口函數,這些視頻設備包括現今市場上流行的TV卡、視頻捕捉卡和USB攝像頭等。對于USB口攝像頭,其驅動程序中需要提供基本的I/O操 作接口函數open、read、write、close的實現。

簡介

對中斷的處理實現,內存映射功能以及對I/O通道的控制接口函數ioct1的實現等,并把 它們定義在struct file_operations中。這樣當應用程序對設備文件進行諸如open、close、read、write等系統(tǒng)調用操作時,Linux內核將通 過file_operations結構訪問驅動程序提供的函數。例如,當應用程序對設備文件執(zhí)行讀操作時,內核將調用file_operations結構 中的read函數。在系統(tǒng)平臺上對USB口數碼攝像頭驅動,首先把USB控制器驅動模塊靜態(tài)編譯進內核,使平臺中支持USB接口,再在需要使用攝像頭采集 時,使用insmod動態(tài)加載其驅動模塊,這樣攝像頭就可正常工作了,接著進行了下一步對視頻流的采集編程。

程序中定義的數據結構

struct video_capability grab_cap;

struct video_picture grab_pic;

struct video_mmap grab_buf;

struct video_mbuf grab_vm;

這些數據結構都是由Video4Linux支持的,它們的用途如下:

*video_capability包含攝像頭的基本信息,例如設備名稱、支持的最大最小分辨率、信號源信息等,分別對應著結構體中成員變量name 、maxwidth、maxheight、minwidth、minheight、channels(信號源個數)、type等;

*voide_picture包含設備采集圖像的各種屬性,如brightness(亮度)、hue(色調)、contrast(對比度)、whiteness(色度)、depth(深度)等;

*video_mmap用于內存映射;

*video_mbuf利用mmap進行映射的幀信息,實際上是輸入到攝像頭存儲器緩沖中的幀信息,包括size(幀的大小)、frames(最多支持的幀數)、offsets(每幀相對基址的偏移)。

程序中用到的主要系統(tǒng)調用函數有:open("/dev/voideo0",int flags)、close(fd)、mmap(void *start,size_t length,int prot,int flags,int fd,off_t offset)、munmap(void *start,size_tlength)和ioctl(int fd,int cmd,…)。

前面提到Linux中把設備看成設備文件,在用戶空間可以通過標準的I/O系統(tǒng)調用函數操作設備文件,從而達到與設備通信交互的目的。當然,在設備驅動中要提供對這些函數的相應支持。這里說明一下ioctl(int fd,int cmd,…)函數,它在用戶程序中用來控制I/O通道,其中,fd代表設備文件描述符,cmd代表用戶程序對設備的控制命令,省略號一般是一個表示類型長度的參數,也可沒有。

(2)采集程序實現過程

首先打開視頻設備,攝像頭在系統(tǒng)中對應的設備文件為/dev/video0,采用系統(tǒng)調用函數grab_fd=open("/dev/video0", O_RDWR),grab_fd是設備打開后返回的文件描述符(打開錯誤返回-1),以后的系統(tǒng)調用函數就可使用它來對設備文件進行操作了。接著,利用 ioctl(grab_fd,VIDIOCGCAP,&grab_cap)函數讀取struct video_capability中有關攝像頭的信息。該函數成功返回后,這些信息從內核空間拷貝到用戶程序空間grab_cap各成員分量中,使用 printf函數就可得到各成員分量信息,例如printf("maxheight=%d",grab_fd.maxheight)獲得最大垂直分辨率的 大小。不規(guī)則用ioctl(grab_fd,VIDIOCGPICT,&grab_pic)函數讀取攝像頭緩沖中voideo_picture信息。在用戶空間程序中可以改變這些信息,具體方法為先給分量賦新值,再調用VIDIOCSPICT ioctl函數,例如:

grab_fd.depth=3;

if(ioctl(grab_fd,VIDIOCSPICT,&grab_pic)<0)

{perror("VIDIOCSPICT");return -1;};

完成以上初始化設備工作后,就可以對視頻圖像截取了,有兩種方法:一種是read()直接讀取;另外一種mmap()內存映射。Read()通過內核緩沖 區(qū)來讀取數據;而mmap()通過把設備文件映射到內存中,繞過了內核緩沖區(qū),最快的磁盤訪問往往還是慢于最慢的內存訪問,所以mmap()方式加速了 I/O訪問。另外,mmap()系統(tǒng)調用使得進程之間通過映射同一文件實現共享內存,各進程可以像訪問普通內存一樣對文件進行訪問,訪問時只需要使用指針 而不用調用文件操作函數。因為mmap()的以上優(yōu)點,所以在程序實現中采用了內存映射方式,即mmap()方式。

利用mmap()方式視頻裁取具體進行操作如下。

①先使用ioctl(grab_fd,VIDIOCGMBUF,&grab_vm)函數獲得攝像頭存儲緩沖區(qū)的幀信息,之后修改voideo_mmap中的設置,例如重新設置圖像幀的垂直及水平分辨率、彩色顯示格式。可利用如下語句

grab_buf.height=240;

Grab_buf.width=320;

grab_buf.format=VIDEO_PALETTE_RGB24;

②接著把攝像頭對應的設備文件映射到內存區(qū),具體使用grab_data=(unsigned char*)mmap(0,grab_vm.size,PROT_READ|PROT_WRITE,MAP_SHARED,grad_fd,0)操作。這 樣設備文件的內容就映射到內存區(qū),該映射內容區(qū)可讀可寫并且不同進程間可共享。該函數成功時返回映像內存區(qū)的指針,挫敗時返回值為-1。

下面對單幀采集和連續(xù)幀采集進行說明:

*單幀采集。在上面獲取的攝像頭存儲緩沖區(qū)幀信息中,最多可支持的幀數(frames的值)一般為兩幀。對于單幀采集只需設置 grab_buf.frame=0,即采集其中的第一幀,使用ioctl(grab_fd,VIDIOCMCAPTURE,&grab_buf) 函數,若調用成功,則激活設備真正開始一幀圖像的截取,是非阻塞的。接著使用ioctl(grab_fd,VIDIOCSYNC,&frame) 函數判斷該幀圖像是否截取完畢,成功返回表示截取完畢,之后就可把圖像數據保存成文件的形式。

*連續(xù)幀采集。在單幀的基礎上,利用grab_fd.frames值確定采集完畢攝像頭幀緩沖區(qū)幀數據進行循環(huán)的次數。在循環(huán)語句中,也是使用VIDIOCMCCAPTURE ioct1和VIDIOCSYNC ioctl函數完成每幀截取,但要給采集到的每幀圖像賦地址,利用語句buf=grab_data+grab_vm.offsets[frame],然后保存文件的形式。若要繼續(xù)采集可再加一個外循環(huán),在外循環(huán)語句只要給原來的內循環(huán)再賦frame=0即可。

小結

筆者最后在宿主機PC上使用交叉編譯器編譯鏈接連續(xù)幀采集程序(以雙幀采集為例并保存成bmp文件文件形式)使之生成可執(zhí)行代碼,并完成了向目標平臺的移 植。為了進一步觀察采集的圖像效果,筆者在目標平臺帶網絡支持的基礎上,編寫了一個簡單的網絡通信程序,把采集到并保存為Beep Media Player的圖像文件通過網絡傳輸到 PC機上進行顯示,把采集到并保存為bmp的圖像文件通過網絡傳輸到PC機上進行顯示,通過對效果的分析,再回到采集程序中重新設置 video_picture中的信息,如亮度、對比度等和video_mmap中的分辨率,重新移植以達到最好效果為準。

在圖1中的嵌入式系統(tǒng)平臺上,應用本文所述方法完成視頻采集工作,再加上相關的視頻處理并接入網絡,就構成了一個智能終端設備,可用于工廠、銀行及小區(qū)等場合全天候的智能監(jiān)控,具有廣闊的市場和應用前景。

參考資料 >

生活家百科家居網