7.46. ioctl VIDIOC_QBUF, VIDIOC_DQBUF

7.46.1. 名稱

VIDIOC_QBUF - VIDIOC_DQBUF - 與驅動程式交換緩衝區

7.46.2. 概要

VIDIOC_QBUF

int ioctl(int fd, VIDIOC_QBUF, struct v4l2_buffer *argp)

VIDIOC_DQBUF

int ioctl(int fd, VIDIOC_DQBUF, struct v4l2_buffer *argp)

7.46.3. 引數

fd

open() 返回的檔案描述符。

argp

指向結構體 v4l2_buffer 的指標。

7.46.4. 描述

應用程式呼叫 VIDIOC_QBUF ioctl 將一個空的(捕獲)或已填充的(輸出)緩衝區排入驅動程式的傳入佇列。語義取決於選擇的 I/O 方法。

要排隊一個緩衝區,應用程式將結構體 v4l2_buffertype 欄位設定為與之前與結構體 v4l2_format type 和結構體 v4l2_requestbuffers type 一起使用的緩衝區型別相同。 應用程式還必須設定 index 欄位。 有效的索引號範圍從零到使用 ioctl VIDIOC_REQBUFS 分配的緩衝區數量(結構體 v4l2_requestbuffers count)減一。 由 ioctl VIDIOC_QUERYBUF ioctl 返回的結構體 v4l2_buffer 的內容也將起作用。 當緩衝區用於輸出(typeV4L2_BUF_TYPE_VIDEO_OUTPUT, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE, 或 V4L2_BUF_TYPE_VBI_OUTPUT)時,應用程式還必須初始化 bytesused, fieldtimestamp 欄位,參見 緩衝區 瞭解詳細資訊。 應用程式還必須將 flags 設定為 0。 reserved2reserved 欄位必須設定為 0。 當使用 多平面 API 時,m.planes 欄位必須包含一個指向已填充的結構體 v4l2_plane 陣列的使用者空間指標,並且 length 欄位必須設定為該陣列中元素的數量。

要排隊一個 記憶體對映 緩衝區,應用程式將 memory 欄位設定為 V4L2_MEMORY_MMAP。 當使用指向此結構的指標呼叫 VIDIOC_QBUF 時,驅動程式將 V4L2_BUF_FLAG_MAPPEDV4L2_BUF_FLAG_QUEUED 標誌,並清除 flags 欄位中的 V4L2_BUF_FLAG_DONE 標誌,或者它返回一個 EINVAL 錯誤程式碼。

要排隊一個 使用者指標 緩衝區,應用程式將 memory 欄位設定為 V4L2_MEMORY_USERPTRm.userptr 欄位設定為緩衝區的地址,length 設定為其大小。 當使用多平面 API 時,必須使用傳遞的結構體 v4l2_plane 陣列的 m.userptrlength 成員。 當使用指向此結構的指標呼叫 VIDIOC_QBUF 時,驅動程式將設定 V4L2_BUF_FLAG_QUEUED 標誌,並清除 flags 欄位中的 V4L2_BUF_FLAG_MAPPEDV4L2_BUF_FLAG_DONE 標誌,或者它返回一個錯誤程式碼。 此 ioctl 會鎖定物理記憶體中的緩衝區記憶體頁,它們無法交換到磁碟。 緩衝區保持鎖定狀態,直到出隊,直到呼叫 VIDIOC_STREAMOFFioctl VIDIOC_REQBUFS ioctl,或直到裝置關閉。

要排隊一個 DMABUF 緩衝區,應用程式將 memory 欄位設定為 V4L2_MEMORY_DMABUF,並將 m.fd 欄位設定為與 DMABUF 緩衝區關聯的檔案描述符。 當使用多平面 API 時,必須使用傳遞的結構體 v4l2_plane 陣列的 m.fd 欄位。 當使用指向此結構的指標呼叫 VIDIOC_QBUF 時,驅動程式將設定 V4L2_BUF_FLAG_QUEUED 標誌,並清除 flags 欄位中的 V4L2_BUF_FLAG_MAPPEDV4L2_BUF_FLAG_DONE 標誌,或者它返回一個錯誤程式碼。 此 ioctl 會鎖定緩衝區。 鎖定緩衝區意味著將其傳遞給驅動程式以進行硬體訪問(通常是 DMA)。 如果應用程式訪問(讀取/寫入)鎖定的緩衝區,則結果未定義。 緩衝區保持鎖定狀態,直到出隊,直到呼叫 VIDIOC_STREAMOFFioctl VIDIOC_REQBUFS ioctl,或直到裝置關閉。

如果正在使用請求,則可以將 request_fd 欄位與 VIDIOC_QBUF ioctl 一起使用,以指定 請求 的檔案描述符。 設定它意味著緩衝區在請求本身排隊之前不會傳遞給驅動程式。 此外,驅動程式將為此緩衝區應用與請求關聯的任何設定。 除非設定了 V4L2_BUF_FLAG_REQUEST_FD 標誌,否則將忽略此欄位。 如果裝置不支援請求,則將返回 EBADR。 如果支援請求但給出了無效的請求檔案描述符,則將返回 EINVAL

警告

不允許混合排隊請求和直接排隊緩衝區。 如果第一個緩衝區直接排隊,然後應用程式嘗試排隊一個請求,或者反之亦然,將返回 EBUSY。 關閉檔案描述符,呼叫 VIDIOC_STREAMOFF 或呼叫 ioctl VIDIOC_REQBUFS 後,對此的檢查將重置。

對於 記憶體到記憶體裝置,您只能為輸出緩衝區指定 request_fd,而不能為捕獲緩衝區指定。 嘗試為捕獲緩衝區指定此項將導致 EBADR 錯誤。

應用程式呼叫 VIDIOC_DQBUF ioctl 從驅動程式的傳出佇列中出隊一個已填充的(捕獲)或已顯示的(輸出)緩衝區。 當使用指向此結構的指標呼叫 VIDIOC_DQBUF 時,它們只需將結構體 v4l2_buffertype, memoryreserved 欄位設定為如上所述,驅動程式將填充所有剩餘欄位或返回錯誤程式碼。 驅動程式還可以在 flags 欄位中設定 V4L2_BUF_FLAG_ERROR。 它表示非關鍵的(可恢復的)流式傳輸錯誤。 在這種情況下,應用程式可以像往常一樣繼續,但應該意識到出隊緩衝區中的資料可能已損壞。 當使用多平面 API 時,也必須傳入平面陣列。

如果應用程式將 memory 欄位設定為 V4L2_MEMORY_DMABUF 以出隊一個 DMABUF 緩衝區,則驅動程式將 m.fd 欄位填充一個檔案描述符,該檔案描述符在數值上與緩衝區排隊時給 VIDIOC_QBUF 的檔案描述符相同。 在出隊時不會建立新的檔案描述符,該值僅為應用程式方便起見。 當使用多平面 API 時,將填充傳遞的結構體 v4l2_plane 陣列的 m.fd 欄位。

預設情況下,當傳出佇列中沒有緩衝區時,VIDIOC_DQBUF 會阻塞。 當 open() 函式具有 O_NONBLOCK 標誌時,當沒有緩衝區可用時,VIDIOC_DQBUF 會立即返回一個 EAGAIN 錯誤程式碼。

結構體 v4l2_buffer 結構在 緩衝區 中指定。

7.46.5. 返回值

成功時返回 0,出錯時返回 -1,並適當設定 errno 變數。 通用錯誤程式碼在 通用錯誤程式碼 章節中描述。

EAGAIN

已使用 O_NONBLOCK 選擇了非阻塞 I/O,並且傳出佇列中沒有緩衝區。

EINVAL

不支援緩衝區 type,或者 index 超出範圍,或者尚未分配緩衝區,或者 userptrlength 無效,或者設定了 V4L2_BUF_FLAG_REQUEST_FD 標誌,但給定的 request_fd 無效,或者 m.fd 是無效的 DMABUF 檔案描述符。

EIO

由於內部錯誤,VIDIOC_DQBUF 失敗。 也可以指示諸如訊號丟失之類的臨時問題。

注意

儘管返回錯誤,驅動程式也可能會出隊一個(空)緩衝區,甚至停止捕獲。 重用此類緩衝區可能不安全,並且其詳細資訊(例如 index)也可能不會返回。 建議驅動程式透過設定 V4L2_BUF_FLAG_ERROR 並返回 0 來指示可恢復的錯誤。 在這種情況下,應用程式應該能夠安全地重用緩衝區並繼續流式傳輸。

EPIPE

如果具有 V4L2_BUF_FLAG_LAST 的緩衝區已被出隊並且預計不會有新的緩衝區可用,則 VIDIOC_DQBUF 會在 mem2mem 編解碼器的空捕獲佇列上返回此錯誤。

EBADR

設定了 V4L2_BUF_FLAG_REQUEST_FD 標誌,但裝置不支援給定緩衝區型別的請求,或者未設定 V4L2_BUF_FLAG_REQUEST_FD 標誌,但裝置要求緩衝區是請求的一部分。

EBUSY

第一個緩衝區是透過請求排隊的,但應用程式現在嘗試直接排隊它,或者反之亦然(不允許混合使用這兩個 API)。