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_buffer
的 type
字段设置为与之前与结构体 v4l2_format
type
和结构体 v4l2_requestbuffers
type
一起使用的缓冲区类型相同。 应用程序还必须设置 index
字段。 有效的索引号范围从零到使用 ioctl VIDIOC_REQBUFS 分配的缓冲区数量(结构体 v4l2_requestbuffers
count
)减一。 由 ioctl VIDIOC_QUERYBUF ioctl 返回的结构体 v4l2_buffer
的内容也将起作用。 当缓冲区用于输出(type
是 V4L2_BUF_TYPE_VIDEO_OUTPUT
, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE
, 或 V4L2_BUF_TYPE_VBI_OUTPUT
)时,应用程序还必须初始化 bytesused
, field
和 timestamp
字段,参见 缓冲区 了解详细信息。 应用程序还必须将 flags
设置为 0。 reserved2
和 reserved
字段必须设置为 0。 当使用 多平面 API 时,m.planes
字段必须包含一个指向已填充的结构体 v4l2_plane
数组的用户空间指针,并且 length
字段必须设置为该数组中元素的数量。
要排队一个 内存映射 缓冲区,应用程序将 memory
字段设置为 V4L2_MEMORY_MMAP
。 当使用指向此结构的指针调用 VIDIOC_QBUF
时,驱动程序将 V4L2_BUF_FLAG_MAPPED
和 V4L2_BUF_FLAG_QUEUED
标志,并清除 flags
字段中的 V4L2_BUF_FLAG_DONE
标志,或者它返回一个 EINVAL
错误代码。
要排队一个 用户指针 缓冲区,应用程序将 memory
字段设置为 V4L2_MEMORY_USERPTR
,m.userptr
字段设置为缓冲区的地址,length
设置为其大小。 当使用多平面 API 时,必须使用传递的结构体 v4l2_plane
数组的 m.userptr
和 length
成员。 当使用指向此结构的指针调用 VIDIOC_QBUF
时,驱动程序将设置 V4L2_BUF_FLAG_QUEUED
标志,并清除 flags
字段中的 V4L2_BUF_FLAG_MAPPED
和 V4L2_BUF_FLAG_DONE
标志,或者它返回一个错误代码。 此 ioctl 会锁定物理内存中的缓冲区内存页,它们无法交换到磁盘。 缓冲区保持锁定状态,直到出队,直到调用 VIDIOC_STREAMOFF 或 ioctl 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_MAPPED
和 V4L2_BUF_FLAG_DONE
标志,或者它返回一个错误代码。 此 ioctl 会锁定缓冲区。 锁定缓冲区意味着将其传递给驱动程序以进行硬件访问(通常是 DMA)。 如果应用程序访问(读取/写入)锁定的缓冲区,则结果未定义。 缓冲区保持锁定状态,直到出队,直到调用 VIDIOC_STREAMOFF 或 ioctl 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_buffer
的 type
, memory
和 reserved
字段设置为如上所述,驱动程序将填充所有剩余字段或返回错误代码。 驱动程序还可以在 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
超出范围,或者尚未分配缓冲区,或者userptr
或length
无效,或者设置了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)。