Show a patch.

GET /api/patches/21807/?format=api
HTTP 200 OK
Allow: GET, PUT, PATCH, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept

{
    "id": 21807,
    "url": "https://patchwork.libcamera.org/api/patches/21807/?format=api",
    "web_url": "https://patchwork.libcamera.org/patch/21807/",
    "project": {
        "id": 1,
        "url": "https://patchwork.libcamera.org/api/projects/1/?format=api",
        "name": "libcamera",
        "link_name": "libcamera",
        "list_id": "libcamera_core",
        "list_email": "libcamera-devel@lists.libcamera.org",
        "web_url": "",
        "scm_url": "",
        "webscm_url": ""
    },
    "msgid": "<20241104153825.21053-1-laurent.pinchart@ideasonboard.com>",
    "date": "2024-11-04T15:38:25",
    "name": "v4l2: v4l2_camera_proxy: Fix VIDIOC_[GS]_PARM support",
    "commit_ref": "77438775b39b04748284ce86fe64e913d711482b",
    "pull_url": null,
    "state": "accepted",
    "archived": false,
    "hash": "8dfeb3b2ea279cb2bde2de7b616027144b1ad813",
    "submitter": {
        "id": 2,
        "url": "https://patchwork.libcamera.org/api/people/2/?format=api",
        "name": "Laurent Pinchart",
        "email": "laurent.pinchart@ideasonboard.com"
    },
    "delegate": null,
    "mbox": "https://patchwork.libcamera.org/patch/21807/mbox/",
    "series": [
        {
            "id": 4766,
            "url": "https://patchwork.libcamera.org/api/series/4766/?format=api",
            "web_url": "https://patchwork.libcamera.org/project/libcamera/list/?series=4766",
            "date": "2024-11-04T15:38:25",
            "name": "v4l2: v4l2_camera_proxy: Fix VIDIOC_[GS]_PARM support",
            "version": 1,
            "mbox": "https://patchwork.libcamera.org/series/4766/mbox/"
        }
    ],
    "comments": "https://patchwork.libcamera.org/api/patches/21807/comments/",
    "check": "pending",
    "checks": "https://patchwork.libcamera.org/api/patches/21807/checks/",
    "tags": {},
    "headers": {
        "Return-Path": "<libcamera-devel-bounces@lists.libcamera.org>",
        "X-Original-To": "parsemail@patchwork.libcamera.org",
        "Delivered-To": "parsemail@patchwork.libcamera.org",
        "Received": [
            "from lancelot.ideasonboard.com (lancelot.ideasonboard.com\n\t[92.243.16.209])\n\tby patchwork.libcamera.org (Postfix) with ESMTPS id 25E60BDB1C\n\tfor <parsemail@patchwork.libcamera.org>;\n\tMon,  4 Nov 2024 15:38:34 +0000 (UTC)",
            "from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 6468165399;\n\tMon,  4 Nov 2024 16:38:33 +0100 (CET)",
            "from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 0D77265399\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tMon,  4 Nov 2024 16:38:32 +0100 (CET)",
            "from pendragon.ideasonboard.com (81-175-209-231.bb.dnainternet.fi\n\t[81.175.209.231])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id E85AD22E;\n\tMon,  4 Nov 2024 16:38:24 +0100 (CET)"
        ],
        "Authentication-Results": "lancelot.ideasonboard.com; dkim=pass (1024-bit key;\n\tunprotected) header.d=ideasonboard.com header.i=@ideasonboard.com\n\theader.b=\"Di0HaqkI\"; dkim-atps=neutral",
        "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1730734705;\n\tbh=9CypzxkxvRi6Ewjw1fN/fXSLB6q5s5/BWsXm+UlRPoM=;\n\th=From:To:Cc:Subject:Date:From;\n\tb=Di0HaqkIx5rIHSrlkxk04Gkh55Qp9ARD3ln3+L72uXtMQpTgAiged7r89N/8meUgy\n\tlpL7pXKOQ+TStmDYyS96kaWobFK/w8Taep5COgBrqBGW4G6zlW1o4/pzhEQi498B2y\n\ti+EE2/WSfcyBpvHrWvGpjJE15+liUg3tTkKGqRko=",
        "From": "Laurent Pinchart <laurent.pinchart@ideasonboard.com>",
        "To": "libcamera-devel@lists.libcamera.org",
        "Cc": "Paul Elder <paul.elder@ideasonboard.com>",
        "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",
        "Content-Transfer-Encoding": "8bit",
        "X-BeenThere": "libcamera-devel@lists.libcamera.org",
        "X-Mailman-Version": "2.1.29",
        "Precedence": "list",
        "List-Id": "<libcamera-devel.lists.libcamera.org>",
        "List-Unsubscribe": "<https://lists.libcamera.org/options/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=unsubscribe>",
        "List-Archive": "<https://lists.libcamera.org/pipermail/libcamera-devel/>",
        "List-Post": "<mailto:libcamera-devel@lists.libcamera.org>",
        "List-Help": "<mailto:libcamera-devel-request@lists.libcamera.org?subject=help>",
        "List-Subscribe": "<https://lists.libcamera.org/listinfo/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=subscribe>",
        "Errors-To": "libcamera-devel-bounces@lists.libcamera.org",
        "Sender": "\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"
    },
    "content": "v4l2-compliance reports an error due to VIDIOC_S_PARM being supported\nwithout VIDIOC_G_PARM. Fix it by implementing VIDIOC_G_PARM. To satisfy\nall compliance tests, VIDIOC_S_PARM also needs to be updated to properly\nzero reserved fields.\n\nSigned-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>\n---\n src/v4l2/v4l2_camera.h         |  1 +\n src/v4l2/v4l2_camera_proxy.cpp | 63 ++++++++++++++++++++++++++++++++--\n src/v4l2/v4l2_camera_proxy.h   |  2 ++\n 3 files changed, 64 insertions(+), 2 deletions(-)\n\n\nbase-commit: 58598f4dde9a3d4236ed52881da9b155443cbc50",
    "diff": "diff --git a/src/v4l2/v4l2_camera.h b/src/v4l2/v4l2_camera.h\nindex e54371fb4e00..9bd161b909de 100644\n--- a/src/v4l2/v4l2_camera.h\n+++ b/src/v4l2/v4l2_camera.h\n@@ -52,6 +52,7 @@ public:\n \t\t\t\t  libcamera::StreamConfiguration *streamConfigOut);\n \n \tlibcamera::ControlList &controls() { return controls_; }\n+\tconst libcamera::ControlInfoMap &controlInfo() { return camera_->controls(); }\n \n \tint allocBuffers(unsigned int count);\n \tvoid freeBuffers();\ndiff --git a/src/v4l2/v4l2_camera_proxy.cpp b/src/v4l2/v4l2_camera_proxy.cpp\nindex 5ac8df4cffef..559ffc6170b1 100644\n--- a/src/v4l2/v4l2_camera_proxy.cpp\n+++ b/src/v4l2/v4l2_camera_proxy.cpp\n@@ -195,6 +195,29 @@ void V4L2CameraProxy::setFmtFromConfig(const StreamConfiguration &streamConfig)\n \tv4l2PixFormat_.xfer_func    = V4L2_XFER_FUNC_DEFAULT;\n \n \tsizeimage_ = streamConfig.frameSize;\n+\n+\tconst ControlInfoMap &controls = vcam_->controlInfo();\n+\tconst auto &it = controls.find(&controls::FrameDurationLimits);\n+\n+\tif (it != controls.end()) {\n+\t\tconst int64_t duration = it->second.def().get<int64_t>();\n+\n+\t\tv4l2TimePerFrame_.numerator = duration;\n+\t\tv4l2TimePerFrame_.denominator = 1000000;\n+\t} else {\n+\t\t/*\n+\t\t * Default to 30fps if the camera doesn't expose the\n+\t\t * FrameDurationLimits control.\n+\t\t *\n+\t\t * \\todo Remove this once all pipeline handlers implement the\n+\t\t * control\n+\t\t */\n+\t\tLOG(V4L2Compat, Warning)\n+\t\t\t<< \"Camera does not support FrameDurationLimits\";\n+\n+\t\tv4l2TimePerFrame_.numerator = 333333;\n+\t\tv4l2TimePerFrame_.denominator = 1000000;\n+\t}\n }\n \n void V4L2CameraProxy::querycap(std::shared_ptr<Camera> camera)\n@@ -758,6 +781,22 @@ int V4L2CameraProxy::vidioc_streamoff(V4L2CameraFile *file, int *arg)\n \treturn ret;\n }\n \n+int V4L2CameraProxy::vidioc_g_parm(V4L2CameraFile *file, struct v4l2_streamparm *arg)\n+{\n+\tLOG(V4L2Compat, Debug)\n+\t\t<< \"[\" << file->description() << \"] \" << __func__ << \"()\";\n+\n+\tif (!validateBufferType(arg->type))\n+\t\treturn -EINVAL;\n+\n+\tmemset(&arg->parm, 0, sizeof(arg->parm));\n+\n+\targ->parm.capture.capability = V4L2_CAP_TIMEPERFRAME;\n+\targ->parm.capture.timeperframe = v4l2TimePerFrame_;\n+\n+\treturn 0;\n+}\n+\n int V4L2CameraProxy::vidioc_s_parm(V4L2CameraFile *file, struct v4l2_streamparm *arg)\n {\n \tLOG(V4L2Compat, Debug)\n@@ -766,9 +805,25 @@ int V4L2CameraProxy::vidioc_s_parm(V4L2CameraFile *file, struct v4l2_streamparm\n \tif (!validateBufferType(arg->type))\n \t\treturn -EINVAL;\n \n-\tstruct v4l2_fract *timeperframe = &arg->parm.capture.timeperframe;\n-\tutils::Duration frameDuration = 1.0s * timeperframe->numerator / timeperframe->denominator;\n+\t/*\n+\t * Store the frame duration if it is valid, otherwise keep the current\n+\t * value.\n+\t *\n+\t * \\todo The provided value should be adjusted based on the camera\n+\t * capabilities.\n+\t */\n+\tif (arg->parm.capture.timeperframe.numerator &&\n+\t    arg->parm.capture.timeperframe.denominator)\n+\t\tv4l2TimePerFrame_ = arg->parm.capture.timeperframe;\n \n+\tmemset(&arg->parm, 0, sizeof(arg->parm));\n+\n+\targ->parm.capture.capability = V4L2_CAP_TIMEPERFRAME;\n+\targ->parm.capture.timeperframe = v4l2TimePerFrame_;\n+\n+\t/* Apply the frame duration. */\n+\tutils::Duration frameDuration = 1.0s * v4l2TimePerFrame_.numerator\n+\t\t\t\t      / v4l2TimePerFrame_.denominator;\n \tint64_t uDuration = frameDuration.get<std::micro>();\n \tvcam_->controls().set(controls::FrameDurationLimits, { uDuration, uDuration });\n \n@@ -795,6 +850,7 @@ const std::set<unsigned long> V4L2CameraProxy::supportedIoctls_ = {\n \tVIDIOC_EXPBUF,\n \tVIDIOC_STREAMON,\n \tVIDIOC_STREAMOFF,\n+\tVIDIOC_G_PARM,\n \tVIDIOC_S_PARM,\n };\n \n@@ -883,6 +939,9 @@ int V4L2CameraProxy::ioctl(V4L2CameraFile *file, unsigned long longRequest, void\n \tcase VIDIOC_STREAMOFF:\n \t\tret = vidioc_streamoff(file, static_cast<int *>(arg));\n \t\tbreak;\n+\tcase VIDIOC_G_PARM:\n+\t\tret = vidioc_g_parm(file, static_cast<struct v4l2_streamparm *>(arg));\n+\t\tbreak;\n \tcase VIDIOC_S_PARM:\n \t\tret = vidioc_s_parm(file, static_cast<struct v4l2_streamparm *>(arg));\n \t\tbreak;\ndiff --git a/src/v4l2/v4l2_camera_proxy.h b/src/v4l2/v4l2_camera_proxy.h\nindex c957db5349cc..5aa352c36f6a 100644\n--- a/src/v4l2/v4l2_camera_proxy.h\n+++ b/src/v4l2/v4l2_camera_proxy.h\n@@ -67,6 +67,7 @@ private:\n \tint vidioc_expbuf(V4L2CameraFile *file, struct v4l2_exportbuffer *arg);\n \tint vidioc_streamon(V4L2CameraFile *file, int *arg);\n \tint vidioc_streamoff(V4L2CameraFile *file, int *arg);\n+\tint vidioc_g_parm(V4L2CameraFile *file, struct v4l2_streamparm *arg);\n \tint vidioc_s_parm(V4L2CameraFile *file, struct v4l2_streamparm *arg);\n \n \tbool hasOwnership(V4L2CameraFile *file);\n@@ -85,6 +86,7 @@ private:\n \n \tstruct v4l2_capability capabilities_;\n \tstruct v4l2_pix_format v4l2PixFormat_;\n+\tstruct v4l2_fract v4l2TimePerFrame_;\n \n \tstd::vector<struct v4l2_buffer> buffers_;\n \tstd::map<void *, unsigned int> mmaps_;\n",
    "prefixes": []
}