From 78a9978b02cfd2c04907d32022c0a250b5489e3d Mon Sep 17 00:00:00 2001 From: claude-noether Date: Sun, 17 May 2026 09:55:39 +0200 Subject: [PATCH] ampere-av1 Phase 2 step 4: AV1 dispatch scaffolding compiles and wires MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit surface.h: av1 substruct (picture + tile_group_entries[AV1_MAX_TILES=128] + num_tile_group_entries counter) picture.c: dispatch VAPictureParameterBufferAV1 + VASliceParameterBufferAV1 into surface->params.av1.*; call av1_set_controls in EndPicture path av1.h: minimal interface (av1_set_controls signature) av1.c: stub set_controls returning -1 with diagnostic; _Static_assert on v4l2_ctrl_av1_tile_group_entry size = 16 (Janet hygiene) meson.build: av1.c + av1.h in source list Verified on ampere with /tmp/test_av1.ivf via LIBVA_DRIVER_NAME=v4l2_request: v4l2-request: ampere-av1: vpu981 AV1 decoder at /dev/video4 + /dev/media3 v4l2-request: ampere-av1: av1_set_controls stub — Phase 2.1 will implement ... [av1] Failed to end picture decode issue: 1 (operation failed). [av1] HW accel end frame fail. [dec:av1] Error submitting packet to decoder: Input/output error Clean graceful failure — vpu981 probe works, dispatch reaches av1.c, stub returns ERROR, ffmpeg falls back to SW. No crash, no IOMMU fault, no kernel taint. Next: Phase 2.1 implementation of fill_sequence + fill_frame + fill_film_grain + fill_tile_group_entries (~700 LoC mirror of Kwiboo v4l2_request_av1.c, applying F1/F2/F3 implementation-time corrections from Janet review v2). Co-Authored-By: Claude Opus 4.7 --- src/av1.c | 91 +++++++++++++++++++++++++++++++++++++++++++++++++ src/av1.h | 45 ++++++++++++++++++++++++ src/meson.build | 2 ++ src/picture.c | 26 ++++++++++++++ src/surface.h | 13 +++++++ 5 files changed, 177 insertions(+) create mode 100644 src/av1.c create mode 100644 src/av1.h diff --git a/src/av1.c b/src/av1.c new file mode 100644 index 0000000..6d10061 --- /dev/null +++ b/src/av1.c @@ -0,0 +1,91 @@ +/* + * Copyright (C) 2026 claude-noether + * + * ampere-av1-enablement Phase 2: AV1 codec dispatcher for libva-v4l2- + * request-fourier. Translates VAAPI AV1 picture/slice parameter buffers + * into V4L2 stateless AV1 controls (V4L2_CID_STATELESS_AV1_*) for the + * Rockchip vpu981 hardware on RK3588. + * + * Reference implementations (field semantics): + * - Kwiboo/FFmpeg v4l2-request-n8.1:libavcodec/v4l2_request_av1.c + * (636 LoC, reads from FFmpeg's AV1RawSequenceHeader; the v4l2_ctrl + * output is identical to what we need) + * - ~/src/libva-v4l2-request-fourier/src/vp9.c (architectural pattern: + * set_controls / multi-control batch / request_fd dispatch) + * + * V4L2 controls (4 per frame, batched in one VIDIOC_S_EXT_CTRLS): + * 1. V4L2_CID_STATELESS_AV1_SEQUENCE (small, set per stream-ish) + * 2. V4L2_CID_STATELESS_AV1_FRAME (the heavy one — 8 sub-structs) + * 3. V4L2_CID_STATELESS_AV1_TILE_GROUP_ENTRY[] (DYNAMIC_ARRAY) + * 4. V4L2_CID_STATELESS_AV1_FILM_GRAIN (conditional on probe) + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR + * THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include "av1.h" + +#include "context.h" +#include "request.h" +#include "surface.h" +#include "utils.h" +#include "v4l2.h" + +#include +#include + +#include +#include +#include + +/* Sanity asserts to catch kernel uAPI drift. If these fire, the kernel + * headers on the build machine are out of sync with what the running + * driver expects — silent register-misalignment bugs result. */ +_Static_assert(sizeof(struct v4l2_ctrl_av1_tile_group_entry) == 16, + "v4l2_ctrl_av1_tile_group_entry size drift — recheck uAPI"); + +/* + * Phase 2 step 4 — stub set_controls. Compiles and links; returns -1 + * with a clear log message so the test infrastructure sees AV1 dispatch + * fail cleanly (not crash) until Phase 2.1 implements the actual field + * mappings. + * + * The full implementation follows Kwiboo's fill_sequence / fill_frame / + * fill_film_grain functions, mapping VAAPI AV1 picture parameters + * (VADecPictureParameterBufferAV1) to V4L2 control structs. Per Janet + * review v2, three implementation-time risks must be specifically + * handled: + * F1 tile_info.mi_col/row_starts sentinel for multi-tile streams + * F2 superres_denom = AV1_SUPERRES_NUM (8) when use_superres=0 + * F3 loop_restoration_size[] gated on USES_LR flag direction + */ +int av1_set_controls(struct request_data *driver_data, + struct object_context *context, + struct object_surface *surface_object) +{ + (void)driver_data; + (void)context; + (void)surface_object; + + request_log("ampere-av1: av1_set_controls stub — Phase 2.1 will " + "implement fill_sequence/fill_frame/fill_film_grain/" + "fill_tile_group_entries\n"); + return -1; +} diff --git a/src/av1.h b/src/av1.h new file mode 100644 index 0000000..828e047 --- /dev/null +++ b/src/av1.h @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2026 claude-noether + * + * ampere-av1-enablement Phase 2: AV1 codec dispatcher header for libva- + * v4l2-request-fourier. Mirrors vp9.h shape — single set_controls entry + * point that translates surface->params.av1.* VAAPI structures into a + * batch of V4L2_CID_STATELESS_AV1_{SEQUENCE,FRAME,TILE_GROUP_ENTRY, + * FILM_GRAIN} controls + the underlying request_fd / OUTPUT plane setup. + * + * V4L2 target: V4L2_PIX_FMT_AV1_FRAME on the vpu981 hantro instance + * (RK3588's dedicated AV1 decoder). + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR + * THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef _AV1_H_ +#define _AV1_H_ + +#include "context.h" +#include "request.h" +#include "surface.h" + +int av1_set_controls(struct request_data *driver_data, + struct object_context *context, + struct object_surface *surface); + +#endif /* _AV1_H_ */ diff --git a/src/meson.build b/src/meson.build index 98b382d..bb6b72a 100644 --- a/src/meson.build +++ b/src/meson.build @@ -50,6 +50,7 @@ sources = [ 'h265.c', 'vp8.c', 'vp9.c', + 'av1.c', 'codec.c', # Vendored GStreamer 1.28.2 H.265 parser + utilities (LGPL v2.1+, @@ -85,6 +86,7 @@ headers = [ 'h265.h', 'vp8.h', 'vp9.h', + 'av1.h', 'codec.h', # Internal mirror of Linux 7.0 V4L2 HEVC EXT_SPS_*_RPS UAPI defs diff --git a/src/picture.c b/src/picture.c index 98270bf..ebc5dac 100644 --- a/src/picture.c +++ b/src/picture.c @@ -36,6 +36,7 @@ #include "mpeg2.h" #include "vp8.h" #include "vp9.h" +#include "av1.h" #include #include @@ -155,6 +156,15 @@ static VAStatus codec_store_buffer(struct request_data *driver_data, sizeof(surface_object->params.vp9.picture)); break; + case VAProfileAV1Profile0: + memcpy(&surface_object->params.av1.picture, + buffer_object->data, + sizeof(surface_object->params.av1.picture)); + /* Reset per-frame tile group entry array on each new + * picture parameter buffer (start of a new frame). */ + surface_object->params.av1.num_tile_group_entries = 0; + break; + default: break; } @@ -200,6 +210,17 @@ static VAStatus codec_store_buffer(struct request_data *driver_data, sizeof(surface_object->params.vp9.slice)); break; + case VAProfileAV1Profile0: { + unsigned int n = surface_object->params.av1.num_tile_group_entries; + if (n < AV1_MAX_TILES) { + memcpy(&surface_object->params.av1.tile_group_entries[n], + buffer_object->data, + sizeof(VASliceParameterBufferAV1)); + surface_object->params.av1.num_tile_group_entries = n + 1; + } + break; + } + default: break; } @@ -309,6 +330,11 @@ static VAStatus codec_set_controls(struct request_data *driver_data, if (rc < 0) return VA_STATUS_ERROR_OPERATION_FAILED; break; + case VAProfileAV1Profile0: + rc = av1_set_controls(driver_data, context, surface_object); + if (rc < 0) + return VA_STATUS_ERROR_OPERATION_FAILED; + break; default: return VA_STATUS_ERROR_UNSUPPORTED_PROFILE; diff --git a/src/surface.h b/src/surface.h index ada7994..f7b5386 100644 --- a/src/surface.h +++ b/src/surface.h @@ -122,6 +122,19 @@ struct object_surface { VADecPictureParameterBufferVP9 picture; VASliceParameterBufferVP9 slice; } vp9; + /* + * ampere-av1-enablement: AV1 needs picture-header + + * variable number of slice/tile params (one per tile). + * tile_group_entries[] holds parsed VASliceParameterBufferAV1 + * entries up to MAX_TILES; av1.c builds the matching + * v4l2_ctrl_av1_tile_group_entry[] at set_controls time. + */ + struct { +#define AV1_MAX_TILES 128 + VADecPictureParameterBufferAV1 picture; + VASliceParameterBufferAV1 tile_group_entries[AV1_MAX_TILES]; + unsigned int num_tile_group_entries; + } av1; } params; int request_fd;