From patchwork Mon Nov 4 15:38:25 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 21807 Return-Path: X-Original-To: parsemail@patchwork.libcamera.org Delivered-To: parsemail@patchwork.libcamera.org Received: from lancelot.ideasonboard.com (lancelot.ideasonboard.com [92.243.16.209]) by patchwork.libcamera.org (Postfix) with ESMTPS id 25E60BDB1C for ; Mon, 4 Nov 2024 15:38:34 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 6468165399; Mon, 4 Nov 2024 16:38:33 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="Di0HaqkI"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 0D77265399 for ; Mon, 4 Nov 2024 16:38:32 +0100 (CET) Received: from pendragon.ideasonboard.com (81-175-209-231.bb.dnainternet.fi [81.175.209.231]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id E85AD22E; Mon, 4 Nov 2024 16:38:24 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1730734705; bh=9CypzxkxvRi6Ewjw1fN/fXSLB6q5s5/BWsXm+UlRPoM=; h=From:To:Cc:Subject:Date:From; b=Di0HaqkIx5rIHSrlkxk04Gkh55Qp9ARD3ln3+L72uXtMQpTgAiged7r89N/8meUgy lpL7pXKOQ+TStmDYyS96kaWobFK/w8Taep5COgBrqBGW4G6zlW1o4/pzhEQi498B2y i+EE2/WSfcyBpvHrWvGpjJE15+liUg3tTkKGqRko= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Cc: Paul Elder Subject: [PATCH] v4l2: v4l2_camera_proxy: Fix VIDIOC_[GS]_PARM support Date: Mon, 4 Nov 2024 17:38:25 +0200 Message-ID: <20241104153825.21053-1-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.45.2 MIME-Version: 1.0 X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" v4l2-compliance reports an error due to VIDIOC_S_PARM being supported without VIDIOC_G_PARM. Fix it by implementing VIDIOC_G_PARM. To satisfy all compliance tests, VIDIOC_S_PARM also needs to be updated to properly zero reserved fields. Signed-off-by: Laurent Pinchart Reviewed-by: Kieran Bingham Reviewed-by: Paul Elder --- src/v4l2/v4l2_camera.h | 1 + src/v4l2/v4l2_camera_proxy.cpp | 63 ++++++++++++++++++++++++++++++++-- src/v4l2/v4l2_camera_proxy.h | 2 ++ 3 files changed, 64 insertions(+), 2 deletions(-) base-commit: 58598f4dde9a3d4236ed52881da9b155443cbc50 diff --git a/src/v4l2/v4l2_camera.h b/src/v4l2/v4l2_camera.h index e54371fb4e00..9bd161b909de 100644 --- a/src/v4l2/v4l2_camera.h +++ b/src/v4l2/v4l2_camera.h @@ -52,6 +52,7 @@ public: libcamera::StreamConfiguration *streamConfigOut); libcamera::ControlList &controls() { return controls_; } + const libcamera::ControlInfoMap &controlInfo() { return camera_->controls(); } int allocBuffers(unsigned int count); void freeBuffers(); diff --git a/src/v4l2/v4l2_camera_proxy.cpp b/src/v4l2/v4l2_camera_proxy.cpp index 5ac8df4cffef..559ffc6170b1 100644 --- a/src/v4l2/v4l2_camera_proxy.cpp +++ b/src/v4l2/v4l2_camera_proxy.cpp @@ -195,6 +195,29 @@ void V4L2CameraProxy::setFmtFromConfig(const StreamConfiguration &streamConfig) v4l2PixFormat_.xfer_func = V4L2_XFER_FUNC_DEFAULT; sizeimage_ = streamConfig.frameSize; + + const ControlInfoMap &controls = vcam_->controlInfo(); + const auto &it = controls.find(&controls::FrameDurationLimits); + + if (it != controls.end()) { + const int64_t duration = it->second.def().get(); + + v4l2TimePerFrame_.numerator = duration; + v4l2TimePerFrame_.denominator = 1000000; + } else { + /* + * Default to 30fps if the camera doesn't expose the + * FrameDurationLimits control. + * + * \todo Remove this once all pipeline handlers implement the + * control + */ + LOG(V4L2Compat, Warning) + << "Camera does not support FrameDurationLimits"; + + v4l2TimePerFrame_.numerator = 333333; + v4l2TimePerFrame_.denominator = 1000000; + } } void V4L2CameraProxy::querycap(std::shared_ptr camera) @@ -758,6 +781,22 @@ int V4L2CameraProxy::vidioc_streamoff(V4L2CameraFile *file, int *arg) return ret; } +int V4L2CameraProxy::vidioc_g_parm(V4L2CameraFile *file, struct v4l2_streamparm *arg) +{ + LOG(V4L2Compat, Debug) + << "[" << file->description() << "] " << __func__ << "()"; + + if (!validateBufferType(arg->type)) + return -EINVAL; + + memset(&arg->parm, 0, sizeof(arg->parm)); + + arg->parm.capture.capability = V4L2_CAP_TIMEPERFRAME; + arg->parm.capture.timeperframe = v4l2TimePerFrame_; + + return 0; +} + int V4L2CameraProxy::vidioc_s_parm(V4L2CameraFile *file, struct v4l2_streamparm *arg) { LOG(V4L2Compat, Debug) @@ -766,9 +805,25 @@ int V4L2CameraProxy::vidioc_s_parm(V4L2CameraFile *file, struct v4l2_streamparm if (!validateBufferType(arg->type)) return -EINVAL; - struct v4l2_fract *timeperframe = &arg->parm.capture.timeperframe; - utils::Duration frameDuration = 1.0s * timeperframe->numerator / timeperframe->denominator; + /* + * Store the frame duration if it is valid, otherwise keep the current + * value. + * + * \todo The provided value should be adjusted based on the camera + * capabilities. + */ + if (arg->parm.capture.timeperframe.numerator && + arg->parm.capture.timeperframe.denominator) + v4l2TimePerFrame_ = arg->parm.capture.timeperframe; + memset(&arg->parm, 0, sizeof(arg->parm)); + + arg->parm.capture.capability = V4L2_CAP_TIMEPERFRAME; + arg->parm.capture.timeperframe = v4l2TimePerFrame_; + + /* Apply the frame duration. */ + utils::Duration frameDuration = 1.0s * v4l2TimePerFrame_.numerator + / v4l2TimePerFrame_.denominator; int64_t uDuration = frameDuration.get(); vcam_->controls().set(controls::FrameDurationLimits, { uDuration, uDuration }); @@ -795,6 +850,7 @@ const std::set V4L2CameraProxy::supportedIoctls_ = { VIDIOC_EXPBUF, VIDIOC_STREAMON, VIDIOC_STREAMOFF, + VIDIOC_G_PARM, VIDIOC_S_PARM, }; @@ -883,6 +939,9 @@ int V4L2CameraProxy::ioctl(V4L2CameraFile *file, unsigned long longRequest, void case VIDIOC_STREAMOFF: ret = vidioc_streamoff(file, static_cast(arg)); break; + case VIDIOC_G_PARM: + ret = vidioc_g_parm(file, static_cast(arg)); + break; case VIDIOC_S_PARM: ret = vidioc_s_parm(file, static_cast(arg)); break; diff --git a/src/v4l2/v4l2_camera_proxy.h b/src/v4l2/v4l2_camera_proxy.h index c957db5349cc..5aa352c36f6a 100644 --- a/src/v4l2/v4l2_camera_proxy.h +++ b/src/v4l2/v4l2_camera_proxy.h @@ -67,6 +67,7 @@ private: int vidioc_expbuf(V4L2CameraFile *file, struct v4l2_exportbuffer *arg); int vidioc_streamon(V4L2CameraFile *file, int *arg); int vidioc_streamoff(V4L2CameraFile *file, int *arg); + int vidioc_g_parm(V4L2CameraFile *file, struct v4l2_streamparm *arg); int vidioc_s_parm(V4L2CameraFile *file, struct v4l2_streamparm *arg); bool hasOwnership(V4L2CameraFile *file); @@ -85,6 +86,7 @@ private: struct v4l2_capability capabilities_; struct v4l2_pix_format v4l2PixFormat_; + struct v4l2_fract v4l2TimePerFrame_; std::vector buffers_; std::map mmaps_;