複製鏈接
請複製以下鏈接發送給好友

Video4Linux

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

目錄

Video4Linux簡介

對中斷的處理實現,內存映射功能以及對I/O通道的控制接口函數ioct1的實現等,並把 它們定義在struct file_operations中。這樣當應用程序對設備文件進行諸如open、close、read、write等系統調用操作時,Linux內核將通 過file_operations結構訪問驅動程序提供的函數。例如,當應用程序對設備文件執行讀操作時,內核將調用file_operations結構 中的read函數。在系統平台上對USB口數碼攝像頭驅動,首先把USB控制器驅動模塊靜態編譯內核,使平台中支持USB接口,再在需要使用攝像頭採集 時,使用insmod動態加載其驅動模塊,這樣攝像頭就可正常工作了,接着進行了下一步對視頻流的採集編程。
程序中定義的數據結構
struct video_capability grab_cap;
struct video_picture grab_pic;
struct video_mmap grab_buf;
struct video_mbuf grab_vm;
這些數據結構都是由Video4Linux支持的,它們的用途如下:
*video_capability包含攝像頭的基本信息,例如設備名稱、支持的最大最小分辨率、信號源信息等,分別對應着結構體成員變量name [32]、maxwidth、maxheight、minwidth、minheight、channels(信號源個數)、type等;
*voide_picture包含設備採集圖像的各種屬性,如brightness(亮度)、hue(色調)、contrast(對比度)、whiteness(色度)、depth(深度)等;
*video_mmap用於內存映射;
*video_mbuf利用mmap進行映射的幀信息,實際上是輸入到攝像頭存儲器緩衝中的幀信息,包括size(幀的大小)、frames(最多支持的幀數)、offsets(每幀相對基址的偏移)。
程序中用到的主要系統調用函數有: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系統調用函數操作設備文件,從而達到與設備通信交互的目的。當然,在設備驅動中要提供對這些函數的相應支持。這裏説明一下ioctl(int fd,int cmd,…)函數,它在用户程序中用來控制I/O通道,其中,fd代表設備文件描述符,cmd代表用户程序對設備的控制命令,省略號一般是一個表示類型長度的參數,也可沒有。
(2)採集程序實現過程
首先打開視頻設備,攝像頭在系統中對應的設備文件為/dev/video0,採用系統調用函數grab_fd=open("/dev/video0", O_RDWR),grab_fd是設備打開後返回的文件描述符(打開錯誤返回-1),以後的系統調用函數就可使用它來對設備文件進行操作了。接着,利用 ioctl(grab_fd,VIDIOCGCAP,&grab_cap)函數讀取struct video_capability中有關攝像頭的信息。該函數成功返回後,這些信息從內核空間拷貝到用户程序空間grab_cap各成員分量中,使用 printf函數就可得到各成員分量信息,例如printf("maxheight=%d",grab_fd.maxheight)獲得最大垂直分辨率的 大小。不規則用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()通過內核緩衝 區來讀取數據;而mmap()通過把設備文件映射到內存中,繞過了內核緩衝區,最快的磁盤訪問往往還是慢於最慢的內存訪問,所以mmap()方式加速了 I/O訪問。另外,mmap()系統調用使得進程之間通過映射同一文件實現共享內存,各進程可以像訪問普通內存一樣對文件進行訪問,訪問時只需要使用指針 而不用調用文件操作函數。因為mmap()的以上優點,所以在程序實現中採用了內存映射方式,即mmap()方式。
利用mmap()方式視頻裁取具體進行操作如下。
①先使用ioctl(grab_fd,VIDIOCGMBUF,&grab_vm)函數獲得攝像頭存儲緩衝區的幀信息,之後修改voideo_mmap中的設置,例如重新設置圖像幀的垂直及水平分辨率、彩色顯示格式。可利用如下語句
grab_buf.height=240;
grab_buf.width=320;
grab_buf.format=VIDEO_PALETTE_RGB24;
②接着把攝像頭對應的設備文件映射到內存區,具體使用grab_data=(unsigned char*)mmap(0,grab_vm.size,PROT_READ|PROT_WRITE,MAP_SHARED,grad_fd,0)操作。這 樣設備文件的內容就映射到內存區,該映射內容區可讀可寫並且不同進程間可共享。該函數成功時返回映像內存區的指針,挫敗時返回值為-1。
下面對單幀採集和連續幀採集進行説明:
*單幀採集。在上面獲取的攝像頭存儲緩衝區幀信息中,最多可支持的幀數(frames的值)一般為兩幀。對於單幀採集只需設置 grab_buf.frame=0,即採集其中的第一幀,使用ioctl(grab_fd,VIDIOCMCAPTURE,&grab_buf) 函數,若調用成功,則激活設備真正開始一幀圖像的截取,是非阻塞的。接着使用ioctl(grab_fd,VIDIOCSYNC,&frame) 函數判斷該幀圖像是否截取完畢,成功返回表示截取完畢,之後就可把圖像數據保存成文件的形式。
*連續幀採集。在單幀的基礎上,利用grab_fd.frames值確定採集完畢攝像頭幀緩衝區幀數據進行循環的次數。在循環語句中,也是使用VIDIOCMCCAPTURE ioct1和VIDIOCSYNC ioctl函數完成每幀截取,但要給採集到的每幀圖像賦地址,利用語句buf=grab_data+grab_vm.offsets[frame],然後保存文件的形式。若要繼續採集可再加一個外循環,在外循環語句只要給原來的內循環再賦frame=0即可。

Video4Linux小結

筆者最後在宿主機PC上使用交叉編譯器編譯鏈接連續幀採集程序(以雙幀採集為例並保存成bmp文件文件形式)使之生成可執行代碼,並完成了向目標平台的移 植。為了進一步觀察採集的圖像效果,筆者在目標平台帶網絡支持的基礎上,編寫了一個簡單的網絡通信程序,把採集到並保存為bmp的圖像文件通過網絡傳輸到 PC機上進行顯示,把採集到並保存為bmp的圖像文件通過網絡傳輸到PC機上進行顯示,通過對效果的分析,再回到採集程序中重新設置 video_picture中的信息,如亮度、對比度等和video_mmap中的分辨率,重新移植以達到最好效果為準。
在圖1中的嵌入式系統平台上,應用本文所述方法完成視頻採集工作,再加上相關的視頻處理並接入網絡,就構成了一個智能終端設備,可用於工廠、銀行及小區等場合全天候的智能監控,具有廣闊的市場和應用前景。