Commit | Line | Data |
---|---|---|
5377d91f MH |
1 | .. -*- coding: utf-8; mode: rst -*- |
2 | ||
3 | .. _mmap: | |
4 | ||
5 | ****************************** | |
6 | Streaming I/O (Memory Mapping) | |
7 | ****************************** | |
8 | ||
9 | Input and output devices support this I/O method when the | |
10 | ``V4L2_CAP_STREAMING`` flag in the ``capabilities`` field of struct | |
e8be7e97 | 11 | :c:type:`v4l2_capability` returned by the |
7347081e | 12 | :ref:`VIDIOC_QUERYCAP` ioctl is set. There are two |
5377d91f | 13 | streaming methods, to determine if the memory mapping flavor is |
071dedfe MCC |
14 | supported applications must call the :ref:`VIDIOC_REQBUFS` ioctl |
15 | with the memory type set to ``V4L2_MEMORY_MMAP``. | |
5377d91f MH |
16 | |
17 | Streaming is an I/O method where only pointers to buffers are exchanged | |
18 | between application and driver, the data itself is not copied. Memory | |
19 | mapping is primarily intended to map buffers in device memory into the | |
20 | application's address space. Device memory can be for example the video | |
21 | memory on a graphics card with a video capture add-on. However, being | |
22 | the most efficient I/O method available for a long time, many other | |
23 | drivers support streaming as well, allocating buffers in DMA-able main | |
24 | memory. | |
25 | ||
26 | A driver can support many sets of buffers. Each set is identified by a | |
27 | unique buffer type value. The sets are independent and each set can hold | |
28 | a different type of data. To access different sets at the same time | |
4855307b | 29 | different file descriptors must be used. [#f1]_ |
5377d91f MH |
30 | |
31 | To allocate device buffers applications call the | |
7347081e | 32 | :ref:`VIDIOC_REQBUFS` ioctl with the desired number |
5377d91f MH |
33 | of buffers and buffer type, for example ``V4L2_BUF_TYPE_VIDEO_CAPTURE``. |
34 | This ioctl can also be used to change the number of buffers or to free | |
35 | the allocated memory, provided none of the buffers are still mapped. | |
36 | ||
37 | Before applications can access the buffers they must map them into their | |
38 | address space with the :ref:`mmap() <func-mmap>` function. The | |
39 | location of the buffers in device memory can be determined with the | |
7347081e | 40 | :ref:`VIDIOC_QUERYBUF` ioctl. In the single-planar |
5377d91f | 41 | API case, the ``m.offset`` and ``length`` returned in a struct |
e8be7e97 | 42 | :c:type:`v4l2_buffer` are passed as sixth and second |
760c7010 | 43 | parameter to the :ref:`mmap() <func-mmap>` function. When using the |
e8be7e97 MCC |
44 | multi-planar API, struct :c:type:`v4l2_buffer` contains an |
45 | array of struct :c:type:`v4l2_plane` structures, each | |
5377d91f MH |
46 | containing its own ``m.offset`` and ``length``. When using the |
47 | multi-planar API, every plane of every buffer has to be mapped | |
48 | separately, so the number of calls to :ref:`mmap() <func-mmap>` should | |
49 | be equal to number of buffers times number of planes in each buffer. The | |
50 | offset and length values must not be modified. Remember, the buffers are | |
51 | allocated in physical memory, as opposed to virtual memory, which can be | |
52 | swapped out to disk. Applications should free the buffers as soon as | |
53 | possible with the :ref:`munmap() <func-munmap>` function. | |
54 | ||
282f02cb MCC |
55 | Example: Mapping buffers in the single-planar API |
56 | ================================================= | |
5377d91f MH |
57 | |
58 | .. code-block:: c | |
59 | ||
60 | struct v4l2_requestbuffers reqbuf; | |
61 | struct { | |
6970f299 MCC |
62 | void *start; |
63 | size_t length; | |
5377d91f MH |
64 | } *buffers; |
65 | unsigned int i; | |
66 | ||
67 | memset(&reqbuf, 0, sizeof(reqbuf)); | |
68 | reqbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | |
69 | reqbuf.memory = V4L2_MEMORY_MMAP; | |
70 | reqbuf.count = 20; | |
71 | ||
72 | if (-1 == ioctl (fd, VIDIOC_REQBUFS, &reqbuf)) { | |
6970f299 MCC |
73 | if (errno == EINVAL) |
74 | printf("Video capturing or mmap-streaming is not supported\\n"); | |
75 | else | |
76 | perror("VIDIOC_REQBUFS"); | |
5377d91f | 77 | |
6970f299 | 78 | exit(EXIT_FAILURE); |
5377d91f MH |
79 | } |
80 | ||
81 | /* We want at least five buffers. */ | |
82 | ||
83 | if (reqbuf.count < 5) { | |
6970f299 MCC |
84 | /* You may need to free the buffers here. */ |
85 | printf("Not enough buffer memory\\n"); | |
86 | exit(EXIT_FAILURE); | |
5377d91f MH |
87 | } |
88 | ||
89 | buffers = calloc(reqbuf.count, sizeof(*buffers)); | |
90 | assert(buffers != NULL); | |
91 | ||
92 | for (i = 0; i < reqbuf.count; i++) { | |
6970f299 MCC |
93 | struct v4l2_buffer buffer; |
94 | ||
95 | memset(&buffer, 0, sizeof(buffer)); | |
96 | buffer.type = reqbuf.type; | |
97 | buffer.memory = V4L2_MEMORY_MMAP; | |
98 | buffer.index = i; | |
99 | ||
100 | if (-1 == ioctl (fd, VIDIOC_QUERYBUF, &buffer)) { | |
101 | perror("VIDIOC_QUERYBUF"); | |
102 | exit(EXIT_FAILURE); | |
103 | } | |
104 | ||
105 | buffers[i].length = buffer.length; /* remember for munmap() */ | |
106 | ||
107 | buffers[i].start = mmap(NULL, buffer.length, | |
108 | PROT_READ | PROT_WRITE, /* recommended */ | |
109 | MAP_SHARED, /* recommended */ | |
110 | fd, buffer.m.offset); | |
111 | ||
112 | if (MAP_FAILED == buffers[i].start) { | |
113 | /* If you do not exit here you should unmap() and free() | |
114 | the buffers mapped so far. */ | |
115 | perror("mmap"); | |
116 | exit(EXIT_FAILURE); | |
117 | } | |
5377d91f MH |
118 | } |
119 | ||
120 | /* Cleanup. */ | |
121 | ||
122 | for (i = 0; i < reqbuf.count; i++) | |
6970f299 | 123 | munmap(buffers[i].start, buffers[i].length); |
5377d91f MH |
124 | |
125 | ||
282f02cb MCC |
126 | Example: Mapping buffers in the multi-planar API |
127 | ================================================ | |
128 | ||
5377d91f MH |
129 | .. code-block:: c |
130 | ||
131 | struct v4l2_requestbuffers reqbuf; | |
132 | /* Our current format uses 3 planes per buffer */ | |
133 | #define FMT_NUM_PLANES = 3 | |
134 | ||
135 | struct { | |
6970f299 MCC |
136 | void *start[FMT_NUM_PLANES]; |
137 | size_t length[FMT_NUM_PLANES]; | |
5377d91f MH |
138 | } *buffers; |
139 | unsigned int i, j; | |
140 | ||
141 | memset(&reqbuf, 0, sizeof(reqbuf)); | |
142 | reqbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; | |
143 | reqbuf.memory = V4L2_MEMORY_MMAP; | |
144 | reqbuf.count = 20; | |
145 | ||
146 | if (ioctl(fd, VIDIOC_REQBUFS, &reqbuf) < 0) { | |
6970f299 MCC |
147 | if (errno == EINVAL) |
148 | printf("Video capturing or mmap-streaming is not supported\\n"); | |
149 | else | |
150 | perror("VIDIOC_REQBUFS"); | |
5377d91f | 151 | |
6970f299 | 152 | exit(EXIT_FAILURE); |
5377d91f MH |
153 | } |
154 | ||
155 | /* We want at least five buffers. */ | |
156 | ||
157 | if (reqbuf.count < 5) { | |
6970f299 MCC |
158 | /* You may need to free the buffers here. */ |
159 | printf("Not enough buffer memory\\n"); | |
160 | exit(EXIT_FAILURE); | |
5377d91f MH |
161 | } |
162 | ||
163 | buffers = calloc(reqbuf.count, sizeof(*buffers)); | |
164 | assert(buffers != NULL); | |
165 | ||
166 | for (i = 0; i < reqbuf.count; i++) { | |
6970f299 MCC |
167 | struct v4l2_buffer buffer; |
168 | struct v4l2_plane planes[FMT_NUM_PLANES]; | |
169 | ||
170 | memset(&buffer, 0, sizeof(buffer)); | |
171 | buffer.type = reqbuf.type; | |
172 | buffer.memory = V4L2_MEMORY_MMAP; | |
173 | buffer.index = i; | |
174 | /* length in struct v4l2_buffer in multi-planar API stores the size | |
175 | * of planes array. */ | |
176 | buffer.length = FMT_NUM_PLANES; | |
177 | buffer.m.planes = planes; | |
178 | ||
179 | if (ioctl(fd, VIDIOC_QUERYBUF, &buffer) < 0) { | |
180 | perror("VIDIOC_QUERYBUF"); | |
181 | exit(EXIT_FAILURE); | |
182 | } | |
183 | ||
184 | /* Every plane has to be mapped separately */ | |
185 | for (j = 0; j < FMT_NUM_PLANES; j++) { | |
186 | buffers[i].length[j] = buffer.m.planes[j].length; /* remember for munmap() */ | |
187 | ||
188 | buffers[i].start[j] = mmap(NULL, buffer.m.planes[j].length, | |
189 | PROT_READ | PROT_WRITE, /* recommended */ | |
190 | MAP_SHARED, /* recommended */ | |
191 | fd, buffer.m.planes[j].m.offset); | |
192 | ||
193 | if (MAP_FAILED == buffers[i].start[j]) { | |
194 | /* If you do not exit here you should unmap() and free() | |
195 | the buffers and planes mapped so far. */ | |
196 | perror("mmap"); | |
197 | exit(EXIT_FAILURE); | |
198 | } | |
199 | } | |
5377d91f MH |
200 | } |
201 | ||
202 | /* Cleanup. */ | |
203 | ||
204 | for (i = 0; i < reqbuf.count; i++) | |
6970f299 MCC |
205 | for (j = 0; j < FMT_NUM_PLANES; j++) |
206 | munmap(buffers[i].start[j], buffers[i].length[j]); | |
5377d91f MH |
207 | |
208 | Conceptually streaming drivers maintain two buffer queues, an incoming | |
209 | and an outgoing queue. They separate the synchronous capture or output | |
210 | operation locked to a video clock from the application which is subject | |
211 | to random disk or network delays and preemption by other processes, | |
212 | thereby reducing the probability of data loss. The queues are organized | |
213 | as FIFOs, buffers will be output in the order enqueued in the incoming | |
214 | FIFO, and were captured in the order dequeued from the outgoing FIFO. | |
215 | ||
216 | The driver may require a minimum number of buffers enqueued at all times | |
217 | to function, apart of this no limit exists on the number of buffers | |
218 | applications can enqueue in advance, or dequeue and process. They can | |
219 | also enqueue in a different order than buffers have been dequeued, and | |
4855307b | 220 | the driver can *fill* enqueued *empty* buffers in any order. [#f2]_ The |
e8be7e97 | 221 | index number of a buffer (struct :c:type:`v4l2_buffer` |
5377d91f MH |
222 | ``index``) plays no role here, it only identifies the buffer. |
223 | ||
224 | Initially all mapped buffers are in dequeued state, inaccessible by the | |
225 | driver. For capturing applications it is customary to first enqueue all | |
226 | mapped buffers, then to start capturing and enter the read loop. Here | |
227 | the application waits until a filled buffer can be dequeued, and | |
228 | re-enqueues the buffer when the data is no longer needed. Output | |
229 | applications fill and enqueue buffers, when enough buffers are stacked | |
6970f299 MCC |
230 | up the output is started with :ref:`VIDIOC_STREAMON <VIDIOC_STREAMON>`. |
231 | In the write loop, when the application runs out of free buffers, it | |
232 | must wait until an empty buffer can be dequeued and reused. | |
233 | ||
234 | To enqueue and dequeue a buffer applications use the :ref:`VIDIOC_QBUF` | |
235 | and :ref:`VIDIOC_DQBUF <VIDIOC_QBUF>` ioctl. The status of a buffer | |
236 | being mapped, enqueued, full or empty can be determined at any time | |
237 | using the :ref:`VIDIOC_QUERYBUF` ioctl. Two methods exist to suspend | |
238 | execution of the application until one or more buffers can be dequeued. | |
239 | By default :ref:`VIDIOC_DQBUF <VIDIOC_QBUF>` blocks when no buffer is | |
240 | in the outgoing queue. When the ``O_NONBLOCK`` flag was given to the | |
241 | :ref:`open() <func-open>` function, :ref:`VIDIOC_DQBUF <VIDIOC_QBUF>` | |
242 | returns immediately with an ``EAGAIN`` error code when no buffer is | |
243 | available. The :ref:`select() <func-select>` or :ref:`poll() | |
244 | <func-poll>` functions are always available. | |
5377d91f MH |
245 | |
246 | To start and stop capturing or output applications call the | |
6970f299 | 247 | :ref:`VIDIOC_STREAMON <VIDIOC_STREAMON>` and :ref:`VIDIOC_STREAMOFF |
706f8a99 MCC |
248 | <VIDIOC_STREAMON>` ioctl. |
249 | ||
250 | .. note:::ref:`VIDIOC_STREAMOFF <VIDIOC_STREAMON>` | |
251 | removes all buffers from both queues as a side effect. Since there is | |
252 | no notion of doing anything "now" on a multitasking system, if an | |
253 | application needs to synchronize with another event it should examine | |
e8be7e97 | 254 | the struct ::c:type:`v4l2_buffer` ``timestamp`` of captured |
706f8a99 | 255 | or outputted buffers. |
5377d91f MH |
256 | |
257 | Drivers implementing memory mapping I/O must support the | |
6970f299 MCC |
258 | :ref:`VIDIOC_REQBUFS <VIDIOC_REQBUFS>`, :ref:`VIDIOC_QUERYBUF |
259 | <VIDIOC_QUERYBUF>`, :ref:`VIDIOC_QBUF <VIDIOC_QBUF>`, :ref:`VIDIOC_DQBUF | |
260 | <VIDIOC_QBUF>`, :ref:`VIDIOC_STREAMON <VIDIOC_STREAMON>` | |
261 | and :ref:`VIDIOC_STREAMOFF <VIDIOC_STREAMON>` ioctls, the :ref:`mmap() | |
262 | <func-mmap>`, :ref:`munmap() <func-munmap>`, :ref:`select() | |
4855307b | 263 | <func-select>` and :ref:`poll() <func-poll>` function. [#f3]_ |
5377d91f MH |
264 | |
265 | [capture example] | |
266 | ||
4855307b | 267 | .. [#f1] |
5377d91f | 268 | One could use one file descriptor and set the buffer type field |
7347081e | 269 | accordingly when calling :ref:`VIDIOC_QBUF` etc., |
760c7010 | 270 | but it makes the :ref:`select() <func-select>` function ambiguous. We also |
5377d91f MH |
271 | like the clean approach of one file descriptor per logical stream. |
272 | Video overlay for example is also a logical stream, although the CPU | |
273 | is not needed for continuous operation. | |
274 | ||
4855307b | 275 | .. [#f2] |
5377d91f MH |
276 | Random enqueue order permits applications processing images out of |
277 | order (such as video codecs) to return buffers earlier, reducing the | |
278 | probability of data loss. Random fill order allows drivers to reuse | |
279 | buffers on a LIFO-basis, taking advantage of caches holding | |
280 | scatter-gather lists and the like. | |
281 | ||
4855307b | 282 | .. [#f3] |
760c7010 MCC |
283 | At the driver level :ref:`select() <func-select>` and :ref:`poll() <func-poll>` are |
284 | the same, and :ref:`select() <func-select>` is too important to be optional. | |
5377d91f | 285 | The rest should be evident. |