diff --git a/src/v4l2.c b/src/v4l2.c index d881cbe..4245c74 100644 --- a/src/v4l2.c +++ b/src/v4l2.c @@ -473,15 +473,29 @@ static int v4l2_ioctl_controls(int video_fd, int request_fd, unsigned long ioc, if (try_rc < 0) { request_log(" TRY_EXT_CTRLS retry: errno=%d (%s) error_idx=%u\n", errno, strerror(errno), try_controls.error_idx); - if (try_controls.error_idx < num_controls) { - request_log(" --> failing control is ctrl[%u]: id=0x%08x size=%u\n", - try_controls.error_idx, - control_array[try_controls.error_idx].id, - control_array[try_controls.error_idx].size); - } } else { request_log(" TRY_EXT_CTRLS retry: passed (S vs TRY semantics differ — likely cluster commit)\n"); } + /* Per-control isolation: TRY each control alone to learn which + * one fails on its own. Exposes per-control compound validators + * (std_validate_compound) below the cluster commit obfuscation. + */ + for (unsigned int i = 0; i < num_controls; i++) { + struct v4l2_ext_controls one_ctrl; + memset(&one_ctrl, 0, sizeof(one_ctrl)); + one_ctrl.controls = &control_array[i]; + one_ctrl.count = 1; + if (request_fd >= 0) { + one_ctrl.which = V4L2_CTRL_WHICH_REQUEST_VAL; + one_ctrl.request_fd = request_fd; + } + int one_rc = ioctl(video_fd, VIDIOC_TRY_EXT_CTRLS, &one_ctrl); + request_log(" TRY[%u] id=0x%08x: %s (errno=%d error_idx=%u)\n", + i, control_array[i].id, + one_rc < 0 ? "FAIL" : "pass", + one_rc < 0 ? errno : 0, + one_ctrl.error_idx); + } errno = saved_errno; } return rc;