Hi3559AV100外接UVC/MJPEG相機實時採圖設計(二):V4L2接口的實現(YUV:640×480像素爲例)

  下面將給出Hi3559AV100外接UVC/MJPEG相機實時採圖設計的總體流程,主要實現是經過V4L2接口將UVC/MJPEG相機採集的數據送入至MPP平臺,通過VDEC、VPSS、VO最後經過HDMI的輸出,給出(二)V4L2接口的實現。html

能夠先參照前面隨筆介紹(一)Linux USB攝像頭驅動加載與分析:https://www.cnblogs.com/iFrank/p/14399421.htmllinux

板載平臺:BOXER-8410AIgit

芯片型號:Hi3559AV100編程

相機型號:Logitch c270ubuntu

開發環境:VM15.5+ubuntu16.04+Hilinux緩存

一、V4L2接口說明

  V4L2是Video for linux2的簡稱,爲linux中關於視頻設備的內核驅動。在Linux中,視頻設備是設備文件,能夠像訪問普通文件同樣對其進行讀寫,攝像頭在/dev/video*下,若是隻有一個視頻設備,一般爲/dev/video0。V4L2是內核提供給應用程序訪問音、視頻驅動的統一接口。V4L2 的相關定義包含在頭文件<linux/videodev2.h> 中。數據結構

  V4L2 支持兩種方式來採集圖像:內存映射(mmap)和直接讀取方式(read)。V4L2 在/usr/include/linux/videodev2.h 文件下定義了一些重要的數據結構,在採集圖像的過程當中,就是經過對這些數據的操做來得到最終的圖像數據。Linux 系統 V4L2 使能可在內核編譯階段配置,默認狀況下是在 make menuconfig 是打開的。應用程序能夠經過 V4L2 進行視頻採集。V4L2 支持內存映射(mmap)方式和直接讀取方式(read)方式採集數據。前者
通常用於連續的視頻數據採集,後者經常使用靜態圖片數據採集。v4l2 中不只定義了通用 API 元素,圖像的格式,輸入/輸出方法,還定義了Linux 內核驅動處理視頻信息的一系列接口,這些接口主要有:
  視頻採集接口——Video Capture interface;
  視頻輸出接口——Video Output Interface;
  視頻覆蓋/預覽接口——Video Overlay Interface;
  視頻輸出覆蓋接口——Video Output Overlay Interface;
  編解碼接口——Codec Interface

IOCTL的實現V4L2的控制ide

  打開視頻設備後,能夠設置該視頻設備的屬性,例如裁剪、縮放等。這一步是可選的。在Linux編程中,通常使用ioctl函數來對設備的I/O通道進行管理:
extern int ioctl (int __fd, unsigned long int __request, …) __THROW;
__fd:設備的ID,例如剛纔用open函數打開視頻通道後返回的cameraFd;
__request:具體的命令標誌符。
在進行V4L2開發中,通常會用到如下的命令標誌符:
 1:分配內存
 2 VIDIOC_QUERYBUF:把VIDIOC_REQBUFS中分配的數據緩存轉換成物理地址
 3 VIDIOC_QUERYCAP:查詢驅動功能
 4 VIDIOC_ENUM_FMT:獲取當前驅動支持的視頻格式
 5 VIDIOC_S_FMT:設置當前驅動的頻捕獲格式
 6 VIDIOC_G_FMT:讀取當前驅動的頻捕獲格式
 7 VIDIOC_TRY_FMT:驗證當前驅動的顯示格式
 8 VIDIOC_CROPCAP:查詢驅動的修剪能力
 9 VIDIOC_S_CROP:設置視頻信號的邊框
10 VIDIOC_G_CROP:讀取視頻信號的邊框
11 VIDIOC_QBUF:把數據放回緩存隊列
12 VIDIOC_DQBUF:把數據從緩存中讀取出來
13 VIDIOC_STREAMON:開始視頻顯示函數
14 VIDIOC_STREAMOFF:結束視頻顯示函數
15 VIDIOC_QUERYSTD:檢查當前視頻設備支持的標準,例如PAL或NTSC。

這些IO調用,有些是必須的,有些是可選擇的,其命令標誌符在在頭文件<linux/videodev2.h> 定義,具體以下:函數

1 #define VIDIOC_QUERYCAP         _IOR('V',  0, struct v4l2_capability)
2 #define VIDIOC_RESERVED          _IO('V',  1)
3 #define VIDIOC_ENUM_FMT         _IOWR('V',  2, struct v4l2_fmtdesc)
4 #define VIDIOC_G_FMT        _IOWR('V',  4, struct v4l2_format)
5 #define VIDIOC_S_FMT        _IOWR('V',  5, struct v4l2_format)
6 #define VIDIOC_REQBUFS        _IOWR('V',  8, struct v4l2_requestbuffers)

Logitch c270支持的像素格式有兩種:測試

 1 YUYV 4:2:2 2 Motion-JPEG 

二、V4L2的實現流程

通常來講V4L2 採集視頻數據分爲五個步驟:
  首先,打開視頻設備文件,進行視頻採集的參數初始化,經過 V4L2 接口設置視頻圖像的採集窗口、採集的點陣大小和格式;
  其次,申請若干視頻採集的幀緩衝區,並將這些幀緩衝區從內核空間映射到用戶空間,便於應用程序讀取/處理視頻數據;
  第三,將申請到的幀緩衝區在視頻採集輸入隊列排隊,並啓動視頻採集;
  第四,驅動開始視頻數據的採集,應用程序從視頻採集輸出隊列取出幀緩衝區,處理完後,將幀緩衝區從新放入視頻採集輸入隊列,循環往復採      集連續的視頻數據;
  第五,中止視頻採集。在本次設計中,定義了幾個函數實現對攝像頭的配置和採集。
一幀圖片採集流程:


 動態視頻採集流程:

 

  圖解過程已經很詳細了,從新總結下。整個過程:
  首先:先啓動視頻採集,驅動程序開始採集一幀數據,把採集的數據放入視頻採集輸入隊列的第一個幀緩衝區,一幀數據採集完成,也就是第
一個幀緩衝區存滿一幀數據後,驅動程序將該幀緩衝區移至視頻採集輸出隊列,等待應用程序從輸出隊列取出。驅動程序則繼續採集下一幀數據放入第二個緩衝區,一樣幀緩衝區存滿下一幀數據後,被放入視頻採集輸出隊列。
  而後:應用程序從視頻採集輸出隊列中取出含有視頻數據的幀緩衝區,處理幀緩衝區中的視頻數據,如存儲或壓縮。
  最後:應用程序將處理完數據的幀緩衝區從新放入視頻採集輸入隊列,這樣能夠循環採集。咱們從攝像頭中獲取的視頻幀數據會放入視頻緩存隊列中,當其餘模塊須要處理對應的視頻幀的時候,就會佔用緩存塊,也就是這一塊內存被佔用,當處理完以後,對應的數據經過 VO/VENC/VDA 顯示以後,這一緩存塊就沒有用了,能夠回收利用。如今來看,其實海思的底層處理和 linux 的底層處理是同樣的。不過海思自己使用的就是 linux 內核。應該也就是對這一塊進行封裝了而已吧!
  海思的公共視頻緩存池按個人理解應該有兩部分,一部分是視頻採集輸入隊列,另外一部分是視頻採集輸出隊列,VI 通道是是視頻採集輸出隊列中獲取的視頻幀,而中間 linux 內核的驅動程序會在視頻採集輸入隊列中填充視頻幀,變成視頻輸出隊列。

部分代碼實現:

 1     /*打開視頻*/
 2     if ((fd = open(FILE_VIDEO, O_RDWR)) == -1) 
 3     {
 4           printf("Error opening V4L interface\n");
 5           return (FALSE);
 6     }
 7     
 8     /*讀video_capability中信息。
 9     經過調用IOCTL函數和接口命令VIDIOC_QUERYCAP查詢
10     攝像頭的信息*/
11     if (ioctl(fd, VIDIOC_QUERYCAP, &cap) == -1)
12     {
13         printf("Error opening device %s: unable to query device.\n",FILE_VIDEO);
14         return (FALSE);
15     }
16     else
17     {
18         printf("driver:\t\t%s\n",cap.driver);
19         printf("card:\t\t%s\n",cap.card);
20         printf("bus_info:\t%s\n",cap.bus_info);
21         printf("version:\t%d\n",cap.version);
22         printf("capabilities:\t%x\n",cap.capabilities);
23 
24         /*其中capabilities: 4000001經過與各類宏位與,
25         能夠得到物理設備的功能屬性*/
26         if ((cap.capabilities & V4L2_CAP_VIDEO_CAPTURE) == V4L2_CAP_VIDEO_CAPTURE)
27         {
28             printf("Device %s: supports capture.\n",FILE_VIDEO);
29         }
30 
31         if ((cap.capabilities & V4L2_CAP_STREAMING) == V4L2_CAP_STREAMING)
32         {
33             printf("Device %s: supports streaming.\n",FILE_VIDEO);
34         }
35     } //VIDIOC_QUERYCAP對應惟一結構體

三、V4L2測試(640×480像素一幀圖片輸出)

  我板載上裝的是Logitch c270攝像頭,從攝像頭支持的圖像像素輸出的信息能夠看出,在Hi3559板載上能夠支持2種像素格式,這裏選用的是V4L2_PIX_FMT_YUV422 格式。從生成image的大小能夠判斷出是正確的(YUV422數據大小 = 長 * 寬 * 1.5 = 640 * 480 * 2 = 614400 bytes = 600k)能夠將image文件拷出來,使用pYUV 軟件查看YUV圖片。這裏須要注意,使用pYUV 查看YUV圖片的時候,須要正確設置圖片格式,按我上面代碼採集的數據格式,最後一幀圖片輸出結果以下:

  以後隨筆將推出結合MPP平臺實現視頻流的輸出。

 問題:

 

  在虛擬機上,腳本運行正常,可是會卡在視頻採集處,我的認爲是虛擬機的緩存問題,而板載緩存比較充足,因此可以很好實現。

相關文章
相關標籤/搜索