基於嵌入式linux和s3c2410平台的視頻採集

admin @ 2014-03-25 , reply:0

        隨著多媒體技術、網路技術的迅猛發展和后PC機時代的到來,利用嵌入式系統實現遠程視頻監控、可視電話和視頻會議等應用已成為可能。為了實現這些應用,實時獲得視頻數據是一個重要環節。針對這一點,本文在基於嵌入式Linux系統平台上,利用Video4Linux 內核應用編程介面函數,實現了單幀圖像和視頻連續幀的採集,並保存成文件的形式供進一步視頻處理和網路傳輸用。

  1 系統平台上的硬體系統

  本文使用的系統平台硬體功能框圖如圖1所示。該平台採用Samsung公司的處理器S3C2410。該處理器內部集成了ARM公司 ARM920T處理器核的32位微控制器,資源豐富,帶獨立的16KB的指令Cache和16KB數據Cache、LCD控制器、RAM控制器、NAND 快閃記憶體控制器、3路UART、4路DMA、4路帶PWM的Timer、并行I/O口、8路10位ADC、Touch Screen介面、I2C介面、I2S介面、2個USB介面控制器、2路SPI,主頻最高可達203MHz。在處理器豐富資源的基礎上,還進行了相關的配置和擴展,平台配置了16MB 16位的Flash和64MB 32位的SDRAM。通過乙太網控制器晶元DM9000E擴展了一個網口,另外引出了一個HOST USB介面。通過在USB介面上外接一個帶USB口的攝像頭,將採集到的視頻圖像數據放入輸入緩衝區中。然後,或者保存成文件的形式,或者運行移植到平台上的圖像處理程序,對緩衝的圖像數據直接進行相關處理,再保存並打成UDP包。最後,通過網路介面將圖像發送到Internet上。本文只討論其中視頻採集部分的具體實現。

  2 系統平台中的軟體系統

  2.1 Linux與嵌入式系統

  Linux具有內核小,效率高,源代碼開放,內核直接提供網路支持等優點。但嵌入式系統的硬體資源畢竟有限,因此不能直接把Linux作為操作系統,需要針對具體的應用通過配置內核、裁減shell和嵌入式C庫對系統定製,使整個系統能夠存放到容量較小的 Flash中。Linux的動態模塊載入,使Linux的裁減極為方便,高度模塊化的部件使添加非常容易。正因為Linux的上述優點,在本文實現的平台上,使用的操作系統是對Linux進行了定製的armlinux。它啟用了MMU(內存管理單元),是針對支持MMU的處理器設計的。

  2.2 開發環境的建立

  絕大多數Linux的軟體開發都以native方式進行,即本機開發、調試,本機運行的方式。這種方式通常不適於嵌入式系統的軟體開發,因為對於嵌入式系統的開發,它沒有足夠的資源在本機(即嵌入式系統平台)運行開發工具和調試工具。通常的嵌入式系統軟體開發採用交叉編譯調試的方式。交叉編譯調試環境建立在宿主機(即圖1所示通過串口連接的宿主機PC)上,對應的開發板叫做目標板(即嵌入式ARM2410系統)。

  通常宿主機和目標板上的處理器不同,宿主機通常為Intel處理器,而目標板如圖1所示為SAMSUNG S3C2410,所以程序需要使用針對處理器特點的編譯器才能生成在相應平台上可運行的代碼。GNU編譯器提供這樣的功能,在編譯時,可以選擇開發所需的宿主機和目標機,從而建立開發環境。在進行嵌入式開發前的第一步工作就是把一台PC機作為宿主機開發機,並在其上安裝指定的操作系統。對於嵌入式 Linux,宿主機PC上應安裝Linux系統。之後,在宿主機上建立交叉編譯調試的開發環境,開發環境的具體建立這裡不細談。本文採用移植性很強的C語言在宿主機上編寫視頻採集程序,再利用交叉編譯調試工具編譯鏈接生成可執行代碼,最後向目標平台移植。

  3 視頻採集的具體實現

  上面提到系統平台上運行的是armlinux。在啟動后,啟用了MMU,系統進入保護模式,所以應用程序就不能直接讀寫外設的I/O區域(包括 I/O埠和I/O內存),這時一般就要藉助於該外設的驅動來進入內核完成這個工作。本系統中的視頻採集分兩步實現:一是為USB口數碼攝像頭在內核中寫入驅動,二是要再寫入上層應用程序獲取視頻數據。本文著重討論后一步。

  3.1 USB口數碼攝像頭的驅動實現

  在Linux下,設備驅動程序可以看成Linux內核與外部設備之間的介面。設備驅動程序嚮應用程序屏蔽了硬體實現了的細節,使得應用程序可以像操作普通文件一樣來操作外部設備,可以使用和操作文件中相同的、標準的系統調用介面函數來完成對硬體設備的打開、關閉、讀寫和I/O控制操作,而驅動程序的主要任務也就是要實現這些系統調用函數。本系統平台使用的嵌入式armLinux系統在內核主要功能上與 Linux操作系統沒本質區別,所以驅動程序要實現的任務也一樣,只要編譯時使用的編譯器、部分頭文件和庫文件等要涉及到具體處理器體系結構,這些都可以在Makefile文件中具體指定。

  Video4Linux(簡V4L)是Linux中關於視頻設備的內核驅動,它為針對視頻設備的應用程序編程提供一系列介面函數,這些視頻設備包括現今市場上流行的TV卡、視頻捕捉卡和USB攝像頭等。對於USB口攝像頭,其驅動程序中需要提供基本的I/O操作介面函數open、read、 write、close的實現。對中斷的處理實現,內存映射功能以及對I/O通道的控制介面函數ioct1的實現等,並把它們定義在struct file_operations中。這樣當應用程序對設備文件進行諸如open、close、read、write等系統調用操作時,Linux內核將通過file_operations結構訪問驅動程序提供的函數。例如,當應用程序對設備文件執行讀操作時,內核將調用file_operations結構中的read函數。在系統平台上對USB口數碼攝像頭驅動,首先把USB控制器驅動模塊靜態編譯進內核,使平台中支持USB介面,再在需要使用攝像頭採集時,使用insmode動態載入其驅動模塊,這樣攝像頭就可正常工作了,接著進行了下一步對視頻流的採集編程。

  3.2 Video4Linux下的攝像頭採集編程

  在USB攝像頭被驅動后,只需要再編寫一個對視頻流採集的應用程序就可以了。根據嵌入式系統開發特徵,先在宿主機上編寫應用程序,再使用交叉編譯器進行編譯鏈接,生成在目標平台的可執行文件。宿主機與目標板通信採用列印終端的方式進行交叉調試,成功后移植到目標平台。本文編寫採集程序是在安裝 Linux操作系統的宿主機PC機上進行的,下面是具體論述。

  (1)程序中定義的數據結構

  struct voide_capability grab_cap;

  struct voide_picture grab_pic;

  struct voide_mmap grab_buf;

  struct voide_mbuf grab_vm;

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

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

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

  *video_mmap用於內存映射;

  *voido_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),以後的系統調用函數就可使用它來對設備文件進行操作了。接著,利用ioct1(grab_fd,VIDIOCGCAP,&grab_cap)函數讀取struct video_capability中有關攝像頭的信息。該函數成功返回后,這些信息從內核空間拷貝到用戶程序空間grab_cap各成員分量中,使用 printf函數就可得到各成員分量信息,例如printf("maxheight=%d",grab_fd.maxheight)獲得最大垂直解析度的大小。不規則用ioct1(grab_fd,VIDIOCGPICT,&grab_pic)函數讀取攝像頭緩衝中voideo_picture信息。在用戶空間程序中可以改變這些信息,具體方法為先給分量賦新值,再調用VIDIOCSPICT ioct1函數,例如:

  grab_fd.depth=3;

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

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

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

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

  ①先使用ioct1(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) 函數,若調用成功,則激活設備真正開始一幀圖像的截取,是非阻塞的。接著使用ioct1(grab_fd,VIDIOCSYNC,&frame) 函數判斷該幀圖像是否截取完畢,成功返回表示截取完畢,之後就可把圖像數據保存成文件的形式。

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

  4 小結

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

  嵌入式系統平台上,應用本文所述方法完成視頻採集工作,再加上相關的視頻處理並接入網路,就構成了一個智能終端設備,可用於工廠、銀行及小區等場合全天候的智能監控,具有廣闊的市場和應用前景




[admin via 研發互助社區 ] 基於嵌入式linux和s3c2410平台的視頻採集已經有828次圍觀

http://cocdig.com/docs/show-post-42896.html