286 lines · plain
1.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later2.. c:namespace:: V4L3 4.. _mmap:5 6******************************7Streaming I/O (Memory Mapping)8******************************9 10Input and output devices support this I/O method when the11``V4L2_CAP_STREAMING`` flag in the ``capabilities`` field of struct12:c:type:`v4l2_capability` returned by the13:ref:`VIDIOC_QUERYCAP` ioctl is set. There are two14streaming methods, to determine if the memory mapping flavor is15supported applications must call the :ref:`VIDIOC_REQBUFS` ioctl16with the memory type set to ``V4L2_MEMORY_MMAP``.17 18Streaming is an I/O method where only pointers to buffers are exchanged19between application and driver, the data itself is not copied. Memory20mapping is primarily intended to map buffers in device memory into the21application's address space. Device memory can be for example the video22memory on a graphics card with a video capture add-on. However, being23the most efficient I/O method available for a long time, many other24drivers support streaming as well, allocating buffers in DMA-able main25memory.26 27A driver can support many sets of buffers. Each set is identified by a28unique buffer type value. The sets are independent and each set can hold29a different type of data. To access different sets at the same time30different file descriptors must be used. [#f1]_31 32To allocate device buffers applications call the33:ref:`VIDIOC_REQBUFS` ioctl with the desired number34of buffers and buffer type, for example ``V4L2_BUF_TYPE_VIDEO_CAPTURE``.35This ioctl can also be used to change the number of buffers or to free36the allocated memory, provided none of the buffers are still mapped.37 38Before applications can access the buffers they must map them into their39address space with the :c:func:`mmap()` function. The40location of the buffers in device memory can be determined with the41:ref:`VIDIOC_QUERYBUF` ioctl. In the single-planar42API case, the ``m.offset`` and ``length`` returned in a struct43:c:type:`v4l2_buffer` are passed as sixth and second44parameter to the :c:func:`mmap()` function. When using the45multi-planar API, struct :c:type:`v4l2_buffer` contains an46array of struct :c:type:`v4l2_plane` structures, each47containing its own ``m.offset`` and ``length``. When using the48multi-planar API, every plane of every buffer has to be mapped49separately, so the number of calls to :c:func:`mmap()` should50be equal to number of buffers times number of planes in each buffer. The51offset and length values must not be modified. Remember, the buffers are52allocated in physical memory, as opposed to virtual memory, which can be53swapped out to disk. Applications should free the buffers as soon as54possible with the :c:func:`munmap()` function.55 56Example: Mapping buffers in the single-planar API57=================================================58 59.. code-block:: c60 61 struct v4l2_requestbuffers reqbuf;62 struct {63 void *start;64 size_t length;65 } *buffers;66 unsigned int i;67 68 memset(&reqbuf, 0, sizeof(reqbuf));69 reqbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;70 reqbuf.memory = V4L2_MEMORY_MMAP;71 reqbuf.count = 20;72 73 if (-1 == ioctl (fd, VIDIOC_REQBUFS, &reqbuf)) {74 if (errno == EINVAL)75 printf("Video capturing or mmap-streaming is not supported\\n");76 else77 perror("VIDIOC_REQBUFS");78 79 exit(EXIT_FAILURE);80 }81 82 /* We want at least five buffers. */83 84 if (reqbuf.count < 5) {85 /* You may need to free the buffers here. */86 printf("Not enough buffer memory\\n");87 exit(EXIT_FAILURE);88 }89 90 buffers = calloc(reqbuf.count, sizeof(*buffers));91 assert(buffers != NULL);92 93 for (i = 0; i < reqbuf.count; i++) {94 struct v4l2_buffer buffer;95 96 memset(&buffer, 0, sizeof(buffer));97 buffer.type = reqbuf.type;98 buffer.memory = V4L2_MEMORY_MMAP;99 buffer.index = i;100 101 if (-1 == ioctl (fd, VIDIOC_QUERYBUF, &buffer)) {102 perror("VIDIOC_QUERYBUF");103 exit(EXIT_FAILURE);104 }105 106 buffers[i].length = buffer.length; /* remember for munmap() */107 108 buffers[i].start = mmap(NULL, buffer.length,109 PROT_READ | PROT_WRITE, /* recommended */110 MAP_SHARED, /* recommended */111 fd, buffer.m.offset);112 113 if (MAP_FAILED == buffers[i].start) {114 /* If you do not exit here you should unmap() and free()115 the buffers mapped so far. */116 perror("mmap");117 exit(EXIT_FAILURE);118 }119 }120 121 /* Cleanup. */122 123 for (i = 0; i < reqbuf.count; i++)124 munmap(buffers[i].start, buffers[i].length);125 126Example: Mapping buffers in the multi-planar API127================================================128 129.. code-block:: c130 131 struct v4l2_requestbuffers reqbuf;132 /* Our current format uses 3 planes per buffer */133 #define FMT_NUM_PLANES = 3134 135 struct {136 void *start[FMT_NUM_PLANES];137 size_t length[FMT_NUM_PLANES];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) {147 if (errno == EINVAL)148 printf("Video capturing or mmap-streaming is not supported\\n");149 else150 perror("VIDIOC_REQBUFS");151 152 exit(EXIT_FAILURE);153 }154 155 /* We want at least five buffers. */156 157 if (reqbuf.count < 5) {158 /* You may need to free the buffers here. */159 printf("Not enough buffer memory\\n");160 exit(EXIT_FAILURE);161 }162 163 buffers = calloc(reqbuf.count, sizeof(*buffers));164 assert(buffers != NULL);165 166 for (i = 0; i < reqbuf.count; i++) {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 size175 * 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.mem_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 }200 }201 202 /* Cleanup. */203 204 for (i = 0; i < reqbuf.count; i++)205 for (j = 0; j < FMT_NUM_PLANES; j++)206 munmap(buffers[i].start[j], buffers[i].length[j]);207 208Conceptually streaming drivers maintain two buffer queues, an incoming209and an outgoing queue. They separate the synchronous capture or output210operation locked to a video clock from the application which is subject211to random disk or network delays and preemption by other processes,212thereby reducing the probability of data loss. The queues are organized213as FIFOs, buffers will be output in the order enqueued in the incoming214FIFO, and were captured in the order dequeued from the outgoing FIFO.215 216The driver may require a minimum number of buffers enqueued at all times217to function, apart of this no limit exists on the number of buffers218applications can enqueue in advance, or dequeue and process. They can219also enqueue in a different order than buffers have been dequeued, and220the driver can *fill* enqueued *empty* buffers in any order. [#f2]_ The221index number of a buffer (struct :c:type:`v4l2_buffer`222``index``) plays no role here, it only identifies the buffer.223 224Initially all mapped buffers are in dequeued state, inaccessible by the225driver. For capturing applications it is customary to first enqueue all226mapped buffers, then to start capturing and enter the read loop. Here227the application waits until a filled buffer can be dequeued, and228re-enqueues the buffer when the data is no longer needed. Output229applications fill and enqueue buffers, when enough buffers are stacked230up the output is started with :ref:`VIDIOC_STREAMON <VIDIOC_STREAMON>`.231In the write loop, when the application runs out of free buffers, it232must wait until an empty buffer can be dequeued and reused.233 234To enqueue and dequeue a buffer applications use the235:ref:`VIDIOC_QBUF <VIDIOC_QBUF>` and :ref:`VIDIOC_DQBUF <VIDIOC_QBUF>`236ioctl. The status of a buffer being mapped, enqueued, full or empty can237be determined at any time using the :ref:`VIDIOC_QUERYBUF` ioctl. Two238methods exist to suspend execution of the application until one or more239buffers can be dequeued. By default :ref:`VIDIOC_DQBUF <VIDIOC_QBUF>`240blocks when no buffer is in the outgoing queue. When the ``O_NONBLOCK``241flag was given to the :c:func:`open()` function,242:ref:`VIDIOC_DQBUF <VIDIOC_QBUF>` returns immediately with an ``EAGAIN``243error code when no buffer is available. The :c:func:`select()`244or :c:func:`poll()` functions are always available.245 246To start and stop capturing or output applications call the247:ref:`VIDIOC_STREAMON <VIDIOC_STREAMON>` and :ref:`VIDIOC_STREAMOFF248<VIDIOC_STREAMON>` ioctl.249 250.. note:::ref:`VIDIOC_STREAMOFF <VIDIOC_STREAMON>`251 removes all buffers from both queues as a side effect. Since there is252 no notion of doing anything "now" on a multitasking system, if an253 application needs to synchronize with another event it should examine254 the struct ::c:type:`v4l2_buffer` ``timestamp`` of captured255 or outputted buffers.256 257Drivers implementing memory mapping I/O must support the258:ref:`VIDIOC_REQBUFS <VIDIOC_REQBUFS>`, :ref:`VIDIOC_QUERYBUF259<VIDIOC_QUERYBUF>`, :ref:`VIDIOC_QBUF <VIDIOC_QBUF>`, :ref:`VIDIOC_DQBUF260<VIDIOC_QBUF>`, :ref:`VIDIOC_STREAMON <VIDIOC_STREAMON>`261and :ref:`VIDIOC_STREAMOFF <VIDIOC_STREAMON>` ioctls, the :ref:`mmap()262<func-mmap>`, :c:func:`munmap()`, :ref:`select()263<func-select>` and :c:func:`poll()` function. [#f3]_264 265[capture example]266 267.. [#f1]268 One could use one file descriptor and set the buffer type field269 accordingly when calling :ref:`VIDIOC_QBUF` etc.,270 but it makes the :c:func:`select()` function ambiguous. We also271 like the clean approach of one file descriptor per logical stream.272 Video overlay for example is also a logical stream, although the CPU273 is not needed for continuous operation.274 275.. [#f2]276 Random enqueue order permits applications processing images out of277 order (such as video codecs) to return buffers earlier, reducing the278 probability of data loss. Random fill order allows drivers to reuse279 buffers on a LIFO-basis, taking advantage of caches holding280 scatter-gather lists and the like.281 282.. [#f3]283 At the driver level :c:func:`select()` and :c:func:`poll()` are284 the same, and :c:func:`select()` is too important to be optional.285 The rest should be evident.286