From 53999cd154cc57e9c25fc0dca1a14c53813bcf4f Mon Sep 17 00:00:00 2001 From: Markus Fritsche Date: Sat, 25 Apr 2026 21:47:30 +0000 Subject: [PATCH] The real multiplanar wedge: probe MPLANE in surface.c, add NV12 mplane MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is what was actually broken — and it's much smaller than the STUDY guessed. The library is in fact multiplanar-aware throughout the v4l2.c helpers (v4l2_setup_format, v4l2_get_format, v4l2_query_buffer, v4l2_queue_buffer, v4l2_dequeue_buffer all branch on v4l2_type_is_mplane). The whole "context.c / picture.c are single-plane" hypothesis from STUDY.md was wrong — they derive output_type and capture_type from video_format->v4l2_mplane and pass them through. The bug is upstream of all that: driver_data->video_format is set in RequestCreateSurfaces only, and the probe there only tries V4L2_BUF_TYPE_VIDEO_CAPTURE (single-plane). On hantro the single-plane ENUM_FMT returns nothing, video_format stays NULL, and every subsequent operation hits the `if (video_format == NULL) return OPERATION_FAILED` guard at the top of context.c / buffer.c / image.c. That's exactly what Brave's vaCreateContext failure was — not a downstream multiplanar fault, just the format-detection short-circuit firing. Three small changes: - src/video.c: add an NV12 multi-plane entry next to the existing single-plane NV12 / Sunxi entries. Same pixelformat fourcc (S264 vs NV12 has nothing to do with mplane), distinguished by the v4l2_mplane bit. - src/video.h + src/video.c: video_format_find() takes a `bool mplane` parameter and matches both fields. Without this the single-plane and multi-plane NV12 entries collide on pixelformat. - src/surface.c: the probe block now tries V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE as a fallback after the single-plane probes return nothing. On a single-plane decoder the mplane probe is a no-op; on hantro it picks the new mplane NV12 entry, video_format gets set, and the rest of the library — already mplane-aware — does the right thing for OUTPUT S_FMT, REQBUFS, EXPBUF, QBUF, DQBUF. Also: src/context.c: the H264 case still referenced V4L2_PIX_FMT_H264_SLICE_RAW that we renamed in commit c1f5108. Caught now. Co-Authored-By: Claude Opus 4.7 (1M context) --- src/context.c | 2 +- src/surface.c | 24 ++++++++++++++++++------ src/video.c | 15 +++++++++++++-- src/video.h | 2 +- 4 files changed, 33 insertions(+), 10 deletions(-) diff --git a/src/context.c b/src/context.c index 04ba9a6..13662ed 100644 --- a/src/context.c +++ b/src/context.c @@ -104,7 +104,7 @@ VAStatus RequestCreateContext(VADriverContextP context, VAConfigID config_id, case VAProfileH264ConstrainedBaseline: case VAProfileH264MultiviewHigh: case VAProfileH264StereoHigh: - pixelformat = V4L2_PIX_FMT_H264_SLICE_RAW; + pixelformat = V4L2_PIX_FMT_H264_SLICE; break; case VAProfileHEVCMain: diff --git a/src/surface.c b/src/surface.c index a6abb9b..2b83304 100644 --- a/src/surface.c +++ b/src/surface.c @@ -73,17 +73,29 @@ VAStatus RequestCreateSurfaces2(VADriverContextP context, unsigned int format, if (!driver_data->video_format) { + /* Single-plane CAPTURE first (the original sunxi-cedrus path) */ found = v4l2_find_format(driver_data->video_fd, V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_PIX_FMT_SUNXI_TILED_NV12); if (found) - video_format = video_format_find(V4L2_PIX_FMT_SUNXI_TILED_NV12); + video_format = video_format_find(V4L2_PIX_FMT_SUNXI_TILED_NV12, false); - found = v4l2_find_format(driver_data->video_fd, - V4L2_BUF_TYPE_VIDEO_CAPTURE, - V4L2_PIX_FMT_NV12); - if (found) - video_format = video_format_find(V4L2_PIX_FMT_NV12); + if (video_format == NULL) { + found = v4l2_find_format(driver_data->video_fd, + V4L2_BUF_TYPE_VIDEO_CAPTURE, + V4L2_PIX_FMT_NV12); + if (found) + video_format = video_format_find(V4L2_PIX_FMT_NV12, false); + } + + /* Multi-plane CAPTURE fallback (Rockchip hantro / RK3588 VDPU381) */ + if (video_format == NULL) { + found = v4l2_find_format(driver_data->video_fd, + V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE, + V4L2_PIX_FMT_NV12); + if (found) + video_format = video_format_find(V4L2_PIX_FMT_NV12, true); + } if (video_format == NULL) return VA_STATUS_ERROR_OPERATION_FAILED; diff --git a/src/video.c b/src/video.c index 3ccbb29..4e521f5 100644 --- a/src/video.c +++ b/src/video.c @@ -45,6 +45,16 @@ static struct video_format formats[] = { .planes_count = 2, .bpp = 16, }, + { + .description = "NV12 YUV (multi-plane)", + .v4l2_format = V4L2_PIX_FMT_NV12, + .v4l2_buffers_count = 1, + .v4l2_mplane = true, + .drm_format = DRM_FORMAT_NV12, + .drm_modifier = DRM_FORMAT_MOD_NONE, + .planes_count = 2, + .bpp = 16, + }, { .description = "Sunxi tiled NV12 YUV", .v4l2_format = V4L2_PIX_FMT_SUNXI_TILED_NV12, @@ -59,12 +69,13 @@ static struct video_format formats[] = { static unsigned int formats_count = sizeof(formats) / sizeof(formats[0]); -struct video_format *video_format_find(unsigned int pixelformat) +struct video_format *video_format_find(unsigned int pixelformat, bool mplane) { unsigned int i; for (i = 0; i < formats_count; i++) - if (formats[i].v4l2_format == pixelformat) + if (formats[i].v4l2_format == pixelformat && + formats[i].v4l2_mplane == mplane) return &formats[i]; return NULL; diff --git a/src/video.h b/src/video.h index 1996fd5..f82aed6 100644 --- a/src/video.h +++ b/src/video.h @@ -38,7 +38,7 @@ struct video_format { unsigned int bpp; }; -struct video_format *video_format_find(unsigned int pixelformat); +struct video_format *video_format_find(unsigned int pixelformat, bool mplane); bool video_format_is_linear(struct video_format *format); #endif