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
指向 struct
v4l2_buffer
的指针。
7.46.4. 描述¶
应用程序调用 VIDIOC_QBUF
ioctl 在驱动程序的传入队列中排入一个空的(捕获)或已填充的(输出)缓冲区。其语义取决于所选的 I/O 方法。
要排队一个缓冲区,应用程序将 struct v4l2_buffer
的 type
字段设置为与先前 struct v4l2_format
type
和 struct v4l2_requestbuffers
type
中使用的缓冲区类型相同。应用程序还必须设置 index
字段。有效的索引号范围从零到使用 ioctl VIDIOC_REQBUFS (struct v4l2_requestbuffers
count
) 分配的缓冲区数量减一。由 ioctl VIDIOC_QUERYBUF ioctl 返回的 struct 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
字段必须包含指向已填充的 struct v4l2_plane
数组的用户空间指针,并且 length
字段必须设置为该数组中的元素数量。
要排队一个 内存映射 缓冲区,应用程序将 memory
字段设置为 V4L2_MEMORY_MMAP
。当使用指向此结构的指针调用 VIDIOC_QBUF
时,驱动程序会在 flags
字段中设置 V4L2_BUF_FLAG_MAPPED
和 V4L2_BUF_FLAG_QUEUED
标志,并清除 V4L2_BUF_FLAG_DONE
标志,否则会返回 EINVAL
错误代码。
要排队一个 用户指针 缓冲区,应用程序将 memory
字段设置为 V4L2_MEMORY_USERPTR
,将 m.userptr
字段设置为缓冲区的地址,并将 length
设置为其大小。当使用多平面 API 时,必须使用传递的 struct v4l2_plane
数组的 m.userptr
和 length
成员。当使用指向此结构的指针调用 VIDIOC_QBUF
时,驱动程序会在 flags
字段中设置 V4L2_BUF_FLAG_QUEUED
标志,并清除 V4L2_BUF_FLAG_MAPPED
和 V4L2_BUF_FLAG_DONE
标志,否则会返回错误代码。此 ioctl 会锁定物理内存中的缓冲区内存页,它们不能被交换到磁盘。缓冲区将保持锁定状态,直到出队,直到调用 VIDIOC_STREAMOFF 或 ioctl VIDIOC_REQBUFS ioctl,或者直到设备关闭。
要排队一个 DMABUF 缓冲区,应用程序将 memory
字段设置为 V4L2_MEMORY_DMABUF
,并将 m.fd
字段设置为与 DMABUF 缓冲区关联的文件描述符。当使用多平面 API 时,必须使用传递的 struct v4l2_plane
数组的 m.fd
字段。当使用指向此结构的指针调用 VIDIOC_QBUF
时,驱动程序会在 flags
字段中设置 V4L2_BUF_FLAG_QUEUED
标志,并清除 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 时,也必须传入 planes 数组。
如果应用程序将 memory
字段设置为 V4L2_MEMORY_DMABUF
以出队一个 DMABUF 缓冲区,驱动程序会使用一个与缓冲区入队时传递给 VIDIOC_QBUF
的文件描述符在数值上相同的文件描述符填充 m.fd
字段。出队时不会创建新的文件描述符,该值仅为了方便应用程序。当使用多平面 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)。