From ff9107be6e93bd04b374da6aca9206aaf76cf8f1 Mon Sep 17 00:00:00 2001 From: "prompt.ac/@jeffrey" Date: Fri, 3 Jul 2026 10:37:46 -0700 Subject: [PATCH] =?UTF-8?q?fedac/native:=20camera=20=E2=80=94=20check=20de?= =?UTF-8?q?vice=5Fcaps,=20not=20capabilities=20(UVC=20metadata=20node=20tr?= =?UTF-8?q?ap)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On UVC devices with a metadata node, 'capabilities' describes the whole physical device, so /dev/video1 (metadata) also advertised VIDEO_CAPTURE and won the highest-numbered pick — then S_FMT failed forever and cap reported no cameras on a working built-in webcam (ThinkPad 04f2:b6d9). Use device_caps when V4L2_CAP_DEVICE_CAPS is set. --- fedac/native/src/camera.c | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/fedac/native/src/camera.c b/fedac/native/src/camera.c index eb1f6360d5..83fe1f9ae6 100644 --- a/fedac/native/src/camera.c +++ b/fedac/native/src/camera.c @@ -39,11 +39,18 @@ int camera_list(char paths[][16], int max) { snprintf(devpath, sizeof(devpath), "/dev/video%d", i); int fd = open(devpath, O_RDWR | O_NONBLOCK); if (fd < 0) continue; - // Capture + streaming caps only (skips UVC metadata nodes) + // Capture + streaming caps only. Must use device_caps when the + // driver sets V4L2_CAP_DEVICE_CAPS: `capabilities` describes the + // whole physical device, so a UVC *metadata* node also advertises + // VIDEO_CAPTURE there and would sneak into the list (then fail + // S_FMT forever — "no cameras found" on a working webcam). struct v4l2_capability cap; - int ok = xioctl(fd, VIDIOC_QUERYCAP, &cap) >= 0 && - (cap.capabilities & V4L2_CAP_VIDEO_CAPTURE) && - (cap.capabilities & V4L2_CAP_STREAMING); + int ok = xioctl(fd, VIDIOC_QUERYCAP, &cap) >= 0; + if (ok) { + uint32_t c = (cap.capabilities & V4L2_CAP_DEVICE_CAPS) + ? cap.device_caps : cap.capabilities; + ok = (c & V4L2_CAP_VIDEO_CAPTURE) && (c & V4L2_CAP_STREAMING); + } close(fd); if (ok) snprintf(paths[count++], 16, "%s", devpath); } @@ -86,9 +93,11 @@ int camera_open_path(ACCamera *cam, const char *devpath) { return -1; } struct v4l2_capability caps; - if (xioctl(cam->fd, VIDIOC_QUERYCAP, &caps) < 0 || - !(caps.capabilities & V4L2_CAP_VIDEO_CAPTURE) || - !(caps.capabilities & V4L2_CAP_STREAMING)) { + uint32_t ecaps = 0; + if (xioctl(cam->fd, VIDIOC_QUERYCAP, &caps) >= 0) + ecaps = (caps.capabilities & V4L2_CAP_DEVICE_CAPS) + ? caps.device_caps : caps.capabilities; + if (!(ecaps & V4L2_CAP_VIDEO_CAPTURE) || !(ecaps & V4L2_CAP_STREAMING)) { snprintf(cam->scan_error, sizeof(cam->scan_error), "%s is not a capture device", devpath); close(cam->fd); -- 2.51.2