context: pre-STREAMON device controls and minimum OUTPUT pool

Two related fixes that surfaced during the first hantro-vpu (RK3568)
smoke test of the multiplanar build:

1. **OUTPUT queue must be non-empty at STREAMON.** Hantro's
   vb2_start_streaming rejects an empty queue with EINVAL. Some
   VA-API callers (notably ffmpeg's vaapi-copy path) call
   vaCreateContext with num_render_targets=0 and allocate render
   targets lazily. The OUTPUT (bitstream-input) pool must NOT be
   sized off surfaces_count alone — it is a request-time resource,
   not per-surface. Quick fix: floor the pool to 4 buffers when
   the caller passes 0. (A proper decoupling of OUTPUT pool from
   surface lifecycle is documented in upstreamable_design.md.)

2. **Device-wide stateless H.264 controls before STREAMON.** The
   V4L2 stateless framework requires V4L2_CID_STATELESS_H264_
   DECODE_MODE and START_CODE be set on the device fd
   (request_fd=-1) before stream start. Per-request controls
   (SPS/PPS/SLICE_PARAMS/etc.) attached to a request_fd come
   later via h264_set_controls(). hantro-vpu accepts only
   DECODE_MODE_FRAME_BASED; START_CODE_ANNEX_B matches what the
   existing slice-assembly path emits.

   This is set unconditionally for now (errors silently ignored)
   to keep cedrus and other backends compatible — they may
   default to SLICE_BASED and not expose DECODE_MODE at all.
   Probe-then-set via VIDIOC_QUERYCTRL is the upstream-correct
   approach (see upstreamable_design.md §3).

After this patch, vainfo still enumerates as before, but the first
mpv vaapi-copy attempt advances past STREAMON and into actual
decode submission.

Signed-off-by: Markus Fritsche <fritsche.markus@gmail.com>
This commit is contained in:
2026-05-01 12:00:00 +00:00
parent 10114f6781
commit 50e0c2b996
+37 -1
View File
@@ -64,6 +64,7 @@ VAStatus RequestCreateContext(VADriverContextP context, VAConfigID config_id,
VAContextID id;
VAStatus status;
unsigned int output_type, capture_type;
unsigned int output_buffers_count;
unsigned int index_base;
unsigned int index;
unsigned int i;
@@ -90,8 +91,16 @@ VAStatus RequestCreateContext(VADriverContextP context, VAConfigID config_id,
}
memset(&context_object->dpb, 0, sizeof(context_object->dpb));
/*
* The OUTPUT (bitstream-input) queue must be non-empty before
* VIDIOC_STREAMON or hantro-class drivers reject with EINVAL.
* VA-API callers (e.g. ffmpeg's vaapi-copy path) may invoke
* vaCreateContext with num_render_targets=0; allocate a small
* minimum pool independent of the caller's surface count.
*/
output_buffers_count = surfaces_count > 0 ? surfaces_count : 4;
rc = v4l2_create_buffers(driver_data->video_fd, output_type,
surfaces_count, &index_base);
output_buffers_count, &index_base);
if (rc < 0) {
status = VA_STATUS_ERROR_ALLOCATION_FAILED;
goto error;
@@ -138,6 +147,33 @@ VAStatus RequestCreateContext(VADriverContextP context, VAConfigID config_id,
surface_object->source_size = length;
}
/*
* Stateless H.264 device-wide controls. The kernel V4L2 stateless
* framework requires DECODE_MODE and START_CODE be set on the
* device fd (request_fd=-1) before VIDIOC_STREAMON; per-request
* controls (SPS/PPS/etc.) attached to a request_fd come later.
*
* hantro-vpu (RK3568) accepts only DECODE_MODE_FRAME_BASED.
* START_CODE_ANNEX_B preserves leading 0x00000001 in the slice
* payload that h264.c assembles. Errors here are not fatal: not
* every backing driver supports both controls (e.g. cedrus may
* default to SLICE_BASED without exposing DECODE_MODE).
*/
{
struct v4l2_ext_control dev_ctrls[2] = {
{
.id = V4L2_CID_STATELESS_H264_DECODE_MODE,
.value = V4L2_STATELESS_H264_DECODE_MODE_FRAME_BASED,
},
{
.id = V4L2_CID_STATELESS_H264_START_CODE,
.value = V4L2_STATELESS_H264_START_CODE_ANNEX_B,
},
};
(void)v4l2_set_controls(driver_data->video_fd, -1,
dev_ctrls, 2);
}
rc = v4l2_set_stream(driver_data->video_fd, output_type, true);
if (rc < 0) {
status = VA_STATUS_ERROR_OPERATION_FAILED;