brintos

brintos / linux-shallow public Read only

0
0
Text · 10.5 KiB · 1a48c3c Raw
286 lines · plain
1.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later2.. c:namespace:: V4L3 4.. _mmap:5 6******************************7Streaming I/O (Memory Mapping)8******************************9 10Input and output devices support this I/O method when the11``V4L2_CAP_STREAMING`` flag in the ``capabilities`` field of struct12:c:type:`v4l2_capability` returned by the13:ref:`VIDIOC_QUERYCAP` ioctl is set. There are two14streaming methods, to determine if the memory mapping flavor is15supported applications must call the :ref:`VIDIOC_REQBUFS` ioctl16with the memory type set to ``V4L2_MEMORY_MMAP``.17 18Streaming is an I/O method where only pointers to buffers are exchanged19between application and driver, the data itself is not copied. Memory20mapping is primarily intended to map buffers in device memory into the21application's address space. Device memory can be for example the video22memory on a graphics card with a video capture add-on. However, being23the most efficient I/O method available for a long time, many other24drivers support streaming as well, allocating buffers in DMA-able main25memory.26 27A driver can support many sets of buffers. Each set is identified by a28unique buffer type value. The sets are independent and each set can hold29a different type of data. To access different sets at the same time30different file descriptors must be used. [#f1]_31 32To allocate device buffers applications call the33:ref:`VIDIOC_REQBUFS` ioctl with the desired number34of buffers and buffer type, for example ``V4L2_BUF_TYPE_VIDEO_CAPTURE``.35This ioctl can also be used to change the number of buffers or to free36the allocated memory, provided none of the buffers are still mapped.37 38Before applications can access the buffers they must map them into their39address space with the :c:func:`mmap()` function. The40location of the buffers in device memory can be determined with the41:ref:`VIDIOC_QUERYBUF` ioctl. In the single-planar42API case, the ``m.offset`` and ``length`` returned in a struct43:c:type:`v4l2_buffer` are passed as sixth and second44parameter to the :c:func:`mmap()` function. When using the45multi-planar API, struct :c:type:`v4l2_buffer` contains an46array of struct :c:type:`v4l2_plane` structures, each47containing its own ``m.offset`` and ``length``. When using the48multi-planar API, every plane of every buffer has to be mapped49separately, so the number of calls to :c:func:`mmap()` should50be equal to number of buffers times number of planes in each buffer. The51offset and length values must not be modified. Remember, the buffers are52allocated in physical memory, as opposed to virtual memory, which can be53swapped out to disk. Applications should free the buffers as soon as54possible with the :c:func:`munmap()` function.55 56Example: Mapping buffers in the single-planar API57=================================================58 59.. code-block:: c60 61    struct v4l2_requestbuffers reqbuf;62    struct {63	void *start;64	size_t length;65    } *buffers;66    unsigned int i;67 68    memset(&reqbuf, 0, sizeof(reqbuf));69    reqbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;70    reqbuf.memory = V4L2_MEMORY_MMAP;71    reqbuf.count = 20;72 73    if (-1 == ioctl (fd, VIDIOC_REQBUFS, &reqbuf)) {74	if (errno == EINVAL)75	    printf("Video capturing or mmap-streaming is not supported\\n");76	else77	    perror("VIDIOC_REQBUFS");78 79	exit(EXIT_FAILURE);80    }81 82    /* We want at least five buffers. */83 84    if (reqbuf.count < 5) {85	/* You may need to free the buffers here. */86	printf("Not enough buffer memory\\n");87	exit(EXIT_FAILURE);88    }89 90    buffers = calloc(reqbuf.count, sizeof(*buffers));91    assert(buffers != NULL);92 93    for (i = 0; i < reqbuf.count; i++) {94	struct v4l2_buffer buffer;95 96	memset(&buffer, 0, sizeof(buffer));97	buffer.type = reqbuf.type;98	buffer.memory = V4L2_MEMORY_MMAP;99	buffer.index = i;100 101	if (-1 == ioctl (fd, VIDIOC_QUERYBUF, &buffer)) {102	    perror("VIDIOC_QUERYBUF");103	    exit(EXIT_FAILURE);104	}105 106	buffers[i].length = buffer.length; /* remember for munmap() */107 108	buffers[i].start = mmap(NULL, buffer.length,109		    PROT_READ | PROT_WRITE, /* recommended */110		    MAP_SHARED,             /* recommended */111		    fd, buffer.m.offset);112 113	if (MAP_FAILED == buffers[i].start) {114	    /* If you do not exit here you should unmap() and free()115	       the buffers mapped so far. */116	    perror("mmap");117	    exit(EXIT_FAILURE);118	}119    }120 121    /* Cleanup. */122 123    for (i = 0; i < reqbuf.count; i++)124	munmap(buffers[i].start, buffers[i].length);125 126Example: Mapping buffers in the multi-planar API127================================================128 129.. code-block:: c130 131    struct v4l2_requestbuffers reqbuf;132    /* Our current format uses 3 planes per buffer */133    #define FMT_NUM_PLANES = 3134 135    struct {136	void *start[FMT_NUM_PLANES];137	size_t length[FMT_NUM_PLANES];138    } *buffers;139    unsigned int i, j;140 141    memset(&reqbuf, 0, sizeof(reqbuf));142    reqbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;143    reqbuf.memory = V4L2_MEMORY_MMAP;144    reqbuf.count = 20;145 146    if (ioctl(fd, VIDIOC_REQBUFS, &reqbuf) < 0) {147	if (errno == EINVAL)148	    printf("Video capturing or mmap-streaming is not supported\\n");149	else150	    perror("VIDIOC_REQBUFS");151 152	exit(EXIT_FAILURE);153    }154 155    /* We want at least five buffers. */156 157    if (reqbuf.count < 5) {158	/* You may need to free the buffers here. */159	printf("Not enough buffer memory\\n");160	exit(EXIT_FAILURE);161    }162 163    buffers = calloc(reqbuf.count, sizeof(*buffers));164    assert(buffers != NULL);165 166    for (i = 0; i < reqbuf.count; i++) {167	struct v4l2_buffer buffer;168	struct v4l2_plane planes[FMT_NUM_PLANES];169 170	memset(&buffer, 0, sizeof(buffer));171	buffer.type = reqbuf.type;172	buffer.memory = V4L2_MEMORY_MMAP;173	buffer.index = i;174	/* length in struct v4l2_buffer in multi-planar API stores the size175	 * of planes array. */176	buffer.length = FMT_NUM_PLANES;177	buffer.m.planes = planes;178 179	if (ioctl(fd, VIDIOC_QUERYBUF, &buffer) < 0) {180	    perror("VIDIOC_QUERYBUF");181	    exit(EXIT_FAILURE);182	}183 184	/* Every plane has to be mapped separately */185	for (j = 0; j < FMT_NUM_PLANES; j++) {186	    buffers[i].length[j] = buffer.m.planes[j].length; /* remember for munmap() */187 188	    buffers[i].start[j] = mmap(NULL, buffer.m.planes[j].length,189		     PROT_READ | PROT_WRITE, /* recommended */190		     MAP_SHARED,             /* recommended */191		     fd, buffer.m.planes[j].m.mem_offset);192 193	    if (MAP_FAILED == buffers[i].start[j]) {194		/* If you do not exit here you should unmap() and free()195		   the buffers and planes mapped so far. */196		perror("mmap");197		exit(EXIT_FAILURE);198	    }199	}200    }201 202    /* Cleanup. */203 204    for (i = 0; i < reqbuf.count; i++)205	for (j = 0; j < FMT_NUM_PLANES; j++)206	    munmap(buffers[i].start[j], buffers[i].length[j]);207 208Conceptually streaming drivers maintain two buffer queues, an incoming209and an outgoing queue. They separate the synchronous capture or output210operation locked to a video clock from the application which is subject211to random disk or network delays and preemption by other processes,212thereby reducing the probability of data loss. The queues are organized213as FIFOs, buffers will be output in the order enqueued in the incoming214FIFO, and were captured in the order dequeued from the outgoing FIFO.215 216The driver may require a minimum number of buffers enqueued at all times217to function, apart of this no limit exists on the number of buffers218applications can enqueue in advance, or dequeue and process. They can219also enqueue in a different order than buffers have been dequeued, and220the driver can *fill* enqueued *empty* buffers in any order.  [#f2]_ The221index number of a buffer (struct :c:type:`v4l2_buffer`222``index``) plays no role here, it only identifies the buffer.223 224Initially all mapped buffers are in dequeued state, inaccessible by the225driver. For capturing applications it is customary to first enqueue all226mapped buffers, then to start capturing and enter the read loop. Here227the application waits until a filled buffer can be dequeued, and228re-enqueues the buffer when the data is no longer needed. Output229applications fill and enqueue buffers, when enough buffers are stacked230up the output is started with :ref:`VIDIOC_STREAMON <VIDIOC_STREAMON>`.231In the write loop, when the application runs out of free buffers, it232must wait until an empty buffer can be dequeued and reused.233 234To enqueue and dequeue a buffer applications use the235:ref:`VIDIOC_QBUF <VIDIOC_QBUF>` and :ref:`VIDIOC_DQBUF <VIDIOC_QBUF>`236ioctl. The status of a buffer being mapped, enqueued, full or empty can237be determined at any time using the :ref:`VIDIOC_QUERYBUF` ioctl. Two238methods exist to suspend execution of the application until one or more239buffers can be dequeued.  By default :ref:`VIDIOC_DQBUF <VIDIOC_QBUF>`240blocks when no buffer is in the outgoing queue. When the ``O_NONBLOCK``241flag was given to the :c:func:`open()` function,242:ref:`VIDIOC_DQBUF <VIDIOC_QBUF>` returns immediately with an ``EAGAIN``243error code when no buffer is available. The :c:func:`select()`244or :c:func:`poll()` functions are always available.245 246To start and stop capturing or output applications call the247:ref:`VIDIOC_STREAMON <VIDIOC_STREAMON>` and :ref:`VIDIOC_STREAMOFF248<VIDIOC_STREAMON>` ioctl.249 250.. note:::ref:`VIDIOC_STREAMOFF <VIDIOC_STREAMON>`251   removes all buffers from both queues as a side effect. Since there is252   no notion of doing anything "now" on a multitasking system, if an253   application needs to synchronize with another event it should examine254   the struct ::c:type:`v4l2_buffer` ``timestamp`` of captured255   or outputted buffers.256 257Drivers implementing memory mapping I/O must support the258:ref:`VIDIOC_REQBUFS <VIDIOC_REQBUFS>`, :ref:`VIDIOC_QUERYBUF259<VIDIOC_QUERYBUF>`, :ref:`VIDIOC_QBUF <VIDIOC_QBUF>`, :ref:`VIDIOC_DQBUF260<VIDIOC_QBUF>`, :ref:`VIDIOC_STREAMON <VIDIOC_STREAMON>`261and :ref:`VIDIOC_STREAMOFF <VIDIOC_STREAMON>` ioctls, the :ref:`mmap()262<func-mmap>`, :c:func:`munmap()`, :ref:`select()263<func-select>` and :c:func:`poll()` function. [#f3]_264 265[capture example]266 267.. [#f1]268   One could use one file descriptor and set the buffer type field269   accordingly when calling :ref:`VIDIOC_QBUF` etc.,270   but it makes the :c:func:`select()` function ambiguous. We also271   like the clean approach of one file descriptor per logical stream.272   Video overlay for example is also a logical stream, although the CPU273   is not needed for continuous operation.274 275.. [#f2]276   Random enqueue order permits applications processing images out of277   order (such as video codecs) to return buffers earlier, reducing the278   probability of data loss. Random fill order allows drivers to reuse279   buffers on a LIFO-basis, taking advantage of caches holding280   scatter-gather lists and the like.281 282.. [#f3]283   At the driver level :c:func:`select()` and :c:func:`poll()` are284   the same, and :c:func:`select()` is too important to be optional.285   The rest should be evident.286