162306a36Sopenharmony_ci.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later
262306a36Sopenharmony_ci.. c:namespace:: V4L
362306a36Sopenharmony_ci
462306a36Sopenharmony_ci.. _mmap:
562306a36Sopenharmony_ci
662306a36Sopenharmony_ci******************************
762306a36Sopenharmony_ciStreaming I/O (Memory Mapping)
862306a36Sopenharmony_ci******************************
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ciInput and output devices support this I/O method when the
1162306a36Sopenharmony_ci``V4L2_CAP_STREAMING`` flag in the ``capabilities`` field of struct
1262306a36Sopenharmony_ci:c:type:`v4l2_capability` returned by the
1362306a36Sopenharmony_ci:ref:`VIDIOC_QUERYCAP` ioctl is set. There are two
1462306a36Sopenharmony_cistreaming methods, to determine if the memory mapping flavor is
1562306a36Sopenharmony_cisupported applications must call the :ref:`VIDIOC_REQBUFS` ioctl
1662306a36Sopenharmony_ciwith the memory type set to ``V4L2_MEMORY_MMAP``.
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_ciStreaming is an I/O method where only pointers to buffers are exchanged
1962306a36Sopenharmony_cibetween application and driver, the data itself is not copied. Memory
2062306a36Sopenharmony_cimapping is primarily intended to map buffers in device memory into the
2162306a36Sopenharmony_ciapplication's address space. Device memory can be for example the video
2262306a36Sopenharmony_cimemory on a graphics card with a video capture add-on. However, being
2362306a36Sopenharmony_cithe most efficient I/O method available for a long time, many other
2462306a36Sopenharmony_cidrivers support streaming as well, allocating buffers in DMA-able main
2562306a36Sopenharmony_cimemory.
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_ciA driver can support many sets of buffers. Each set is identified by a
2862306a36Sopenharmony_ciunique buffer type value. The sets are independent and each set can hold
2962306a36Sopenharmony_cia different type of data. To access different sets at the same time
3062306a36Sopenharmony_cidifferent file descriptors must be used. [#f1]_
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_ciTo allocate device buffers applications call the
3362306a36Sopenharmony_ci:ref:`VIDIOC_REQBUFS` ioctl with the desired number
3462306a36Sopenharmony_ciof buffers and buffer type, for example ``V4L2_BUF_TYPE_VIDEO_CAPTURE``.
3562306a36Sopenharmony_ciThis ioctl can also be used to change the number of buffers or to free
3662306a36Sopenharmony_cithe allocated memory, provided none of the buffers are still mapped.
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_ciBefore applications can access the buffers they must map them into their
3962306a36Sopenharmony_ciaddress space with the :c:func:`mmap()` function. The
4062306a36Sopenharmony_cilocation of the buffers in device memory can be determined with the
4162306a36Sopenharmony_ci:ref:`VIDIOC_QUERYBUF` ioctl. In the single-planar
4262306a36Sopenharmony_ciAPI case, the ``m.offset`` and ``length`` returned in a struct
4362306a36Sopenharmony_ci:c:type:`v4l2_buffer` are passed as sixth and second
4462306a36Sopenharmony_ciparameter to the :c:func:`mmap()` function. When using the
4562306a36Sopenharmony_cimulti-planar API, struct :c:type:`v4l2_buffer` contains an
4662306a36Sopenharmony_ciarray of struct :c:type:`v4l2_plane` structures, each
4762306a36Sopenharmony_cicontaining its own ``m.offset`` and ``length``. When using the
4862306a36Sopenharmony_cimulti-planar API, every plane of every buffer has to be mapped
4962306a36Sopenharmony_ciseparately, so the number of calls to :c:func:`mmap()` should
5062306a36Sopenharmony_cibe equal to number of buffers times number of planes in each buffer. The
5162306a36Sopenharmony_cioffset and length values must not be modified. Remember, the buffers are
5262306a36Sopenharmony_ciallocated in physical memory, as opposed to virtual memory, which can be
5362306a36Sopenharmony_ciswapped out to disk. Applications should free the buffers as soon as
5462306a36Sopenharmony_cipossible with the :c:func:`munmap()` function.
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_ciExample: Mapping buffers in the single-planar API
5762306a36Sopenharmony_ci=================================================
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_ci.. code-block:: c
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_ci    struct v4l2_requestbuffers reqbuf;
6262306a36Sopenharmony_ci    struct {
6362306a36Sopenharmony_ci	void *start;
6462306a36Sopenharmony_ci	size_t length;
6562306a36Sopenharmony_ci    } *buffers;
6662306a36Sopenharmony_ci    unsigned int i;
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_ci    memset(&reqbuf, 0, sizeof(reqbuf));
6962306a36Sopenharmony_ci    reqbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
7062306a36Sopenharmony_ci    reqbuf.memory = V4L2_MEMORY_MMAP;
7162306a36Sopenharmony_ci    reqbuf.count = 20;
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_ci    if (-1 == ioctl (fd, VIDIOC_REQBUFS, &reqbuf)) {
7462306a36Sopenharmony_ci	if (errno == EINVAL)
7562306a36Sopenharmony_ci	    printf("Video capturing or mmap-streaming is not supported\\n");
7662306a36Sopenharmony_ci	else
7762306a36Sopenharmony_ci	    perror("VIDIOC_REQBUFS");
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_ci	exit(EXIT_FAILURE);
8062306a36Sopenharmony_ci    }
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_ci    /* We want at least five buffers. */
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_ci    if (reqbuf.count < 5) {
8562306a36Sopenharmony_ci	/* You may need to free the buffers here. */
8662306a36Sopenharmony_ci	printf("Not enough buffer memory\\n");
8762306a36Sopenharmony_ci	exit(EXIT_FAILURE);
8862306a36Sopenharmony_ci    }
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_ci    buffers = calloc(reqbuf.count, sizeof(*buffers));
9162306a36Sopenharmony_ci    assert(buffers != NULL);
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_ci    for (i = 0; i < reqbuf.count; i++) {
9462306a36Sopenharmony_ci	struct v4l2_buffer buffer;
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_ci	memset(&buffer, 0, sizeof(buffer));
9762306a36Sopenharmony_ci	buffer.type = reqbuf.type;
9862306a36Sopenharmony_ci	buffer.memory = V4L2_MEMORY_MMAP;
9962306a36Sopenharmony_ci	buffer.index = i;
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_ci	if (-1 == ioctl (fd, VIDIOC_QUERYBUF, &buffer)) {
10262306a36Sopenharmony_ci	    perror("VIDIOC_QUERYBUF");
10362306a36Sopenharmony_ci	    exit(EXIT_FAILURE);
10462306a36Sopenharmony_ci	}
10562306a36Sopenharmony_ci
10662306a36Sopenharmony_ci	buffers[i].length = buffer.length; /* remember for munmap() */
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_ci	buffers[i].start = mmap(NULL, buffer.length,
10962306a36Sopenharmony_ci		    PROT_READ | PROT_WRITE, /* recommended */
11062306a36Sopenharmony_ci		    MAP_SHARED,             /* recommended */
11162306a36Sopenharmony_ci		    fd, buffer.m.offset);
11262306a36Sopenharmony_ci
11362306a36Sopenharmony_ci	if (MAP_FAILED == buffers[i].start) {
11462306a36Sopenharmony_ci	    /* If you do not exit here you should unmap() and free()
11562306a36Sopenharmony_ci	       the buffers mapped so far. */
11662306a36Sopenharmony_ci	    perror("mmap");
11762306a36Sopenharmony_ci	    exit(EXIT_FAILURE);
11862306a36Sopenharmony_ci	}
11962306a36Sopenharmony_ci    }
12062306a36Sopenharmony_ci
12162306a36Sopenharmony_ci    /* Cleanup. */
12262306a36Sopenharmony_ci
12362306a36Sopenharmony_ci    for (i = 0; i < reqbuf.count; i++)
12462306a36Sopenharmony_ci	munmap(buffers[i].start, buffers[i].length);
12562306a36Sopenharmony_ci
12662306a36Sopenharmony_ciExample: Mapping buffers in the multi-planar API
12762306a36Sopenharmony_ci================================================
12862306a36Sopenharmony_ci
12962306a36Sopenharmony_ci.. code-block:: c
13062306a36Sopenharmony_ci
13162306a36Sopenharmony_ci    struct v4l2_requestbuffers reqbuf;
13262306a36Sopenharmony_ci    /* Our current format uses 3 planes per buffer */
13362306a36Sopenharmony_ci    #define FMT_NUM_PLANES = 3
13462306a36Sopenharmony_ci
13562306a36Sopenharmony_ci    struct {
13662306a36Sopenharmony_ci	void *start[FMT_NUM_PLANES];
13762306a36Sopenharmony_ci	size_t length[FMT_NUM_PLANES];
13862306a36Sopenharmony_ci    } *buffers;
13962306a36Sopenharmony_ci    unsigned int i, j;
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_ci    memset(&reqbuf, 0, sizeof(reqbuf));
14262306a36Sopenharmony_ci    reqbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
14362306a36Sopenharmony_ci    reqbuf.memory = V4L2_MEMORY_MMAP;
14462306a36Sopenharmony_ci    reqbuf.count = 20;
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_ci    if (ioctl(fd, VIDIOC_REQBUFS, &reqbuf) < 0) {
14762306a36Sopenharmony_ci	if (errno == EINVAL)
14862306a36Sopenharmony_ci	    printf("Video capturing or mmap-streaming is not supported\\n");
14962306a36Sopenharmony_ci	else
15062306a36Sopenharmony_ci	    perror("VIDIOC_REQBUFS");
15162306a36Sopenharmony_ci
15262306a36Sopenharmony_ci	exit(EXIT_FAILURE);
15362306a36Sopenharmony_ci    }
15462306a36Sopenharmony_ci
15562306a36Sopenharmony_ci    /* We want at least five buffers. */
15662306a36Sopenharmony_ci
15762306a36Sopenharmony_ci    if (reqbuf.count < 5) {
15862306a36Sopenharmony_ci	/* You may need to free the buffers here. */
15962306a36Sopenharmony_ci	printf("Not enough buffer memory\\n");
16062306a36Sopenharmony_ci	exit(EXIT_FAILURE);
16162306a36Sopenharmony_ci    }
16262306a36Sopenharmony_ci
16362306a36Sopenharmony_ci    buffers = calloc(reqbuf.count, sizeof(*buffers));
16462306a36Sopenharmony_ci    assert(buffers != NULL);
16562306a36Sopenharmony_ci
16662306a36Sopenharmony_ci    for (i = 0; i < reqbuf.count; i++) {
16762306a36Sopenharmony_ci	struct v4l2_buffer buffer;
16862306a36Sopenharmony_ci	struct v4l2_plane planes[FMT_NUM_PLANES];
16962306a36Sopenharmony_ci
17062306a36Sopenharmony_ci	memset(&buffer, 0, sizeof(buffer));
17162306a36Sopenharmony_ci	buffer.type = reqbuf.type;
17262306a36Sopenharmony_ci	buffer.memory = V4L2_MEMORY_MMAP;
17362306a36Sopenharmony_ci	buffer.index = i;
17462306a36Sopenharmony_ci	/* length in struct v4l2_buffer in multi-planar API stores the size
17562306a36Sopenharmony_ci	 * of planes array. */
17662306a36Sopenharmony_ci	buffer.length = FMT_NUM_PLANES;
17762306a36Sopenharmony_ci	buffer.m.planes = planes;
17862306a36Sopenharmony_ci
17962306a36Sopenharmony_ci	if (ioctl(fd, VIDIOC_QUERYBUF, &buffer) < 0) {
18062306a36Sopenharmony_ci	    perror("VIDIOC_QUERYBUF");
18162306a36Sopenharmony_ci	    exit(EXIT_FAILURE);
18262306a36Sopenharmony_ci	}
18362306a36Sopenharmony_ci
18462306a36Sopenharmony_ci	/* Every plane has to be mapped separately */
18562306a36Sopenharmony_ci	for (j = 0; j < FMT_NUM_PLANES; j++) {
18662306a36Sopenharmony_ci	    buffers[i].length[j] = buffer.m.planes[j].length; /* remember for munmap() */
18762306a36Sopenharmony_ci
18862306a36Sopenharmony_ci	    buffers[i].start[j] = mmap(NULL, buffer.m.planes[j].length,
18962306a36Sopenharmony_ci		     PROT_READ | PROT_WRITE, /* recommended */
19062306a36Sopenharmony_ci		     MAP_SHARED,             /* recommended */
19162306a36Sopenharmony_ci		     fd, buffer.m.planes[j].m.offset);
19262306a36Sopenharmony_ci
19362306a36Sopenharmony_ci	    if (MAP_FAILED == buffers[i].start[j]) {
19462306a36Sopenharmony_ci		/* If you do not exit here you should unmap() and free()
19562306a36Sopenharmony_ci		   the buffers and planes mapped so far. */
19662306a36Sopenharmony_ci		perror("mmap");
19762306a36Sopenharmony_ci		exit(EXIT_FAILURE);
19862306a36Sopenharmony_ci	    }
19962306a36Sopenharmony_ci	}
20062306a36Sopenharmony_ci    }
20162306a36Sopenharmony_ci
20262306a36Sopenharmony_ci    /* Cleanup. */
20362306a36Sopenharmony_ci
20462306a36Sopenharmony_ci    for (i = 0; i < reqbuf.count; i++)
20562306a36Sopenharmony_ci	for (j = 0; j < FMT_NUM_PLANES; j++)
20662306a36Sopenharmony_ci	    munmap(buffers[i].start[j], buffers[i].length[j]);
20762306a36Sopenharmony_ci
20862306a36Sopenharmony_ciConceptually streaming drivers maintain two buffer queues, an incoming
20962306a36Sopenharmony_ciand an outgoing queue. They separate the synchronous capture or output
21062306a36Sopenharmony_cioperation locked to a video clock from the application which is subject
21162306a36Sopenharmony_cito random disk or network delays and preemption by other processes,
21262306a36Sopenharmony_cithereby reducing the probability of data loss. The queues are organized
21362306a36Sopenharmony_cias FIFOs, buffers will be output in the order enqueued in the incoming
21462306a36Sopenharmony_ciFIFO, and were captured in the order dequeued from the outgoing FIFO.
21562306a36Sopenharmony_ci
21662306a36Sopenharmony_ciThe driver may require a minimum number of buffers enqueued at all times
21762306a36Sopenharmony_cito function, apart of this no limit exists on the number of buffers
21862306a36Sopenharmony_ciapplications can enqueue in advance, or dequeue and process. They can
21962306a36Sopenharmony_cialso enqueue in a different order than buffers have been dequeued, and
22062306a36Sopenharmony_cithe driver can *fill* enqueued *empty* buffers in any order.  [#f2]_ The
22162306a36Sopenharmony_ciindex number of a buffer (struct :c:type:`v4l2_buffer`
22262306a36Sopenharmony_ci``index``) plays no role here, it only identifies the buffer.
22362306a36Sopenharmony_ci
22462306a36Sopenharmony_ciInitially all mapped buffers are in dequeued state, inaccessible by the
22562306a36Sopenharmony_cidriver. For capturing applications it is customary to first enqueue all
22662306a36Sopenharmony_cimapped buffers, then to start capturing and enter the read loop. Here
22762306a36Sopenharmony_cithe application waits until a filled buffer can be dequeued, and
22862306a36Sopenharmony_cire-enqueues the buffer when the data is no longer needed. Output
22962306a36Sopenharmony_ciapplications fill and enqueue buffers, when enough buffers are stacked
23062306a36Sopenharmony_ciup the output is started with :ref:`VIDIOC_STREAMON <VIDIOC_STREAMON>`.
23162306a36Sopenharmony_ciIn the write loop, when the application runs out of free buffers, it
23262306a36Sopenharmony_cimust wait until an empty buffer can be dequeued and reused.
23362306a36Sopenharmony_ci
23462306a36Sopenharmony_ciTo enqueue and dequeue a buffer applications use the
23562306a36Sopenharmony_ci:ref:`VIDIOC_QBUF <VIDIOC_QBUF>` and :ref:`VIDIOC_DQBUF <VIDIOC_QBUF>`
23662306a36Sopenharmony_ciioctl. The status of a buffer being mapped, enqueued, full or empty can
23762306a36Sopenharmony_cibe determined at any time using the :ref:`VIDIOC_QUERYBUF` ioctl. Two
23862306a36Sopenharmony_cimethods exist to suspend execution of the application until one or more
23962306a36Sopenharmony_cibuffers can be dequeued.  By default :ref:`VIDIOC_DQBUF <VIDIOC_QBUF>`
24062306a36Sopenharmony_ciblocks when no buffer is in the outgoing queue. When the ``O_NONBLOCK``
24162306a36Sopenharmony_ciflag was given to the :c:func:`open()` function,
24262306a36Sopenharmony_ci:ref:`VIDIOC_DQBUF <VIDIOC_QBUF>` returns immediately with an ``EAGAIN``
24362306a36Sopenharmony_cierror code when no buffer is available. The :c:func:`select()`
24462306a36Sopenharmony_cior :c:func:`poll()` functions are always available.
24562306a36Sopenharmony_ci
24662306a36Sopenharmony_ciTo start and stop capturing or output applications call the
24762306a36Sopenharmony_ci:ref:`VIDIOC_STREAMON <VIDIOC_STREAMON>` and :ref:`VIDIOC_STREAMOFF
24862306a36Sopenharmony_ci<VIDIOC_STREAMON>` ioctl.
24962306a36Sopenharmony_ci
25062306a36Sopenharmony_ci.. note:::ref:`VIDIOC_STREAMOFF <VIDIOC_STREAMON>`
25162306a36Sopenharmony_ci   removes all buffers from both queues as a side effect. Since there is
25262306a36Sopenharmony_ci   no notion of doing anything "now" on a multitasking system, if an
25362306a36Sopenharmony_ci   application needs to synchronize with another event it should examine
25462306a36Sopenharmony_ci   the struct ::c:type:`v4l2_buffer` ``timestamp`` of captured
25562306a36Sopenharmony_ci   or outputted buffers.
25662306a36Sopenharmony_ci
25762306a36Sopenharmony_ciDrivers implementing memory mapping I/O must support the
25862306a36Sopenharmony_ci:ref:`VIDIOC_REQBUFS <VIDIOC_REQBUFS>`, :ref:`VIDIOC_QUERYBUF
25962306a36Sopenharmony_ci<VIDIOC_QUERYBUF>`, :ref:`VIDIOC_QBUF <VIDIOC_QBUF>`, :ref:`VIDIOC_DQBUF
26062306a36Sopenharmony_ci<VIDIOC_QBUF>`, :ref:`VIDIOC_STREAMON <VIDIOC_STREAMON>`
26162306a36Sopenharmony_ciand :ref:`VIDIOC_STREAMOFF <VIDIOC_STREAMON>` ioctls, the :ref:`mmap()
26262306a36Sopenharmony_ci<func-mmap>`, :c:func:`munmap()`, :ref:`select()
26362306a36Sopenharmony_ci<func-select>` and :c:func:`poll()` function. [#f3]_
26462306a36Sopenharmony_ci
26562306a36Sopenharmony_ci[capture example]
26662306a36Sopenharmony_ci
26762306a36Sopenharmony_ci.. [#f1]
26862306a36Sopenharmony_ci   One could use one file descriptor and set the buffer type field
26962306a36Sopenharmony_ci   accordingly when calling :ref:`VIDIOC_QBUF` etc.,
27062306a36Sopenharmony_ci   but it makes the :c:func:`select()` function ambiguous. We also
27162306a36Sopenharmony_ci   like the clean approach of one file descriptor per logical stream.
27262306a36Sopenharmony_ci   Video overlay for example is also a logical stream, although the CPU
27362306a36Sopenharmony_ci   is not needed for continuous operation.
27462306a36Sopenharmony_ci
27562306a36Sopenharmony_ci.. [#f2]
27662306a36Sopenharmony_ci   Random enqueue order permits applications processing images out of
27762306a36Sopenharmony_ci   order (such as video codecs) to return buffers earlier, reducing the
27862306a36Sopenharmony_ci   probability of data loss. Random fill order allows drivers to reuse
27962306a36Sopenharmony_ci   buffers on a LIFO-basis, taking advantage of caches holding
28062306a36Sopenharmony_ci   scatter-gather lists and the like.
28162306a36Sopenharmony_ci
28262306a36Sopenharmony_ci.. [#f3]
28362306a36Sopenharmony_ci   At the driver level :c:func:`select()` and :c:func:`poll()` are
28462306a36Sopenharmony_ci   the same, and :c:func:`select()` is too important to be optional.
28562306a36Sopenharmony_ci   The rest should be evident.
286