From 50e0c2b996eef909b666b4019fd91ae07434a73e Mon Sep 17 00:00:00 2001 From: Markus Fritsche Date: Fri, 1 May 2026 12:00:00 +0000 Subject: [PATCH] context: pre-STREAMON device controls and minimum OUTPUT pool MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 --- src/context.c | 38 +++++++++++++++++++++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-) diff --git a/src/context.c b/src/context.c index d07cea6..9ca78fd 100644 --- a/src/context.c +++ b/src/context.c @@ -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;