[{"id":32014,"web_url":"https://patchwork.libcamera.org/comment/32014/","msgid":"<173073698028.2721096.12299227467236363203@ping.linuxembedded.co.uk>","date":"2024-11-04T16:16:20","subject":"Re: [PATCH] v4l2: v4l2_camera_proxy: Fix VIDIOC_[GS]_PARM support","submitter":{"id":4,"url":"https://patchwork.libcamera.org/api/people/4/","name":"Kieran Bingham","email":"kieran.bingham@ideasonboard.com"},"content":"Quoting Laurent Pinchart (2024-11-04 15:38:25)\n> v4l2-compliance reports an error due to VIDIOC_S_PARM being supported\n> without VIDIOC_G_PARM. Fix it by implementing VIDIOC_G_PARM. To satisfy\n> all compliance tests, VIDIOC_S_PARM also needs to be updated to properly\n> zero reserved fields.\n\nFixes tag ?\n\n> Signed-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> diff --git a/src/v4l2/v4l2_camera.h b/src/v4l2/v4l2_camera.h\n> index e54371fb4e00..9bd161b909de 100644\n> --- a/src/v4l2/v4l2_camera.h\n> +++ b/src/v4l2/v4l2_camera.h\n> @@ -52,6 +52,7 @@ public:\n>                                   libcamera::StreamConfiguration *streamConfigOut);\n>  \n>         libcamera::ControlList &controls() { return controls_; }\n> +       const libcamera::ControlInfoMap &controlInfo() { return camera_->controls(); }\n>  \n>         int allocBuffers(unsigned int count);\n>         void freeBuffers();\n> diff --git a/src/v4l2/v4l2_camera_proxy.cpp b/src/v4l2/v4l2_camera_proxy.cpp\n> index 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>         v4l2PixFormat_.xfer_func    = V4L2_XFER_FUNC_DEFAULT;\n>  \n>         sizeimage_ = streamConfig.frameSize;\n> +\n> +       const ControlInfoMap &controls = vcam_->controlInfo();\n> +       const auto &it = controls.find(&controls::FrameDurationLimits);\n> +\n> +       if (it != controls.end()) {\n> +               const int64_t duration = it->second.def().get<int64_t>();\n> +\n> +               v4l2TimePerFrame_.numerator = duration;\n> +               v4l2TimePerFrame_.denominator = 1000000;\n> +       } else {\n> +               /*\n> +                * Default to 30fps if the camera doesn't expose the\n> +                * FrameDurationLimits control.\n> +                *\n> +                * \\todo Remove this once all pipeline handlers implement the\n> +                * control\n> +                */\n> +               LOG(V4L2Compat, Warning)\n> +                       << \"Camera does not support FrameDurationLimits\";\n> +\n> +               v4l2TimePerFrame_.numerator = 333333;\n> +               v4l2TimePerFrame_.denominator = 1000000;\n> +       }\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>         return ret;\n>  }\n>  \n> +int V4L2CameraProxy::vidioc_g_parm(V4L2CameraFile *file, struct v4l2_streamparm *arg)\n> +{\n> +       LOG(V4L2Compat, Debug)\n> +               << \"[\" << file->description() << \"] \" << __func__ << \"()\";\n> +\n> +       if (!validateBufferType(arg->type))\n> +               return -EINVAL;\n> +\n> +       memset(&arg->parm, 0, sizeof(arg->parm));\n> +\n> +       arg->parm.capture.capability = V4L2_CAP_TIMEPERFRAME;\n\nI guess this wasn't being handled at all before ?\n\n> +       arg->parm.capture.timeperframe = v4l2TimePerFrame_;\n\nWhat does this return /before/ the camera is configured? Does it work ?\n\n\nOtherwise seems like a good fix.\n\n\nReviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com>\n\n> +\n> +       return 0;\n> +}\n> +\n>  int V4L2CameraProxy::vidioc_s_parm(V4L2CameraFile *file, struct v4l2_streamparm *arg)\n>  {\n>         LOG(V4L2Compat, Debug)\n> @@ -766,9 +805,25 @@ int V4L2CameraProxy::vidioc_s_parm(V4L2CameraFile *file, struct v4l2_streamparm\n>         if (!validateBufferType(arg->type))\n>                 return -EINVAL;\n>  \n> -       struct v4l2_fract *timeperframe = &arg->parm.capture.timeperframe;\n> -       utils::Duration frameDuration = 1.0s * timeperframe->numerator / timeperframe->denominator;\n> +       /*\n> +        * Store the frame duration if it is valid, otherwise keep the current\n> +        * value.\n> +        *\n> +        * \\todo The provided value should be adjusted based on the camera\n> +        * capabilities.\n> +        */\n> +       if (arg->parm.capture.timeperframe.numerator &&\n> +           arg->parm.capture.timeperframe.denominator)\n> +               v4l2TimePerFrame_ = arg->parm.capture.timeperframe;\n>  \n> +       memset(&arg->parm, 0, sizeof(arg->parm));\n> +\n> +       arg->parm.capture.capability = V4L2_CAP_TIMEPERFRAME;\n> +       arg->parm.capture.timeperframe = v4l2TimePerFrame_;\n> +\n> +       /* Apply the frame duration. */\n> +       utils::Duration frameDuration = 1.0s * v4l2TimePerFrame_.numerator\n> +                                     / v4l2TimePerFrame_.denominator;\n>         int64_t uDuration = frameDuration.get<std::micro>();\n>         vcam_->controls().set(controls::FrameDurationLimits, { uDuration, uDuration });\n>  \n> @@ -795,6 +850,7 @@ const std::set<unsigned long> V4L2CameraProxy::supportedIoctls_ = {\n>         VIDIOC_EXPBUF,\n>         VIDIOC_STREAMON,\n>         VIDIOC_STREAMOFF,\n> +       VIDIOC_G_PARM,\n>         VIDIOC_S_PARM,\n>  };\n>  \n> @@ -883,6 +939,9 @@ int V4L2CameraProxy::ioctl(V4L2CameraFile *file, unsigned long longRequest, void\n>         case VIDIOC_STREAMOFF:\n>                 ret = vidioc_streamoff(file, static_cast<int *>(arg));\n>                 break;\n> +       case VIDIOC_G_PARM:\n> +               ret = vidioc_g_parm(file, static_cast<struct v4l2_streamparm *>(arg));\n> +               break;\n>         case VIDIOC_S_PARM:\n>                 ret = vidioc_s_parm(file, static_cast<struct v4l2_streamparm *>(arg));\n>                 break;\n> diff --git a/src/v4l2/v4l2_camera_proxy.h b/src/v4l2/v4l2_camera_proxy.h\n> index 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>         int vidioc_expbuf(V4L2CameraFile *file, struct v4l2_exportbuffer *arg);\n>         int vidioc_streamon(V4L2CameraFile *file, int *arg);\n>         int vidioc_streamoff(V4L2CameraFile *file, int *arg);\n> +       int vidioc_g_parm(V4L2CameraFile *file, struct v4l2_streamparm *arg);\n>         int vidioc_s_parm(V4L2CameraFile *file, struct v4l2_streamparm *arg);\n>  \n>         bool hasOwnership(V4L2CameraFile *file);\n> @@ -85,6 +86,7 @@ private:\n>  \n>         struct v4l2_capability capabilities_;\n>         struct v4l2_pix_format v4l2PixFormat_;\n> +       struct v4l2_fract v4l2TimePerFrame_;\n>  \n>         std::vector<struct v4l2_buffer> buffers_;\n>         std::map<void *, unsigned int> mmaps_;\n> \n> base-commit: 58598f4dde9a3d4236ed52881da9b155443cbc50\n> -- \n> Regards,\n> \n> Laurent Pinchart\n>","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 AC598BDC71\n\tfor <parsemail@patchwork.libcamera.org>;\n\tMon,  4 Nov 2024 16:16:26 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id A419B653DA;\n\tMon,  4 Nov 2024 17:16:25 +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 6CFC965399\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tMon,  4 Nov 2024 17:16:23 +0100 (CET)","from pendragon.ideasonboard.com\n\t(cpc89244-aztw30-2-0-cust6594.18-1.cable.virginm.net [86.31.185.195])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id 70CAF526;\n\tMon,  4 Nov 2024 17:16:16 +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=\"vKM+LBLM\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1730736976;\n\tbh=bBAjEmHq3/r3RuiNc7WcLpNQlX0PRjtWeFVfAxgfaE0=;\n\th=In-Reply-To:References:Subject:From:Cc:To:Date:From;\n\tb=vKM+LBLMI/NhyllXCBFLr8JSroevL2Xt55YoI1JPLGiC7ct6UVXdXrpmbYYqx2J1a\n\t2F/24j9q1X9nHXno8A9zztZWUuNS/03BCXKT2xtlmTOyv43T24mu/cpL0zw3T6bElO\n\tmg6pxs6uuMqcx2epbuJxOd9kQO4qBSQUektBcaeM=","Content-Type":"text/plain; charset=\"utf-8\"","MIME-Version":"1.0","Content-Transfer-Encoding":"quoted-printable","In-Reply-To":"<20241104153825.21053-1-laurent.pinchart@ideasonboard.com>","References":"<20241104153825.21053-1-laurent.pinchart@ideasonboard.com>","Subject":"Re: [PATCH] v4l2: v4l2_camera_proxy: Fix VIDIOC_[GS]_PARM support","From":"Kieran Bingham <kieran.bingham@ideasonboard.com>","Cc":"Paul Elder <paul.elder@ideasonboard.com>","To":"Laurent Pinchart <laurent.pinchart@ideasonboard.com>,\n\tlibcamera-devel@lists.libcamera.org","Date":"Mon, 04 Nov 2024 16:16:20 +0000","Message-ID":"<173073698028.2721096.12299227467236363203@ping.linuxembedded.co.uk>","User-Agent":"alot/0.10","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>"}},{"id":32018,"web_url":"https://patchwork.libcamera.org/comment/32018/","msgid":"<20241104221035.GA19140@pendragon.ideasonboard.com>","date":"2024-11-04T22:10:35","subject":"Re: [PATCH] v4l2: v4l2_camera_proxy: Fix VIDIOC_[GS]_PARM support","submitter":{"id":2,"url":"https://patchwork.libcamera.org/api/people/2/","name":"Laurent Pinchart","email":"laurent.pinchart@ideasonboard.com"},"content":"Hi Kieran,\n\nOn Mon, Nov 04, 2024 at 04:16:20PM +0000, Kieran Bingham wrote:\n> Quoting Laurent Pinchart (2024-11-04 15:38:25)\n> > v4l2-compliance reports an error due to VIDIOC_S_PARM being supported\n> > without VIDIOC_G_PARM. Fix it by implementing VIDIOC_G_PARM. To satisfy\n> > all compliance tests, VIDIOC_S_PARM also needs to be updated to properly\n> > zero reserved fields.\n> \n> Fixes tag ?\n\nIt has never worked. I can point to the commit that introduced the\ncompat layer.\n\n> > Signed-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> > diff --git a/src/v4l2/v4l2_camera.h b/src/v4l2/v4l2_camera.h\n> > index e54371fb4e00..9bd161b909de 100644\n> > --- a/src/v4l2/v4l2_camera.h\n> > +++ b/src/v4l2/v4l2_camera.h\n> > @@ -52,6 +52,7 @@ public:\n> >                                   libcamera::StreamConfiguration *streamConfigOut);\n> >  \n> >         libcamera::ControlList &controls() { return controls_; }\n> > +       const libcamera::ControlInfoMap &controlInfo() { return camera_->controls(); }\n> >  \n> >         int allocBuffers(unsigned int count);\n> >         void freeBuffers();\n> > diff --git a/src/v4l2/v4l2_camera_proxy.cpp b/src/v4l2/v4l2_camera_proxy.cpp\n> > index 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> >         v4l2PixFormat_.xfer_func    = V4L2_XFER_FUNC_DEFAULT;\n> >  \n> >         sizeimage_ = streamConfig.frameSize;\n> > +\n> > +       const ControlInfoMap &controls = vcam_->controlInfo();\n> > +       const auto &it = controls.find(&controls::FrameDurationLimits);\n> > +\n> > +       if (it != controls.end()) {\n> > +               const int64_t duration = it->second.def().get<int64_t>();\n> > +\n> > +               v4l2TimePerFrame_.numerator = duration;\n> > +               v4l2TimePerFrame_.denominator = 1000000;\n> > +       } else {\n> > +               /*\n> > +                * Default to 30fps if the camera doesn't expose the\n> > +                * FrameDurationLimits control.\n> > +                *\n> > +                * \\todo Remove this once all pipeline handlers implement the\n> > +                * control\n> > +                */\n> > +               LOG(V4L2Compat, Warning)\n> > +                       << \"Camera does not support FrameDurationLimits\";\n> > +\n> > +               v4l2TimePerFrame_.numerator = 333333;\n> > +               v4l2TimePerFrame_.denominator = 1000000;\n> > +       }\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> >         return ret;\n> >  }\n> >  \n> > +int V4L2CameraProxy::vidioc_g_parm(V4L2CameraFile *file, struct v4l2_streamparm *arg)\n> > +{\n> > +       LOG(V4L2Compat, Debug)\n> > +               << \"[\" << file->description() << \"] \" << __func__ << \"()\";\n> > +\n> > +       if (!validateBufferType(arg->type))\n> > +               return -EINVAL;\n> > +\n> > +       memset(&arg->parm, 0, sizeof(arg->parm));\n> > +\n> > +       arg->parm.capture.capability = V4L2_CAP_TIMEPERFRAME;\n> \n> I guess this wasn't being handled at all before ?\n\nG_PARM wasn't handled at all. Or is your comment about something else ?\n\n> > +       arg->parm.capture.timeperframe = v4l2TimePerFrame_;\n> \n> What does this return /before/ the camera is configured? Does it work ?\n\nsetFmtFromConfig() is called from the class constructor, so\nv4l2TimePerFrame_ is always initialized.\n\n> Otherwise seems like a good fix.\n> \n> \n> Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com>\n> \n> > +\n> > +       return 0;\n> > +}\n> > +\n> >  int V4L2CameraProxy::vidioc_s_parm(V4L2CameraFile *file, struct v4l2_streamparm *arg)\n> >  {\n> >         LOG(V4L2Compat, Debug)\n> > @@ -766,9 +805,25 @@ int V4L2CameraProxy::vidioc_s_parm(V4L2CameraFile *file, struct v4l2_streamparm\n> >         if (!validateBufferType(arg->type))\n> >                 return -EINVAL;\n> >  \n> > -       struct v4l2_fract *timeperframe = &arg->parm.capture.timeperframe;\n> > -       utils::Duration frameDuration = 1.0s * timeperframe->numerator / timeperframe->denominator;\n> > +       /*\n> > +        * Store the frame duration if it is valid, otherwise keep the current\n> > +        * value.\n> > +        *\n> > +        * \\todo The provided value should be adjusted based on the camera\n> > +        * capabilities.\n> > +        */\n> > +       if (arg->parm.capture.timeperframe.numerator &&\n> > +           arg->parm.capture.timeperframe.denominator)\n> > +               v4l2TimePerFrame_ = arg->parm.capture.timeperframe;\n> >  \n> > +       memset(&arg->parm, 0, sizeof(arg->parm));\n> > +\n> > +       arg->parm.capture.capability = V4L2_CAP_TIMEPERFRAME;\n> > +       arg->parm.capture.timeperframe = v4l2TimePerFrame_;\n> > +\n> > +       /* Apply the frame duration. */\n> > +       utils::Duration frameDuration = 1.0s * v4l2TimePerFrame_.numerator\n> > +                                     / v4l2TimePerFrame_.denominator;\n> >         int64_t uDuration = frameDuration.get<std::micro>();\n> >         vcam_->controls().set(controls::FrameDurationLimits, { uDuration, uDuration });\n> >  \n> > @@ -795,6 +850,7 @@ const std::set<unsigned long> V4L2CameraProxy::supportedIoctls_ = {\n> >         VIDIOC_EXPBUF,\n> >         VIDIOC_STREAMON,\n> >         VIDIOC_STREAMOFF,\n> > +       VIDIOC_G_PARM,\n> >         VIDIOC_S_PARM,\n> >  };\n> >  \n> > @@ -883,6 +939,9 @@ int V4L2CameraProxy::ioctl(V4L2CameraFile *file, unsigned long longRequest, void\n> >         case VIDIOC_STREAMOFF:\n> >                 ret = vidioc_streamoff(file, static_cast<int *>(arg));\n> >                 break;\n> > +       case VIDIOC_G_PARM:\n> > +               ret = vidioc_g_parm(file, static_cast<struct v4l2_streamparm *>(arg));\n> > +               break;\n> >         case VIDIOC_S_PARM:\n> >                 ret = vidioc_s_parm(file, static_cast<struct v4l2_streamparm *>(arg));\n> >                 break;\n> > diff --git a/src/v4l2/v4l2_camera_proxy.h b/src/v4l2/v4l2_camera_proxy.h\n> > index 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> >         int vidioc_expbuf(V4L2CameraFile *file, struct v4l2_exportbuffer *arg);\n> >         int vidioc_streamon(V4L2CameraFile *file, int *arg);\n> >         int vidioc_streamoff(V4L2CameraFile *file, int *arg);\n> > +       int vidioc_g_parm(V4L2CameraFile *file, struct v4l2_streamparm *arg);\n> >         int vidioc_s_parm(V4L2CameraFile *file, struct v4l2_streamparm *arg);\n> >  \n> >         bool hasOwnership(V4L2CameraFile *file);\n> > @@ -85,6 +86,7 @@ private:\n> >  \n> >         struct v4l2_capability capabilities_;\n> >         struct v4l2_pix_format v4l2PixFormat_;\n> > +       struct v4l2_fract v4l2TimePerFrame_;\n> >  \n> >         std::vector<struct v4l2_buffer> buffers_;\n> >         std::map<void *, unsigned int> mmaps_;\n> > \n> > base-commit: 58598f4dde9a3d4236ed52881da9b155443cbc50","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 441BABDB1C\n\tfor <parsemail@patchwork.libcamera.org>;\n\tMon,  4 Nov 2024 22:10:45 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 63171653E1;\n\tMon,  4 Nov 2024 23:10:44 +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 5D54365399\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tMon,  4 Nov 2024 23:10:42 +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 0CB45526;\n\tMon,  4 Nov 2024 23:10:34 +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=\"wpXqwPd3\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1730758235;\n\tbh=noHz9CTbl5V+ZkTAeZMXmqUPmftoPGp+6z6aeLmYq/Y=;\n\th=Date:From:To:Cc:Subject:References:In-Reply-To:From;\n\tb=wpXqwPd35TAtjo4pJ3/pucqVeSMYFCxXprJTKxZO4GYe+LHO2MXd8Gxks9hyZopwy\n\tBytSx6LZs24Loh3pbaccNjUGcHw1Qh0PR9G56kAhIujwcpjY0mw2Z4Lnjoe9oUZLq4\n\tMbhzQGah4++DPGuph60awTJWJe4qDl3hTPXCu3xc=","Date":"Tue, 5 Nov 2024 00:10:35 +0200","From":"Laurent Pinchart <laurent.pinchart@ideasonboard.com>","To":"Kieran Bingham <kieran.bingham@ideasonboard.com>","Cc":"libcamera-devel@lists.libcamera.org,\n\tPaul Elder <paul.elder@ideasonboard.com>","Subject":"Re: [PATCH] v4l2: v4l2_camera_proxy: Fix VIDIOC_[GS]_PARM support","Message-ID":"<20241104221035.GA19140@pendragon.ideasonboard.com>","References":"<20241104153825.21053-1-laurent.pinchart@ideasonboard.com>\n\t<173073698028.2721096.12299227467236363203@ping.linuxembedded.co.uk>","MIME-Version":"1.0","Content-Type":"text/plain; charset=utf-8","Content-Disposition":"inline","In-Reply-To":"<173073698028.2721096.12299227467236363203@ping.linuxembedded.co.uk>","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>"}},{"id":32019,"web_url":"https://patchwork.libcamera.org/comment/32019/","msgid":"<20241104225459.GD27775@pendragon.ideasonboard.com>","date":"2024-11-04T22:54:59","subject":"Re: [PATCH] v4l2: v4l2_camera_proxy: Fix VIDIOC_[GS]_PARM support","submitter":{"id":2,"url":"https://patchwork.libcamera.org/api/people/2/","name":"Laurent Pinchart","email":"laurent.pinchart@ideasonboard.com"},"content":"On Tue, Nov 05, 2024 at 12:10:35AM +0200, Laurent Pinchart wrote:\n> Hi Kieran,\n> \n> On Mon, Nov 04, 2024 at 04:16:20PM +0000, Kieran Bingham wrote:\n> > Quoting Laurent Pinchart (2024-11-04 15:38:25)\n> > > v4l2-compliance reports an error due to VIDIOC_S_PARM being supported\n> > > without VIDIOC_G_PARM. Fix it by implementing VIDIOC_G_PARM. To satisfy\n> > > all compliance tests, VIDIOC_S_PARM also needs to be updated to properly\n> > > zero reserved fields.\n> > \n> > Fixes tag ?\n> \n> It has never worked. I can point to the commit that introduced the\n> compat layer.\n> \n> > > Signed-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> > > diff --git a/src/v4l2/v4l2_camera.h b/src/v4l2/v4l2_camera.h\n> > > index e54371fb4e00..9bd161b909de 100644\n> > > --- a/src/v4l2/v4l2_camera.h\n> > > +++ b/src/v4l2/v4l2_camera.h\n> > > @@ -52,6 +52,7 @@ public:\n> > >                                   libcamera::StreamConfiguration *streamConfigOut);\n> > >  \n> > >         libcamera::ControlList &controls() { return controls_; }\n> > > +       const libcamera::ControlInfoMap &controlInfo() { return camera_->controls(); }\n> > >  \n> > >         int allocBuffers(unsigned int count);\n> > >         void freeBuffers();\n> > > diff --git a/src/v4l2/v4l2_camera_proxy.cpp b/src/v4l2/v4l2_camera_proxy.cpp\n> > > index 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> > >         v4l2PixFormat_.xfer_func    = V4L2_XFER_FUNC_DEFAULT;\n> > >  \n> > >         sizeimage_ = streamConfig.frameSize;\n> > > +\n> > > +       const ControlInfoMap &controls = vcam_->controlInfo();\n> > > +       const auto &it = controls.find(&controls::FrameDurationLimits);\n> > > +\n> > > +       if (it != controls.end()) {\n> > > +               const int64_t duration = it->second.def().get<int64_t>();\n> > > +\n> > > +               v4l2TimePerFrame_.numerator = duration;\n> > > +               v4l2TimePerFrame_.denominator = 1000000;\n> > > +       } else {\n> > > +               /*\n> > > +                * Default to 30fps if the camera doesn't expose the\n> > > +                * FrameDurationLimits control.\n> > > +                *\n> > > +                * \\todo Remove this once all pipeline handlers implement the\n> > > +                * control\n> > > +                */\n> > > +               LOG(V4L2Compat, Warning)\n> > > +                       << \"Camera does not support FrameDurationLimits\";\n> > > +\n> > > +               v4l2TimePerFrame_.numerator = 333333;\n> > > +               v4l2TimePerFrame_.denominator = 1000000;\n> > > +       }\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> > >         return ret;\n> > >  }\n> > >  \n> > > +int V4L2CameraProxy::vidioc_g_parm(V4L2CameraFile *file, struct v4l2_streamparm *arg)\n> > > +{\n> > > +       LOG(V4L2Compat, Debug)\n> > > +               << \"[\" << file->description() << \"] \" << __func__ << \"()\";\n> > > +\n> > > +       if (!validateBufferType(arg->type))\n> > > +               return -EINVAL;\n> > > +\n> > > +       memset(&arg->parm, 0, sizeof(arg->parm));\n> > > +\n> > > +       arg->parm.capture.capability = V4L2_CAP_TIMEPERFRAME;\n> > \n> > I guess this wasn't being handled at all before ?\n> \n> G_PARM wasn't handled at all. Or is your comment about something else ?\n> \n> > > +       arg->parm.capture.timeperframe = v4l2TimePerFrame_;\n> > \n> > What does this return /before/ the camera is configured? Does it work ?\n> \n> setFmtFromConfig() is called from the class constructor, so\n> v4l2TimePerFrame_ is always initialized.\n\nI meant the open() function, not the constructor, sorry. The conclusion\nstill holds.\n\n> > Otherwise seems like a good fix.\n> > \n> > \n> > Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com>\n> > \n> > > +\n> > > +       return 0;\n> > > +}\n> > > +\n> > >  int V4L2CameraProxy::vidioc_s_parm(V4L2CameraFile *file, struct v4l2_streamparm *arg)\n> > >  {\n> > >         LOG(V4L2Compat, Debug)\n> > > @@ -766,9 +805,25 @@ int V4L2CameraProxy::vidioc_s_parm(V4L2CameraFile *file, struct v4l2_streamparm\n> > >         if (!validateBufferType(arg->type))\n> > >                 return -EINVAL;\n> > >  \n> > > -       struct v4l2_fract *timeperframe = &arg->parm.capture.timeperframe;\n> > > -       utils::Duration frameDuration = 1.0s * timeperframe->numerator / timeperframe->denominator;\n> > > +       /*\n> > > +        * Store the frame duration if it is valid, otherwise keep the current\n> > > +        * value.\n> > > +        *\n> > > +        * \\todo The provided value should be adjusted based on the camera\n> > > +        * capabilities.\n> > > +        */\n> > > +       if (arg->parm.capture.timeperframe.numerator &&\n> > > +           arg->parm.capture.timeperframe.denominator)\n> > > +               v4l2TimePerFrame_ = arg->parm.capture.timeperframe;\n> > >  \n> > > +       memset(&arg->parm, 0, sizeof(arg->parm));\n> > > +\n> > > +       arg->parm.capture.capability = V4L2_CAP_TIMEPERFRAME;\n> > > +       arg->parm.capture.timeperframe = v4l2TimePerFrame_;\n> > > +\n> > > +       /* Apply the frame duration. */\n> > > +       utils::Duration frameDuration = 1.0s * v4l2TimePerFrame_.numerator\n> > > +                                     / v4l2TimePerFrame_.denominator;\n> > >         int64_t uDuration = frameDuration.get<std::micro>();\n> > >         vcam_->controls().set(controls::FrameDurationLimits, { uDuration, uDuration });\n> > >  \n> > > @@ -795,6 +850,7 @@ const std::set<unsigned long> V4L2CameraProxy::supportedIoctls_ = {\n> > >         VIDIOC_EXPBUF,\n> > >         VIDIOC_STREAMON,\n> > >         VIDIOC_STREAMOFF,\n> > > +       VIDIOC_G_PARM,\n> > >         VIDIOC_S_PARM,\n> > >  };\n> > >  \n> > > @@ -883,6 +939,9 @@ int V4L2CameraProxy::ioctl(V4L2CameraFile *file, unsigned long longRequest, void\n> > >         case VIDIOC_STREAMOFF:\n> > >                 ret = vidioc_streamoff(file, static_cast<int *>(arg));\n> > >                 break;\n> > > +       case VIDIOC_G_PARM:\n> > > +               ret = vidioc_g_parm(file, static_cast<struct v4l2_streamparm *>(arg));\n> > > +               break;\n> > >         case VIDIOC_S_PARM:\n> > >                 ret = vidioc_s_parm(file, static_cast<struct v4l2_streamparm *>(arg));\n> > >                 break;\n> > > diff --git a/src/v4l2/v4l2_camera_proxy.h b/src/v4l2/v4l2_camera_proxy.h\n> > > index 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> > >         int vidioc_expbuf(V4L2CameraFile *file, struct v4l2_exportbuffer *arg);\n> > >         int vidioc_streamon(V4L2CameraFile *file, int *arg);\n> > >         int vidioc_streamoff(V4L2CameraFile *file, int *arg);\n> > > +       int vidioc_g_parm(V4L2CameraFile *file, struct v4l2_streamparm *arg);\n> > >         int vidioc_s_parm(V4L2CameraFile *file, struct v4l2_streamparm *arg);\n> > >  \n> > >         bool hasOwnership(V4L2CameraFile *file);\n> > > @@ -85,6 +86,7 @@ private:\n> > >  \n> > >         struct v4l2_capability capabilities_;\n> > >         struct v4l2_pix_format v4l2PixFormat_;\n> > > +       struct v4l2_fract v4l2TimePerFrame_;\n> > >  \n> > >         std::vector<struct v4l2_buffer> buffers_;\n> > >         std::map<void *, unsigned int> mmaps_;\n> > > \n> > > base-commit: 58598f4dde9a3d4236ed52881da9b155443cbc50","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 10545BDC71\n\tfor <parsemail@patchwork.libcamera.org>;\n\tMon,  4 Nov 2024 22:55:09 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 1C1BD653E3;\n\tMon,  4 Nov 2024 23:55:08 +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 09FBB65399\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tMon,  4 Nov 2024 23:55:05 +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 4E054526;\n\tMon,  4 Nov 2024 23:54:58 +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=\"QDBteY4P\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1730760898;\n\tbh=tc0TP3w9vynIeQci9sUg+tMJmt3SlqOZJEkt5sg9cz8=;\n\th=Date:From:To:Cc:Subject:References:In-Reply-To:From;\n\tb=QDBteY4PYpFbJusP8yMa1AIEWLkrP5OSRLx2uGbXbjqtrTGIzkqRmgwRLvqQXWSnf\n\t1YnHwripo+EuDvB0B890Cyv30udkwrEwhbieg4U/vZN5XP5nGH97JfO7qZTvMZUjE8\n\tleLESOdWts87NZDQV+5ueYWrPPTewJaFqZrSbiAU=","Date":"Tue, 5 Nov 2024 00:54:59 +0200","From":"Laurent Pinchart <laurent.pinchart@ideasonboard.com>","To":"Kieran Bingham <kieran.bingham@ideasonboard.com>","Cc":"libcamera-devel@lists.libcamera.org,\n\tPaul Elder <paul.elder@ideasonboard.com>","Subject":"Re: [PATCH] v4l2: v4l2_camera_proxy: Fix VIDIOC_[GS]_PARM support","Message-ID":"<20241104225459.GD27775@pendragon.ideasonboard.com>","References":"<20241104153825.21053-1-laurent.pinchart@ideasonboard.com>\n\t<173073698028.2721096.12299227467236363203@ping.linuxembedded.co.uk>\n\t<20241104221035.GA19140@pendragon.ideasonboard.com>","MIME-Version":"1.0","Content-Type":"text/plain; charset=utf-8","Content-Disposition":"inline","In-Reply-To":"<20241104221035.GA19140@pendragon.ideasonboard.com>","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>"}},{"id":32021,"web_url":"https://patchwork.libcamera.org/comment/32021/","msgid":"<173079780144.3353069.17915569556417996806@ping.linuxembedded.co.uk>","date":"2024-11-05T09:10:01","subject":"Re: [PATCH] v4l2: v4l2_camera_proxy: Fix VIDIOC_[GS]_PARM support","submitter":{"id":4,"url":"https://patchwork.libcamera.org/api/people/4/","name":"Kieran Bingham","email":"kieran.bingham@ideasonboard.com"},"content":"Quoting Laurent Pinchart (2024-11-04 22:10:35)\n> Hi Kieran,\n> \n> On Mon, Nov 04, 2024 at 04:16:20PM +0000, Kieran Bingham wrote:\n> > Quoting Laurent Pinchart (2024-11-04 15:38:25)\n> > > v4l2-compliance reports an error due to VIDIOC_S_PARM being supported\n> > > without VIDIOC_G_PARM. Fix it by implementing VIDIOC_G_PARM. To satisfy\n> > > all compliance tests, VIDIOC_S_PARM also needs to be updated to properly\n> > > zero reserved fields.\n> > \n> > Fixes tag ?\n> \n> It has never worked. I can point to the commit that introduced the\n> compat layer.\n\nBut the VIDIOC_S_PARM was added?\n\n> > > Signed-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> > > diff --git a/src/v4l2/v4l2_camera.h b/src/v4l2/v4l2_camera.h\n> > > index e54371fb4e00..9bd161b909de 100644\n> > > --- a/src/v4l2/v4l2_camera.h\n> > > +++ b/src/v4l2/v4l2_camera.h\n> > > @@ -52,6 +52,7 @@ public:\n> > >                                   libcamera::StreamConfiguration *streamConfigOut);\n> > >  \n> > >         libcamera::ControlList &controls() { return controls_; }\n> > > +       const libcamera::ControlInfoMap &controlInfo() { return camera_->controls(); }\n> > >  \n> > >         int allocBuffers(unsigned int count);\n> > >         void freeBuffers();\n> > > diff --git a/src/v4l2/v4l2_camera_proxy.cpp b/src/v4l2/v4l2_camera_proxy.cpp\n> > > index 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> > >         v4l2PixFormat_.xfer_func    = V4L2_XFER_FUNC_DEFAULT;\n> > >  \n> > >         sizeimage_ = streamConfig.frameSize;\n> > > +\n> > > +       const ControlInfoMap &controls = vcam_->controlInfo();\n> > > +       const auto &it = controls.find(&controls::FrameDurationLimits);\n> > > +\n> > > +       if (it != controls.end()) {\n> > > +               const int64_t duration = it->second.def().get<int64_t>();\n> > > +\n> > > +               v4l2TimePerFrame_.numerator = duration;\n> > > +               v4l2TimePerFrame_.denominator = 1000000;\n> > > +       } else {\n> > > +               /*\n> > > +                * Default to 30fps if the camera doesn't expose the\n> > > +                * FrameDurationLimits control.\n> > > +                *\n> > > +                * \\todo Remove this once all pipeline handlers implement the\n> > > +                * control\n> > > +                */\n> > > +               LOG(V4L2Compat, Warning)\n> > > +                       << \"Camera does not support FrameDurationLimits\";\n> > > +\n> > > +               v4l2TimePerFrame_.numerator = 333333;\n> > > +               v4l2TimePerFrame_.denominator = 1000000;\n> > > +       }\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> > >         return ret;\n> > >  }\n> > >  \n> > > +int V4L2CameraProxy::vidioc_g_parm(V4L2CameraFile *file, struct v4l2_streamparm *arg)\n> > > +{\n> > > +       LOG(V4L2Compat, Debug)\n> > > +               << \"[\" << file->description() << \"] \" << __func__ << \"()\";\n> > > +\n> > > +       if (!validateBufferType(arg->type))\n> > > +               return -EINVAL;\n> > > +\n> > > +       memset(&arg->parm, 0, sizeof(arg->parm));\n> > > +\n> > > +       arg->parm.capture.capability = V4L2_CAP_TIMEPERFRAME;\n> > \n> > I guess this wasn't being handled at all before ?\n> \n> G_PARM wasn't handled at all. Or is your comment about something else ?\n> \n> > > +       arg->parm.capture.timeperframe = v4l2TimePerFrame_;\n> > \n> > What does this return /before/ the camera is configured? Does it work ?\n> \n> setFmtFromConfig() is called from the class constructor, so\n> v4l2TimePerFrame_ is always initialized.\n\nI meant that V4L2_CAP_TIMEPERFRAME wasn't used during\nV4L2CameraProxy::vidioc_s_parm before this patch...\n\n> \n> > Otherwise seems like a good fix.\n> > \n> > \n> > Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com>\n> > \n> > > +\n> > > +       return 0;\n> > > +}\n> > > +\n> > >  int V4L2CameraProxy::vidioc_s_parm(V4L2CameraFile *file, struct v4l2_streamparm *arg)\n> > >  {\n> > >         LOG(V4L2Compat, Debug)\n> > > @@ -766,9 +805,25 @@ int V4L2CameraProxy::vidioc_s_parm(V4L2CameraFile *file, struct v4l2_streamparm\n> > >         if (!validateBufferType(arg->type))\n> > >                 return -EINVAL;\n> > >  \n> > > -       struct v4l2_fract *timeperframe = &arg->parm.capture.timeperframe;\n> > > -       utils::Duration frameDuration = 1.0s * timeperframe->numerator / timeperframe->denominator;\n> > > +       /*\n> > > +        * Store the frame duration if it is valid, otherwise keep the current\n> > > +        * value.\n> > > +        *\n> > > +        * \\todo The provided value should be adjusted based on the camera\n> > > +        * capabilities.\n> > > +        */\n> > > +       if (arg->parm.capture.timeperframe.numerator &&\n> > > +           arg->parm.capture.timeperframe.denominator)\n> > > +               v4l2TimePerFrame_ = arg->parm.capture.timeperframe;\n> > >  \n> > > +       memset(&arg->parm, 0, sizeof(arg->parm));\n> > > +\n> > > +       arg->parm.capture.capability = V4L2_CAP_TIMEPERFRAME;\n> > > +       arg->parm.capture.timeperframe = v4l2TimePerFrame_;\n> > > +\n> > > +       /* Apply the frame duration. */\n> > > +       utils::Duration frameDuration = 1.0s * v4l2TimePerFrame_.numerator\n> > > +                                     / v4l2TimePerFrame_.denominator;\n> > >         int64_t uDuration = frameDuration.get<std::micro>();\n> > >         vcam_->controls().set(controls::FrameDurationLimits, { uDuration, uDuration });\n> > >  \n> > > @@ -795,6 +850,7 @@ const std::set<unsigned long> V4L2CameraProxy::supportedIoctls_ = {\n> > >         VIDIOC_EXPBUF,\n> > >         VIDIOC_STREAMON,\n> > >         VIDIOC_STREAMOFF,\n> > > +       VIDIOC_G_PARM,\n> > >         VIDIOC_S_PARM,\n> > >  };\n> > >  \n> > > @@ -883,6 +939,9 @@ int V4L2CameraProxy::ioctl(V4L2CameraFile *file, unsigned long longRequest, void\n> > >         case VIDIOC_STREAMOFF:\n> > >                 ret = vidioc_streamoff(file, static_cast<int *>(arg));\n> > >                 break;\n> > > +       case VIDIOC_G_PARM:\n> > > +               ret = vidioc_g_parm(file, static_cast<struct v4l2_streamparm *>(arg));\n> > > +               break;\n> > >         case VIDIOC_S_PARM:\n> > >                 ret = vidioc_s_parm(file, static_cast<struct v4l2_streamparm *>(arg));\n> > >                 break;\n> > > diff --git a/src/v4l2/v4l2_camera_proxy.h b/src/v4l2/v4l2_camera_proxy.h\n> > > index 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> > >         int vidioc_expbuf(V4L2CameraFile *file, struct v4l2_exportbuffer *arg);\n> > >         int vidioc_streamon(V4L2CameraFile *file, int *arg);\n> > >         int vidioc_streamoff(V4L2CameraFile *file, int *arg);\n> > > +       int vidioc_g_parm(V4L2CameraFile *file, struct v4l2_streamparm *arg);\n> > >         int vidioc_s_parm(V4L2CameraFile *file, struct v4l2_streamparm *arg);\n> > >  \n> > >         bool hasOwnership(V4L2CameraFile *file);\n> > > @@ -85,6 +86,7 @@ private:\n> > >  \n> > >         struct v4l2_capability capabilities_;\n> > >         struct v4l2_pix_format v4l2PixFormat_;\n> > > +       struct v4l2_fract v4l2TimePerFrame_;\n> > >  \n> > >         std::vector<struct v4l2_buffer> buffers_;\n> > >         std::map<void *, unsigned int> mmaps_;\n> > > \n> > > base-commit: 58598f4dde9a3d4236ed52881da9b155443cbc50\n> \n> -- \n> Regards,\n> \n> Laurent Pinchart","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 CA31BBE173\n\tfor <parsemail@patchwork.libcamera.org>;\n\tTue,  5 Nov 2024 09:10:07 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id AFD5B653E7;\n\tTue,  5 Nov 2024 10:10:06 +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 7A9E96035B\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tTue,  5 Nov 2024 10:10:04 +0100 (CET)","from pendragon.ideasonboard.com\n\t(cpc89244-aztw30-2-0-cust6594.18-1.cable.virginm.net [86.31.185.195])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id BBE1021C;\n\tTue,  5 Nov 2024 10:09:56 +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=\"Z65gVpEI\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1730797796;\n\tbh=y0GXfHFa06GaHzc7uEg08YnfqL+IXYf9gzbD55tf160=;\n\th=In-Reply-To:References:Subject:From:Cc:To:Date:From;\n\tb=Z65gVpEIvmSbVLgQPjglCpuCvoHeR2smSd7Tz/ZhPKLrwcwVa3KWfORUZZO0iK5V/\n\tR/zdJyPR0ba09ja+xSfucKXEXyNflQ2EETp7ycGPigZltQfa+/ce+TpnVQn5iVKVQt\n\t+BurryVDzXWOOrldpp02cJlO9ejvgh05ahhyLr3A=","Content-Type":"text/plain; charset=\"utf-8\"","MIME-Version":"1.0","Content-Transfer-Encoding":"quoted-printable","In-Reply-To":"<20241104221035.GA19140@pendragon.ideasonboard.com>","References":"<20241104153825.21053-1-laurent.pinchart@ideasonboard.com>\n\t<173073698028.2721096.12299227467236363203@ping.linuxembedded.co.uk>\n\t<20241104221035.GA19140@pendragon.ideasonboard.com>","Subject":"Re: [PATCH] v4l2: v4l2_camera_proxy: Fix VIDIOC_[GS]_PARM support","From":"Kieran Bingham <kieran.bingham@ideasonboard.com>","Cc":"libcamera-devel@lists.libcamera.org,\n\tPaul Elder <paul.elder@ideasonboard.com>","To":"Laurent Pinchart <laurent.pinchart@ideasonboard.com>","Date":"Tue, 05 Nov 2024 09:10:01 +0000","Message-ID":"<173079780144.3353069.17915569556417996806@ping.linuxembedded.co.uk>","User-Agent":"alot/0.10","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>"}},{"id":32022,"web_url":"https://patchwork.libcamera.org/comment/32022/","msgid":"<20241105092336.GI27775@pendragon.ideasonboard.com>","date":"2024-11-05T09:23:36","subject":"Re: [PATCH] v4l2: v4l2_camera_proxy: Fix VIDIOC_[GS]_PARM support","submitter":{"id":2,"url":"https://patchwork.libcamera.org/api/people/2/","name":"Laurent Pinchart","email":"laurent.pinchart@ideasonboard.com"},"content":"On Tue, Nov 05, 2024 at 09:10:01AM +0000, Kieran Bingham wrote:\n> Quoting Laurent Pinchart (2024-11-04 22:10:35)\n> > On Mon, Nov 04, 2024 at 04:16:20PM +0000, Kieran Bingham wrote:\n> > > Quoting Laurent Pinchart (2024-11-04 15:38:25)\n> > > > v4l2-compliance reports an error due to VIDIOC_S_PARM being supported\n> > > > without VIDIOC_G_PARM. Fix it by implementing VIDIOC_G_PARM. To satisfy\n> > > > all compliance tests, VIDIOC_S_PARM also needs to be updated to properly\n> > > > zero reserved fields.\n> > > \n> > > Fixes tag ?\n> > \n> > It has never worked. I can point to the commit that introduced the\n> > compat layer.\n> \n> But the VIDIOC_S_PARM was added?\n\nI'll use\n\nFixes: 5456e02d3f5b (\"v4l2: Support setting frame rate in the V4L2 Adaptation layer\")\n\n> > > > Signed-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> > > > diff --git a/src/v4l2/v4l2_camera.h b/src/v4l2/v4l2_camera.h\n> > > > index e54371fb4e00..9bd161b909de 100644\n> > > > --- a/src/v4l2/v4l2_camera.h\n> > > > +++ b/src/v4l2/v4l2_camera.h\n> > > > @@ -52,6 +52,7 @@ public:\n> > > >                                   libcamera::StreamConfiguration *streamConfigOut);\n> > > >  \n> > > >         libcamera::ControlList &controls() { return controls_; }\n> > > > +       const libcamera::ControlInfoMap &controlInfo() { return camera_->controls(); }\n> > > >  \n> > > >         int allocBuffers(unsigned int count);\n> > > >         void freeBuffers();\n> > > > diff --git a/src/v4l2/v4l2_camera_proxy.cpp b/src/v4l2/v4l2_camera_proxy.cpp\n> > > > index 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> > > >         v4l2PixFormat_.xfer_func    = V4L2_XFER_FUNC_DEFAULT;\n> > > >  \n> > > >         sizeimage_ = streamConfig.frameSize;\n> > > > +\n> > > > +       const ControlInfoMap &controls = vcam_->controlInfo();\n> > > > +       const auto &it = controls.find(&controls::FrameDurationLimits);\n> > > > +\n> > > > +       if (it != controls.end()) {\n> > > > +               const int64_t duration = it->second.def().get<int64_t>();\n> > > > +\n> > > > +               v4l2TimePerFrame_.numerator = duration;\n> > > > +               v4l2TimePerFrame_.denominator = 1000000;\n> > > > +       } else {\n> > > > +               /*\n> > > > +                * Default to 30fps if the camera doesn't expose the\n> > > > +                * FrameDurationLimits control.\n> > > > +                *\n> > > > +                * \\todo Remove this once all pipeline handlers implement the\n> > > > +                * control\n> > > > +                */\n> > > > +               LOG(V4L2Compat, Warning)\n> > > > +                       << \"Camera does not support FrameDurationLimits\";\n> > > > +\n> > > > +               v4l2TimePerFrame_.numerator = 333333;\n> > > > +               v4l2TimePerFrame_.denominator = 1000000;\n> > > > +       }\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> > > >         return ret;\n> > > >  }\n> > > >  \n> > > > +int V4L2CameraProxy::vidioc_g_parm(V4L2CameraFile *file, struct v4l2_streamparm *arg)\n> > > > +{\n> > > > +       LOG(V4L2Compat, Debug)\n> > > > +               << \"[\" << file->description() << \"] \" << __func__ << \"()\";\n> > > > +\n> > > > +       if (!validateBufferType(arg->type))\n> > > > +               return -EINVAL;\n> > > > +\n> > > > +       memset(&arg->parm, 0, sizeof(arg->parm));\n> > > > +\n> > > > +       arg->parm.capture.capability = V4L2_CAP_TIMEPERFRAME;\n> > > \n> > > I guess this wasn't being handled at all before ?\n> > \n> > G_PARM wasn't handled at all. Or is your comment about something else ?\n> > \n> > > > +       arg->parm.capture.timeperframe = v4l2TimePerFrame_;\n> > > \n> > > What does this return /before/ the camera is configured? Does it work ?\n> > \n> > setFmtFromConfig() is called from the class constructor, so\n> > v4l2TimePerFrame_ is always initialized.\n> \n> I meant that V4L2_CAP_TIMEPERFRAME wasn't used during\n> V4L2CameraProxy::vidioc_s_parm before this patch...\n\nI right. Yes, this patch also modified vidioc_s_parm() below to handle\nV4L2_CAP_TIMEPERFRAME.\n\nI thought about addressing that in a separate patch, but (if I recall\ncorrectly) it then causes another compliance issue if g_parm isn't set.\nIt was not immediately possible to test that change independently, so I\nended up bundling everything in a single patch.\n\n> > > Otherwise seems like a good fix.\n> > > \n> > > \n> > > Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com>\n> > > \n> > > > +\n> > > > +       return 0;\n> > > > +}\n> > > > +\n> > > >  int V4L2CameraProxy::vidioc_s_parm(V4L2CameraFile *file, struct v4l2_streamparm *arg)\n> > > >  {\n> > > >         LOG(V4L2Compat, Debug)\n> > > > @@ -766,9 +805,25 @@ int V4L2CameraProxy::vidioc_s_parm(V4L2CameraFile *file, struct v4l2_streamparm\n> > > >         if (!validateBufferType(arg->type))\n> > > >                 return -EINVAL;\n> > > >  \n> > > > -       struct v4l2_fract *timeperframe = &arg->parm.capture.timeperframe;\n> > > > -       utils::Duration frameDuration = 1.0s * timeperframe->numerator / timeperframe->denominator;\n> > > > +       /*\n> > > > +        * Store the frame duration if it is valid, otherwise keep the current\n> > > > +        * value.\n> > > > +        *\n> > > > +        * \\todo The provided value should be adjusted based on the camera\n> > > > +        * capabilities.\n> > > > +        */\n> > > > +       if (arg->parm.capture.timeperframe.numerator &&\n> > > > +           arg->parm.capture.timeperframe.denominator)\n> > > > +               v4l2TimePerFrame_ = arg->parm.capture.timeperframe;\n> > > >  \n> > > > +       memset(&arg->parm, 0, sizeof(arg->parm));\n> > > > +\n> > > > +       arg->parm.capture.capability = V4L2_CAP_TIMEPERFRAME;\n> > > > +       arg->parm.capture.timeperframe = v4l2TimePerFrame_;\n> > > > +\n> > > > +       /* Apply the frame duration. */\n> > > > +       utils::Duration frameDuration = 1.0s * v4l2TimePerFrame_.numerator\n> > > > +                                     / v4l2TimePerFrame_.denominator;\n> > > >         int64_t uDuration = frameDuration.get<std::micro>();\n> > > >         vcam_->controls().set(controls::FrameDurationLimits, { uDuration, uDuration });\n> > > >  \n> > > > @@ -795,6 +850,7 @@ const std::set<unsigned long> V4L2CameraProxy::supportedIoctls_ = {\n> > > >         VIDIOC_EXPBUF,\n> > > >         VIDIOC_STREAMON,\n> > > >         VIDIOC_STREAMOFF,\n> > > > +       VIDIOC_G_PARM,\n> > > >         VIDIOC_S_PARM,\n> > > >  };\n> > > >  \n> > > > @@ -883,6 +939,9 @@ int V4L2CameraProxy::ioctl(V4L2CameraFile *file, unsigned long longRequest, void\n> > > >         case VIDIOC_STREAMOFF:\n> > > >                 ret = vidioc_streamoff(file, static_cast<int *>(arg));\n> > > >                 break;\n> > > > +       case VIDIOC_G_PARM:\n> > > > +               ret = vidioc_g_parm(file, static_cast<struct v4l2_streamparm *>(arg));\n> > > > +               break;\n> > > >         case VIDIOC_S_PARM:\n> > > >                 ret = vidioc_s_parm(file, static_cast<struct v4l2_streamparm *>(arg));\n> > > >                 break;\n> > > > diff --git a/src/v4l2/v4l2_camera_proxy.h b/src/v4l2/v4l2_camera_proxy.h\n> > > > index 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> > > >         int vidioc_expbuf(V4L2CameraFile *file, struct v4l2_exportbuffer *arg);\n> > > >         int vidioc_streamon(V4L2CameraFile *file, int *arg);\n> > > >         int vidioc_streamoff(V4L2CameraFile *file, int *arg);\n> > > > +       int vidioc_g_parm(V4L2CameraFile *file, struct v4l2_streamparm *arg);\n> > > >         int vidioc_s_parm(V4L2CameraFile *file, struct v4l2_streamparm *arg);\n> > > >  \n> > > >         bool hasOwnership(V4L2CameraFile *file);\n> > > > @@ -85,6 +86,7 @@ private:\n> > > >  \n> > > >         struct v4l2_capability capabilities_;\n> > > >         struct v4l2_pix_format v4l2PixFormat_;\n> > > > +       struct v4l2_fract v4l2TimePerFrame_;\n> > > >  \n> > > >         std::vector<struct v4l2_buffer> buffers_;\n> > > >         std::map<void *, unsigned int> mmaps_;\n> > > > \n> > > > base-commit: 58598f4dde9a3d4236ed52881da9b155443cbc50","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 88C6EBDB1C\n\tfor <parsemail@patchwork.libcamera.org>;\n\tTue,  5 Nov 2024 09:23:45 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 81D06653E7;\n\tTue,  5 Nov 2024 10:23:44 +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 8E0B76035B\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tTue,  5 Nov 2024 10:23:42 +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 1C83C21C;\n\tTue,  5 Nov 2024 10:23:35 +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=\"EHzvlQRD\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1730798615;\n\tbh=+rRAzqJ5Wndyfs+kG/L7/fq5uI27TOMdGKl5vFtiaSc=;\n\th=Date:From:To:Cc:Subject:References:In-Reply-To:From;\n\tb=EHzvlQRDMq+cavM0dFpAk7yX3Rh24CXqZIB5LZUScS/Xa51azDsa4QiFkXSGeLtBd\n\tB/tZ7LdltnZE+q02pKRiiZcMZMpGUqzKYynGgE3JBtuZdl8vxwt3l8k4TqesKzn0O/\n\tEPPr4wlbNblLQGvRtJ4RJC9YzkpUsinD73Bb3KYE=","Date":"Tue, 5 Nov 2024 11:23:36 +0200","From":"Laurent Pinchart <laurent.pinchart@ideasonboard.com>","To":"Kieran Bingham <kieran.bingham@ideasonboard.com>","Cc":"libcamera-devel@lists.libcamera.org,\n\tPaul Elder <paul.elder@ideasonboard.com>","Subject":"Re: [PATCH] v4l2: v4l2_camera_proxy: Fix VIDIOC_[GS]_PARM support","Message-ID":"<20241105092336.GI27775@pendragon.ideasonboard.com>","References":"<20241104153825.21053-1-laurent.pinchart@ideasonboard.com>\n\t<173073698028.2721096.12299227467236363203@ping.linuxembedded.co.uk>\n\t<20241104221035.GA19140@pendragon.ideasonboard.com>\n\t<173079780144.3353069.17915569556417996806@ping.linuxembedded.co.uk>","MIME-Version":"1.0","Content-Type":"text/plain; charset=utf-8","Content-Disposition":"inline","In-Reply-To":"<173079780144.3353069.17915569556417996806@ping.linuxembedded.co.uk>","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>"}},{"id":32024,"web_url":"https://patchwork.libcamera.org/comment/32024/","msgid":"<173080110207.3353069.4638004017506979514@ping.linuxembedded.co.uk>","date":"2024-11-05T10:05:02","subject":"Re: [PATCH] v4l2: v4l2_camera_proxy: Fix VIDIOC_[GS]_PARM support","submitter":{"id":4,"url":"https://patchwork.libcamera.org/api/people/4/","name":"Kieran Bingham","email":"kieran.bingham@ideasonboard.com"},"content":"Quoting Laurent Pinchart (2024-11-05 09:23:36)\n> On Tue, Nov 05, 2024 at 09:10:01AM +0000, Kieran Bingham wrote:\n> > Quoting Laurent Pinchart (2024-11-04 22:10:35)\n> > > On Mon, Nov 04, 2024 at 04:16:20PM +0000, Kieran Bingham wrote:\n> > > > Quoting Laurent Pinchart (2024-11-04 15:38:25)\n> > > > > v4l2-compliance reports an error due to VIDIOC_S_PARM being supported\n> > > > > without VIDIOC_G_PARM. Fix it by implementing VIDIOC_G_PARM. To satisfy\n> > > > > all compliance tests, VIDIOC_S_PARM also needs to be updated to properly\n> > > > > zero reserved fields.\n> > > > \n> > > > Fixes tag ?\n> > > \n> > > It has never worked. I can point to the commit that introduced the\n> > > compat layer.\n> > \n> > But the VIDIOC_S_PARM was added?\n> \n> I'll use\n> \n> Fixes: 5456e02d3f5b (\"v4l2: Support setting frame rate in the V4L2 Adaptation layer\")\n\nAck, that's what I was expecting..\n\n> \n> > > > > Signed-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> > > > > diff --git a/src/v4l2/v4l2_camera.h b/src/v4l2/v4l2_camera.h\n> > > > > index e54371fb4e00..9bd161b909de 100644\n> > > > > --- a/src/v4l2/v4l2_camera.h\n> > > > > +++ b/src/v4l2/v4l2_camera.h\n> > > > > @@ -52,6 +52,7 @@ public:\n> > > > >                                   libcamera::StreamConfiguration *streamConfigOut);\n> > > > >  \n> > > > >         libcamera::ControlList &controls() { return controls_; }\n> > > > > +       const libcamera::ControlInfoMap &controlInfo() { return camera_->controls(); }\n> > > > >  \n> > > > >         int allocBuffers(unsigned int count);\n> > > > >         void freeBuffers();\n> > > > > diff --git a/src/v4l2/v4l2_camera_proxy.cpp b/src/v4l2/v4l2_camera_proxy.cpp\n> > > > > index 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> > > > >         v4l2PixFormat_.xfer_func    = V4L2_XFER_FUNC_DEFAULT;\n> > > > >  \n> > > > >         sizeimage_ = streamConfig.frameSize;\n> > > > > +\n> > > > > +       const ControlInfoMap &controls = vcam_->controlInfo();\n> > > > > +       const auto &it = controls.find(&controls::FrameDurationLimits);\n> > > > > +\n> > > > > +       if (it != controls.end()) {\n> > > > > +               const int64_t duration = it->second.def().get<int64_t>();\n> > > > > +\n> > > > > +               v4l2TimePerFrame_.numerator = duration;\n> > > > > +               v4l2TimePerFrame_.denominator = 1000000;\n> > > > > +       } else {\n> > > > > +               /*\n> > > > > +                * Default to 30fps if the camera doesn't expose the\n> > > > > +                * FrameDurationLimits control.\n> > > > > +                *\n> > > > > +                * \\todo Remove this once all pipeline handlers implement the\n> > > > > +                * control\n> > > > > +                */\n> > > > > +               LOG(V4L2Compat, Warning)\n> > > > > +                       << \"Camera does not support FrameDurationLimits\";\n> > > > > +\n> > > > > +               v4l2TimePerFrame_.numerator = 333333;\n> > > > > +               v4l2TimePerFrame_.denominator = 1000000;\n> > > > > +       }\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> > > > >         return ret;\n> > > > >  }\n> > > > >  \n> > > > > +int V4L2CameraProxy::vidioc_g_parm(V4L2CameraFile *file, struct v4l2_streamparm *arg)\n> > > > > +{\n> > > > > +       LOG(V4L2Compat, Debug)\n> > > > > +               << \"[\" << file->description() << \"] \" << __func__ << \"()\";\n> > > > > +\n> > > > > +       if (!validateBufferType(arg->type))\n> > > > > +               return -EINVAL;\n> > > > > +\n> > > > > +       memset(&arg->parm, 0, sizeof(arg->parm));\n> > > > > +\n> > > > > +       arg->parm.capture.capability = V4L2_CAP_TIMEPERFRAME;\n> > > > \n> > > > I guess this wasn't being handled at all before ?\n> > > \n> > > G_PARM wasn't handled at all. Or is your comment about something else ?\n> > > \n> > > > > +       arg->parm.capture.timeperframe = v4l2TimePerFrame_;\n> > > > \n> > > > What does this return /before/ the camera is configured? Does it work ?\n> > > \n> > > setFmtFromConfig() is called from the class constructor, so\n> > > v4l2TimePerFrame_ is always initialized.\n> > \n> > I meant that V4L2_CAP_TIMEPERFRAME wasn't used during\n> > V4L2CameraProxy::vidioc_s_parm before this patch...\n> \n> I right. Yes, this patch also modified vidioc_s_parm() below to handle\n> V4L2_CAP_TIMEPERFRAME.\n> \n> I thought about addressing that in a separate patch, but (if I recall\n> correctly) it then causes another compliance issue if g_parm isn't set.\n> It was not immediately possible to test that change independently, so I\n> ended up bundling everything in a single patch.\n\nTogether is fine with me.\n\nThe Fixes tag will mean it will appear in the Fixes section of the next\nlibcamera release notes. That's the only reason I care for it ;-)\n\n--\nKieran\n\n\n> \n> > > > Otherwise seems like a good fix.\n> > > > \n> > > > \n> > > > Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com>\n> > > > \n> > > > > +\n> > > > > +       return 0;\n> > > > > +}\n> > > > > +\n> > > > >  int V4L2CameraProxy::vidioc_s_parm(V4L2CameraFile *file, struct v4l2_streamparm *arg)\n> > > > >  {\n> > > > >         LOG(V4L2Compat, Debug)\n> > > > > @@ -766,9 +805,25 @@ int V4L2CameraProxy::vidioc_s_parm(V4L2CameraFile *file, struct v4l2_streamparm\n> > > > >         if (!validateBufferType(arg->type))\n> > > > >                 return -EINVAL;\n> > > > >  \n> > > > > -       struct v4l2_fract *timeperframe = &arg->parm.capture.timeperframe;\n> > > > > -       utils::Duration frameDuration = 1.0s * timeperframe->numerator / timeperframe->denominator;\n> > > > > +       /*\n> > > > > +        * Store the frame duration if it is valid, otherwise keep the current\n> > > > > +        * value.\n> > > > > +        *\n> > > > > +        * \\todo The provided value should be adjusted based on the camera\n> > > > > +        * capabilities.\n> > > > > +        */\n> > > > > +       if (arg->parm.capture.timeperframe.numerator &&\n> > > > > +           arg->parm.capture.timeperframe.denominator)\n> > > > > +               v4l2TimePerFrame_ = arg->parm.capture.timeperframe;\n> > > > >  \n> > > > > +       memset(&arg->parm, 0, sizeof(arg->parm));\n> > > > > +\n> > > > > +       arg->parm.capture.capability = V4L2_CAP_TIMEPERFRAME;\n> > > > > +       arg->parm.capture.timeperframe = v4l2TimePerFrame_;\n> > > > > +\n> > > > > +       /* Apply the frame duration. */\n> > > > > +       utils::Duration frameDuration = 1.0s * v4l2TimePerFrame_.numerator\n> > > > > +                                     / v4l2TimePerFrame_.denominator;\n> > > > >         int64_t uDuration = frameDuration.get<std::micro>();\n> > > > >         vcam_->controls().set(controls::FrameDurationLimits, { uDuration, uDuration });\n> > > > >  \n> > > > > @@ -795,6 +850,7 @@ const std::set<unsigned long> V4L2CameraProxy::supportedIoctls_ = {\n> > > > >         VIDIOC_EXPBUF,\n> > > > >         VIDIOC_STREAMON,\n> > > > >         VIDIOC_STREAMOFF,\n> > > > > +       VIDIOC_G_PARM,\n> > > > >         VIDIOC_S_PARM,\n> > > > >  };\n> > > > >  \n> > > > > @@ -883,6 +939,9 @@ int V4L2CameraProxy::ioctl(V4L2CameraFile *file, unsigned long longRequest, void\n> > > > >         case VIDIOC_STREAMOFF:\n> > > > >                 ret = vidioc_streamoff(file, static_cast<int *>(arg));\n> > > > >                 break;\n> > > > > +       case VIDIOC_G_PARM:\n> > > > > +               ret = vidioc_g_parm(file, static_cast<struct v4l2_streamparm *>(arg));\n> > > > > +               break;\n> > > > >         case VIDIOC_S_PARM:\n> > > > >                 ret = vidioc_s_parm(file, static_cast<struct v4l2_streamparm *>(arg));\n> > > > >                 break;\n> > > > > diff --git a/src/v4l2/v4l2_camera_proxy.h b/src/v4l2/v4l2_camera_proxy.h\n> > > > > index 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> > > > >         int vidioc_expbuf(V4L2CameraFile *file, struct v4l2_exportbuffer *arg);\n> > > > >         int vidioc_streamon(V4L2CameraFile *file, int *arg);\n> > > > >         int vidioc_streamoff(V4L2CameraFile *file, int *arg);\n> > > > > +       int vidioc_g_parm(V4L2CameraFile *file, struct v4l2_streamparm *arg);\n> > > > >         int vidioc_s_parm(V4L2CameraFile *file, struct v4l2_streamparm *arg);\n> > > > >  \n> > > > >         bool hasOwnership(V4L2CameraFile *file);\n> > > > > @@ -85,6 +86,7 @@ private:\n> > > > >  \n> > > > >         struct v4l2_capability capabilities_;\n> > > > >         struct v4l2_pix_format v4l2PixFormat_;\n> > > > > +       struct v4l2_fract v4l2TimePerFrame_;\n> > > > >  \n> > > > >         std::vector<struct v4l2_buffer> buffers_;\n> > > > >         std::map<void *, unsigned int> mmaps_;\n> > > > > \n> > > > > base-commit: 58598f4dde9a3d4236ed52881da9b155443cbc50\n> \n> -- \n> Regards,\n> \n> Laurent Pinchart","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 80E97BDB1C\n\tfor <parsemail@patchwork.libcamera.org>;\n\tTue,  5 Nov 2024 10:05:10 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 548FE653EA;\n\tTue,  5 Nov 2024 11:05:09 +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 2E3E06035B\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tTue,  5 Nov 2024 11:05:07 +0100 (CET)","from pendragon.ideasonboard.com\n\t(cpc89244-aztw30-2-0-cust6594.18-1.cable.virginm.net [86.31.185.195])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id D7AE121C;\n\tTue,  5 Nov 2024 11:04:58 +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=\"BJhxGzMe\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1730801099;\n\tbh=2R2T7aFlZFUVY0yQVtw0mt+V9q2bHy/RV8zPLr5UN/Q=;\n\th=In-Reply-To:References:Subject:From:Cc:To:Date:From;\n\tb=BJhxGzMe6qBEGnRvdkLb4cOVBqfbuGNli4SdNra1Fyz+Ke6SG/f0vEsl0Ha7L3CJD\n\tucOGElj91LXevT5Dfkata+RyXddLytQg9vSuJbuwwoYeHF4nu6BqZfIHNmV2TNYB08\n\tSrqxkvJ0Ghokp+MvqFETspf+/1ymrQM6ZezdUFgA=","Content-Type":"text/plain; charset=\"utf-8\"","MIME-Version":"1.0","Content-Transfer-Encoding":"quoted-printable","In-Reply-To":"<20241105092336.GI27775@pendragon.ideasonboard.com>","References":"<20241104153825.21053-1-laurent.pinchart@ideasonboard.com>\n\t<173073698028.2721096.12299227467236363203@ping.linuxembedded.co.uk>\n\t<20241104221035.GA19140@pendragon.ideasonboard.com>\n\t<173079780144.3353069.17915569556417996806@ping.linuxembedded.co.uk>\n\t<20241105092336.GI27775@pendragon.ideasonboard.com>","Subject":"Re: [PATCH] v4l2: v4l2_camera_proxy: Fix VIDIOC_[GS]_PARM support","From":"Kieran Bingham <kieran.bingham@ideasonboard.com>","Cc":"libcamera-devel@lists.libcamera.org,\n\tPaul Elder <paul.elder@ideasonboard.com>","To":"Laurent Pinchart <laurent.pinchart@ideasonboard.com>","Date":"Tue, 05 Nov 2024 10:05:02 +0000","Message-ID":"<173080110207.3353069.4638004017506979514@ping.linuxembedded.co.uk>","User-Agent":"alot/0.10","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>"}},{"id":32031,"web_url":"https://patchwork.libcamera.org/comment/32031/","msgid":"<ZyoFCEwaKwkcKaS2@pyrite.rasen.tech>","date":"2024-11-05T11:44:08","subject":"Re: [PATCH] v4l2: v4l2_camera_proxy: Fix VIDIOC_[GS]_PARM support","submitter":{"id":17,"url":"https://patchwork.libcamera.org/api/people/17/","name":"Paul Elder","email":"paul.elder@ideasonboard.com"},"content":"On Mon, Nov 04, 2024 at 05:38:25PM +0200, Laurent Pinchart wrote:\n> v4l2-compliance reports an error due to VIDIOC_S_PARM being supported\n> without VIDIOC_G_PARM. Fix it by implementing VIDIOC_G_PARM. To satisfy\n> all compliance tests, VIDIOC_S_PARM also needs to be updated to properly\n> zero reserved fields.\n> \n> Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>\n\nLooks good to me.\n\nReviewed-by: Paul Elder <paul.elder@ideasonboard.com>\n\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> diff --git a/src/v4l2/v4l2_camera.h b/src/v4l2/v4l2_camera.h\n> index 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();\n> diff --git a/src/v4l2/v4l2_camera_proxy.cpp b/src/v4l2/v4l2_camera_proxy.cpp\n> index 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;\n> diff --git a/src/v4l2/v4l2_camera_proxy.h b/src/v4l2/v4l2_camera_proxy.h\n> index 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> \n> base-commit: 58598f4dde9a3d4236ed52881da9b155443cbc50\n> -- \n> Regards,\n> \n> Laurent Pinchart\n>","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 951B3BE173\n\tfor <parsemail@patchwork.libcamera.org>;\n\tTue,  5 Nov 2024 11:44:19 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id AC12B6035B;\n\tTue,  5 Nov 2024 12:44:18 +0100 (CET)","from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[213.167.242.64])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id A3DE46035B\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tTue,  5 Nov 2024 12:44:16 +0100 (CET)","from pyrite.rasen.tech (unknown\n\t[IPv6:2404:7a81:160:2100:aeeb:73f4:759a:31aa])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id 4ACAE22E;\n\tTue,  5 Nov 2024 12:44:08 +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=\"Jl7X5A0V\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1730807049;\n\tbh=LiuoHVhbc04ZlrFmQMtW0YAckfSexrftiiakzekVfw8=;\n\th=Date:From:To:Cc:Subject:References:In-Reply-To:From;\n\tb=Jl7X5A0VLImYPgiWflSBj/8O+W9Qb9Dz/2Vi6wbVgvApwVE6WdALGXz1BMnqESqix\n\ts9heh+WE1uu2NY+D13R2qXGPBvkQWJ1UAXauppGkT17+wPiJ8SWfQwkl5F1jtK5+5f\n\trQ6xPlAnM3wRK5NW1J8+ixwhJWl9L+bBCkNoVlKk=","Date":"Tue, 5 Nov 2024 20:44:08 +0900","From":"Paul Elder <paul.elder@ideasonboard.com>","To":"Laurent Pinchart <laurent.pinchart@ideasonboard.com>","Cc":"libcamera-devel@lists.libcamera.org","Subject":"Re: [PATCH] v4l2: v4l2_camera_proxy: Fix VIDIOC_[GS]_PARM support","Message-ID":"<ZyoFCEwaKwkcKaS2@pyrite.rasen.tech>","References":"<20241104153825.21053-1-laurent.pinchart@ideasonboard.com>","MIME-Version":"1.0","Content-Type":"text/plain; charset=us-ascii","Content-Disposition":"inline","In-Reply-To":"<20241104153825.21053-1-laurent.pinchart@ideasonboard.com>","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>"}}]