V4L2文档翻译(十三)

http://linuxtv.org/downloads/v4l-dvb-apis/dmabuf.html

I/O流 (DMA缓存引用)

这是一个实验性接口,将来可能发生改变

DMABUF框架提供了在多设备见共享缓存的通用方法,支持DMABUF的设备驱动可以将一个DMA缓存以文件句柄的方式输出到用户空间(输出者规则),以文件句柄的方式从用户空间获取一个DMA缓存,这个文件句柄是之前其他或相同的设备所输出的(引入者规则),或都是。此章节描述在V4L2中DMABUF的引入者规则。

V4L2缓存以DMABUF文件句柄方式进行DMABUF输出。

支持I/O流方法的输入和输出设备在通过VIDIOC_QUERYCAP ioctl查询时,返回的struct v4l2_capability中capabilities成员会包含V4L2_CAP_STREAMING标签。是否支持通过DMABUF文件句柄引入DMABUF缓存决定了在调用VIDIOC_REQBUFS时内存类型是否要设定为V4L2_MEMORY_DMABUF。

这种I/O方法专用于在不同设备间共享DMA缓存,这些设备可以是V4L设备或是其他视频相关设备(如DRM)。缓存(面)通过应用程序控制驱动来申请。然后,这些缓存通过使用特殊API以文件句柄的方式输出给应用程序,交换的只有文件句柄。句柄和信息存在于struct v4l2_buffer(多平面API中是struct v4l2_plane)。在VIDIOC_REQBUFS ioctl执行后驱动必须切换到DMABUF I/O模式中。

例3.4 通过DMABUF文件句柄初始化I/O流

struct v4l2_requestbuffers reqbuf;

memset(&reqbuf, 0, sizeof (reqbuf));
reqbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
reqbuf.memory = V4L2_MEMORY_DMABUF;
reqbuf.count = 1;

if (ioctl(fd, VIDIOC_REQBUFS, &reqbuf) == -1) {
    if (errno == EINVAL)
        printf("Video capturing or DMABUF streaming is not supported\n");
    else
        perror("VIDIOC_REQBUFS");

    exit(EXIT_FAILURE);
}

缓存(面)文件描述符通过VIDIOC_QBUF ioctl传输。在多平面中,每个面都申请了一个不同的DMABUF描述符,尽管缓存通常是循环的,应用程序也要每次通过不同的DMABUF描述符进行VIDIOC_QBUF请求处理。

例3.5 单一平面API中入列DMABUF

int buffer_queue(int v4lfd, int index, int dmafd)
{
    struct v4l2_buffer buf;

    memset(&buf, 0, sizeof buf);
    buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    buf.memory = V4L2_MEMORY_DMABUF;
    buf.index = index;
    buf.m.fd = dmafd;

    if (ioctl(v4lfd, VIDIOC_QBUF, &buf) == -1) {
        perror("VIDIOC_QBUF");
        return -1;
    }

    return 0;
}

例3.6 多平面API中入列DMABUF

int buffer_queue_mp(int v4lfd, int index, int dmafd[], int n_planes)
{
    struct v4l2_buffer buf;
    struct v4l2_plane planes[VIDEO_MAX_PLANES];
    int i;

    memset(&buf, 0, sizeof buf);
    buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
    buf.memory = V4L2_MEMORY_DMABUF;
    buf.index = index;
    buf.m.planes = planes;
    buf.length = n_planes;

    memset(&planes, 0, sizeof(planes));

    for (i = 0; i < n_planes; ++i)
        buf.m.planes[i].m.fd = dmafd[i];

    if (ioctl(v4lfd, VIDIOC_QBUF, &buf) == -1) {
        perror("VIDIOC_QBUF");
        return -1;
    }

    return 0;
}

捕捉或显示缓存都通过VIDIOC_DQBUF ioctl进行出列操作。驱动在这个ioctl和DMA完成的期间可以在任何时候对缓存进行解锁。当VIDIOC_STREAMOFF或VIDIOC_REQBUFS调用,以及设备关闭的时候内存都会被解锁。

对于捕捉应用程序来说,在开始捕捉及进入读循环前通常要入列一定数量的空缓存。一旦已填充过的缓存可以出列,应用程序在其数据不再需要的时候会将此缓存重新入列。而输出程序对缓存进行填充和入列操作,当堆积了足够的缓存后输出就开始了,在写循环中,当程序没有空闲缓存可用了,它需要等待有可出列的空缓存然后对其重新利用。两种方法都会阻塞程序的执行直到有缓存可以出列为止。VIDIOC_DQBUF当输出序列中没有可用缓存时默认是阻塞的,若open()时带有O_NONBLOCK标签,在出现这种情况的时候VIDIOC_DQBUF会直接返回EAGAIN错误码。而select()和poll()函数一直都是有效的。

通过调用VIDIOC_STREAMON和VIDIOC_STREAMOFF ioctl可以开始及停止程序进行捕捉或输出,这里请注意,VIDIOC_STREAMOFF会将所有序列中的缓存都移除,并且解锁。因为在多任务系统中没有“当前”的概念,所以如果程序需要与其他事件进行同步,需要通过捕捉或输出缓存的struct v4l2_buffer中的timestamp成员进行。

声明了DMABUF流方法的驱动必须支持VIDIOC_REQBUFS,VIDIOC_QBUF,VIDIOC_DQBUF,VIDIOC_STREAMON,VIDIOC_STREAMOFF这些ioctl,以及select()和poll()函数。

同步I/O

此方法尚未定义。

你可能感兴趣的:(V4L2文档翻译(十三))