diff options
Diffstat (limited to 'Documentation/media/uapi/v4l/mmap.rst')
-rw-r--r-- | Documentation/media/uapi/v4l/mmap.rst | 292 |
1 files changed, 0 insertions, 292 deletions
diff --git a/Documentation/media/uapi/v4l/mmap.rst b/Documentation/media/uapi/v4l/mmap.rst deleted file mode 100644 index c47708bf2c87..000000000000 --- a/Documentation/media/uapi/v4l/mmap.rst +++ /dev/null @@ -1,292 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -.. _mmap: - -****************************** -Streaming I/O (Memory Mapping) -****************************** - -Input and output devices support this I/O method when the -``V4L2_CAP_STREAMING`` flag in the ``capabilities`` field of struct -:c:type:`v4l2_capability` returned by the -:ref:`VIDIOC_QUERYCAP` ioctl is set. There are two -streaming methods, to determine if the memory mapping flavor is -supported applications must call the :ref:`VIDIOC_REQBUFS` ioctl -with the memory type set to ``V4L2_MEMORY_MMAP``. - -Streaming is an I/O method where only pointers to buffers are exchanged -between application and driver, the data itself is not copied. Memory -mapping is primarily intended to map buffers in device memory into the -application's address space. Device memory can be for example the video -memory on a graphics card with a video capture add-on. However, being -the most efficient I/O method available for a long time, many other -drivers support streaming as well, allocating buffers in DMA-able main -memory. - -A driver can support many sets of buffers. Each set is identified by a -unique buffer type value. The sets are independent and each set can hold -a different type of data. To access different sets at the same time -different file descriptors must be used. [#f1]_ - -To allocate device buffers applications call the -:ref:`VIDIOC_REQBUFS` ioctl with the desired number -of buffers and buffer type, for example ``V4L2_BUF_TYPE_VIDEO_CAPTURE``. -This ioctl can also be used to change the number of buffers or to free -the allocated memory, provided none of the buffers are still mapped. - -Before applications can access the buffers they must map them into their -address space with the :ref:`mmap() <func-mmap>` function. The -location of the buffers in device memory can be determined with the -:ref:`VIDIOC_QUERYBUF` ioctl. In the single-planar -API case, the ``m.offset`` and ``length`` returned in a struct -:c:type:`v4l2_buffer` are passed as sixth and second -parameter to the :ref:`mmap() <func-mmap>` function. When using the -multi-planar API, struct :c:type:`v4l2_buffer` contains an -array of struct :c:type:`v4l2_plane` structures, each -containing its own ``m.offset`` and ``length``. When using the -multi-planar API, every plane of every buffer has to be mapped -separately, so the number of calls to :ref:`mmap() <func-mmap>` should -be equal to number of buffers times number of planes in each buffer. The -offset and length values must not be modified. Remember, the buffers are -allocated in physical memory, as opposed to virtual memory, which can be -swapped out to disk. Applications should free the buffers as soon as -possible with the :ref:`munmap() <func-munmap>` function. - -Example: Mapping buffers in the single-planar API -================================================= - -.. code-block:: c - - struct v4l2_requestbuffers reqbuf; - struct { - void *start; - size_t length; - } *buffers; - unsigned int i; - - memset(&reqbuf, 0, sizeof(reqbuf)); - reqbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - reqbuf.memory = V4L2_MEMORY_MMAP; - reqbuf.count = 20; - - if (-1 == ioctl (fd, VIDIOC_REQBUFS, &reqbuf)) { - if (errno == EINVAL) - printf("Video capturing or mmap-streaming is not supported\\n"); - else - perror("VIDIOC_REQBUFS"); - - exit(EXIT_FAILURE); - } - - /* We want at least five buffers. */ - - if (reqbuf.count < 5) { - /* You may need to free the buffers here. */ - printf("Not enough buffer memory\\n"); - exit(EXIT_FAILURE); - } - - buffers = calloc(reqbuf.count, sizeof(*buffers)); - assert(buffers != NULL); - - for (i = 0; i < reqbuf.count; i++) { - struct v4l2_buffer buffer; - - memset(&buffer, 0, sizeof(buffer)); - buffer.type = reqbuf.type; - buffer.memory = V4L2_MEMORY_MMAP; - buffer.index = i; - - if (-1 == ioctl (fd, VIDIOC_QUERYBUF, &buffer)) { - perror("VIDIOC_QUERYBUF"); - exit(EXIT_FAILURE); - } - - buffers[i].length = buffer.length; /* remember for munmap() */ - - buffers[i].start = mmap(NULL, buffer.length, - PROT_READ | PROT_WRITE, /* recommended */ - MAP_SHARED, /* recommended */ - fd, buffer.m.offset); - - if (MAP_FAILED == buffers[i].start) { - /* If you do not exit here you should unmap() and free() - the buffers mapped so far. */ - perror("mmap"); - exit(EXIT_FAILURE); - } - } - - /* Cleanup. */ - - for (i = 0; i < reqbuf.count; i++) - munmap(buffers[i].start, buffers[i].length); - - -Example: Mapping buffers in the multi-planar API -================================================ - -.. code-block:: c - - struct v4l2_requestbuffers reqbuf; - /* Our current format uses 3 planes per buffer */ - #define FMT_NUM_PLANES = 3 - - struct { - void *start[FMT_NUM_PLANES]; - size_t length[FMT_NUM_PLANES]; - } *buffers; - unsigned int i, j; - - memset(&reqbuf, 0, sizeof(reqbuf)); - reqbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; - reqbuf.memory = V4L2_MEMORY_MMAP; - reqbuf.count = 20; - - if (ioctl(fd, VIDIOC_REQBUFS, &reqbuf) < 0) { - if (errno == EINVAL) - printf("Video capturing or mmap-streaming is not supported\\n"); - else - perror("VIDIOC_REQBUFS"); - - exit(EXIT_FAILURE); - } - - /* We want at least five buffers. */ - - if (reqbuf.count < 5) { - /* You may need to free the buffers here. */ - printf("Not enough buffer memory\\n"); - exit(EXIT_FAILURE); - } - - buffers = calloc(reqbuf.count, sizeof(*buffers)); - assert(buffers != NULL); - - for (i = 0; i < reqbuf.count; i++) { - struct v4l2_buffer buffer; - struct v4l2_plane planes[FMT_NUM_PLANES]; - - memset(&buffer, 0, sizeof(buffer)); - buffer.type = reqbuf.type; - buffer.memory = V4L2_MEMORY_MMAP; - buffer.index = i; - /* length in struct v4l2_buffer in multi-planar API stores the size - * of planes array. */ - buffer.length = FMT_NUM_PLANES; - buffer.m.planes = planes; - - if (ioctl(fd, VIDIOC_QUERYBUF, &buffer) < 0) { - perror("VIDIOC_QUERYBUF"); - exit(EXIT_FAILURE); - } - - /* Every plane has to be mapped separately */ - for (j = 0; j < FMT_NUM_PLANES; j++) { - buffers[i].length[j] = buffer.m.planes[j].length; /* remember for munmap() */ - - buffers[i].start[j] = mmap(NULL, buffer.m.planes[j].length, - PROT_READ | PROT_WRITE, /* recommended */ - MAP_SHARED, /* recommended */ - fd, buffer.m.planes[j].m.offset); - - if (MAP_FAILED == buffers[i].start[j]) { - /* If you do not exit here you should unmap() and free() - the buffers and planes mapped so far. */ - perror("mmap"); - exit(EXIT_FAILURE); - } - } - } - - /* Cleanup. */ - - for (i = 0; i < reqbuf.count; i++) - for (j = 0; j < FMT_NUM_PLANES; j++) - munmap(buffers[i].start[j], buffers[i].length[j]); - -Conceptually streaming drivers maintain two buffer queues, an incoming -and an outgoing queue. They separate the synchronous capture or output -operation locked to a video clock from the application which is subject -to random disk or network delays and preemption by other processes, -thereby reducing the probability of data loss. The queues are organized -as FIFOs, buffers will be output in the order enqueued in the incoming -FIFO, and were captured in the order dequeued from the outgoing FIFO. - -The driver may require a minimum number of buffers enqueued at all times -to function, apart of this no limit exists on the number of buffers -applications can enqueue in advance, or dequeue and process. They can -also enqueue in a different order than buffers have been dequeued, and -the driver can *fill* enqueued *empty* buffers in any order. [#f2]_ The -index number of a buffer (struct :c:type:`v4l2_buffer` -``index``) plays no role here, it only identifies the buffer. - -Initially all mapped buffers are in dequeued state, inaccessible by the -driver. For capturing applications it is customary to first enqueue all -mapped buffers, then to start capturing and enter the read loop. Here -the application waits until a filled buffer can be dequeued, and -re-enqueues the buffer when the data is no longer needed. Output -applications fill and enqueue buffers, when enough buffers are stacked -up the output is started with :ref:`VIDIOC_STREAMON <VIDIOC_STREAMON>`. -In the write loop, when the application runs out of free buffers, it -must wait until an empty buffer can be dequeued and reused. - -To enqueue and dequeue a buffer applications use the -:ref:`VIVIOC_QBUF <VIDIOC_QBUF>` and :ref:`VIDIOC_DQBUF <VIDIOC_QBUF>` -ioctl. The status of a buffer being mapped, enqueued, full or empty can -be determined at any time using the :ref:`VIDIOC_QUERYBUF` ioctl. Two -methods exist to suspend execution of the application until one or more -buffers can be dequeued. By default :ref:`VIDIOC_DQBUF <VIDIOC_QBUF>` -blocks when no buffer is in the outgoing queue. When the ``O_NONBLOCK`` -flag was given to the :ref:`open() <func-open>` function, -:ref:`VIDIOC_DQBUF <VIDIOC_QBUF>` returns immediately with an ``EAGAIN`` -error code when no buffer is available. The :ref:`select() <func-select>` -or :ref:`poll() <func-poll>` functions are always available. - -To start and stop capturing or output applications call the -:ref:`VIDIOC_STREAMON <VIDIOC_STREAMON>` and :ref:`VIDIOC_STREAMOFF -<VIDIOC_STREAMON>` ioctl. - -.. note:::ref:`VIDIOC_STREAMOFF <VIDIOC_STREAMON>` - removes all buffers from both queues as a side effect. Since there is - no notion of doing anything "now" on a multitasking system, if an - application needs to synchronize with another event it should examine - the struct ::c:type:`v4l2_buffer` ``timestamp`` of captured - or outputted buffers. - -Drivers implementing memory mapping I/O must support the -:ref:`VIDIOC_REQBUFS <VIDIOC_REQBUFS>`, :ref:`VIDIOC_QUERYBUF -<VIDIOC_QUERYBUF>`, :ref:`VIDIOC_QBUF <VIDIOC_QBUF>`, :ref:`VIDIOC_DQBUF -<VIDIOC_QBUF>`, :ref:`VIDIOC_STREAMON <VIDIOC_STREAMON>` -and :ref:`VIDIOC_STREAMOFF <VIDIOC_STREAMON>` ioctls, the :ref:`mmap() -<func-mmap>`, :ref:`munmap() <func-munmap>`, :ref:`select() -<func-select>` and :ref:`poll() <func-poll>` function. [#f3]_ - -[capture example] - -.. [#f1] - One could use one file descriptor and set the buffer type field - accordingly when calling :ref:`VIDIOC_QBUF` etc., - but it makes the :ref:`select() <func-select>` function ambiguous. We also - like the clean approach of one file descriptor per logical stream. - Video overlay for example is also a logical stream, although the CPU - is not needed for continuous operation. - -.. [#f2] - Random enqueue order permits applications processing images out of - order (such as video codecs) to return buffers earlier, reducing the - probability of data loss. Random fill order allows drivers to reuse - buffers on a LIFO-basis, taking advantage of caches holding - scatter-gather lists and the like. - -.. [#f3] - At the driver level :ref:`select() <func-select>` and :ref:`poll() <func-poll>` are - the same, and :ref:`select() <func-select>` is too important to be optional. - The rest should be evident. |