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