Back to home page

OSCL-LXR

 
 

    


0001 .. SPDX-License-Identifier: GPL-2.0 OR GFDL-1.1-no-invariants-or-later
0002 .. c:namespace:: MC
0003 
0004 .. _media-request-api:
0005 
0006 Request API
0007 ===========
0008 
0009 The Request API has been designed to allow V4L2 to deal with requirements of
0010 modern devices (stateless codecs, complex camera pipelines, ...) and APIs
0011 (Android Codec v2). One such requirement is the ability for devices belonging to
0012 the same pipeline to reconfigure and collaborate closely on a per-frame basis.
0013 Another is support of stateless codecs, which require controls to be applied
0014 to specific frames (aka 'per-frame controls') in order to be used efficiently.
0015 
0016 While the initial use-case was V4L2, it can be extended to other subsystems
0017 as well, as long as they use the media controller.
0018 
0019 Supporting these features without the Request API is not always possible and if
0020 it is, it is terribly inefficient: user-space would have to flush all activity
0021 on the media pipeline, reconfigure it for the next frame, queue the buffers to
0022 be processed with that configuration, and wait until they are all available for
0023 dequeuing before considering the next frame. This defeats the purpose of having
0024 buffer queues since in practice only one buffer would be queued at a time.
0025 
0026 The Request API allows a specific configuration of the pipeline (media
0027 controller topology + configuration for each media entity) to be associated with
0028 specific buffers. This allows user-space to schedule several tasks ("requests")
0029 with different configurations in advance, knowing that the configuration will be
0030 applied when needed to get the expected result. Configuration values at the time
0031 of request completion are also available for reading.
0032 
0033 General Usage
0034 -------------
0035 
0036 The Request API extends the Media Controller API and cooperates with
0037 subsystem-specific APIs to support request usage. At the Media Controller
0038 level, requests are allocated from the supporting Media Controller device
0039 node. Their life cycle is then managed through the request file descriptors in
0040 an opaque way. Configuration data, buffer handles and processing results
0041 stored in requests are accessed through subsystem-specific APIs extended for
0042 request support, such as V4L2 APIs that take an explicit ``request_fd``
0043 parameter.
0044 
0045 Request Allocation
0046 ------------------
0047 
0048 User-space allocates requests using :ref:`MEDIA_IOC_REQUEST_ALLOC`
0049 for the media device node. This returns a file descriptor representing the
0050 request. Typically, several such requests will be allocated.
0051 
0052 Request Preparation
0053 -------------------
0054 
0055 Standard V4L2 ioctls can then receive a request file descriptor to express the
0056 fact that the ioctl is part of said request, and is not to be applied
0057 immediately. See :ref:`MEDIA_IOC_REQUEST_ALLOC` for a list of ioctls that
0058 support this. Configurations set with a ``request_fd`` parameter are stored
0059 instead of being immediately applied, and buffers queued to a request do not
0060 enter the regular buffer queue until the request itself is queued.
0061 
0062 Request Submission
0063 ------------------
0064 
0065 Once the configuration and buffers of the request are specified, it can be
0066 queued by calling :ref:`MEDIA_REQUEST_IOC_QUEUE` on the request file descriptor.
0067 A request must contain at least one buffer, otherwise ``ENOENT`` is returned.
0068 A queued request cannot be modified anymore.
0069 
0070 .. caution::
0071    For :ref:`memory-to-memory devices <mem2mem>` you can use requests only for
0072    output buffers, not for capture buffers. Attempting to add a capture buffer
0073    to a request will result in an ``EBADR`` error.
0074 
0075 If the request contains configurations for multiple entities, individual drivers
0076 may synchronize so the requested pipeline's topology is applied before the
0077 buffers are processed. Media controller drivers do a best effort implementation
0078 since perfect atomicity may not be possible due to hardware limitations.
0079 
0080 .. caution::
0081 
0082    It is not allowed to mix queuing requests with directly queuing buffers:
0083    whichever method is used first locks this in place until
0084    :ref:`VIDIOC_STREAMOFF <VIDIOC_STREAMON>` is called or the device is
0085    :ref:`closed <func-close>`. Attempts to directly queue a buffer when earlier
0086    a buffer was queued via a request or vice versa will result in an ``EBUSY``
0087    error.
0088 
0089 Controls can still be set without a request and are applied immediately,
0090 regardless of whether a request is in use or not.
0091 
0092 .. caution::
0093 
0094    Setting the same control through a request and also directly can lead to
0095    undefined behavior!
0096 
0097 User-space can :c:func:`poll()` a request file descriptor in
0098 order to wait until the request completes. A request is considered complete
0099 once all its associated buffers are available for dequeuing and all the
0100 associated controls have been updated with the values at the time of completion.
0101 Note that user-space does not need to wait for the request to complete to
0102 dequeue its buffers: buffers that are available halfway through a request can
0103 be dequeued independently of the request's state.
0104 
0105 A completed request contains the state of the device after the request was
0106 executed. User-space can query that state by calling
0107 :ref:`ioctl VIDIOC_G_EXT_CTRLS <VIDIOC_G_EXT_CTRLS>` with the request file
0108 descriptor. Calling :ref:`ioctl VIDIOC_G_EXT_CTRLS <VIDIOC_G_EXT_CTRLS>` for a
0109 request that has been queued but not yet completed will return ``EBUSY``
0110 since the control values might be changed at any time by the driver while the
0111 request is in flight.
0112 
0113 .. _media-request-life-time:
0114 
0115 Recycling and Destruction
0116 -------------------------
0117 
0118 Finally, a completed request can either be discarded or be reused. Calling
0119 :c:func:`close()` on a request file descriptor will make
0120 that file descriptor unusable and the request will be freed once it is no
0121 longer in use by the kernel. That is, if the request is queued and then the
0122 file descriptor is closed, then it won't be freed until the driver completed
0123 the request.
0124 
0125 The :ref:`MEDIA_REQUEST_IOC_REINIT` will clear a request's state and make it
0126 available again. No state is retained by this operation: the request is as
0127 if it had just been allocated.
0128 
0129 Example for a Codec Device
0130 --------------------------
0131 
0132 For use-cases such as :ref:`codecs <mem2mem>`, the request API can be used
0133 to associate specific controls to
0134 be applied by the driver for the OUTPUT buffer, allowing user-space
0135 to queue many such buffers in advance. It can also take advantage of requests'
0136 ability to capture the state of controls when the request completes to read back
0137 information that may be subject to change.
0138 
0139 Put into code, after obtaining a request, user-space can assign controls and one
0140 OUTPUT buffer to it:
0141 
0142 .. code-block:: c
0143 
0144         struct v4l2_buffer buf;
0145         struct v4l2_ext_controls ctrls;
0146         int req_fd;
0147         ...
0148         if (ioctl(media_fd, MEDIA_IOC_REQUEST_ALLOC, &req_fd))
0149                 return errno;
0150         ...
0151         ctrls.which = V4L2_CTRL_WHICH_REQUEST_VAL;
0152         ctrls.request_fd = req_fd;
0153         if (ioctl(codec_fd, VIDIOC_S_EXT_CTRLS, &ctrls))
0154                 return errno;
0155         ...
0156         buf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
0157         buf.flags |= V4L2_BUF_FLAG_REQUEST_FD;
0158         buf.request_fd = req_fd;
0159         if (ioctl(codec_fd, VIDIOC_QBUF, &buf))
0160                 return errno;
0161 
0162 Note that it is not allowed to use the Request API for CAPTURE buffers
0163 since there are no per-frame settings to report there.
0164 
0165 Once the request is fully prepared, it can be queued to the driver:
0166 
0167 .. code-block:: c
0168 
0169         if (ioctl(req_fd, MEDIA_REQUEST_IOC_QUEUE))
0170                 return errno;
0171 
0172 User-space can then either wait for the request to complete by calling poll() on
0173 its file descriptor, or start dequeuing CAPTURE buffers. Most likely, it will
0174 want to get CAPTURE buffers as soon as possible and this can be done using a
0175 regular :ref:`VIDIOC_DQBUF <VIDIOC_QBUF>`:
0176 
0177 .. code-block:: c
0178 
0179         struct v4l2_buffer buf;
0180 
0181         memset(&buf, 0, sizeof(buf));
0182         buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
0183         if (ioctl(codec_fd, VIDIOC_DQBUF, &buf))
0184                 return errno;
0185 
0186 Note that this example assumes for simplicity that for every OUTPUT buffer
0187 there will be one CAPTURE buffer, but this does not have to be the case.
0188 
0189 We can then, after ensuring that the request is completed via polling the
0190 request file descriptor, query control values at the time of its completion via
0191 a call to :ref:`VIDIOC_G_EXT_CTRLS <VIDIOC_G_EXT_CTRLS>`.
0192 This is particularly useful for volatile controls for which we want to
0193 query values as soon as the capture buffer is produced.
0194 
0195 .. code-block:: c
0196 
0197         struct pollfd pfd = { .events = POLLPRI, .fd = req_fd };
0198         poll(&pfd, 1, -1);
0199         ...
0200         ctrls.which = V4L2_CTRL_WHICH_REQUEST_VAL;
0201         ctrls.request_fd = req_fd;
0202         if (ioctl(codec_fd, VIDIOC_G_EXT_CTRLS, &ctrls))
0203                 return errno;
0204 
0205 Once we don't need the request anymore, we can either recycle it for reuse with
0206 :ref:`MEDIA_REQUEST_IOC_REINIT`...
0207 
0208 .. code-block:: c
0209 
0210         if (ioctl(req_fd, MEDIA_REQUEST_IOC_REINIT))
0211                 return errno;
0212 
0213 ... or close its file descriptor to completely dispose of it.
0214 
0215 .. code-block:: c
0216 
0217         close(req_fd);
0218 
0219 Example for a Simple Capture Device
0220 -----------------------------------
0221 
0222 With a simple capture device, requests can be used to specify controls to apply
0223 for a given CAPTURE buffer.
0224 
0225 .. code-block:: c
0226 
0227         struct v4l2_buffer buf;
0228         struct v4l2_ext_controls ctrls;
0229         int req_fd;
0230         ...
0231         if (ioctl(media_fd, MEDIA_IOC_REQUEST_ALLOC, &req_fd))
0232                 return errno;
0233         ...
0234         ctrls.which = V4L2_CTRL_WHICH_REQUEST_VAL;
0235         ctrls.request_fd = req_fd;
0236         if (ioctl(camera_fd, VIDIOC_S_EXT_CTRLS, &ctrls))
0237                 return errno;
0238         ...
0239         buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
0240         buf.flags |= V4L2_BUF_FLAG_REQUEST_FD;
0241         buf.request_fd = req_fd;
0242         if (ioctl(camera_fd, VIDIOC_QBUF, &buf))
0243                 return errno;
0244 
0245 Once the request is fully prepared, it can be queued to the driver:
0246 
0247 .. code-block:: c
0248 
0249         if (ioctl(req_fd, MEDIA_REQUEST_IOC_QUEUE))
0250                 return errno;
0251 
0252 User-space can then dequeue buffers, wait for the request completion, query
0253 controls and recycle the request as in the M2M example above.