18c2ecf20Sopenharmony_ci.. SPDX-License-Identifier: GPL-2.0 OR GFDL-1.1-no-invariants-or-later
28c2ecf20Sopenharmony_ci.. c:namespace:: MC
38c2ecf20Sopenharmony_ci
48c2ecf20Sopenharmony_ci.. _media-request-api:
58c2ecf20Sopenharmony_ci
68c2ecf20Sopenharmony_ciRequest API
78c2ecf20Sopenharmony_ci===========
88c2ecf20Sopenharmony_ci
98c2ecf20Sopenharmony_ciThe Request API has been designed to allow V4L2 to deal with requirements of
108c2ecf20Sopenharmony_cimodern devices (stateless codecs, complex camera pipelines, ...) and APIs
118c2ecf20Sopenharmony_ci(Android Codec v2). One such requirement is the ability for devices belonging to
128c2ecf20Sopenharmony_cithe same pipeline to reconfigure and collaborate closely on a per-frame basis.
138c2ecf20Sopenharmony_ciAnother is support of stateless codecs, which require controls to be applied
148c2ecf20Sopenharmony_cito specific frames (aka 'per-frame controls') in order to be used efficiently.
158c2ecf20Sopenharmony_ci
168c2ecf20Sopenharmony_ciWhile the initial use-case was V4L2, it can be extended to other subsystems
178c2ecf20Sopenharmony_cias well, as long as they use the media controller.
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_ciSupporting these features without the Request API is not always possible and if
208c2ecf20Sopenharmony_ciit is, it is terribly inefficient: user-space would have to flush all activity
218c2ecf20Sopenharmony_cion the media pipeline, reconfigure it for the next frame, queue the buffers to
228c2ecf20Sopenharmony_cibe processed with that configuration, and wait until they are all available for
238c2ecf20Sopenharmony_cidequeuing before considering the next frame. This defeats the purpose of having
248c2ecf20Sopenharmony_cibuffer queues since in practice only one buffer would be queued at a time.
258c2ecf20Sopenharmony_ci
268c2ecf20Sopenharmony_ciThe Request API allows a specific configuration of the pipeline (media
278c2ecf20Sopenharmony_cicontroller topology + configuration for each media entity) to be associated with
288c2ecf20Sopenharmony_cispecific buffers. This allows user-space to schedule several tasks ("requests")
298c2ecf20Sopenharmony_ciwith different configurations in advance, knowing that the configuration will be
308c2ecf20Sopenharmony_ciapplied when needed to get the expected result. Configuration values at the time
318c2ecf20Sopenharmony_ciof request completion are also available for reading.
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_ciGeneral Usage
348c2ecf20Sopenharmony_ci-------------
358c2ecf20Sopenharmony_ci
368c2ecf20Sopenharmony_ciThe Request API extends the Media Controller API and cooperates with
378c2ecf20Sopenharmony_cisubsystem-specific APIs to support request usage. At the Media Controller
388c2ecf20Sopenharmony_cilevel, requests are allocated from the supporting Media Controller device
398c2ecf20Sopenharmony_cinode. Their life cycle is then managed through the request file descriptors in
408c2ecf20Sopenharmony_cian opaque way. Configuration data, buffer handles and processing results
418c2ecf20Sopenharmony_cistored in requests are accessed through subsystem-specific APIs extended for
428c2ecf20Sopenharmony_cirequest support, such as V4L2 APIs that take an explicit ``request_fd``
438c2ecf20Sopenharmony_ciparameter.
448c2ecf20Sopenharmony_ci
458c2ecf20Sopenharmony_ciRequest Allocation
468c2ecf20Sopenharmony_ci------------------
478c2ecf20Sopenharmony_ci
488c2ecf20Sopenharmony_ciUser-space allocates requests using :ref:`MEDIA_IOC_REQUEST_ALLOC`
498c2ecf20Sopenharmony_cifor the media device node. This returns a file descriptor representing the
508c2ecf20Sopenharmony_cirequest. Typically, several such requests will be allocated.
518c2ecf20Sopenharmony_ci
528c2ecf20Sopenharmony_ciRequest Preparation
538c2ecf20Sopenharmony_ci-------------------
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_ciStandard V4L2 ioctls can then receive a request file descriptor to express the
568c2ecf20Sopenharmony_cifact that the ioctl is part of said request, and is not to be applied
578c2ecf20Sopenharmony_ciimmediately. See :ref:`MEDIA_IOC_REQUEST_ALLOC` for a list of ioctls that
588c2ecf20Sopenharmony_cisupport this. Configurations set with a ``request_fd`` parameter are stored
598c2ecf20Sopenharmony_ciinstead of being immediately applied, and buffers queued to a request do not
608c2ecf20Sopenharmony_cienter the regular buffer queue until the request itself is queued.
618c2ecf20Sopenharmony_ci
628c2ecf20Sopenharmony_ciRequest Submission
638c2ecf20Sopenharmony_ci------------------
648c2ecf20Sopenharmony_ci
658c2ecf20Sopenharmony_ciOnce the configuration and buffers of the request are specified, it can be
668c2ecf20Sopenharmony_ciqueued by calling :ref:`MEDIA_REQUEST_IOC_QUEUE` on the request file descriptor.
678c2ecf20Sopenharmony_ciA request must contain at least one buffer, otherwise ``ENOENT`` is returned.
688c2ecf20Sopenharmony_ciA queued request cannot be modified anymore.
698c2ecf20Sopenharmony_ci
708c2ecf20Sopenharmony_ci.. caution::
718c2ecf20Sopenharmony_ci   For :ref:`memory-to-memory devices <mem2mem>` you can use requests only for
728c2ecf20Sopenharmony_ci   output buffers, not for capture buffers. Attempting to add a capture buffer
738c2ecf20Sopenharmony_ci   to a request will result in an ``EBADR`` error.
748c2ecf20Sopenharmony_ci
758c2ecf20Sopenharmony_ciIf the request contains configurations for multiple entities, individual drivers
768c2ecf20Sopenharmony_cimay synchronize so the requested pipeline's topology is applied before the
778c2ecf20Sopenharmony_cibuffers are processed. Media controller drivers do a best effort implementation
788c2ecf20Sopenharmony_cisince perfect atomicity may not be possible due to hardware limitations.
798c2ecf20Sopenharmony_ci
808c2ecf20Sopenharmony_ci.. caution::
818c2ecf20Sopenharmony_ci
828c2ecf20Sopenharmony_ci   It is not allowed to mix queuing requests with directly queuing buffers:
838c2ecf20Sopenharmony_ci   whichever method is used first locks this in place until
848c2ecf20Sopenharmony_ci   :ref:`VIDIOC_STREAMOFF <VIDIOC_STREAMON>` is called or the device is
858c2ecf20Sopenharmony_ci   :ref:`closed <func-close>`. Attempts to directly queue a buffer when earlier
868c2ecf20Sopenharmony_ci   a buffer was queued via a request or vice versa will result in an ``EBUSY``
878c2ecf20Sopenharmony_ci   error.
888c2ecf20Sopenharmony_ci
898c2ecf20Sopenharmony_ciControls can still be set without a request and are applied immediately,
908c2ecf20Sopenharmony_ciregardless of whether a request is in use or not.
918c2ecf20Sopenharmony_ci
928c2ecf20Sopenharmony_ci.. caution::
938c2ecf20Sopenharmony_ci
948c2ecf20Sopenharmony_ci   Setting the same control through a request and also directly can lead to
958c2ecf20Sopenharmony_ci   undefined behavior!
968c2ecf20Sopenharmony_ci
978c2ecf20Sopenharmony_ciUser-space can :c:func:`poll()` a request file descriptor in
988c2ecf20Sopenharmony_ciorder to wait until the request completes. A request is considered complete
998c2ecf20Sopenharmony_cionce all its associated buffers are available for dequeuing and all the
1008c2ecf20Sopenharmony_ciassociated controls have been updated with the values at the time of completion.
1018c2ecf20Sopenharmony_ciNote that user-space does not need to wait for the request to complete to
1028c2ecf20Sopenharmony_cidequeue its buffers: buffers that are available halfway through a request can
1038c2ecf20Sopenharmony_cibe dequeued independently of the request's state.
1048c2ecf20Sopenharmony_ci
1058c2ecf20Sopenharmony_ciA completed request contains the state of the device after the request was
1068c2ecf20Sopenharmony_ciexecuted. User-space can query that state by calling
1078c2ecf20Sopenharmony_ci:ref:`ioctl VIDIOC_G_EXT_CTRLS <VIDIOC_G_EXT_CTRLS>` with the request file
1088c2ecf20Sopenharmony_cidescriptor. Calling :ref:`ioctl VIDIOC_G_EXT_CTRLS <VIDIOC_G_EXT_CTRLS>` for a
1098c2ecf20Sopenharmony_cirequest that has been queued but not yet completed will return ``EBUSY``
1108c2ecf20Sopenharmony_cisince the control values might be changed at any time by the driver while the
1118c2ecf20Sopenharmony_cirequest is in flight.
1128c2ecf20Sopenharmony_ci
1138c2ecf20Sopenharmony_ci.. _media-request-life-time:
1148c2ecf20Sopenharmony_ci
1158c2ecf20Sopenharmony_ciRecycling and Destruction
1168c2ecf20Sopenharmony_ci-------------------------
1178c2ecf20Sopenharmony_ci
1188c2ecf20Sopenharmony_ciFinally, a completed request can either be discarded or be reused. Calling
1198c2ecf20Sopenharmony_ci:c:func:`close()` on a request file descriptor will make
1208c2ecf20Sopenharmony_cithat file descriptor unusable and the request will be freed once it is no
1218c2ecf20Sopenharmony_cilonger in use by the kernel. That is, if the request is queued and then the
1228c2ecf20Sopenharmony_cifile descriptor is closed, then it won't be freed until the driver completed
1238c2ecf20Sopenharmony_cithe request.
1248c2ecf20Sopenharmony_ci
1258c2ecf20Sopenharmony_ciThe :ref:`MEDIA_REQUEST_IOC_REINIT` will clear a request's state and make it
1268c2ecf20Sopenharmony_ciavailable again. No state is retained by this operation: the request is as
1278c2ecf20Sopenharmony_ciif it had just been allocated.
1288c2ecf20Sopenharmony_ci
1298c2ecf20Sopenharmony_ciExample for a Codec Device
1308c2ecf20Sopenharmony_ci--------------------------
1318c2ecf20Sopenharmony_ci
1328c2ecf20Sopenharmony_ciFor use-cases such as :ref:`codecs <mem2mem>`, the request API can be used
1338c2ecf20Sopenharmony_cito associate specific controls to
1348c2ecf20Sopenharmony_cibe applied by the driver for the OUTPUT buffer, allowing user-space
1358c2ecf20Sopenharmony_cito queue many such buffers in advance. It can also take advantage of requests'
1368c2ecf20Sopenharmony_ciability to capture the state of controls when the request completes to read back
1378c2ecf20Sopenharmony_ciinformation that may be subject to change.
1388c2ecf20Sopenharmony_ci
1398c2ecf20Sopenharmony_ciPut into code, after obtaining a request, user-space can assign controls and one
1408c2ecf20Sopenharmony_ciOUTPUT buffer to it:
1418c2ecf20Sopenharmony_ci
1428c2ecf20Sopenharmony_ci.. code-block:: c
1438c2ecf20Sopenharmony_ci
1448c2ecf20Sopenharmony_ci	struct v4l2_buffer buf;
1458c2ecf20Sopenharmony_ci	struct v4l2_ext_controls ctrls;
1468c2ecf20Sopenharmony_ci	int req_fd;
1478c2ecf20Sopenharmony_ci	...
1488c2ecf20Sopenharmony_ci	if (ioctl(media_fd, MEDIA_IOC_REQUEST_ALLOC, &req_fd))
1498c2ecf20Sopenharmony_ci		return errno;
1508c2ecf20Sopenharmony_ci	...
1518c2ecf20Sopenharmony_ci	ctrls.which = V4L2_CTRL_WHICH_REQUEST_VAL;
1528c2ecf20Sopenharmony_ci	ctrls.request_fd = req_fd;
1538c2ecf20Sopenharmony_ci	if (ioctl(codec_fd, VIDIOC_S_EXT_CTRLS, &ctrls))
1548c2ecf20Sopenharmony_ci		return errno;
1558c2ecf20Sopenharmony_ci	...
1568c2ecf20Sopenharmony_ci	buf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
1578c2ecf20Sopenharmony_ci	buf.flags |= V4L2_BUF_FLAG_REQUEST_FD;
1588c2ecf20Sopenharmony_ci	buf.request_fd = req_fd;
1598c2ecf20Sopenharmony_ci	if (ioctl(codec_fd, VIDIOC_QBUF, &buf))
1608c2ecf20Sopenharmony_ci		return errno;
1618c2ecf20Sopenharmony_ci
1628c2ecf20Sopenharmony_ciNote that it is not allowed to use the Request API for CAPTURE buffers
1638c2ecf20Sopenharmony_cisince there are no per-frame settings to report there.
1648c2ecf20Sopenharmony_ci
1658c2ecf20Sopenharmony_ciOnce the request is fully prepared, it can be queued to the driver:
1668c2ecf20Sopenharmony_ci
1678c2ecf20Sopenharmony_ci.. code-block:: c
1688c2ecf20Sopenharmony_ci
1698c2ecf20Sopenharmony_ci	if (ioctl(req_fd, MEDIA_REQUEST_IOC_QUEUE))
1708c2ecf20Sopenharmony_ci		return errno;
1718c2ecf20Sopenharmony_ci
1728c2ecf20Sopenharmony_ciUser-space can then either wait for the request to complete by calling poll() on
1738c2ecf20Sopenharmony_ciits file descriptor, or start dequeuing CAPTURE buffers. Most likely, it will
1748c2ecf20Sopenharmony_ciwant to get CAPTURE buffers as soon as possible and this can be done using a
1758c2ecf20Sopenharmony_ciregular :ref:`VIDIOC_DQBUF <VIDIOC_QBUF>`:
1768c2ecf20Sopenharmony_ci
1778c2ecf20Sopenharmony_ci.. code-block:: c
1788c2ecf20Sopenharmony_ci
1798c2ecf20Sopenharmony_ci	struct v4l2_buffer buf;
1808c2ecf20Sopenharmony_ci
1818c2ecf20Sopenharmony_ci	memset(&buf, 0, sizeof(buf));
1828c2ecf20Sopenharmony_ci	buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
1838c2ecf20Sopenharmony_ci	if (ioctl(codec_fd, VIDIOC_DQBUF, &buf))
1848c2ecf20Sopenharmony_ci		return errno;
1858c2ecf20Sopenharmony_ci
1868c2ecf20Sopenharmony_ciNote that this example assumes for simplicity that for every OUTPUT buffer
1878c2ecf20Sopenharmony_cithere will be one CAPTURE buffer, but this does not have to be the case.
1888c2ecf20Sopenharmony_ci
1898c2ecf20Sopenharmony_ciWe can then, after ensuring that the request is completed via polling the
1908c2ecf20Sopenharmony_cirequest file descriptor, query control values at the time of its completion via
1918c2ecf20Sopenharmony_cia call to :ref:`VIDIOC_G_EXT_CTRLS <VIDIOC_G_EXT_CTRLS>`.
1928c2ecf20Sopenharmony_ciThis is particularly useful for volatile controls for which we want to
1938c2ecf20Sopenharmony_ciquery values as soon as the capture buffer is produced.
1948c2ecf20Sopenharmony_ci
1958c2ecf20Sopenharmony_ci.. code-block:: c
1968c2ecf20Sopenharmony_ci
1978c2ecf20Sopenharmony_ci	struct pollfd pfd = { .events = POLLPRI, .fd = req_fd };
1988c2ecf20Sopenharmony_ci	poll(&pfd, 1, -1);
1998c2ecf20Sopenharmony_ci	...
2008c2ecf20Sopenharmony_ci	ctrls.which = V4L2_CTRL_WHICH_REQUEST_VAL;
2018c2ecf20Sopenharmony_ci	ctrls.request_fd = req_fd;
2028c2ecf20Sopenharmony_ci	if (ioctl(codec_fd, VIDIOC_G_EXT_CTRLS, &ctrls))
2038c2ecf20Sopenharmony_ci		return errno;
2048c2ecf20Sopenharmony_ci
2058c2ecf20Sopenharmony_ciOnce we don't need the request anymore, we can either recycle it for reuse with
2068c2ecf20Sopenharmony_ci:ref:`MEDIA_REQUEST_IOC_REINIT`...
2078c2ecf20Sopenharmony_ci
2088c2ecf20Sopenharmony_ci.. code-block:: c
2098c2ecf20Sopenharmony_ci
2108c2ecf20Sopenharmony_ci	if (ioctl(req_fd, MEDIA_REQUEST_IOC_REINIT))
2118c2ecf20Sopenharmony_ci		return errno;
2128c2ecf20Sopenharmony_ci
2138c2ecf20Sopenharmony_ci... or close its file descriptor to completely dispose of it.
2148c2ecf20Sopenharmony_ci
2158c2ecf20Sopenharmony_ci.. code-block:: c
2168c2ecf20Sopenharmony_ci
2178c2ecf20Sopenharmony_ci	close(req_fd);
2188c2ecf20Sopenharmony_ci
2198c2ecf20Sopenharmony_ciExample for a Simple Capture Device
2208c2ecf20Sopenharmony_ci-----------------------------------
2218c2ecf20Sopenharmony_ci
2228c2ecf20Sopenharmony_ciWith a simple capture device, requests can be used to specify controls to apply
2238c2ecf20Sopenharmony_cifor a given CAPTURE buffer.
2248c2ecf20Sopenharmony_ci
2258c2ecf20Sopenharmony_ci.. code-block:: c
2268c2ecf20Sopenharmony_ci
2278c2ecf20Sopenharmony_ci	struct v4l2_buffer buf;
2288c2ecf20Sopenharmony_ci	struct v4l2_ext_controls ctrls;
2298c2ecf20Sopenharmony_ci	int req_fd;
2308c2ecf20Sopenharmony_ci	...
2318c2ecf20Sopenharmony_ci	if (ioctl(media_fd, MEDIA_IOC_REQUEST_ALLOC, &req_fd))
2328c2ecf20Sopenharmony_ci		return errno;
2338c2ecf20Sopenharmony_ci	...
2348c2ecf20Sopenharmony_ci	ctrls.which = V4L2_CTRL_WHICH_REQUEST_VAL;
2358c2ecf20Sopenharmony_ci	ctrls.request_fd = req_fd;
2368c2ecf20Sopenharmony_ci	if (ioctl(camera_fd, VIDIOC_S_EXT_CTRLS, &ctrls))
2378c2ecf20Sopenharmony_ci		return errno;
2388c2ecf20Sopenharmony_ci	...
2398c2ecf20Sopenharmony_ci	buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
2408c2ecf20Sopenharmony_ci	buf.flags |= V4L2_BUF_FLAG_REQUEST_FD;
2418c2ecf20Sopenharmony_ci	buf.request_fd = req_fd;
2428c2ecf20Sopenharmony_ci	if (ioctl(camera_fd, VIDIOC_QBUF, &buf))
2438c2ecf20Sopenharmony_ci		return errno;
2448c2ecf20Sopenharmony_ci
2458c2ecf20Sopenharmony_ciOnce the request is fully prepared, it can be queued to the driver:
2468c2ecf20Sopenharmony_ci
2478c2ecf20Sopenharmony_ci.. code-block:: c
2488c2ecf20Sopenharmony_ci
2498c2ecf20Sopenharmony_ci	if (ioctl(req_fd, MEDIA_REQUEST_IOC_QUEUE))
2508c2ecf20Sopenharmony_ci		return errno;
2518c2ecf20Sopenharmony_ci
2528c2ecf20Sopenharmony_ciUser-space can then dequeue buffers, wait for the request completion, query
2538c2ecf20Sopenharmony_cicontrols and recycle the request as in the M2M example above.
254