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

此方法尚未定義。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章