V4L2 中文 Made by:魚在飛(467350479) 個人翻譯,轉載請申明!
Chapter 3. 輸入/輸出(Input/Output)
V4L2 API規定了若干個不同的讀寫設備的方法。驅動和應用程序間進行數據交換必須支持其中的一種。
傳統的I/O方法是打開V4L2設備後會自動的調用read()和write()函數。如果驅動沒有支持這種方法,任何讀寫設備的嘗試都將失敗。
用其他的方法必須事先協商好了。選用通過mmap或者用戶空間緩衝區的流式I/O方法,應用程序可以調用VIDIOC_REQBUFS方法。目前,異步I/O方法還沒定義呢(如果你有好的建議可以隨時關注V4L2的郵件列表)。
video overlay也是一種值得考慮的I/O方法,儘管應用程序並不會直接接收圖像數據。調用VIDIOC_S_FMT可以初始化videooverlay。查看4.2節獲得更多信息。
通常,確切的說任何一種I/O方法,當然也包括overlay,都有他們對應的fd。唯一相同的是應用程序並不直接和驅動進行數據交換(面板應用,詳見1.1節),並且驅動允許使用同一個fd進行連續不間斷的視頻採集和overlay,主要是爲了和V4L以及V4L2的早期版本保持兼容。
VIDIOC_S_FMT和VIDIOC_REQBUFS的允許(切換方法)程度是有限的,但爲了簡潔,驅動除了通過關閉和重新打開設備來切換I/O方法外無需再支持其它的切換方式。
接下來的幾小節會詳細討論各種I/O方法。
3.1. 讀和寫(Read/Write)
VIDIOC_QUERYCAP方法會返回結構v4l2_capability,而其capabilities域中有個V4L2_CAP_READWRITE標誌,如果被設置了,那麼輸入和輸出設備會分別支持read()和write()函數。
驅動可能會藉助cpu來拷貝數據,當然他們也可能支持DMA方式,因此該I/0方法並不一定沒有其他通過交換緩衝區指針交換數據的方法來的低效。但這仍然屬於低級的,原因在於沒有傳遞過像幀計數器或者時間戳這樣的元信息(meta-information)。這些個信息是相當必要的,因爲他們可以用來確定幀是否被丟棄了或者用來同其他應用程序進行數據流同步。儘管如此,這也是一種最簡單的進行I/O的方法,只需要請求少量或者不用進行設置就可交換數據。可以使用如下的命令行技巧來操作(其中vidctrl工具是假想的):
> vidctrl /dev/video--input=0 --format=YUYV --size=352x288
> dd if=/dev/videoof=myimage.422 bs=202752 count=1
使用read()函數進行讀設備,write()則進行寫。假使驅動要和應用程序交換數據,它必須實現一種I/O方法,但這也不是必要的1。當之處讀或者寫時,驅動也必須支持select()和poll()2。
3.2. 流式I/O(內存映射)(Streaming I/O(MemoryMapping))
就是說當標誌位V4L2_CAP_STREAMING置1時,就會支持這種I/O方法。有倆種streaming方法,應用程序可通過調用VIDIOC_REQBUFS來確定是不是支持內存映射。
streaming是一種I/O方法,它主要是通過和應用程序交換緩衝區指針來交換數據,即不用拷貝數據了。內存映射主要是將設備內存緩衝映射到應用程序的地址空間去。設備內存可以是,就像獨立顯卡它有自己的存儲區吧,這存儲區就是設備內存。當然了最要效的還屬DMA了。
一個驅動可能支持多集合buffer。通過一獨一無二的buffer類型值來辨識每一集合。它們是相互獨立的並且可以擁有一個不同類型的數據。必須使用不用的fd來同時訪問不同的集合3。
應用程序可以調用VIDIOC_REQBUFS來分配想要的設備內存,只要提供buffer數和buffer類型(例子:V4L2_BUF_TYPE_VIDEO_CAPTURE)。當然上面的ioctl方法也可以用來更改buffer數或者釋放分配的內存,如果仍有處於maped狀態,它可能不做任何改變。
應用程序可以訪問這些buffer之前還必須通過mmap()(這驅動編程中很常見的哦)將這些buffer映射到應用程序的地址空間去。可以用VIDIOC_QUERYBUF來獲得設備內存中的這些個buffer地址。mmap()第六和第二個參數是m.offset和length(由結構v4l2_buffer返回),這倆參數可別瞎改。謹記一點,這些個buffer地址是物理地址而不是虛擬地址(內核空間,用戶空間;物理地址,虛擬地址,進程地址...不同架構範圍是不同的)。資源有限,不用的就munmap()掉吧。