Back to home page

OSCL-LXR

 
 

    


0001 .. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later
0002 .. c:namespace:: V4L
0003 
0004 .. _mmap:
0005 
0006 ******************************
0007 Streaming I/O (Memory Mapping)
0008 ******************************
0009 
0010 Input and output devices support this I/O method when the
0011 ``V4L2_CAP_STREAMING`` flag in the ``capabilities`` field of struct
0012 :c:type:`v4l2_capability` returned by the
0013 :ref:`VIDIOC_QUERYCAP` ioctl is set. There are two
0014 streaming methods, to determine if the memory mapping flavor is
0015 supported applications must call the :ref:`VIDIOC_REQBUFS` ioctl
0016 with the memory type set to ``V4L2_MEMORY_MMAP``.
0017 
0018 Streaming is an I/O method where only pointers to buffers are exchanged
0019 between application and driver, the data itself is not copied. Memory
0020 mapping is primarily intended to map buffers in device memory into the
0021 application's address space. Device memory can be for example the video
0022 memory on a graphics card with a video capture add-on. However, being
0023 the most efficient I/O method available for a long time, many other
0024 drivers support streaming as well, allocating buffers in DMA-able main
0025 memory.
0026 
0027 A driver can support many sets of buffers. Each set is identified by a
0028 unique buffer type value. The sets are independent and each set can hold
0029 a different type of data. To access different sets at the same time
0030 different file descriptors must be used. [#f1]_
0031 
0032 To allocate device buffers applications call the
0033 :ref:`VIDIOC_REQBUFS` ioctl with the desired number
0034 of buffers and buffer type, for example ``V4L2_BUF_TYPE_VIDEO_CAPTURE``.
0035 This ioctl can also be used to change the number of buffers or to free
0036 the allocated memory, provided none of the buffers are still mapped.
0037 
0038 Before applications can access the buffers they must map them into their
0039 address space with the :c:func:`mmap()` function. The
0040 location of the buffers in device memory can be determined with the
0041 :ref:`VIDIOC_QUERYBUF` ioctl. In the single-planar
0042 API case, the ``m.offset`` and ``length`` returned in a struct
0043 :c:type:`v4l2_buffer` are passed as sixth and second
0044 parameter to the :c:func:`mmap()` function. When using the
0045 multi-planar API, struct :c:type:`v4l2_buffer` contains an
0046 array of struct :c:type:`v4l2_plane` structures, each
0047 containing its own ``m.offset`` and ``length``. When using the
0048 multi-planar API, every plane of every buffer has to be mapped
0049 separately, so the number of calls to :c:func:`mmap()` should
0050 be equal to number of buffers times number of planes in each buffer. The
0051 offset and length values must not be modified. Remember, the buffers are
0052 allocated in physical memory, as opposed to virtual memory, which can be
0053 swapped out to disk. Applications should free the buffers as soon as
0054 possible with the :c:func:`munmap()` function.
0055 
0056 Example: Mapping buffers in the single-planar API
0057 =================================================
0058 
0059 .. code-block:: c
0060 
0061     struct v4l2_requestbuffers reqbuf;
0062     struct {
0063         void *start;
0064         size_t length;
0065     } *buffers;
0066     unsigned int i;
0067 
0068     memset(&reqbuf, 0, sizeof(reqbuf));
0069     reqbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
0070     reqbuf.memory = V4L2_MEMORY_MMAP;
0071     reqbuf.count = 20;
0072 
0073     if (-1 == ioctl (fd, VIDIOC_REQBUFS, &reqbuf)) {
0074         if (errno == EINVAL)
0075             printf("Video capturing or mmap-streaming is not supported\\n");
0076         else
0077             perror("VIDIOC_REQBUFS");
0078 
0079         exit(EXIT_FAILURE);
0080     }
0081 
0082     /* We want at least five buffers. */
0083 
0084     if (reqbuf.count < 5) {
0085         /* You may need to free the buffers here. */
0086         printf("Not enough buffer memory\\n");
0087         exit(EXIT_FAILURE);
0088     }
0089 
0090     buffers = calloc(reqbuf.count, sizeof(*buffers));
0091     assert(buffers != NULL);
0092 
0093     for (i = 0; i < reqbuf.count; i++) {
0094         struct v4l2_buffer buffer;
0095 
0096         memset(&buffer, 0, sizeof(buffer));
0097         buffer.type = reqbuf.type;
0098         buffer.memory = V4L2_MEMORY_MMAP;
0099         buffer.index = i;
0100 
0101         if (-1 == ioctl (fd, VIDIOC_QUERYBUF, &buffer)) {
0102             perror("VIDIOC_QUERYBUF");
0103             exit(EXIT_FAILURE);
0104         }
0105 
0106         buffers[i].length = buffer.length; /* remember for munmap() */
0107 
0108         buffers[i].start = mmap(NULL, buffer.length,
0109                     PROT_READ | PROT_WRITE, /* recommended */
0110                     MAP_SHARED,             /* recommended */
0111                     fd, buffer.m.offset);
0112 
0113         if (MAP_FAILED == buffers[i].start) {
0114             /* If you do not exit here you should unmap() and free()
0115                the buffers mapped so far. */
0116             perror("mmap");
0117             exit(EXIT_FAILURE);
0118         }
0119     }
0120 
0121     /* Cleanup. */
0122 
0123     for (i = 0; i < reqbuf.count; i++)
0124         munmap(buffers[i].start, buffers[i].length);
0125 
0126 Example: Mapping buffers in the multi-planar API
0127 ================================================
0128 
0129 .. code-block:: c
0130 
0131     struct v4l2_requestbuffers reqbuf;
0132     /* Our current format uses 3 planes per buffer */
0133     #define FMT_NUM_PLANES = 3
0134 
0135     struct {
0136         void *start[FMT_NUM_PLANES];
0137         size_t length[FMT_NUM_PLANES];
0138     } *buffers;
0139     unsigned int i, j;
0140 
0141     memset(&reqbuf, 0, sizeof(reqbuf));
0142     reqbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
0143     reqbuf.memory = V4L2_MEMORY_MMAP;
0144     reqbuf.count = 20;
0145 
0146     if (ioctl(fd, VIDIOC_REQBUFS, &reqbuf) < 0) {
0147         if (errno == EINVAL)
0148             printf("Video capturing or mmap-streaming is not supported\\n");
0149         else
0150             perror("VIDIOC_REQBUFS");
0151 
0152         exit(EXIT_FAILURE);
0153     }
0154 
0155     /* We want at least five buffers. */
0156 
0157     if (reqbuf.count < 5) {
0158         /* You may need to free the buffers here. */
0159         printf("Not enough buffer memory\\n");
0160         exit(EXIT_FAILURE);
0161     }
0162 
0163     buffers = calloc(reqbuf.count, sizeof(*buffers));
0164     assert(buffers != NULL);
0165 
0166     for (i = 0; i < reqbuf.count; i++) {
0167         struct v4l2_buffer buffer;
0168         struct v4l2_plane planes[FMT_NUM_PLANES];
0169 
0170         memset(&buffer, 0, sizeof(buffer));
0171         buffer.type = reqbuf.type;
0172         buffer.memory = V4L2_MEMORY_MMAP;
0173         buffer.index = i;
0174         /* length in struct v4l2_buffer in multi-planar API stores the size
0175          * of planes array. */
0176         buffer.length = FMT_NUM_PLANES;
0177         buffer.m.planes = planes;
0178 
0179         if (ioctl(fd, VIDIOC_QUERYBUF, &buffer) < 0) {
0180             perror("VIDIOC_QUERYBUF");
0181             exit(EXIT_FAILURE);
0182         }
0183 
0184         /* Every plane has to be mapped separately */
0185         for (j = 0; j < FMT_NUM_PLANES; j++) {
0186             buffers[i].length[j] = buffer.m.planes[j].length; /* remember for munmap() */
0187 
0188             buffers[i].start[j] = mmap(NULL, buffer.m.planes[j].length,
0189                      PROT_READ | PROT_WRITE, /* recommended */
0190                      MAP_SHARED,             /* recommended */
0191                      fd, buffer.m.planes[j].m.offset);
0192 
0193             if (MAP_FAILED == buffers[i].start[j]) {
0194                 /* If you do not exit here you should unmap() and free()
0195                    the buffers and planes mapped so far. */
0196                 perror("mmap");
0197                 exit(EXIT_FAILURE);
0198             }
0199         }
0200     }
0201 
0202     /* Cleanup. */
0203 
0204     for (i = 0; i < reqbuf.count; i++)
0205         for (j = 0; j < FMT_NUM_PLANES; j++)
0206             munmap(buffers[i].start[j], buffers[i].length[j]);
0207 
0208 Conceptually streaming drivers maintain two buffer queues, an incoming
0209 and an outgoing queue. They separate the synchronous capture or output
0210 operation locked to a video clock from the application which is subject
0211 to random disk or network delays and preemption by other processes,
0212 thereby reducing the probability of data loss. The queues are organized
0213 as FIFOs, buffers will be output in the order enqueued in the incoming
0214 FIFO, and were captured in the order dequeued from the outgoing FIFO.
0215 
0216 The driver may require a minimum number of buffers enqueued at all times
0217 to function, apart of this no limit exists on the number of buffers
0218 applications can enqueue in advance, or dequeue and process. They can
0219 also enqueue in a different order than buffers have been dequeued, and
0220 the driver can *fill* enqueued *empty* buffers in any order.  [#f2]_ The
0221 index number of a buffer (struct :c:type:`v4l2_buffer`
0222 ``index``) plays no role here, it only identifies the buffer.
0223 
0224 Initially all mapped buffers are in dequeued state, inaccessible by the
0225 driver. For capturing applications it is customary to first enqueue all
0226 mapped buffers, then to start capturing and enter the read loop. Here
0227 the application waits until a filled buffer can be dequeued, and
0228 re-enqueues the buffer when the data is no longer needed. Output
0229 applications fill and enqueue buffers, when enough buffers are stacked
0230 up the output is started with :ref:`VIDIOC_STREAMON <VIDIOC_STREAMON>`.
0231 In the write loop, when the application runs out of free buffers, it
0232 must wait until an empty buffer can be dequeued and reused.
0233 
0234 To enqueue and dequeue a buffer applications use the
0235 :ref:`VIDIOC_QBUF <VIDIOC_QBUF>` and :ref:`VIDIOC_DQBUF <VIDIOC_QBUF>`
0236 ioctl. The status of a buffer being mapped, enqueued, full or empty can
0237 be determined at any time using the :ref:`VIDIOC_QUERYBUF` ioctl. Two
0238 methods exist to suspend execution of the application until one or more
0239 buffers can be dequeued.  By default :ref:`VIDIOC_DQBUF <VIDIOC_QBUF>`
0240 blocks when no buffer is in the outgoing queue. When the ``O_NONBLOCK``
0241 flag was given to the :c:func:`open()` function,
0242 :ref:`VIDIOC_DQBUF <VIDIOC_QBUF>` returns immediately with an ``EAGAIN``
0243 error code when no buffer is available. The :c:func:`select()`
0244 or :c:func:`poll()` functions are always available.
0245 
0246 To start and stop capturing or output applications call the
0247 :ref:`VIDIOC_STREAMON <VIDIOC_STREAMON>` and :ref:`VIDIOC_STREAMOFF
0248 <VIDIOC_STREAMON>` ioctl.
0249 
0250 .. note:::ref:`VIDIOC_STREAMOFF <VIDIOC_STREAMON>`
0251    removes all buffers from both queues as a side effect. Since there is
0252    no notion of doing anything "now" on a multitasking system, if an
0253    application needs to synchronize with another event it should examine
0254    the struct ::c:type:`v4l2_buffer` ``timestamp`` of captured
0255    or outputted buffers.
0256 
0257 Drivers implementing memory mapping I/O must support the
0258 :ref:`VIDIOC_REQBUFS <VIDIOC_REQBUFS>`, :ref:`VIDIOC_QUERYBUF
0259 <VIDIOC_QUERYBUF>`, :ref:`VIDIOC_QBUF <VIDIOC_QBUF>`, :ref:`VIDIOC_DQBUF
0260 <VIDIOC_QBUF>`, :ref:`VIDIOC_STREAMON <VIDIOC_STREAMON>`
0261 and :ref:`VIDIOC_STREAMOFF <VIDIOC_STREAMON>` ioctls, the :ref:`mmap()
0262 <func-mmap>`, :c:func:`munmap()`, :ref:`select()
0263 <func-select>` and :c:func:`poll()` function. [#f3]_
0264 
0265 [capture example]
0266 
0267 .. [#f1]
0268    One could use one file descriptor and set the buffer type field
0269    accordingly when calling :ref:`VIDIOC_QBUF` etc.,
0270    but it makes the :c:func:`select()` function ambiguous. We also
0271    like the clean approach of one file descriptor per logical stream.
0272    Video overlay for example is also a logical stream, although the CPU
0273    is not needed for continuous operation.
0274 
0275 .. [#f2]
0276    Random enqueue order permits applications processing images out of
0277    order (such as video codecs) to return buffers earlier, reducing the
0278    probability of data loss. Random fill order allows drivers to reuse
0279    buffers on a LIFO-basis, taking advantage of caches holding
0280    scatter-gather lists and the like.
0281 
0282 .. [#f3]
0283    At the driver level :c:func:`select()` and :c:func:`poll()` are
0284    the same, and :c:func:`select()` is too important to be optional.
0285    The rest should be evident.