基於Linux視頻驅動接口V4L2視頻採集編程

http://blog.mcuol.com/User/GuoHuiCao/Article/44253_1.htm

 

Linux系統中,視頻設備被當作一個設備文件來看待,設備文件存放在 /dev目錄下,完整路徑的設備文件名爲: /dev/video0 .

 

視頻採集基本步驟流程如下: 打開視頻設備,設置視頻設備屬性及採集方式、視頻數據處理,關閉視頻設備,如下圖所示:

 

 

一、打開視頻設備

打開視頻設備非常簡單,在V4L2中,視頻設備被看做一個文件。使用open函數打開這個設備:

1.     用非阻塞模式打開攝像頭設備
int cameraFd;
cameraFd = open("/dev/video0", O_RDWR | O_NONBLOCK);
 

2.     如果用阻塞模式打開攝像頭設備,上述代碼變爲:
cameraFd = open("/dev/video0", O_RDWR);

 

關於阻塞模式和非阻塞模式

應用程序能夠使用阻塞模式或非阻塞模式打開視頻設備,如果使用非阻塞模式調用視頻設備,即使尚未捕獲到信息,驅動依舊會把緩存(DQBUFF)裏的東西返回給應用程序。

 

二、Linux視頻設備驅動常用控制命令使用說明

 

設置視頻設備屬性通過ioctl來進行設置,ioctl有三個參數,分別是fd, cmd,parameter,表示設備描述符,控制命令和控制命令參數。

 

Linux 視頻設備驅動接口V4L2支持的常用控制命令如下:

 

1. 控制命令 VIDIOC_ENUM_FMT

功能: 獲取當前視頻設備支持的視頻格式

參數說明:參數類型爲V4L2的視頻格式描述符類型 struct v4l2_fmtdesc

返回值說明: 執行成功時,函數返回值爲 0struct v4l2_fmtdesc 結構體中的 .pixelformat .description 成員返回當前視頻設備所支持的視頻格式;

使用舉例:

-------------------------------------------------------------------------------------------------

struct v4l2_fmtdesc fmt;

       memset(&fmt, 0, sizeof(fmt));

       fmt.index = 0;

       fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;

       while ((ret = ioctl(dev, VIDIOC_ENUM_FMT, &fmt)) == 0) {

              fmt.index++;

              printf("{ pixelformat = ''%c%c%c%c'', description = ''%s'' }/n",

                            fmt.pixelformat & 0xFF, (fmt.pixelformat >> 8) & 0xFF,

                            (fmt.pixelformat >> 16) & 0xFF, (fmt.pixelformat >> 24) & 0xFF,

                            fmt.description);

       }

---------------------------------------------------------------------------------------------------------------

 

2. 控制命令VIDIOC_QUERYCAP

功能: 查詢視頻設備的功能

參數說明:參數類型爲V4L2的能力描述類型struct v4l2_capability

返回值說明: 執行成功時,函數返回值爲 0;函數執行成功後,struct v4l2_capability 結構體變量中的返回當前視頻設備所支持的功能;例如支持視頻捕獲功能V4L2_CAP_VIDEO_CAPTUREV4L2_CAP_STREAMING等。

使用舉例:

-----------------------------------------------------------------------------------------------------------

struct v4l2_capability cap; 

iret = ioctl(fd_usbcam, VIDIOC_QUERYCAP, &cap);

if(iret < 0)

{

              printf("get vidieo capability error,error code: %d /n", errno);

              return ;

}

----------------------------------------------------------------------------------------------------------

執行完VIDIOC_QUERYCAP命令後,cap變量中包含了該視頻設備的能力信息,程序中通過檢查cap中的設備能力信息來判斷設備是否支持某項功能。

 

3. 控制命令VIDIOC_S_FMT

功能: 設置視頻設備的視頻數據格式,例如設置視頻圖像數據的長、寬,圖像格式(JPEGYUYV格式);

參數說明:參數類型爲V4L2的視頻數據格式類型 struct v4l2_format  

返回值說明: 執行成功時,函數返回值爲 0

使用舉例:

----------------------------------------------------------------------------------------------------------

       struct v4l2_format tv4l2_format; 

tv4l2_format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 

     tv4l2_format.fmt.pix.width = img_width; 

     tv4l2_format.fmt.pix.height = img_height; 

     tv4l2_format.fmt.pix.pixelformat = V4L2_PIX_FMT_YUV420; 

     tv4l2_format.fmt.pix.field = V4L2_FIELD_INTERLACED; 

 

       iret = ioctl(fd_usbcam, VIDIOC_S_FMT, &tv4l2_format);

-----------------------------------------------------------------------------------------------------------

注意:如果該視頻設備驅動不支持你所設定的圖像格式,視頻驅動會重新修改struct v4l2_format結構體變量的值爲該視頻設備所支持的圖像格式,所以在程序設計中,設定完所有的視頻格式後,要獲取實際的視頻格式,要重新讀取struct v4l2_format結構體變量。

 

4. 控制命令VIDIOC_REQBUFS

功能: 請求V4L2驅動分配視頻緩衝區(申請V4L2視頻驅動分配內存),V4L2是視頻設備的驅動層,位於內核空間,所以通過VIDIOC_REQBUFS控制命令字申請的內存位於內核空間,應用程序不能直接訪問,需要通過調用mmap內存映射函數把內核空間內存映射到用戶空間後,應用程序通過訪問用戶空間地址來訪問內核空間。

參數說明:參數類型爲V4L2的申請緩衝區數據結構體類型struct v4l2_requestbuffers  

返回值說明: 執行成功時,函數返回值爲 0V4L2驅動層分配好了視頻緩衝區;

使用舉例:

-----------------------------------------------------------------------------------------------------------

struct v4l2_requestbuffers  tV4L2_reqbuf;

memset(&tV4L2_reqbuf, 0, sizeof(struct v4l2_requestbuffers ));

 

tV4L2_reqbuf.count = 1;    //申請緩衝區的個數

tV4L2_reqbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 

tV4L2_reqbuf.memory = V4L2_MEMORY_MMAP;

 

iret = ioctl(fd_usbcam, VIDIOC_REQBUFS, &tV4L2_reqbuf);

--------------------------------------------------------------------------------------------------------------

注意:VIDIOC_REQBUFS會修改tV4L2_reqbufcount值,tV4L2_reqbufcount值返回實際申請成功的視頻緩衝區數目;

 

5. 控制命令VIDIOC_QUERYBUF

功能: 查詢已經分配的V4L2的視頻緩衝區的相關信息,包括視頻緩衝區的使用狀態、在內核空間的偏移地址、緩衝區長度等。在應用程序設計中通過調VIDIOC_QUERYBUF來獲取內核空間的視頻緩衝區信息,然後調用函數mmap把內核空間地址映射到用戶空間,這樣應用程序才能夠訪問位於內核空間的視頻緩衝區。

參數說明:參數類型爲V4L2緩衝區數據結構類型 struct v4l2_buffer  

返回值說明: 執行成功時,函數返回值爲 0struct v4l2_buffer結構體變量中保存了指令的緩衝區的相關信息;

一般情況下,應用程序中調用VIDIOC_QUERYBUF取得了內核緩衝區信息後,緊接着調用mmap函數把內核空間地址映射到用戶空間,方便用戶空間應用程序的訪問。

使用舉例:

----------------------------------------------------------------------------------------------------------------

struct v4l2_buffer tV4L2buf; 

memset(&tV4L2buf, 0, sizeof(struct v4l2_buffer));

 

tV4L2buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 

tV4L2buf.memory = V4L2_MEMORY_MMAP; 

tV4L2buf.index = i;  // 要獲取內核視頻緩衝區的信息編號

iret = ioctl(fd_usbcam, VIDIOC_QUERYBUF, &tV4L2buf);

// 把內核空間緩衝區映射到用戶空間緩衝區

AppBufLength  = tV4L2buf.length;

AppBufStartAddr = mmap(NULL /* start anywhere */ , 

                       tV4L2buf.length, 

                       PROT_READ | PROT_WRITE /* access privilege */ , 

                       MAP_SHARED /* recommended */ , 

                       fd_usbcam, tV4L2buf.m.offset); 

------------------------------------------------------------------------------------------------------------------

上述代碼在通過調用VIDIOC_QUERYBUF取得內核空間的緩衝區信息後,接着調用mmap函數把內核空間緩衝區映射到用戶空間;關於mmap函數的用法,請讀者查詢相關資料;

 

6. 控制命令VIDIOC_QBUF

功能: 投放一個空的視頻緩衝區到視頻緩衝區輸入隊列中

參數說明:參數類型爲V4L2緩衝區數據結構類型 struct v4l2_buffer

返回值說明: 執行成功時,函數返回值爲 0;函數執行成功後,指令的視頻緩衝區進入視頻輸入隊列,在啓動視頻設備拍攝圖像時,相應的視頻數據被保存到視頻輸入隊列相應的視頻緩衝區中。

使用舉例:

-------------------------------------------------------------------------------------------------------------

struct v4l2_buffer tV4L2buf; 

memset(&tV4L2buf, 0, sizeof(struct v4l2_buffer));

 

tV4L2buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 

tV4L2buf.memory = V4L2_MEMORY_MMAP; 

tV4L2buf.index = i; //指令要投放到視頻輸入隊列中的內核空間視頻緩衝區的編號;

 

iret = ioctl(fd_usbcam, VIDIOC_QBUF, &tV4L2buf);

----------------------------------------------------------------------------------------------------------

 

7. 控制命令VIDIOC_STREAMON

功能: 啓動視頻採集命令,應用程序調用VIDIOC_STREAMON啓動視頻採集命令後,視頻設備驅動程序開始採集視頻數據,並把採集到的視頻數據保存到視頻驅動的視頻緩衝區中。

參數說明:參數類型爲V4L2的視頻緩衝區類型 enum v4l2_buf_type

返回值說明: 執行成功時,函數返回值爲 0;函數執行成功後,視頻設備驅動程序開始採集視頻數據,此時應用程序一般通過調用select函數來判斷一幀視頻數據是否採集完成,當視頻設備驅動完成一幀視頻數據採集並保存到視頻緩衝區中時,select函數返回,應用程序接着可以讀取視頻數據;否則select函數阻塞直到視頻數據採集完成。Select函數的使用請讀者參考相關資料。

使用舉例:

----------------------------------------------------------------------------------------------------------

enum v4l2_buf_type v4l2type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 

fd_set    fds ; 

struct timeval   tv; 

iret = ioctl(fd_usbcam, VIDIOC_STREAMON, &v4l2type);

 

FD_ZERO(&fds); 

FD_SET(fd_usbcam,  &fds); 

tv.tv_sec = 2;       /* Timeout. */ 

tv.tv_usec = 0; 

 

iret = select(fd_usbcam+ 1, &fds, NULL, NULL, &tv); 

----------------------------------------------------------------------------------------------------------

 

8. 控制命令VIDIOC_DQBUF

功能: 從視頻緩衝區的輸出隊列中取得一個已經保存有一幀視頻數據的視頻緩衝區;

參數說明:參數類型爲V4L2緩衝區數據結構類型 struct v4l2_buffer

返回值說明: 執行成功時,函數返回值爲 0;函數執行成功後,相應的內核視頻緩衝區中保存有當前拍攝到的視頻數據,應用程序可以通過訪問用戶空間來讀取該視頻數據。(前面已經通過調用函數mmap做了用戶空間和內核空間的內存映射).

使用舉例:

----------------------------------------------------------------------------------------------------------

struct v4l2_buffer tV4L2buf; 

memset(&tV4L2buf, 0, sizeof(struct v4l2_buffer));

 

tV4L2buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 

tV4L2buf.memory = V4L2_MEMORY_MMAP; 

 

iret = ioctl(fd_usbcam, VIDIOC_DQBUF, &tV4L2buf);

----------------------------------------------------------------------------------------------------------

 

9. 控制命令VIDIOC_STREAMOFF

功能: 停止視頻採集命令,應用程序調用VIDIOC_ STREAMOFF停止視頻採集命令後,視頻設備驅動程序不在採集視頻數據。

參數說明:參數類型爲V4L2的視頻緩衝區類型 enum v4l2_buf_type

返回值說明: 執行成功時,函數返回值爲 0;函數執行成功後,視頻設備停止採集視頻數據。

使用舉例:

----------------------------------------------------------------------------------------------------------

enum v4l2_buf_type  v4l2type; 

v4l2type = V4L2_BUF_TYPE_VIDEO_CAPTURE;  

iret = ioctl(fd_usbcam, VIDIOC_STREAMOFF, &v4l2type);

-----------------------------------------------------------------------------------------------------------

以上就是Linux 視頻設備驅動V4L2最常用的控制命令使用說明,通過使用以上控制命令,可以完成一幅視頻數據的採集過程。V4L2更多的控制命令使用說明請參考:http://v4l2spec.bytesex.org/spec/book1.htm

 

希望本文對大家理解linux下的視頻驅動編程有所幫助。

 

 

---------------------------------------------------------------------------------------------------------------------

作者: 曹國輝  南京凌嵌教育嵌入式Linux金牌講師 

QQ: 1539730715 歡迎嵌入式Linux愛好者一起交流。

凌嵌教育科技是江蘇地區權威的嵌入式linxu培訓專家、專業代理飛凌、優龍嵌入式ARM開發板。網址: http://www.jslinux.com

2010-11.14

 

版權申明:本文版權歸作者所有, 未經允許不得用於商業目的。

歡迎轉載,轉載需註明出處 http://www.jslinux.com

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章