mirror of https://github.com/Qortal/Brooklyn
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
424 lines
17 KiB
424 lines
17 KiB
.. SPDX-License-Identifier: GPL-2.0 |
|
|
|
.. _stateless_decoder: |
|
|
|
************************************************** |
|
Memory-to-memory Stateless Video Decoder Interface |
|
************************************************** |
|
|
|
A stateless decoder is a decoder that works without retaining any kind of state |
|
between processed frames. This means that each frame is decoded independently |
|
of any previous and future frames, and that the client is responsible for |
|
maintaining the decoding state and providing it to the decoder with each |
|
decoding request. This is in contrast to the stateful video decoder interface, |
|
where the hardware and driver maintain the decoding state and all the client |
|
has to do is to provide the raw encoded stream and dequeue decoded frames in |
|
display order. |
|
|
|
This section describes how user-space ("the client") is expected to communicate |
|
with stateless decoders in order to successfully decode an encoded stream. |
|
Compared to stateful codecs, the decoder/client sequence is simpler, but the |
|
cost of this simplicity is extra complexity in the client which is responsible |
|
for maintaining a consistent decoding state. |
|
|
|
Stateless decoders make use of the :ref:`media-request-api`. A stateless |
|
decoder must expose the ``V4L2_BUF_CAP_SUPPORTS_REQUESTS`` capability on its |
|
``OUTPUT`` queue when :c:func:`VIDIOC_REQBUFS` or :c:func:`VIDIOC_CREATE_BUFS` |
|
are invoked. |
|
|
|
Depending on the encoded formats supported by the decoder, a single decoded |
|
frame may be the result of several decode requests (for instance, H.264 streams |
|
with multiple slices per frame). Decoders that support such formats must also |
|
expose the ``V4L2_BUF_CAP_SUPPORTS_M2M_HOLD_CAPTURE_BUF`` capability on their |
|
``OUTPUT`` queue. |
|
|
|
Querying capabilities |
|
===================== |
|
|
|
1. To enumerate the set of coded formats supported by the decoder, the client |
|
calls :c:func:`VIDIOC_ENUM_FMT` on the ``OUTPUT`` queue. |
|
|
|
* The driver must always return the full set of supported ``OUTPUT`` formats, |
|
irrespective of the format currently set on the ``CAPTURE`` queue. |
|
|
|
* Simultaneously, the driver must restrain the set of values returned by |
|
codec-specific capability controls (such as H.264 profiles) to the set |
|
actually supported by the hardware. |
|
|
|
2. To enumerate the set of supported raw formats, the client calls |
|
:c:func:`VIDIOC_ENUM_FMT` on the ``CAPTURE`` queue. |
|
|
|
* The driver must return only the formats supported for the format currently |
|
active on the ``OUTPUT`` queue. |
|
|
|
* Depending on the currently set ``OUTPUT`` format, the set of supported raw |
|
formats may depend on the value of some codec-dependent controls. |
|
The client is responsible for making sure that these controls are set |
|
before querying the ``CAPTURE`` queue. Failure to do so will result in the |
|
default values for these controls being used, and a returned set of formats |
|
that may not be usable for the media the client is trying to decode. |
|
|
|
3. The client may use :c:func:`VIDIOC_ENUM_FRAMESIZES` to detect supported |
|
resolutions for a given format, passing desired pixel format in |
|
:c:type:`v4l2_frmsizeenum`'s ``pixel_format``. |
|
|
|
4. Supported profiles and levels for the current ``OUTPUT`` format, if |
|
applicable, may be queried using their respective controls via |
|
:c:func:`VIDIOC_QUERYCTRL`. |
|
|
|
Initialization |
|
============== |
|
|
|
1. Set the coded format on the ``OUTPUT`` queue via :c:func:`VIDIOC_S_FMT`. |
|
|
|
* **Required fields:** |
|
|
|
``type`` |
|
a ``V4L2_BUF_TYPE_*`` enum appropriate for ``OUTPUT``. |
|
|
|
``pixelformat`` |
|
a coded pixel format. |
|
|
|
``width``, ``height`` |
|
coded width and height parsed from the stream. |
|
|
|
other fields |
|
follow standard semantics. |
|
|
|
.. note:: |
|
|
|
Changing the ``OUTPUT`` format may change the currently set ``CAPTURE`` |
|
format. The driver will derive a new ``CAPTURE`` format from the |
|
``OUTPUT`` format being set, including resolution, colorimetry |
|
parameters, etc. If the client needs a specific ``CAPTURE`` format, |
|
it must adjust it afterwards. |
|
|
|
2. Call :c:func:`VIDIOC_S_EXT_CTRLS` to set all the controls (parsed headers, |
|
etc.) required by the ``OUTPUT`` format to enumerate the ``CAPTURE`` formats. |
|
|
|
3. Call :c:func:`VIDIOC_G_FMT` for ``CAPTURE`` queue to get the format for the |
|
destination buffers parsed/decoded from the bytestream. |
|
|
|
* **Required fields:** |
|
|
|
``type`` |
|
a ``V4L2_BUF_TYPE_*`` enum appropriate for ``CAPTURE``. |
|
|
|
* **Returned fields:** |
|
|
|
``width``, ``height`` |
|
frame buffer resolution for the decoded frames. |
|
|
|
``pixelformat`` |
|
pixel format for decoded frames. |
|
|
|
``num_planes`` (for _MPLANE ``type`` only) |
|
number of planes for pixelformat. |
|
|
|
``sizeimage``, ``bytesperline`` |
|
as per standard semantics; matching frame buffer format. |
|
|
|
.. note:: |
|
|
|
The value of ``pixelformat`` may be any pixel format supported for the |
|
``OUTPUT`` format, based on the hardware capabilities. It is suggested |
|
that the driver chooses the preferred/optimal format for the current |
|
configuration. For example, a YUV format may be preferred over an RGB |
|
format, if an additional conversion step would be required for RGB. |
|
|
|
4. *[optional]* Enumerate ``CAPTURE`` formats via :c:func:`VIDIOC_ENUM_FMT` on |
|
the ``CAPTURE`` queue. The client may use this ioctl to discover which |
|
alternative raw formats are supported for the current ``OUTPUT`` format and |
|
select one of them via :c:func:`VIDIOC_S_FMT`. |
|
|
|
.. note:: |
|
|
|
The driver will return only formats supported for the currently selected |
|
``OUTPUT`` format and currently set controls, even if more formats may be |
|
supported by the decoder in general. |
|
|
|
For example, a decoder may support YUV and RGB formats for |
|
resolutions 1920x1088 and lower, but only YUV for higher resolutions (due |
|
to hardware limitations). After setting a resolution of 1920x1088 or lower |
|
as the ``OUTPUT`` format, :c:func:`VIDIOC_ENUM_FMT` may return a set of |
|
YUV and RGB pixel formats, but after setting a resolution higher than |
|
1920x1088, the driver will not return RGB pixel formats, since they are |
|
unsupported for this resolution. |
|
|
|
5. *[optional]* Choose a different ``CAPTURE`` format than suggested via |
|
:c:func:`VIDIOC_S_FMT` on ``CAPTURE`` queue. It is possible for the client to |
|
choose a different format than selected/suggested by the driver in |
|
:c:func:`VIDIOC_G_FMT`. |
|
|
|
* **Required fields:** |
|
|
|
``type`` |
|
a ``V4L2_BUF_TYPE_*`` enum appropriate for ``CAPTURE``. |
|
|
|
``pixelformat`` |
|
a raw pixel format. |
|
|
|
``width``, ``height`` |
|
frame buffer resolution of the decoded stream; typically unchanged from |
|
what was returned with :c:func:`VIDIOC_G_FMT`, but it may be different |
|
if the hardware supports composition and/or scaling. |
|
|
|
After performing this step, the client must perform step 3 again in order |
|
to obtain up-to-date information about the buffers size and layout. |
|
|
|
6. Allocate source (bytestream) buffers via :c:func:`VIDIOC_REQBUFS` on |
|
``OUTPUT`` queue. |
|
|
|
* **Required fields:** |
|
|
|
``count`` |
|
requested number of buffers to allocate; greater than zero. |
|
|
|
``type`` |
|
a ``V4L2_BUF_TYPE_*`` enum appropriate for ``OUTPUT``. |
|
|
|
``memory`` |
|
follows standard semantics. |
|
|
|
* **Return fields:** |
|
|
|
``count`` |
|
actual number of buffers allocated. |
|
|
|
* If required, the driver will adjust ``count`` to be equal or bigger to the |
|
minimum of required number of ``OUTPUT`` buffers for the given format and |
|
requested count. The client must check this value after the ioctl returns |
|
to get the actual number of buffers allocated. |
|
|
|
7. Allocate destination (raw format) buffers via :c:func:`VIDIOC_REQBUFS` on the |
|
``CAPTURE`` queue. |
|
|
|
* **Required fields:** |
|
|
|
``count`` |
|
requested number of buffers to allocate; greater than zero. The client |
|
is responsible for deducing the minimum number of buffers required |
|
for the stream to be properly decoded (taking e.g. reference frames |
|
into account) and pass an equal or bigger number. |
|
|
|
``type`` |
|
a ``V4L2_BUF_TYPE_*`` enum appropriate for ``CAPTURE``. |
|
|
|
``memory`` |
|
follows standard semantics. ``V4L2_MEMORY_USERPTR`` is not supported |
|
for ``CAPTURE`` buffers. |
|
|
|
* **Return fields:** |
|
|
|
``count`` |
|
adjusted to allocated number of buffers, in case the codec requires |
|
more buffers than requested. |
|
|
|
* The driver must adjust count to the minimum of required number of |
|
``CAPTURE`` buffers for the current format, stream configuration and |
|
requested count. The client must check this value after the ioctl |
|
returns to get the number of buffers allocated. |
|
|
|
8. Allocate requests (likely one per ``OUTPUT`` buffer) via |
|
:c:func:`MEDIA_IOC_REQUEST_ALLOC` on the media device. |
|
|
|
9. Start streaming on both ``OUTPUT`` and ``CAPTURE`` queues via |
|
:c:func:`VIDIOC_STREAMON`. |
|
|
|
Decoding |
|
======== |
|
|
|
For each frame, the client is responsible for submitting at least one request to |
|
which the following is attached: |
|
|
|
* The amount of encoded data expected by the codec for its current |
|
configuration, as a buffer submitted to the ``OUTPUT`` queue. Typically, this |
|
corresponds to one frame worth of encoded data, but some formats may allow (or |
|
require) different amounts per unit. |
|
* All the metadata needed to decode the submitted encoded data, in the form of |
|
controls relevant to the format being decoded. |
|
|
|
The amount of data and contents of the source ``OUTPUT`` buffer, as well as the |
|
controls that must be set on the request, depend on the active coded pixel |
|
format and might be affected by codec-specific extended controls, as stated in |
|
documentation of each format. |
|
|
|
If there is a possibility that the decoded frame will require one or more |
|
decode requests after the current one in order to be produced, then the client |
|
must set the ``V4L2_BUF_FLAG_M2M_HOLD_CAPTURE_BUF`` flag on the ``OUTPUT`` |
|
buffer. This will result in the (potentially partially) decoded ``CAPTURE`` |
|
buffer not being made available for dequeueing, and reused for the next decode |
|
request if the timestamp of the next ``OUTPUT`` buffer has not changed. |
|
|
|
A typical frame would thus be decoded using the following sequence: |
|
|
|
1. Queue an ``OUTPUT`` buffer containing one unit of encoded bytestream data for |
|
the decoding request, using :c:func:`VIDIOC_QBUF`. |
|
|
|
* **Required fields:** |
|
|
|
``index`` |
|
index of the buffer being queued. |
|
|
|
``type`` |
|
type of the buffer. |
|
|
|
``bytesused`` |
|
number of bytes taken by the encoded data frame in the buffer. |
|
|
|
``flags`` |
|
the ``V4L2_BUF_FLAG_REQUEST_FD`` flag must be set. Additionally, if |
|
we are not sure that the current decode request is the last one needed |
|
to produce a fully decoded frame, then |
|
``V4L2_BUF_FLAG_M2M_HOLD_CAPTURE_BUF`` must also be set. |
|
|
|
``request_fd`` |
|
must be set to the file descriptor of the decoding request. |
|
|
|
``timestamp`` |
|
must be set to a unique value per frame. This value will be propagated |
|
into the decoded frame's buffer and can also be used to use this frame |
|
as the reference of another. If using multiple decode requests per |
|
frame, then the timestamps of all the ``OUTPUT`` buffers for a given |
|
frame must be identical. If the timestamp changes, then the currently |
|
held ``CAPTURE`` buffer will be made available for dequeuing and the |
|
current request will work on a new ``CAPTURE`` buffer. |
|
|
|
2. Set the codec-specific controls for the decoding request, using |
|
:c:func:`VIDIOC_S_EXT_CTRLS`. |
|
|
|
* **Required fields:** |
|
|
|
``which`` |
|
must be ``V4L2_CTRL_WHICH_REQUEST_VAL``. |
|
|
|
``request_fd`` |
|
must be set to the file descriptor of the decoding request. |
|
|
|
other fields |
|
other fields are set as usual when setting controls. The ``controls`` |
|
array must contain all the codec-specific controls required to decode |
|
a frame. |
|
|
|
.. note:: |
|
|
|
It is possible to specify the controls in different invocations of |
|
:c:func:`VIDIOC_S_EXT_CTRLS`, or to overwrite a previously set control, as |
|
long as ``request_fd`` and ``which`` are properly set. The controls state |
|
at the moment of request submission is the one that will be considered. |
|
|
|
.. note:: |
|
|
|
The order in which steps 1 and 2 take place is interchangeable. |
|
|
|
3. Submit the request by invoking :c:func:`MEDIA_REQUEST_IOC_QUEUE` on the |
|
request FD. |
|
|
|
If the request is submitted without an ``OUTPUT`` buffer, or if some of the |
|
required controls are missing from the request, then |
|
:c:func:`MEDIA_REQUEST_IOC_QUEUE` will return ``-ENOENT``. If more than one |
|
``OUTPUT`` buffer is queued, then it will return ``-EINVAL``. |
|
:c:func:`MEDIA_REQUEST_IOC_QUEUE` returning non-zero means that no |
|
``CAPTURE`` buffer will be produced for this request. |
|
|
|
``CAPTURE`` buffers must not be part of the request, and are queued |
|
independently. They are returned in decode order (i.e. the same order as coded |
|
frames were submitted to the ``OUTPUT`` queue). |
|
|
|
Runtime decoding errors are signaled by the dequeued ``CAPTURE`` buffers |
|
carrying the ``V4L2_BUF_FLAG_ERROR`` flag. If a decoded reference frame has an |
|
error, then all following decoded frames that refer to it also have the |
|
``V4L2_BUF_FLAG_ERROR`` flag set, although the decoder will still try to |
|
produce (likely corrupted) frames. |
|
|
|
Buffer management while decoding |
|
================================ |
|
Contrary to stateful decoders, a stateless decoder does not perform any kind of |
|
buffer management: it only guarantees that dequeued ``CAPTURE`` buffers can be |
|
used by the client for as long as they are not queued again. "Used" here |
|
encompasses using the buffer for compositing or display. |
|
|
|
A dequeued capture buffer can also be used as the reference frame of another |
|
buffer. |
|
|
|
A frame is specified as reference by converting its timestamp into nanoseconds, |
|
and storing it into the relevant member of a codec-dependent control structure. |
|
The :c:func:`v4l2_timeval_to_ns` function must be used to perform that |
|
conversion. The timestamp of a frame can be used to reference it as soon as all |
|
its units of encoded data are successfully submitted to the ``OUTPUT`` queue. |
|
|
|
A decoded buffer containing a reference frame must not be reused as a decoding |
|
target until all the frames referencing it have been decoded. The safest way to |
|
achieve this is to refrain from queueing a reference buffer until all the |
|
decoded frames referencing it have been dequeued. However, if the driver can |
|
guarantee that buffers queued to the ``CAPTURE`` queue are processed in queued |
|
order, then user-space can take advantage of this guarantee and queue a |
|
reference buffer when the following conditions are met: |
|
|
|
1. All the requests for frames affected by the reference frame have been |
|
queued, and |
|
|
|
2. A sufficient number of ``CAPTURE`` buffers to cover all the decoded |
|
referencing frames have been queued. |
|
|
|
When queuing a decoding request, the driver will increase the reference count of |
|
all the resources associated with reference frames. This means that the client |
|
can e.g. close the DMABUF file descriptors of reference frame buffers if it |
|
won't need them afterwards. |
|
|
|
Seeking |
|
======= |
|
In order to seek, the client just needs to submit requests using input buffers |
|
corresponding to the new stream position. It must however be aware that |
|
resolution may have changed and follow the dynamic resolution change sequence in |
|
that case. Also depending on the codec used, picture parameters (e.g. SPS/PPS |
|
for H.264) may have changed and the client is responsible for making sure that a |
|
valid state is sent to the decoder. |
|
|
|
The client is then free to ignore any returned ``CAPTURE`` buffer that comes |
|
from the pre-seek position. |
|
|
|
Pausing |
|
======= |
|
|
|
In order to pause, the client can just cease queuing buffers onto the ``OUTPUT`` |
|
queue. Without source bytestream data, there is no data to process and the codec |
|
will remain idle. |
|
|
|
Dynamic resolution change |
|
========================= |
|
|
|
If the client detects a resolution change in the stream, it will need to perform |
|
the initialization sequence again with the new resolution: |
|
|
|
1. If the last submitted request resulted in a ``CAPTURE`` buffer being |
|
held by the use of the ``V4L2_BUF_FLAG_M2M_HOLD_CAPTURE_BUF`` flag, then the |
|
last frame is not available on the ``CAPTURE`` queue. In this case, a |
|
``V4L2_DEC_CMD_FLUSH`` command shall be sent. This will make the driver |
|
dequeue the held ``CAPTURE`` buffer. |
|
|
|
2. Wait until all submitted requests have completed and dequeue the |
|
corresponding output buffers. |
|
|
|
3. Call :c:func:`VIDIOC_STREAMOFF` on both the ``OUTPUT`` and ``CAPTURE`` |
|
queues. |
|
|
|
4. Free all ``CAPTURE`` buffers by calling :c:func:`VIDIOC_REQBUFS` on the |
|
``CAPTURE`` queue with a buffer count of zero. |
|
|
|
5. Perform the initialization sequence again (minus the allocation of |
|
``OUTPUT`` buffers), with the new resolution set on the ``OUTPUT`` queue. |
|
Note that due to resolution constraints, a different format may need to be |
|
picked on the ``CAPTURE`` queue. |
|
|
|
Drain |
|
===== |
|
|
|
If the last submitted request resulted in a ``CAPTURE`` buffer being |
|
held by the use of the ``V4L2_BUF_FLAG_M2M_HOLD_CAPTURE_BUF`` flag, then the |
|
last frame is not available on the ``CAPTURE`` queue. In this case, a |
|
``V4L2_DEC_CMD_FLUSH`` command shall be sent. This will make the driver |
|
dequeue the held ``CAPTURE`` buffer. |
|
|
|
After that, in order to drain the stream on a stateless decoder, the client |
|
just needs to wait until all the submitted requests are completed.
|
|
|