← Documents Documentation/userspace-api/media/v4l/userp.rst GitHub 원문 ↗

Linux 6.18.37 · Userspace API / Media / V4L

V4L2 USERPTR 스트리밍

응용 프로그램 소유 버퍼를 사용자 포인터로 큐에 전달하는 스트리밍 I/O를 설명합니다.

Source pathDocumentation/userspace-api/media/v4l/userp.rst
Source versionLinux v6.18.37
TranslationDUJINLABS 전문 번역 + 해설

요약·해설과 원문, 전문 번역을 서로 분리했습니다. API 이름, symbol, source path는 원문 표기를 사용합니다.

1. 요약·해설

원문의 핵심 논리와 kernel programming 관점의 보충 설명입니다. 아래의 전문 번역과는 별도로 작성했습니다.

요약·해설

userp.rst:1-122

응용 프로그램 소유 버퍼를 사용자 포인터로 큐에 전달하는 스트리밍 I/O를 설명합니다.

2. 영어 원문 전체

번역 기준이 된 Linux v6.18.37 원문입니다. 줄 번호는 이 버전의 파일 좌표입니다.

원문 전체 펼치기
1 .. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later
2 .. c:namespace:: V4L
3
4 .. _userp:
5
6 *****************************
7 Streaming I/O (User Pointers)
8 *****************************
9
10 Input and output devices support this I/O method when the
11 ``V4L2_CAP_STREAMING`` flag in the ``capabilities`` field of struct
12 :c:type:`v4l2_capability` returned by the
13 :ref:`VIDIOC_QUERYCAP` ioctl is set. If the
14 particular user pointer method (not only memory mapping) is supported
15 must be determined by calling the :ref:`VIDIOC_REQBUFS` ioctl
16 with the memory type set to ``V4L2_MEMORY_USERPTR``.
17
18 This I/O method combines advantages of the read/write and memory mapping
19 methods. Buffers (planes) are allocated by the application itself, and
20 can reside for example in virtual or shared memory. Only pointers to
21 data are exchanged, these pointers and meta-information are passed in
22 struct :c:type:`v4l2_buffer` (or in struct
23 :c:type:`v4l2_plane` in the multi-planar API case). The
24 driver must be switched into user pointer I/O mode by calling the
25 :ref:`VIDIOC_REQBUFS` with the desired buffer type.
26 No buffers (planes) are allocated beforehand, consequently they are not
27 indexed and cannot be queried like mapped buffers with the
28 :ref:`VIDIOC_QUERYBUF <VIDIOC_QUERYBUF>` ioctl.
29
30 Example: Initiating streaming I/O with user pointers
31 ====================================================
32
33 .. code-block:: c
34
35 struct v4l2_requestbuffers reqbuf;
36
37 memset (&reqbuf, 0, sizeof (reqbuf));
38 reqbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
39 reqbuf.memory = V4L2_MEMORY_USERPTR;
40
41 if (ioctl (fd, VIDIOC_REQBUFS, &reqbuf) == -1) {
42 if (errno == EINVAL)
43 printf ("Video capturing or user pointer streaming is not supported\\n");
44 else
45 perror ("VIDIOC_REQBUFS");
46
47 exit (EXIT_FAILURE);
48 }
49
50 Buffer (plane) addresses and sizes are passed on the fly with the
51 :ref:`VIDIOC_QBUF <VIDIOC_QBUF>` ioctl. Although buffers are commonly
52 cycled, applications can pass different addresses and sizes at each
53 :ref:`VIDIOC_QBUF <VIDIOC_QBUF>` call. If required by the hardware the
54 driver swaps memory pages within physical memory to create a continuous
55 area of memory. This happens transparently to the application in the
56 virtual memory subsystem of the kernel. When buffer pages have been
57 swapped out to disk they are brought back and finally locked in physical
58 memory for DMA. [#f1]_
59
60 Filled or displayed buffers are dequeued with the
61 :ref:`VIDIOC_DQBUF <VIDIOC_QBUF>` ioctl. The driver can unlock the
62 memory pages at any time between the completion of the DMA and this
63 ioctl. The memory is also unlocked when
64 :ref:`VIDIOC_STREAMOFF <VIDIOC_STREAMON>` is called,
65 :ref:`VIDIOC_REQBUFS`, or when the device is closed.
66 Applications must take care not to free buffers without dequeuing.
67 Firstly, the buffers remain locked for longer, wasting physical memory.
68 Secondly the driver will not be notified when the memory is returned to
69 the application's free list and subsequently reused for other purposes,
70 possibly completing the requested DMA and overwriting valuable data.
71
72 For capturing applications it is customary to enqueue a number of empty
73 buffers, to start capturing and enter the read loop. Here the
74 application waits until a filled buffer can be dequeued, and re-enqueues
75 the buffer when the data is no longer needed. Output applications fill
76 and enqueue buffers, when enough buffers are stacked up output is
77 started. In the write loop, when the application runs out of free
78 buffers it must wait until an empty buffer can be dequeued and reused.
79 Two methods exist to suspend execution of the application until one or
80 more buffers can be dequeued. By default :ref:`VIDIOC_DQBUF
81 <VIDIOC_QBUF>` blocks when no buffer is in the outgoing queue. When the
82 ``O_NONBLOCK`` flag was given to the :c:func:`open()` function,
83 :ref:`VIDIOC_DQBUF <VIDIOC_QBUF>` returns immediately with an ``EAGAIN``
84 error code when no buffer is available. The :ref:`select()
85 <func-select>` or :c:func:`poll()` function are always
86 available.
87
88 To start and stop capturing or output applications call the
89 :ref:`VIDIOC_STREAMON <VIDIOC_STREAMON>` and
90 :ref:`VIDIOC_STREAMOFF <VIDIOC_STREAMON>` ioctl.
91
92 .. note::
93
94 :ref:`VIDIOC_STREAMOFF <VIDIOC_STREAMON>` removes all buffers from
95 both queues and unlocks all buffers as a side effect. Since there is no
96 notion of doing anything "now" on a multitasking system, if an
97 application needs to synchronize with another event it should examine
98 the struct :c:type:`v4l2_buffer` ``timestamp`` of captured or
99 outputted buffers.
100
101 Drivers implementing user pointer I/O must support the
102 :ref:`VIDIOC_REQBUFS <VIDIOC_REQBUFS>`, :ref:`VIDIOC_QBUF <VIDIOC_QBUF>`,
103 :ref:`VIDIOC_DQBUF <VIDIOC_QBUF>`, :ref:`VIDIOC_STREAMON <VIDIOC_STREAMON>`
104 and :ref:`VIDIOC_STREAMOFF <VIDIOC_STREAMON>` ioctls, the
105 :c:func:`select()` and :c:func:`poll()` function. [#f2]_
106
107 .. [#f1]
108 We expect that frequently used buffers are typically not swapped out.
109 Anyway, the process of swapping, locking or generating scatter-gather
110 lists may be time consuming. The delay can be masked by the depth of
111 the incoming buffer queue, and perhaps by maintaining caches assuming
112 a buffer will be soon enqueued again. On the other hand, to optimize
113 memory usage drivers can limit the number of buffers locked in
114 advance and recycle the most recently used buffers first. Of course,
115 the pages of empty buffers in the incoming queue need not be saved to
116 disk. Output buffers must be saved on the incoming and outgoing queue
117 because an application may share them with other processes.
118
119 .. [#f2]
120 At the driver level :c:func:`select()` and :c:func:`poll()` are
121 the same, and :c:func:`select()` is too important to be optional.
122 The rest should be evident.
123

3. 한국어 전문 번역

영어 원문의 문단 순서와 의미를 유지한 전체 번역입니다. 코드, 함수명, symbol과 URL은 원문 표기를 유지합니다.

USERPTR 지원 확인과 메모리 소유권

1-29

입출력 장치는 `VIDIOC_QUERYCAP`의 `v4l2_capability.capabilities`에 `V4L2_CAP_STREAMING`이 설정되어 있을 때 스트리밍 I/O를 지원합니다. 그중 사용자 포인터 방식의 실제 지원 여부는 `VIDIOC_REQBUFS`의 메모리 유형을 `V4L2_MEMORY_USERPTR`로 지정해 확인해야 합니다.

USERPTR은 read/write 방식과 메모리 매핑 방식의 장점을 결합합니다. 응용 프로그램이 가상 또는 공유 메모리 등에 버퍼와 평면을 직접 할당하고, 드라이버와는 `v4l2_buffer` 또는 다중 평면 API의 `v4l2_plane`을 통해 포인터와 메타정보만 교환합니다.

`VIDIOC_REQBUFS`로 원하는 버퍼 유형과 USERPTR 모드를 선택하지만 드라이버가 버퍼를 미리 할당하지는 않습니다. 따라서 버퍼에는 고정 인덱스가 없고 mmap 버퍼처럼 `VIDIOC_QUERYBUF`로 조회할 수 없습니다.

.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later
.. c:namespace:: V4L

.. _userp:

*****************************
Streaming I/O (User Pointers)
*****************************

Input and output devices support this I/O method when the
``V4L2_CAP_STREAMING`` flag in the ``capabilities`` field of struct
:c:type:`v4l2_capability` returned by the
:ref:`VIDIOC_QUERYCAP` ioctl is set. If the
particular user pointer method (not only memory mapping) is supported
must be determined by calling the :ref:`VIDIOC_REQBUFS` ioctl
with the memory type set to ``V4L2_MEMORY_USERPTR``.

This I/O method combines advantages of the read/write and memory mapping
methods. Buffers (planes) are allocated by the application itself, and
can reside for example in virtual or shared memory. Only pointers to
data are exchanged, these pointers and meta-information are passed in
struct :c:type:`v4l2_buffer` (or in struct
:c:type:`v4l2_plane` in the multi-planar API case). The
driver must be switched into user pointer I/O mode by calling the
:ref:`VIDIOC_REQBUFS` with the desired buffer type.
No buffers (planes) are allocated beforehand, consequently they are not
indexed and cannot be queried like mapped buffers with the
:ref:`VIDIOC_QUERYBUF <VIDIOC_QUERYBUF>` ioctl.

USERPTR 모드 시작과 DMA 메모리 준비

30-58

`v4l2_requestbuffers`를 0으로 초기화하고 `type`에 스트림 유형, `memory`에 `V4L2_MEMORY_USERPTR`을 지정한 뒤 `VIDIOC_REQBUFS`를 호출합니다. `EINVAL`이면 해당 장치가 캡처 또는 사용자 포인터 스트리밍을 지원하지 않는다는 뜻입니다.

struct v4l2_requestbuffers reqbuf = { 0 };
reqbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
reqbuf.memory = V4L2_MEMORY_USERPTR;
if (ioctl(fd, VIDIOC_REQBUFS, &reqbuf) == -1) {
    if (errno == EINVAL)
        printf("USERPTR streaming is not supported\n");
}

버퍼 주소와 크기는 `VIDIOC_QBUF` 호출마다 전달하므로 매번 다른 주소와 크기를 사용할 수 있습니다. 하드웨어가 연속 물리 메모리를 요구하면 드라이버와 커널 가상 메모리 계층이 페이지를 투명하게 재배치하고, 스왑 아웃된 페이지를 불러와 DMA 동안 물리 메모리에 고정합니다.

Example: Initiating streaming I/O with user pointers
====================================================

.. code-block:: c

    struct v4l2_requestbuffers reqbuf;

    memset (&reqbuf, 0, sizeof (reqbuf));
    reqbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    reqbuf.memory = V4L2_MEMORY_USERPTR;

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

	exit (EXIT_FAILURE);
    }

Buffer (plane) addresses and sizes are passed on the fly with the
:ref:`VIDIOC_QBUF <VIDIOC_QBUF>` ioctl. Although buffers are commonly
cycled, applications can pass different addresses and sizes at each
:ref:`VIDIOC_QBUF <VIDIOC_QBUF>` call. If required by the hardware the
driver swaps memory pages within physical memory to create a continuous
area of memory. This happens transparently to the application in the
virtual memory subsystem of the kernel. When buffer pages have been
swapped out to disk they are brought back and finally locked in physical
memory for DMA. [#f1]_

큐 수명주기와 블로킹 동작

59-100

처리된 버퍼는 `VIDIOC_DQBUF`로 꺼냅니다. 드라이버는 DMA 완료와 dequeue 사이에 페이지 잠금을 해제할 수 있으며, `VIDIOC_STREAMOFF`, `VIDIOC_REQBUFS` 재호출 또는 장치 닫기 때도 잠금이 풀립니다. 응용 프로그램은 dequeue하지 않은 버퍼를 해제해서는 안 됩니다. 그렇지 않으면 물리 메모리를 오래 점유하거나, 재사용된 메모리를 뒤늦은 DMA가 덮어쓸 수 있습니다.

캡처는 빈 버퍼 여러 개를 enqueue하고 스트림을 시작한 뒤 채워진 버퍼를 dequeue하고 사용이 끝나면 다시 enqueue합니다. 출력은 데이터를 채운 버퍼를 쌓아 스트림을 시작하고, 빈 버퍼가 부족하면 처리 완료 버퍼를 dequeue해 재사용합니다.

기본 `VIDIOC_DQBUF`는 출력 큐에 버퍼가 없으면 블록합니다. 장치를 `O_NONBLOCK`으로 열었다면 즉시 `EAGAIN`을 반환하며, `select()`와 `poll()`은 항상 사용할 수 있습니다. `VIDIOC_STREAMON`과 `VIDIOC_STREAMOFF`로 스트림을 시작하고 중지합니다.

`VIDIOC_STREAMOFF`는 양쪽 큐에서 모든 버퍼를 제거하고 잠금을 해제합니다. 다른 사건과 동기화해야 한다면 멀티태스킹 환경의 '지금'에 의존하지 말고 캡처 또는 출력 버퍼의 `v4l2_buffer.timestamp`를 검사해야 합니다.

USERPTR 스트리밍 순환
응용 프로그램이 버퍼를 할당하고 VIDIOC_QBUF로 포인터와 크기를 제출합니다.VIDIOC_STREAMON 뒤 드라이버가 페이지를 고정하고 DMA를 수행합니다.select/poll 또는 블로킹 VIDIOC_DQBUF로 완료 버퍼를 기다립니다.버퍼 데이터를 사용하거나 다시 채운 뒤 VIDIOC_QBUF로 재사용합니다.VIDIOC_STREAMOFF로 모든 큐와 페이지 잠금을 정리합니다.

응용 프로그램 소유 버퍼가 드라이버 큐를 오가는 흐름입니다.


Filled or displayed buffers are dequeued with the
:ref:`VIDIOC_DQBUF <VIDIOC_QBUF>` ioctl. The driver can unlock the
memory pages at any time between the completion of the DMA and this
ioctl. The memory is also unlocked when
:ref:`VIDIOC_STREAMOFF <VIDIOC_STREAMON>` is called,
:ref:`VIDIOC_REQBUFS`, or when the device is closed.
Applications must take care not to free buffers without dequeuing.
Firstly, the buffers remain locked for longer, wasting physical memory.
Secondly the driver will not be notified when the memory is returned to
the application's free list and subsequently reused for other purposes,
possibly completing the requested DMA and overwriting valuable data.

For capturing applications it is customary to enqueue a number of empty
buffers, to start capturing and enter the read loop. Here the
application waits until a filled buffer can be dequeued, and re-enqueues
the buffer when the data is no longer needed. Output applications fill
and enqueue buffers, when enough buffers are stacked up output is
started. In the write loop, when the application runs out of free
buffers it must wait until an empty buffer can be dequeued and reused.
Two methods exist to suspend execution of the application until one or
more buffers can be dequeued. By default :ref:`VIDIOC_DQBUF
<VIDIOC_QBUF>` blocks when no buffer is in the outgoing queue. When the
``O_NONBLOCK`` flag was given to the :c:func:`open()` function,
:ref:`VIDIOC_DQBUF <VIDIOC_QBUF>` returns immediately with an ``EAGAIN``
error code when no buffer is available. The :ref:`select()
<func-select>` or :c:func:`poll()` function are always
available.

To start and stop capturing or output applications call the
:ref:`VIDIOC_STREAMON <VIDIOC_STREAMON>` and
:ref:`VIDIOC_STREAMOFF <VIDIOC_STREAMON>` ioctl.

.. note::

   :ref:`VIDIOC_STREAMOFF <VIDIOC_STREAMON>` removes all buffers from
   both queues and unlocks all buffers as a side effect. Since there is no
   notion of doing anything "now" on a multitasking system, if an
   application needs to synchronize with another event it should examine
   the struct :c:type:`v4l2_buffer` ``timestamp`` of captured or
   outputted buffers.

드라이버 필수 호출과 성능 고려

101-122

USERPTR I/O 드라이버는 `VIDIOC_REQBUFS`, `VIDIOC_QBUF`, `VIDIOC_DQBUF`, `VIDIOC_STREAMON`, `VIDIOC_STREAMOFF`, `select()`와 `poll()`을 지원해야 합니다. 드라이버 수준에서 select와 poll은 같은 동작이며 select는 선택 사항으로 둘 수 없을 만큼 중요합니다.

자주 쓰는 버퍼는 대개 스왑되지 않지만 페이지 스왑, 잠금, scatter-gather 목록 생성에는 시간이 걸릴 수 있습니다. 입력 큐 깊이와 재사용 캐시로 지연을 숨길 수 있고, 메모리 절약이 필요하면 미리 잠그는 버퍼 수를 제한하고 최근 사용 버퍼부터 재활용할 수 있습니다. 출력 버퍼는 다른 프로세스와 공유될 수 있으므로 입력·출력 큐 양쪽에서 보존해야 합니다.

Drivers implementing user pointer I/O must support the
:ref:`VIDIOC_REQBUFS <VIDIOC_REQBUFS>`, :ref:`VIDIOC_QBUF <VIDIOC_QBUF>`,
:ref:`VIDIOC_DQBUF <VIDIOC_QBUF>`, :ref:`VIDIOC_STREAMON <VIDIOC_STREAMON>`
and :ref:`VIDIOC_STREAMOFF <VIDIOC_STREAMON>` ioctls, the
:c:func:`select()` and :c:func:`poll()` function. [#f2]_

.. [#f1]
   We expect that frequently used buffers are typically not swapped out.
   Anyway, the process of swapping, locking or generating scatter-gather
   lists may be time consuming. The delay can be masked by the depth of
   the incoming buffer queue, and perhaps by maintaining caches assuming
   a buffer will be soon enqueued again. On the other hand, to optimize
   memory usage drivers can limit the number of buffers locked in
   advance and recycle the most recently used buffers first. Of course,
   the pages of empty buffers in the incoming queue need not be saved to
   disk. Output buffers must be saved on the incoming and outgoing queue
   because an application may share them with other processes.

.. [#f2]
   At the driver level :c:func:`select()` and :c:func:`poll()` are
   the same, and :c:func:`select()` is too important to be optional.
   The rest should be evident.