18c2ecf20Sopenharmony_ci.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later
28c2ecf20Sopenharmony_ci.. c:namespace:: V4L
38c2ecf20Sopenharmony_ci
48c2ecf20Sopenharmony_ci.. _mmap:
58c2ecf20Sopenharmony_ci
68c2ecf20Sopenharmony_ci******************************
78c2ecf20Sopenharmony_ciStreaming I/O (Memory Mapping)
88c2ecf20Sopenharmony_ci******************************
98c2ecf20Sopenharmony_ci
108c2ecf20Sopenharmony_ciInput and output devices support this I/O method when the
118c2ecf20Sopenharmony_ci``V4L2_CAP_STREAMING`` flag in the ``capabilities`` field of struct
128c2ecf20Sopenharmony_ci:c:type:`v4l2_capability` returned by the
138c2ecf20Sopenharmony_ci:ref:`VIDIOC_QUERYCAP` ioctl is set. There are two
148c2ecf20Sopenharmony_cistreaming methods, to determine if the memory mapping flavor is
158c2ecf20Sopenharmony_cisupported applications must call the :ref:`VIDIOC_REQBUFS` ioctl
168c2ecf20Sopenharmony_ciwith the memory type set to ``V4L2_MEMORY_MMAP``.
178c2ecf20Sopenharmony_ci
188c2ecf20Sopenharmony_ciStreaming is an I/O method where only pointers to buffers are exchanged
198c2ecf20Sopenharmony_cibetween application and driver, the data itself is not copied. Memory
208c2ecf20Sopenharmony_cimapping is primarily intended to map buffers in device memory into the
218c2ecf20Sopenharmony_ciapplication's address space. Device memory can be for example the video
228c2ecf20Sopenharmony_cimemory on a graphics card with a video capture add-on. However, being
238c2ecf20Sopenharmony_cithe most efficient I/O method available for a long time, many other
248c2ecf20Sopenharmony_cidrivers support streaming as well, allocating buffers in DMA-able main
258c2ecf20Sopenharmony_cimemory.
268c2ecf20Sopenharmony_ci
278c2ecf20Sopenharmony_ciA driver can support many sets of buffers. Each set is identified by a
288c2ecf20Sopenharmony_ciunique buffer type value. The sets are independent and each set can hold
298c2ecf20Sopenharmony_cia different type of data. To access different sets at the same time
308c2ecf20Sopenharmony_cidifferent file descriptors must be used. [#f1]_
318c2ecf20Sopenharmony_ci
328c2ecf20Sopenharmony_ciTo allocate device buffers applications call the
338c2ecf20Sopenharmony_ci:ref:`VIDIOC_REQBUFS` ioctl with the desired number
348c2ecf20Sopenharmony_ciof buffers and buffer type, for example ``V4L2_BUF_TYPE_VIDEO_CAPTURE``.
358c2ecf20Sopenharmony_ciThis ioctl can also be used to change the number of buffers or to free
368c2ecf20Sopenharmony_cithe allocated memory, provided none of the buffers are still mapped.
378c2ecf20Sopenharmony_ci
388c2ecf20Sopenharmony_ciBefore applications can access the buffers they must map them into their
398c2ecf20Sopenharmony_ciaddress space with the :c:func:`mmap()` function. The
408c2ecf20Sopenharmony_cilocation of the buffers in device memory can be determined with the
418c2ecf20Sopenharmony_ci:ref:`VIDIOC_QUERYBUF` ioctl. In the single-planar
428c2ecf20Sopenharmony_ciAPI case, the ``m.offset`` and ``length`` returned in a struct
438c2ecf20Sopenharmony_ci:c:type:`v4l2_buffer` are passed as sixth and second
448c2ecf20Sopenharmony_ciparameter to the :c:func:`mmap()` function. When using the
458c2ecf20Sopenharmony_cimulti-planar API, struct :c:type:`v4l2_buffer` contains an
468c2ecf20Sopenharmony_ciarray of struct :c:type:`v4l2_plane` structures, each
478c2ecf20Sopenharmony_cicontaining its own ``m.offset`` and ``length``. When using the
488c2ecf20Sopenharmony_cimulti-planar API, every plane of every buffer has to be mapped
498c2ecf20Sopenharmony_ciseparately, so the number of calls to :c:func:`mmap()` should
508c2ecf20Sopenharmony_cibe equal to number of buffers times number of planes in each buffer. The
518c2ecf20Sopenharmony_cioffset and length values must not be modified. Remember, the buffers are
528c2ecf20Sopenharmony_ciallocated in physical memory, as opposed to virtual memory, which can be
538c2ecf20Sopenharmony_ciswapped out to disk. Applications should free the buffers as soon as
548c2ecf20Sopenharmony_cipossible with the :c:func:`munmap()` function.
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_ciExample: Mapping buffers in the single-planar API
578c2ecf20Sopenharmony_ci=================================================
588c2ecf20Sopenharmony_ci
598c2ecf20Sopenharmony_ci.. code-block:: c
608c2ecf20Sopenharmony_ci
618c2ecf20Sopenharmony_ci    struct v4l2_requestbuffers reqbuf;
628c2ecf20Sopenharmony_ci    struct {
638c2ecf20Sopenharmony_ci	void *start;
648c2ecf20Sopenharmony_ci	size_t length;
658c2ecf20Sopenharmony_ci    } *buffers;
668c2ecf20Sopenharmony_ci    unsigned int i;
678c2ecf20Sopenharmony_ci
688c2ecf20Sopenharmony_ci    memset(&reqbuf, 0, sizeof(reqbuf));
698c2ecf20Sopenharmony_ci    reqbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
708c2ecf20Sopenharmony_ci    reqbuf.memory = V4L2_MEMORY_MMAP;
718c2ecf20Sopenharmony_ci    reqbuf.count = 20;
728c2ecf20Sopenharmony_ci
738c2ecf20Sopenharmony_ci    if (-1 == ioctl (fd, VIDIOC_REQBUFS, &reqbuf)) {
748c2ecf20Sopenharmony_ci	if (errno == EINVAL)
758c2ecf20Sopenharmony_ci	    printf("Video capturing or mmap-streaming is not supported\\n");
768c2ecf20Sopenharmony_ci	else
778c2ecf20Sopenharmony_ci	    perror("VIDIOC_REQBUFS");
788c2ecf20Sopenharmony_ci
798c2ecf20Sopenharmony_ci	exit(EXIT_FAILURE);
808c2ecf20Sopenharmony_ci    }
818c2ecf20Sopenharmony_ci
828c2ecf20Sopenharmony_ci    /* We want at least five buffers. */
838c2ecf20Sopenharmony_ci
848c2ecf20Sopenharmony_ci    if (reqbuf.count < 5) {
858c2ecf20Sopenharmony_ci	/* You may need to free the buffers here. */
868c2ecf20Sopenharmony_ci	printf("Not enough buffer memory\\n");
878c2ecf20Sopenharmony_ci	exit(EXIT_FAILURE);
888c2ecf20Sopenharmony_ci    }
898c2ecf20Sopenharmony_ci
908c2ecf20Sopenharmony_ci    buffers = calloc(reqbuf.count, sizeof(*buffers));
918c2ecf20Sopenharmony_ci    assert(buffers != NULL);
928c2ecf20Sopenharmony_ci
938c2ecf20Sopenharmony_ci    for (i = 0; i < reqbuf.count; i++) {
948c2ecf20Sopenharmony_ci	struct v4l2_buffer buffer;
958c2ecf20Sopenharmony_ci
968c2ecf20Sopenharmony_ci	memset(&buffer, 0, sizeof(buffer));
978c2ecf20Sopenharmony_ci	buffer.type = reqbuf.type;
988c2ecf20Sopenharmony_ci	buffer.memory = V4L2_MEMORY_MMAP;
998c2ecf20Sopenharmony_ci	buffer.index = i;
1008c2ecf20Sopenharmony_ci
1018c2ecf20Sopenharmony_ci	if (-1 == ioctl (fd, VIDIOC_QUERYBUF, &buffer)) {
1028c2ecf20Sopenharmony_ci	    perror("VIDIOC_QUERYBUF");
1038c2ecf20Sopenharmony_ci	    exit(EXIT_FAILURE);
1048c2ecf20Sopenharmony_ci	}
1058c2ecf20Sopenharmony_ci
1068c2ecf20Sopenharmony_ci	buffers[i].length = buffer.length; /* remember for munmap() */
1078c2ecf20Sopenharmony_ci
1088c2ecf20Sopenharmony_ci	buffers[i].start = mmap(NULL, buffer.length,
1098c2ecf20Sopenharmony_ci		    PROT_READ | PROT_WRITE, /* recommended */
1108c2ecf20Sopenharmony_ci		    MAP_SHARED,             /* recommended */
1118c2ecf20Sopenharmony_ci		    fd, buffer.m.offset);
1128c2ecf20Sopenharmony_ci
1138c2ecf20Sopenharmony_ci	if (MAP_FAILED == buffers[i].start) {
1148c2ecf20Sopenharmony_ci	    /* If you do not exit here you should unmap() and free()
1158c2ecf20Sopenharmony_ci	       the buffers mapped so far. */
1168c2ecf20Sopenharmony_ci	    perror("mmap");
1178c2ecf20Sopenharmony_ci	    exit(EXIT_FAILURE);
1188c2ecf20Sopenharmony_ci	}
1198c2ecf20Sopenharmony_ci    }
1208c2ecf20Sopenharmony_ci
1218c2ecf20Sopenharmony_ci    /* Cleanup. */
1228c2ecf20Sopenharmony_ci
1238c2ecf20Sopenharmony_ci    for (i = 0; i < reqbuf.count; i++)
1248c2ecf20Sopenharmony_ci	munmap(buffers[i].start, buffers[i].length);
1258c2ecf20Sopenharmony_ci
1268c2ecf20Sopenharmony_ciExample: Mapping buffers in the multi-planar API
1278c2ecf20Sopenharmony_ci================================================
1288c2ecf20Sopenharmony_ci
1298c2ecf20Sopenharmony_ci.. code-block:: c
1308c2ecf20Sopenharmony_ci
1318c2ecf20Sopenharmony_ci    struct v4l2_requestbuffers reqbuf;
1328c2ecf20Sopenharmony_ci    /* Our current format uses 3 planes per buffer */
1338c2ecf20Sopenharmony_ci    #define FMT_NUM_PLANES = 3
1348c2ecf20Sopenharmony_ci
1358c2ecf20Sopenharmony_ci    struct {
1368c2ecf20Sopenharmony_ci	void *start[FMT_NUM_PLANES];
1378c2ecf20Sopenharmony_ci	size_t length[FMT_NUM_PLANES];
1388c2ecf20Sopenharmony_ci    } *buffers;
1398c2ecf20Sopenharmony_ci    unsigned int i, j;
1408c2ecf20Sopenharmony_ci
1418c2ecf20Sopenharmony_ci    memset(&reqbuf, 0, sizeof(reqbuf));
1428c2ecf20Sopenharmony_ci    reqbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
1438c2ecf20Sopenharmony_ci    reqbuf.memory = V4L2_MEMORY_MMAP;
1448c2ecf20Sopenharmony_ci    reqbuf.count = 20;
1458c2ecf20Sopenharmony_ci
1468c2ecf20Sopenharmony_ci    if (ioctl(fd, VIDIOC_REQBUFS, &reqbuf) < 0) {
1478c2ecf20Sopenharmony_ci	if (errno == EINVAL)
1488c2ecf20Sopenharmony_ci	    printf("Video capturing or mmap-streaming is not supported\\n");
1498c2ecf20Sopenharmony_ci	else
1508c2ecf20Sopenharmony_ci	    perror("VIDIOC_REQBUFS");
1518c2ecf20Sopenharmony_ci
1528c2ecf20Sopenharmony_ci	exit(EXIT_FAILURE);
1538c2ecf20Sopenharmony_ci    }
1548c2ecf20Sopenharmony_ci
1558c2ecf20Sopenharmony_ci    /* We want at least five buffers. */
1568c2ecf20Sopenharmony_ci
1578c2ecf20Sopenharmony_ci    if (reqbuf.count < 5) {
1588c2ecf20Sopenharmony_ci	/* You may need to free the buffers here. */
1598c2ecf20Sopenharmony_ci	printf("Not enough buffer memory\\n");
1608c2ecf20Sopenharmony_ci	exit(EXIT_FAILURE);
1618c2ecf20Sopenharmony_ci    }
1628c2ecf20Sopenharmony_ci
1638c2ecf20Sopenharmony_ci    buffers = calloc(reqbuf.count, sizeof(*buffers));
1648c2ecf20Sopenharmony_ci    assert(buffers != NULL);
1658c2ecf20Sopenharmony_ci
1668c2ecf20Sopenharmony_ci    for (i = 0; i < reqbuf.count; i++) {
1678c2ecf20Sopenharmony_ci	struct v4l2_buffer buffer;
1688c2ecf20Sopenharmony_ci	struct v4l2_plane planes[FMT_NUM_PLANES];
1698c2ecf20Sopenharmony_ci
1708c2ecf20Sopenharmony_ci	memset(&buffer, 0, sizeof(buffer));
1718c2ecf20Sopenharmony_ci	buffer.type = reqbuf.type;
1728c2ecf20Sopenharmony_ci	buffer.memory = V4L2_MEMORY_MMAP;
1738c2ecf20Sopenharmony_ci	buffer.index = i;
1748c2ecf20Sopenharmony_ci	/* length in struct v4l2_buffer in multi-planar API stores the size
1758c2ecf20Sopenharmony_ci	 * of planes array. */
1768c2ecf20Sopenharmony_ci	buffer.length = FMT_NUM_PLANES;
1778c2ecf20Sopenharmony_ci	buffer.m.planes = planes;
1788c2ecf20Sopenharmony_ci
1798c2ecf20Sopenharmony_ci	if (ioctl(fd, VIDIOC_QUERYBUF, &buffer) < 0) {
1808c2ecf20Sopenharmony_ci	    perror("VIDIOC_QUERYBUF");
1818c2ecf20Sopenharmony_ci	    exit(EXIT_FAILURE);
1828c2ecf20Sopenharmony_ci	}
1838c2ecf20Sopenharmony_ci
1848c2ecf20Sopenharmony_ci	/* Every plane has to be mapped separately */
1858c2ecf20Sopenharmony_ci	for (j = 0; j < FMT_NUM_PLANES; j++) {
1868c2ecf20Sopenharmony_ci	    buffers[i].length[j] = buffer.m.planes[j].length; /* remember for munmap() */
1878c2ecf20Sopenharmony_ci
1888c2ecf20Sopenharmony_ci	    buffers[i].start[j] = mmap(NULL, buffer.m.planes[j].length,
1898c2ecf20Sopenharmony_ci		     PROT_READ | PROT_WRITE, /* recommended */
1908c2ecf20Sopenharmony_ci		     MAP_SHARED,             /* recommended */
1918c2ecf20Sopenharmony_ci		     fd, buffer.m.planes[j].m.offset);
1928c2ecf20Sopenharmony_ci
1938c2ecf20Sopenharmony_ci	    if (MAP_FAILED == buffers[i].start[j]) {
1948c2ecf20Sopenharmony_ci		/* If you do not exit here you should unmap() and free()
1958c2ecf20Sopenharmony_ci		   the buffers and planes mapped so far. */
1968c2ecf20Sopenharmony_ci		perror("mmap");
1978c2ecf20Sopenharmony_ci		exit(EXIT_FAILURE);
1988c2ecf20Sopenharmony_ci	    }
1998c2ecf20Sopenharmony_ci	}
2008c2ecf20Sopenharmony_ci    }
2018c2ecf20Sopenharmony_ci
2028c2ecf20Sopenharmony_ci    /* Cleanup. */
2038c2ecf20Sopenharmony_ci
2048c2ecf20Sopenharmony_ci    for (i = 0; i < reqbuf.count; i++)
2058c2ecf20Sopenharmony_ci	for (j = 0; j < FMT_NUM_PLANES; j++)
2068c2ecf20Sopenharmony_ci	    munmap(buffers[i].start[j], buffers[i].length[j]);
2078c2ecf20Sopenharmony_ci
2088c2ecf20Sopenharmony_ciConceptually streaming drivers maintain two buffer queues, an incoming
2098c2ecf20Sopenharmony_ciand an outgoing queue. They separate the synchronous capture or output
2108c2ecf20Sopenharmony_cioperation locked to a video clock from the application which is subject
2118c2ecf20Sopenharmony_cito random disk or network delays and preemption by other processes,
2128c2ecf20Sopenharmony_cithereby reducing the probability of data loss. The queues are organized
2138c2ecf20Sopenharmony_cias FIFOs, buffers will be output in the order enqueued in the incoming
2148c2ecf20Sopenharmony_ciFIFO, and were captured in the order dequeued from the outgoing FIFO.
2158c2ecf20Sopenharmony_ci
2168c2ecf20Sopenharmony_ciThe driver may require a minimum number of buffers enqueued at all times
2178c2ecf20Sopenharmony_cito function, apart of this no limit exists on the number of buffers
2188c2ecf20Sopenharmony_ciapplications can enqueue in advance, or dequeue and process. They can
2198c2ecf20Sopenharmony_cialso enqueue in a different order than buffers have been dequeued, and
2208c2ecf20Sopenharmony_cithe driver can *fill* enqueued *empty* buffers in any order.  [#f2]_ The
2218c2ecf20Sopenharmony_ciindex number of a buffer (struct :c:type:`v4l2_buffer`
2228c2ecf20Sopenharmony_ci``index``) plays no role here, it only identifies the buffer.
2238c2ecf20Sopenharmony_ci
2248c2ecf20Sopenharmony_ciInitially all mapped buffers are in dequeued state, inaccessible by the
2258c2ecf20Sopenharmony_cidriver. For capturing applications it is customary to first enqueue all
2268c2ecf20Sopenharmony_cimapped buffers, then to start capturing and enter the read loop. Here
2278c2ecf20Sopenharmony_cithe application waits until a filled buffer can be dequeued, and
2288c2ecf20Sopenharmony_cire-enqueues the buffer when the data is no longer needed. Output
2298c2ecf20Sopenharmony_ciapplications fill and enqueue buffers, when enough buffers are stacked
2308c2ecf20Sopenharmony_ciup the output is started with :ref:`VIDIOC_STREAMON <VIDIOC_STREAMON>`.
2318c2ecf20Sopenharmony_ciIn the write loop, when the application runs out of free buffers, it
2328c2ecf20Sopenharmony_cimust wait until an empty buffer can be dequeued and reused.
2338c2ecf20Sopenharmony_ci
2348c2ecf20Sopenharmony_ciTo enqueue and dequeue a buffer applications use the
2358c2ecf20Sopenharmony_ci:ref:`VIVIOC_QBUF <VIDIOC_QBUF>` and :ref:`VIDIOC_DQBUF <VIDIOC_QBUF>`
2368c2ecf20Sopenharmony_ciioctl. The status of a buffer being mapped, enqueued, full or empty can
2378c2ecf20Sopenharmony_cibe determined at any time using the :ref:`VIDIOC_QUERYBUF` ioctl. Two
2388c2ecf20Sopenharmony_cimethods exist to suspend execution of the application until one or more
2398c2ecf20Sopenharmony_cibuffers can be dequeued.  By default :ref:`VIDIOC_DQBUF <VIDIOC_QBUF>`
2408c2ecf20Sopenharmony_ciblocks when no buffer is in the outgoing queue. When the ``O_NONBLOCK``
2418c2ecf20Sopenharmony_ciflag was given to the :c:func:`open()` function,
2428c2ecf20Sopenharmony_ci:ref:`VIDIOC_DQBUF <VIDIOC_QBUF>` returns immediately with an ``EAGAIN``
2438c2ecf20Sopenharmony_cierror code when no buffer is available. The :c:func:`select()`
2448c2ecf20Sopenharmony_cior :c:func:`poll()` functions are always available.
2458c2ecf20Sopenharmony_ci
2468c2ecf20Sopenharmony_ciTo start and stop capturing or output applications call the
2478c2ecf20Sopenharmony_ci:ref:`VIDIOC_STREAMON <VIDIOC_STREAMON>` and :ref:`VIDIOC_STREAMOFF
2488c2ecf20Sopenharmony_ci<VIDIOC_STREAMON>` ioctl.
2498c2ecf20Sopenharmony_ci
2508c2ecf20Sopenharmony_ci.. note:::ref:`VIDIOC_STREAMOFF <VIDIOC_STREAMON>`
2518c2ecf20Sopenharmony_ci   removes all buffers from both queues as a side effect. Since there is
2528c2ecf20Sopenharmony_ci   no notion of doing anything "now" on a multitasking system, if an
2538c2ecf20Sopenharmony_ci   application needs to synchronize with another event it should examine
2548c2ecf20Sopenharmony_ci   the struct ::c:type:`v4l2_buffer` ``timestamp`` of captured
2558c2ecf20Sopenharmony_ci   or outputted buffers.
2568c2ecf20Sopenharmony_ci
2578c2ecf20Sopenharmony_ciDrivers implementing memory mapping I/O must support the
2588c2ecf20Sopenharmony_ci:ref:`VIDIOC_REQBUFS <VIDIOC_REQBUFS>`, :ref:`VIDIOC_QUERYBUF
2598c2ecf20Sopenharmony_ci<VIDIOC_QUERYBUF>`, :ref:`VIDIOC_QBUF <VIDIOC_QBUF>`, :ref:`VIDIOC_DQBUF
2608c2ecf20Sopenharmony_ci<VIDIOC_QBUF>`, :ref:`VIDIOC_STREAMON <VIDIOC_STREAMON>`
2618c2ecf20Sopenharmony_ciand :ref:`VIDIOC_STREAMOFF <VIDIOC_STREAMON>` ioctls, the :ref:`mmap()
2628c2ecf20Sopenharmony_ci<func-mmap>`, :c:func:`munmap()`, :ref:`select()
2638c2ecf20Sopenharmony_ci<func-select>` and :c:func:`poll()` function. [#f3]_
2648c2ecf20Sopenharmony_ci
2658c2ecf20Sopenharmony_ci[capture example]
2668c2ecf20Sopenharmony_ci
2678c2ecf20Sopenharmony_ci.. [#f1]
2688c2ecf20Sopenharmony_ci   One could use one file descriptor and set the buffer type field
2698c2ecf20Sopenharmony_ci   accordingly when calling :ref:`VIDIOC_QBUF` etc.,
2708c2ecf20Sopenharmony_ci   but it makes the :c:func:`select()` function ambiguous. We also
2718c2ecf20Sopenharmony_ci   like the clean approach of one file descriptor per logical stream.
2728c2ecf20Sopenharmony_ci   Video overlay for example is also a logical stream, although the CPU
2738c2ecf20Sopenharmony_ci   is not needed for continuous operation.
2748c2ecf20Sopenharmony_ci
2758c2ecf20Sopenharmony_ci.. [#f2]
2768c2ecf20Sopenharmony_ci   Random enqueue order permits applications processing images out of
2778c2ecf20Sopenharmony_ci   order (such as video codecs) to return buffers earlier, reducing the
2788c2ecf20Sopenharmony_ci   probability of data loss. Random fill order allows drivers to reuse
2798c2ecf20Sopenharmony_ci   buffers on a LIFO-basis, taking advantage of caches holding
2808c2ecf20Sopenharmony_ci   scatter-gather lists and the like.
2818c2ecf20Sopenharmony_ci
2828c2ecf20Sopenharmony_ci.. [#f3]
2838c2ecf20Sopenharmony_ci   At the driver level :c:func:`select()` and :c:func:`poll()` are
2848c2ecf20Sopenharmony_ci   the same, and :c:func:`select()` is too important to be optional.
2858c2ecf20Sopenharmony_ci   The rest should be evident.
286