From 0a3432ad64dbebc4f3d10c5a72e23c01674212d6 Mon Sep 17 00:00:00 2001 From: Markus Fritsche Date: Sat, 25 Apr 2026 22:03:38 +0000 Subject: [PATCH] Eager CAPTURE format probe in RequestInit MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Chromium's vaapi_video_decoder may call vaCreateContext with surfaces=NULL, surfaces_count=0 and then create surfaces afterwards via vaCreateSurfaces2. In that order driver_data->video_format is still NULL when CreateContext runs and our early `video_format == NULL` guard returns OPERATION_FAILED. Confirmed via temporary request_log() — Brave hits exactly that path on ohm. Move the probe out of RequestCreateSurfaces into a new video_format_probe() helper in video.c, and call it eagerly from RequestInit. RequestCreateSurfaces still re-probes if init came up NULL, which preserves the original lazy behaviour for any caller that needs it. Also small clean-up of surface.c since the probe block moved out: drop the now-dead `bool found` local. Co-Authored-By: Claude Opus 4.7 (1M context) --- src/request.c | 14 +++++++++++++ src/surface.c | 55 +++++++++++++++------------------------------------ src/video.c | 35 ++++++++++++++++++++++++++++++++ src/video.h | 1 + 4 files changed, 66 insertions(+), 39 deletions(-) diff --git a/src/request.c b/src/request.c index b54c0f5..1054a46 100644 --- a/src/request.c +++ b/src/request.c @@ -39,6 +39,7 @@ #include "request.h" #include "utils.h" #include "v4l2.h" +#include "video.h" #include #include @@ -179,6 +180,19 @@ VAStatus VA_DRIVER_INIT_FUNC(VADriverContextP context) driver_data->video_fd = video_fd; driver_data->media_fd = media_fd; + /* Probe the CAPTURE pixel format eagerly so vaCreateContext doesn't + * race ahead of vaCreateSurfaces. Fine if this returns NULL — we + * still let the driver init succeed and let surface creation try + * again later (preserves the original lazy behaviour for any caller + * that needs it). */ + driver_data->video_format = video_format_probe(video_fd); + if (driver_data->video_format != NULL) + request_log("Init: detected CAPTURE format %s (mplane=%d)\n", + driver_data->video_format->description, + driver_data->video_format->v4l2_mplane); + else + request_log("Init: no CAPTURE format detected at probe time\n"); + status = VA_STATUS_SUCCESS; goto complete; diff --git a/src/surface.c b/src/surface.c index 2b83304..b8ec932 100644 --- a/src/surface.c +++ b/src/surface.c @@ -65,54 +65,31 @@ VAStatus RequestCreateSurfaces2(VADriverContextP context, unsigned int format, unsigned int index; unsigned int i, j; VASurfaceID id; - bool found; int rc; if (format != VA_RT_FORMAT_YUV420) return VA_STATUS_ERROR_UNSUPPORTED_RT_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, false); - - 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) + if (!driver_data->video_format) { + /* Could happen if RequestInit's eager probe came back NULL — + * try one more time here in case the device only became + * format-enumerable after streaming setup. */ + driver_data->video_format = video_format_probe(driver_data->video_fd); + if (driver_data->video_format == NULL) return VA_STATUS_ERROR_OPERATION_FAILED; - - driver_data->video_format = video_format; - - capture_type = v4l2_type_video_capture(video_format->v4l2_mplane); - - rc = v4l2_set_format(driver_data->video_fd, capture_type, - video_format->v4l2_format, width, height); - if (rc < 0) - return VA_STATUS_ERROR_OPERATION_FAILED; - } else { - video_format = driver_data->video_format; - capture_type = v4l2_type_video_capture(video_format->v4l2_mplane); } + video_format = driver_data->video_format; + capture_type = v4l2_type_video_capture(video_format->v4l2_mplane); + + /* Set the CAPTURE format on first surface creation so the size is + * pinned to the picture dimensions the caller passed in. */ + rc = v4l2_set_format(driver_data->video_fd, capture_type, + video_format->v4l2_format, width, height); + if (rc < 0) + return VA_STATUS_ERROR_OPERATION_FAILED; + rc = v4l2_get_format(driver_data->video_fd, capture_type, &format_width, &format_height, destination_bytesperlines, destination_sizes, NULL); diff --git a/src/video.c b/src/video.c index 4e521f5..b3e4aad 100644 --- a/src/video.c +++ b/src/video.c @@ -32,6 +32,7 @@ #include #include "utils.h" +#include "v4l2.h" #include "video.h" static struct video_format formats[] = { @@ -81,6 +82,40 @@ struct video_format *video_format_find(unsigned int pixelformat, bool mplane) return NULL; } +/* + * Probe the V4L2 video device for a supported CAPTURE pixel format and + * return the matching video_format entry. Tries single-plane CAPTURE first + * (the original sunxi-cedrus path: SUNXI_TILED_NV12 or NV12), then falls + * back to multi-plane CAPTURE (Rockchip hantro / RK3588 VDPU381). Returns + * NULL if no match. + * + * Centralised here so RequestInit can populate driver_data->video_format + * before any vaCreateContext call. The original library set it lazily in + * RequestCreateSurfaces, but Chromium's vaapi_video_decoder may call + * vaCreateContext first (with surfaces=NULL, surfaces_count=0) and only + * create surfaces afterwards via vaCreateSurfaces2. + */ +struct video_format *video_format_probe(int video_fd) +{ + struct video_format *format = NULL; + + if (v4l2_find_format(video_fd, V4L2_BUF_TYPE_VIDEO_CAPTURE, + V4L2_PIX_FMT_SUNXI_TILED_NV12)) + format = video_format_find(V4L2_PIX_FMT_SUNXI_TILED_NV12, false); + + if (format == NULL && + v4l2_find_format(video_fd, V4L2_BUF_TYPE_VIDEO_CAPTURE, + V4L2_PIX_FMT_NV12)) + format = video_format_find(V4L2_PIX_FMT_NV12, false); + + if (format == NULL && + v4l2_find_format(video_fd, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE, + V4L2_PIX_FMT_NV12)) + format = video_format_find(V4L2_PIX_FMT_NV12, true); + + return format; +} + bool video_format_is_linear(struct video_format *format) { if (format == NULL) diff --git a/src/video.h b/src/video.h index f82aed6..2617526 100644 --- a/src/video.h +++ b/src/video.h @@ -39,6 +39,7 @@ struct video_format { }; struct video_format *video_format_find(unsigned int pixelformat, bool mplane); +struct video_format *video_format_probe(int video_fd); bool video_format_is_linear(struct video_format *format); #endif