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