[{"id":23564,"web_url":"https://patchwork.libcamera.org/comment/23564/","msgid":"<165605893776.1149771.3323508296523593025@Monstersaurus>","date":"2022-06-24T08:22:17","subject":"Re: [libcamera-devel] [RFC v1 3/7] py: Move ControlValue helpers to\n\tpy_helpers.cpp","submitter":{"id":4,"url":"https://patchwork.libcamera.org/api/people/4/","name":"Kieran Bingham","email":"kieran.bingham@ideasonboard.com"},"content":"Quoting Tomi Valkeinen (2022-06-23 15:47:32)\n> Clean up the py_main.cpp a bit by moving the ControlValue helpers to a\n> separate file.\n> \n> Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>\n> ---\n>  src/py/libcamera/meson.build    |  1 +\n>  src/py/libcamera/py_helpers.cpp | 98 +++++++++++++++++++++++++++++++++\n>  src/py/libcamera/py_helpers.h   | 13 +++++\n>  src/py/libcamera/py_main.cpp    | 83 +---------------------------\n>  4 files changed, 114 insertions(+), 81 deletions(-)\n>  create mode 100644 src/py/libcamera/py_helpers.cpp\n>  create mode 100644 src/py/libcamera/py_helpers.h\n> \n> diff --git a/src/py/libcamera/meson.build b/src/py/libcamera/meson.build\n> index eb884538..04578bac 100644\n> --- a/src/py/libcamera/meson.build\n> +++ b/src/py/libcamera/meson.build\n> @@ -15,6 +15,7 @@ pybind11_dep = pybind11_proj.get_variable('pybind11_dep')\n>  pycamera_sources = files([\n>      'py_enums.cpp',\n>      'py_geometry.cpp',\n> +    'py_helpers.cpp',\n\nShould this be called py_controls? Or do you expect other support code\nto go in here too. Or maybe it's more about types, 'py_types' ..\n\n\n>      'py_main.cpp',\n>  ])\n>  \n> diff --git a/src/py/libcamera/py_helpers.cpp b/src/py/libcamera/py_helpers.cpp\n> new file mode 100644\n> index 00000000..d0a8b5c4\n> --- /dev/null\n> +++ b/src/py/libcamera/py_helpers.cpp\n> @@ -0,0 +1,98 @@\n> +/* SPDX-License-Identifier: LGPL-2.1-or-later */\n> +/*\n> + * Copyright (C) 2022, Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>\n> + */\n> +\n> +#include \"py_helpers.h\"\n> +\n> +#include <libcamera/libcamera.h>\n> +\n> +#include <pybind11/functional.h>\n> +#include <pybind11/smart_holder.h>\n\nYou have this in the py_helpers header too, so I don't think it needs to\nbe duplicated here.\n\nWhat's it used for? I thought it was just for the Camera destructor or\nsomething, I don't see Camera used here ?\n\nAnyway, the code move to it's own component file makes sense to me.\n\n\nReviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com>\n\n> +#include <pybind11/stl.h>\n> +#include <pybind11/stl_bind.h>\n> +\n> +namespace py = pybind11;\n> +\n> +using namespace libcamera;\n> +\n> +template<typename T>\n> +static py::object valueOrTuple(const ControlValue &cv)\n> +{\n> +       if (cv.isArray()) {\n> +               const T *v = reinterpret_cast<const T *>(cv.data().data());\n> +               auto t = py::tuple(cv.numElements());\n> +\n> +               for (size_t i = 0; i < cv.numElements(); ++i)\n> +                       t[i] = v[i];\n> +\n> +               return std::move(t);\n> +       }\n> +\n> +       return py::cast(cv.get<T>());\n> +}\n> +\n> +py::object controlValueToPy(const ControlValue &cv)\n> +{\n> +       switch (cv.type()) {\n> +       case ControlTypeBool:\n> +               return valueOrTuple<bool>(cv);\n> +       case ControlTypeByte:\n> +               return valueOrTuple<uint8_t>(cv);\n> +       case ControlTypeInteger32:\n> +               return valueOrTuple<int32_t>(cv);\n> +       case ControlTypeInteger64:\n> +               return valueOrTuple<int64_t>(cv);\n> +       case ControlTypeFloat:\n> +               return valueOrTuple<float>(cv);\n> +       case ControlTypeString:\n> +               return py::cast(cv.get<std::string>());\n> +       case ControlTypeRectangle: {\n> +               const Rectangle *v = reinterpret_cast<const Rectangle *>(cv.data().data());\n> +               return py::cast(v);\n> +       }\n> +       case ControlTypeSize: {\n> +               const Size *v = reinterpret_cast<const Size *>(cv.data().data());\n> +               return py::cast(v);\n> +       }\n> +       case ControlTypeNone:\n> +       default:\n> +               throw std::runtime_error(\"Unsupported ControlValue type\");\n> +       }\n> +}\n> +\n> +template<typename T>\n> +static ControlValue controlValueMaybeArray(const py::object &ob)\n> +{\n> +       if (py::isinstance<py::list>(ob) || py::isinstance<py::tuple>(ob)) {\n> +               std::vector<T> vec = ob.cast<std::vector<T>>();\n> +               return ControlValue(Span<const T>(vec));\n> +       }\n> +\n> +       return ControlValue(ob.cast<T>());\n> +}\n> +\n> +ControlValue pyToControlValue(const py::object &ob, ControlType type)\n> +{\n> +       switch (type) {\n> +       case ControlTypeBool:\n> +               return ControlValue(ob.cast<bool>());\n> +       case ControlTypeByte:\n> +               return controlValueMaybeArray<uint8_t>(ob);\n> +       case ControlTypeInteger32:\n> +               return controlValueMaybeArray<int32_t>(ob);\n> +       case ControlTypeInteger64:\n> +               return controlValueMaybeArray<int64_t>(ob);\n> +       case ControlTypeFloat:\n> +               return controlValueMaybeArray<float>(ob);\n> +       case ControlTypeString:\n> +               return ControlValue(ob.cast<std::string>());\n> +       case ControlTypeRectangle:\n> +               return ControlValue(ob.cast<Rectangle>());\n> +       case ControlTypeSize:\n> +               return ControlValue(ob.cast<Size>());\n> +       case ControlTypeNone:\n> +       default:\n> +               throw std::runtime_error(\"Control type not implemented\");\n> +       }\n> +}\n> diff --git a/src/py/libcamera/py_helpers.h b/src/py/libcamera/py_helpers.h\n> new file mode 100644\n> index 00000000..cd31e2cc\n> --- /dev/null\n> +++ b/src/py/libcamera/py_helpers.h\n> @@ -0,0 +1,13 @@\n> +/* SPDX-License-Identifier: LGPL-2.1-or-later */\n> +/*\n> + * Copyright (C) 2022, Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>\n> + */\n> +\n> +#pragma once\n> +\n> +#include <libcamera/libcamera.h>\n> +\n> +#include <pybind11/smart_holder.h>\n> +\n> +pybind11::object controlValueToPy(const libcamera::ControlValue &cv);\n> +libcamera::ControlValue pyToControlValue(const pybind11::object &ob, libcamera::ControlType type);\n> diff --git a/src/py/libcamera/py_main.cpp b/src/py/libcamera/py_main.cpp\n> index 17b17f60..5a423ece 100644\n> --- a/src/py/libcamera/py_main.cpp\n> +++ b/src/py/libcamera/py_main.cpp\n> @@ -21,93 +21,14 @@\n>  #include <pybind11/stl.h>\n>  #include <pybind11/stl_bind.h>\n>  \n> +#include \"py_helpers.h\"\n> +\n>  namespace py = pybind11;\n>  \n>  using namespace libcamera;\n>  \n>  LOG_DEFINE_CATEGORY(Python)\n>  \n> -template<typename T>\n> -static py::object valueOrTuple(const ControlValue &cv)\n> -{\n> -       if (cv.isArray()) {\n> -               const T *v = reinterpret_cast<const T *>(cv.data().data());\n> -               auto t = py::tuple(cv.numElements());\n> -\n> -               for (size_t i = 0; i < cv.numElements(); ++i)\n> -                       t[i] = v[i];\n> -\n> -               return std::move(t);\n> -       }\n> -\n> -       return py::cast(cv.get<T>());\n> -}\n> -\n> -static py::object controlValueToPy(const ControlValue &cv)\n> -{\n> -       switch (cv.type()) {\n> -       case ControlTypeBool:\n> -               return valueOrTuple<bool>(cv);\n> -       case ControlTypeByte:\n> -               return valueOrTuple<uint8_t>(cv);\n> -       case ControlTypeInteger32:\n> -               return valueOrTuple<int32_t>(cv);\n> -       case ControlTypeInteger64:\n> -               return valueOrTuple<int64_t>(cv);\n> -       case ControlTypeFloat:\n> -               return valueOrTuple<float>(cv);\n> -       case ControlTypeString:\n> -               return py::cast(cv.get<std::string>());\n> -       case ControlTypeRectangle: {\n> -               const Rectangle *v = reinterpret_cast<const Rectangle *>(cv.data().data());\n> -               return py::cast(v);\n> -       }\n> -       case ControlTypeSize: {\n> -               const Size *v = reinterpret_cast<const Size *>(cv.data().data());\n> -               return py::cast(v);\n> -       }\n> -       case ControlTypeNone:\n> -       default:\n> -               throw std::runtime_error(\"Unsupported ControlValue type\");\n> -       }\n> -}\n> -\n> -template<typename T>\n> -static ControlValue controlValueMaybeArray(const py::object &ob)\n> -{\n> -       if (py::isinstance<py::list>(ob) || py::isinstance<py::tuple>(ob)) {\n> -               std::vector<T> vec = ob.cast<std::vector<T>>();\n> -               return ControlValue(Span<const T>(vec));\n> -       }\n> -\n> -       return ControlValue(ob.cast<T>());\n> -}\n> -\n> -static ControlValue pyToControlValue(const py::object &ob, ControlType type)\n> -{\n> -       switch (type) {\n> -       case ControlTypeBool:\n> -               return ControlValue(ob.cast<bool>());\n> -       case ControlTypeByte:\n> -               return controlValueMaybeArray<uint8_t>(ob);\n> -       case ControlTypeInteger32:\n> -               return controlValueMaybeArray<int32_t>(ob);\n> -       case ControlTypeInteger64:\n> -               return controlValueMaybeArray<int64_t>(ob);\n> -       case ControlTypeFloat:\n> -               return controlValueMaybeArray<float>(ob);\n> -       case ControlTypeString:\n> -               return ControlValue(ob.cast<std::string>());\n> -       case ControlTypeRectangle:\n> -               return ControlValue(ob.cast<Rectangle>());\n> -       case ControlTypeSize:\n> -               return ControlValue(ob.cast<Size>());\n> -       case ControlTypeNone:\n> -       default:\n> -               throw std::runtime_error(\"Control type not implemented\");\n> -       }\n> -}\n> -\n>  static std::weak_ptr<CameraManager> gCameraManager;\n>  static int gEventfd;\n>  static std::mutex gReqlistMutex;\n> -- \n> 2.34.1\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 1E8A6BE173\n\tfor <parsemail@patchwork.libcamera.org>;\n\tFri, 24 Jun 2022 08:22:22 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 6A31F65635;\n\tFri, 24 Jun 2022 10:22:21 +0200 (CEST)","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 91B3B65631\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tFri, 24 Jun 2022 10:22:20 +0200 (CEST)","from pendragon.ideasonboard.com\n\t(cpc89244-aztw30-2-0-cust3082.18-1.cable.virginm.net [86.31.172.11])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id EBA66DD;\n\tFri, 24 Jun 2022 10:22:19 +0200 (CEST)"],"DKIM-Signature":["v=1; a=rsa-sha256; c=relaxed/simple; d=libcamera.org;\n\ts=mail; t=1656058941;\n\tbh=1SVHzUKDULeYxFwUPiveQcNEUfykidjqXNsyBVElmos=;\n\th=In-Reply-To:References:To:Date:Subject:List-Id:List-Unsubscribe:\n\tList-Archive:List-Post:List-Help:List-Subscribe:From:Reply-To:\n\tFrom;\n\tb=qXXMIVti7BEUDMSaMHInmvVQQ+OUChDpEtQuAowybxPEBvQMfNCgYxIKNyknJVGfS\n\tBeqrJ/AHA5g2D0gIGOzYYsS06rHptMtfpsV2BCnjkf49oidMaMo7ZgZrx51lBmbkbf\n\tbzrOJCfe9UhF0JzD3LVf23u9qkM2/74wwz+ZDlLYltnqTkI9K3BJhF66qcuYPeIiFq\n\tqBto4oSrP8bqeWfiWukMwR8ooaGbL1/ONoLPNQvcIPYpGCG5zO+Ksceb7AizT8CaZj\n\tiTs7abdaeXo1gVhhKZdO60ky6oyPKRCxAg5Exv4C3nI5CUZzZ3+TbY2TYjdYnUH31e\n\t7jtfu9+A/QTuw==","v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1656058940;\n\tbh=1SVHzUKDULeYxFwUPiveQcNEUfykidjqXNsyBVElmos=;\n\th=In-Reply-To:References:Subject:From:Cc:To:Date:From;\n\tb=C/l8VHzJBC3GaERbY1GJwE8/rVGahbTCkk8hdRLkV4F2DFLt5f9P5KxGOt34h9gnj\n\tnlPqOCyTBICW9ZfKQDItqrcSSU04dMxsBfteLObRJKZl9G/04xmJ/jTXhQ+BPJOjWz\n\thGLSl0gSUIpzPxiixt94J4gUAwZaz+x4+L7f+7mE="],"Authentication-Results":"lancelot.ideasonboard.com; dkim=pass (1024-bit key; \n\tunprotected) header.d=ideasonboard.com\n\theader.i=@ideasonboard.com\n\theader.b=\"C/l8VHzJ\"; dkim-atps=neutral","Content-Type":"text/plain; charset=\"utf-8\"","MIME-Version":"1.0","Content-Transfer-Encoding":"quoted-printable","In-Reply-To":"<20220623144736.78537-4-tomi.valkeinen@ideasonboard.com>","References":"<20220623144736.78537-1-tomi.valkeinen@ideasonboard.com>\n\t<20220623144736.78537-4-tomi.valkeinen@ideasonboard.com>","To":"David Plowman <david.plowman@raspberrypi.com>,\n\tJacopo Mondi <jacopo@jmondi.org>,\n\tLaurent Pinchart <laurent.pinchart@ideasonboard.com>,\n\tTomi Valkeinen <tomi.valkeinen@ideasonboard.com>,\n\tlibcamera-devel@lists.libcamera.org","Date":"Fri, 24 Jun 2022 09:22:17 +0100","Message-ID":"<165605893776.1149771.3323508296523593025@Monstersaurus>","User-Agent":"alot/0.10","Subject":"Re: [libcamera-devel] [RFC v1 3/7] py: Move ControlValue helpers to\n\tpy_helpers.cpp","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>","From":"Kieran Bingham via libcamera-devel\n\t<libcamera-devel@lists.libcamera.org>","Reply-To":"Kieran Bingham <kieran.bingham@ideasonboard.com>","Errors-To":"libcamera-devel-bounces@lists.libcamera.org","Sender":"\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"}},{"id":23574,"web_url":"https://patchwork.libcamera.org/comment/23574/","msgid":"<YrWwDQ0IIRpBpPrC@pendragon.ideasonboard.com>","date":"2022-06-24T12:37:33","subject":"Re: [libcamera-devel] [RFC v1 3/7] py: Move ControlValue helpers to\n\tpy_helpers.cpp","submitter":{"id":2,"url":"https://patchwork.libcamera.org/api/people/2/","name":"Laurent Pinchart","email":"laurent.pinchart@ideasonboard.com"},"content":"On Fri, Jun 24, 2022 at 09:22:17AM +0100, Kieran Bingham wrote:\n> Quoting Tomi Valkeinen (2022-06-23 15:47:32)\n> > Clean up the py_main.cpp a bit by moving the ControlValue helpers to a\n> > separate file.\n> > \n> > Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>\n> > ---\n> >  src/py/libcamera/meson.build    |  1 +\n> >  src/py/libcamera/py_helpers.cpp | 98 +++++++++++++++++++++++++++++++++\n> >  src/py/libcamera/py_helpers.h   | 13 +++++\n> >  src/py/libcamera/py_main.cpp    | 83 +---------------------------\n> >  4 files changed, 114 insertions(+), 81 deletions(-)\n> >  create mode 100644 src/py/libcamera/py_helpers.cpp\n> >  create mode 100644 src/py/libcamera/py_helpers.h\n> > \n> > diff --git a/src/py/libcamera/meson.build b/src/py/libcamera/meson.build\n> > index eb884538..04578bac 100644\n> > --- a/src/py/libcamera/meson.build\n> > +++ b/src/py/libcamera/meson.build\n> > @@ -15,6 +15,7 @@ pybind11_dep = pybind11_proj.get_variable('pybind11_dep')\n> >  pycamera_sources = files([\n> >      'py_enums.cpp',\n> >      'py_geometry.cpp',\n> > +    'py_helpers.cpp',\n> \n> Should this be called py_controls? Or do you expect other support code\n> to go in here too. Or maybe it's more about types, 'py_types' ..\n> \n> >      'py_main.cpp',\n> >  ])\n> >  \n> > diff --git a/src/py/libcamera/py_helpers.cpp b/src/py/libcamera/py_helpers.cpp\n> > new file mode 100644\n> > index 00000000..d0a8b5c4\n> > --- /dev/null\n> > +++ b/src/py/libcamera/py_helpers.cpp\n> > @@ -0,0 +1,98 @@\n> > +/* SPDX-License-Identifier: LGPL-2.1-or-later */\n> > +/*\n> > + * Copyright (C) 2022, Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>\n> > + */\n> > +\n> > +#include \"py_helpers.h\"\n> > +\n> > +#include <libcamera/libcamera.h>\n> > +\n> > +#include <pybind11/functional.h>\n> > +#include <pybind11/smart_holder.h>\n> \n> You have this in the py_helpers header too, so I don't think it needs to\n> be duplicated here.\n> \n> What's it used for? I thought it was just for the Camera destructor or\n> something, I don't see Camera used here ?\n> \n> Anyway, the code move to it's own component file makes sense to me.\n> \n> \n> Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com>\n\nReviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>\n\n> > +#include <pybind11/stl.h>\n> > +#include <pybind11/stl_bind.h>\n> > +\n> > +namespace py = pybind11;\n> > +\n> > +using namespace libcamera;\n> > +\n> > +template<typename T>\n> > +static py::object valueOrTuple(const ControlValue &cv)\n> > +{\n> > +       if (cv.isArray()) {\n> > +               const T *v = reinterpret_cast<const T *>(cv.data().data());\n> > +               auto t = py::tuple(cv.numElements());\n> > +\n> > +               for (size_t i = 0; i < cv.numElements(); ++i)\n> > +                       t[i] = v[i];\n> > +\n> > +               return std::move(t);\n> > +       }\n> > +\n> > +       return py::cast(cv.get<T>());\n> > +}\n> > +\n> > +py::object controlValueToPy(const ControlValue &cv)\n> > +{\n> > +       switch (cv.type()) {\n> > +       case ControlTypeBool:\n> > +               return valueOrTuple<bool>(cv);\n> > +       case ControlTypeByte:\n> > +               return valueOrTuple<uint8_t>(cv);\n> > +       case ControlTypeInteger32:\n> > +               return valueOrTuple<int32_t>(cv);\n> > +       case ControlTypeInteger64:\n> > +               return valueOrTuple<int64_t>(cv);\n> > +       case ControlTypeFloat:\n> > +               return valueOrTuple<float>(cv);\n> > +       case ControlTypeString:\n> > +               return py::cast(cv.get<std::string>());\n> > +       case ControlTypeRectangle: {\n> > +               const Rectangle *v = reinterpret_cast<const Rectangle *>(cv.data().data());\n> > +               return py::cast(v);\n> > +       }\n> > +       case ControlTypeSize: {\n> > +               const Size *v = reinterpret_cast<const Size *>(cv.data().data());\n> > +               return py::cast(v);\n> > +       }\n> > +       case ControlTypeNone:\n> > +       default:\n> > +               throw std::runtime_error(\"Unsupported ControlValue type\");\n> > +       }\n> > +}\n> > +\n> > +template<typename T>\n> > +static ControlValue controlValueMaybeArray(const py::object &ob)\n> > +{\n> > +       if (py::isinstance<py::list>(ob) || py::isinstance<py::tuple>(ob)) {\n> > +               std::vector<T> vec = ob.cast<std::vector<T>>();\n> > +               return ControlValue(Span<const T>(vec));\n> > +       }\n> > +\n> > +       return ControlValue(ob.cast<T>());\n> > +}\n> > +\n> > +ControlValue pyToControlValue(const py::object &ob, ControlType type)\n> > +{\n> > +       switch (type) {\n> > +       case ControlTypeBool:\n> > +               return ControlValue(ob.cast<bool>());\n> > +       case ControlTypeByte:\n> > +               return controlValueMaybeArray<uint8_t>(ob);\n> > +       case ControlTypeInteger32:\n> > +               return controlValueMaybeArray<int32_t>(ob);\n> > +       case ControlTypeInteger64:\n> > +               return controlValueMaybeArray<int64_t>(ob);\n> > +       case ControlTypeFloat:\n> > +               return controlValueMaybeArray<float>(ob);\n> > +       case ControlTypeString:\n> > +               return ControlValue(ob.cast<std::string>());\n> > +       case ControlTypeRectangle:\n> > +               return ControlValue(ob.cast<Rectangle>());\n> > +       case ControlTypeSize:\n> > +               return ControlValue(ob.cast<Size>());\n> > +       case ControlTypeNone:\n> > +       default:\n> > +               throw std::runtime_error(\"Control type not implemented\");\n> > +       }\n> > +}\n> > diff --git a/src/py/libcamera/py_helpers.h b/src/py/libcamera/py_helpers.h\n> > new file mode 100644\n> > index 00000000..cd31e2cc\n> > --- /dev/null\n> > +++ b/src/py/libcamera/py_helpers.h\n> > @@ -0,0 +1,13 @@\n> > +/* SPDX-License-Identifier: LGPL-2.1-or-later */\n> > +/*\n> > + * Copyright (C) 2022, Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>\n> > + */\n> > +\n> > +#pragma once\n> > +\n> > +#include <libcamera/libcamera.h>\n> > +\n> > +#include <pybind11/smart_holder.h>\n> > +\n> > +pybind11::object controlValueToPy(const libcamera::ControlValue &cv);\n> > +libcamera::ControlValue pyToControlValue(const pybind11::object &ob, libcamera::ControlType type);\n> > diff --git a/src/py/libcamera/py_main.cpp b/src/py/libcamera/py_main.cpp\n> > index 17b17f60..5a423ece 100644\n> > --- a/src/py/libcamera/py_main.cpp\n> > +++ b/src/py/libcamera/py_main.cpp\n> > @@ -21,93 +21,14 @@\n> >  #include <pybind11/stl.h>\n> >  #include <pybind11/stl_bind.h>\n> >  \n> > +#include \"py_helpers.h\"\n> > +\n> >  namespace py = pybind11;\n> >  \n> >  using namespace libcamera;\n> >  \n> >  LOG_DEFINE_CATEGORY(Python)\n> >  \n> > -template<typename T>\n> > -static py::object valueOrTuple(const ControlValue &cv)\n> > -{\n> > -       if (cv.isArray()) {\n> > -               const T *v = reinterpret_cast<const T *>(cv.data().data());\n> > -               auto t = py::tuple(cv.numElements());\n> > -\n> > -               for (size_t i = 0; i < cv.numElements(); ++i)\n> > -                       t[i] = v[i];\n> > -\n> > -               return std::move(t);\n> > -       }\n> > -\n> > -       return py::cast(cv.get<T>());\n> > -}\n> > -\n> > -static py::object controlValueToPy(const ControlValue &cv)\n> > -{\n> > -       switch (cv.type()) {\n> > -       case ControlTypeBool:\n> > -               return valueOrTuple<bool>(cv);\n> > -       case ControlTypeByte:\n> > -               return valueOrTuple<uint8_t>(cv);\n> > -       case ControlTypeInteger32:\n> > -               return valueOrTuple<int32_t>(cv);\n> > -       case ControlTypeInteger64:\n> > -               return valueOrTuple<int64_t>(cv);\n> > -       case ControlTypeFloat:\n> > -               return valueOrTuple<float>(cv);\n> > -       case ControlTypeString:\n> > -               return py::cast(cv.get<std::string>());\n> > -       case ControlTypeRectangle: {\n> > -               const Rectangle *v = reinterpret_cast<const Rectangle *>(cv.data().data());\n> > -               return py::cast(v);\n> > -       }\n> > -       case ControlTypeSize: {\n> > -               const Size *v = reinterpret_cast<const Size *>(cv.data().data());\n> > -               return py::cast(v);\n> > -       }\n> > -       case ControlTypeNone:\n> > -       default:\n> > -               throw std::runtime_error(\"Unsupported ControlValue type\");\n> > -       }\n> > -}\n> > -\n> > -template<typename T>\n> > -static ControlValue controlValueMaybeArray(const py::object &ob)\n> > -{\n> > -       if (py::isinstance<py::list>(ob) || py::isinstance<py::tuple>(ob)) {\n> > -               std::vector<T> vec = ob.cast<std::vector<T>>();\n> > -               return ControlValue(Span<const T>(vec));\n> > -       }\n> > -\n> > -       return ControlValue(ob.cast<T>());\n> > -}\n> > -\n> > -static ControlValue pyToControlValue(const py::object &ob, ControlType type)\n> > -{\n> > -       switch (type) {\n> > -       case ControlTypeBool:\n> > -               return ControlValue(ob.cast<bool>());\n> > -       case ControlTypeByte:\n> > -               return controlValueMaybeArray<uint8_t>(ob);\n> > -       case ControlTypeInteger32:\n> > -               return controlValueMaybeArray<int32_t>(ob);\n> > -       case ControlTypeInteger64:\n> > -               return controlValueMaybeArray<int64_t>(ob);\n> > -       case ControlTypeFloat:\n> > -               return controlValueMaybeArray<float>(ob);\n> > -       case ControlTypeString:\n> > -               return ControlValue(ob.cast<std::string>());\n> > -       case ControlTypeRectangle:\n> > -               return ControlValue(ob.cast<Rectangle>());\n> > -       case ControlTypeSize:\n> > -               return ControlValue(ob.cast<Size>());\n> > -       case ControlTypeNone:\n> > -       default:\n> > -               throw std::runtime_error(\"Control type not implemented\");\n> > -       }\n> > -}\n> > -\n> >  static std::weak_ptr<CameraManager> gCameraManager;\n> >  static int gEventfd;\n> >  static std::mutex gReqlistMutex;","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 82D15BD808\n\tfor <parsemail@patchwork.libcamera.org>;\n\tFri, 24 Jun 2022 12:37:52 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 0C7746559A;\n\tFri, 24 Jun 2022 14:37:52 +0200 (CEST)","from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[213.167.242.64])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id DBE40600EC\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tFri, 24 Jun 2022 14:37:49 +0200 (CEST)","from pendragon.ideasonboard.com (62-78-145-57.bb.dnainternet.fi\n\t[62.78.145.57])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id 25D5B47C;\n\tFri, 24 Jun 2022 14:37:49 +0200 (CEST)"],"DKIM-Signature":["v=1; a=rsa-sha256; c=relaxed/simple; d=libcamera.org;\n\ts=mail; t=1656074272;\n\tbh=G9Jqjsf7f/we1fE6IGg3SjS0p4QJhuHjxNbhzn83FoU=;\n\th=Date:To:References:In-Reply-To:Subject:List-Id:List-Unsubscribe:\n\tList-Archive:List-Post:List-Help:List-Subscribe:From:Reply-To:Cc:\n\tFrom;\n\tb=CGY1nLJaZoKlsswW3FsUawK9CxSnpVjHP+UPQ/7PqZwtBOsFoeq70SV0kBcYCXrzQ\n\tl8c84fW9Z8h05Zl/zdK3HKc7dLMzitsqLGS/GYGn2PXyEc5/7ZT2yqPZVRrUi/rtGQ\n\tpoA6FGF6uEKuYnu8QlR8zb9vzTI0ppN2sFzaYd826NHbmZW3/G4ovFBRWSvGmr6ZkY\n\tK7QZjNMzwldv6YYppiRqbVG6oBpseB/lzC3ZjdLsQrUpRzJhjqltY4FDUlJNiodD56\n\tZIzortBSl7PVidHcwQg+y1iNmcRRpvJ2nBQ2lDX1wcjLmCWdOiu5udMUBUekpvCNJg\n\tZqnDZzFstwyzg==","v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1656074269;\n\tbh=G9Jqjsf7f/we1fE6IGg3SjS0p4QJhuHjxNbhzn83FoU=;\n\th=Date:From:To:Cc:Subject:References:In-Reply-To:From;\n\tb=Ob2nxKulpQmYHlS7c1ifswzV8OC3F5F4crQ7EG9Dzr0/4M674nuJiEfYan0wYOj+h\n\tCB0eXtcfW6re5/KQ2f58fukw2hNMG7DW0isz7LQMTyN7IowrB/CJh8vvG7cwwwHoxr\n\teLQ0USpstYVerTn/bTplkmoqVx6n2nwlCtCCMIEc="],"Authentication-Results":"lancelot.ideasonboard.com; dkim=pass (1024-bit key; \n\tunprotected) header.d=ideasonboard.com\n\theader.i=@ideasonboard.com\n\theader.b=\"Ob2nxKul\"; dkim-atps=neutral","Date":"Fri, 24 Jun 2022 15:37:33 +0300","To":"Kieran Bingham <kieran.bingham@ideasonboard.com>","Message-ID":"<YrWwDQ0IIRpBpPrC@pendragon.ideasonboard.com>","References":"<20220623144736.78537-1-tomi.valkeinen@ideasonboard.com>\n\t<20220623144736.78537-4-tomi.valkeinen@ideasonboard.com>\n\t<165605893776.1149771.3323508296523593025@Monstersaurus>","MIME-Version":"1.0","Content-Type":"text/plain; charset=utf-8","Content-Disposition":"inline","In-Reply-To":"<165605893776.1149771.3323508296523593025@Monstersaurus>","Subject":"Re: [libcamera-devel] [RFC v1 3/7] py: Move ControlValue helpers to\n\tpy_helpers.cpp","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>","From":"Laurent Pinchart via libcamera-devel\n\t<libcamera-devel@lists.libcamera.org>","Reply-To":"Laurent Pinchart <laurent.pinchart@ideasonboard.com>","Cc":"libcamera-devel@lists.libcamera.org","Errors-To":"libcamera-devel-bounces@lists.libcamera.org","Sender":"\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"}},{"id":23588,"web_url":"https://patchwork.libcamera.org/comment/23588/","msgid":"<5e774804-3b15-4e20-588b-b1a745465e6a@ideasonboard.com>","date":"2022-06-27T07:11:22","subject":"Re: [libcamera-devel] [RFC v1 3/7] py: Move ControlValue helpers to\n\tpy_helpers.cpp","submitter":{"id":109,"url":"https://patchwork.libcamera.org/api/people/109/","name":"Tomi Valkeinen","email":"tomi.valkeinen@ideasonboard.com"},"content":"On 24/06/2022 11:22, Kieran Bingham wrote:\n> Quoting Tomi Valkeinen (2022-06-23 15:47:32)\n>> Clean up the py_main.cpp a bit by moving the ControlValue helpers to a\n>> separate file.\n>>\n>> Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>\n>> ---\n>>   src/py/libcamera/meson.build    |  1 +\n>>   src/py/libcamera/py_helpers.cpp | 98 +++++++++++++++++++++++++++++++++\n>>   src/py/libcamera/py_helpers.h   | 13 +++++\n>>   src/py/libcamera/py_main.cpp    | 83 +---------------------------\n>>   4 files changed, 114 insertions(+), 81 deletions(-)\n>>   create mode 100644 src/py/libcamera/py_helpers.cpp\n>>   create mode 100644 src/py/libcamera/py_helpers.h\n>>\n>> diff --git a/src/py/libcamera/meson.build b/src/py/libcamera/meson.build\n>> index eb884538..04578bac 100644\n>> --- a/src/py/libcamera/meson.build\n>> +++ b/src/py/libcamera/meson.build\n>> @@ -15,6 +15,7 @@ pybind11_dep = pybind11_proj.get_variable('pybind11_dep')\n>>   pycamera_sources = files([\n>>       'py_enums.cpp',\n>>       'py_geometry.cpp',\n>> +    'py_helpers.cpp',\n> \n> Should this be called py_controls? Or do you expect other support code\n> to go in here too. Or maybe it's more about types, 'py_types' ..\n\nI felt that a dedicated file for just these controlvalue related \nfunctions is a bit too much, so I thought the file can be a holder of \nmisc small things needed for the bindings.\n\n>>       'py_main.cpp',\n>>   ])\n>>   \n>> diff --git a/src/py/libcamera/py_helpers.cpp b/src/py/libcamera/py_helpers.cpp\n>> new file mode 100644\n>> index 00000000..d0a8b5c4\n>> --- /dev/null\n>> +++ b/src/py/libcamera/py_helpers.cpp\n>> @@ -0,0 +1,98 @@\n>> +/* SPDX-License-Identifier: LGPL-2.1-or-later */\n>> +/*\n>> + * Copyright (C) 2022, Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>\n>> + */\n>> +\n>> +#include \"py_helpers.h\"\n>> +\n>> +#include <libcamera/libcamera.h>\n>> +\n>> +#include <pybind11/functional.h>\n>> +#include <pybind11/smart_holder.h>\n> \n> You have this in the py_helpers header too, so I don't think it needs to\n> be duplicated here.\n\nOk.\n\n> What's it used for? I thought it was just for the Camera destructor or\n> something, I don't see Camera used here ?\n\nIt's the main pybind11 header file, when using the smart_holder branch. \nAlthough... Now that I think about it, we're using the \"always use smart \nholder\" mode, which probably means we don't need to include \nsmart_holder.h but pybind11.h would be fine. Well, it doesn't really \nmatter here which one we include to get the pybind11::object.\n\n   Tomi","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 704F2BE173\n\tfor <parsemail@patchwork.libcamera.org>;\n\tMon, 27 Jun 2022 07:11:28 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id DF3C265635;\n\tMon, 27 Jun 2022 09:11:27 +0200 (CEST)","from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[213.167.242.64])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id E2F0560412\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tMon, 27 Jun 2022 09:11:25 +0200 (CEST)","from [192.168.1.111] (91-158-154-79.elisa-laajakaista.fi\n\t[91.158.154.79])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id 1364B47C;\n\tMon, 27 Jun 2022 09:11:25 +0200 (CEST)"],"DKIM-Signature":["v=1; a=rsa-sha256; c=relaxed/simple; d=libcamera.org;\n\ts=mail; t=1656313887;\n\tbh=430aldUkTQkRiHEGpUP+s/SOUbRwoHKhjhVQHFPIQo0=;\n\th=Date:To:References:In-Reply-To:Subject:List-Id:List-Unsubscribe:\n\tList-Archive:List-Post:List-Help:List-Subscribe:From:Reply-To:\n\tFrom;\n\tb=Euq8VViW0tq5v0Yg5s37+ZUR2bfIjhjBQBVWe3zCp1exNucnOIXGNJy1gDoHFjaNS\n\tNxBbCe82D0PKkddAM4fByCpbI+uH53XaZxJdsSZy9wW3Qa4NkKmBPAjfZ1oFv5FtvZ\n\t3eTmP794vGoafGV0+VqlR7YUZOIN6do/1mb0AO/B14iX3o1URvaS2quf1Rlw98H1so\n\tYfZtjnq/gskM6whrgrb8FMCN5vh9BfD8wAyDLgmQLdOleo8j1TUrxfI8mYuU/sP7vO\n\tXti29suWCbPFk4Llk386eup7g/DgHetY/tZkb/OHFtggSZyr1aEJ9oS0tgwgCIZsh2\n\tSqy0/NJirnI4g==","v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1656313885;\n\tbh=430aldUkTQkRiHEGpUP+s/SOUbRwoHKhjhVQHFPIQo0=;\n\th=Date:Subject:To:References:From:In-Reply-To:From;\n\tb=fRb/fNsATBYYDYp8q0vR+eHeEEfzzApXGTYF0Bva0Fm8eDbs9AVHfJuKm7wJChPW6\n\tjzke0Vx8rG2ULK1l1AemLU5H7NQpRexbudA9PVIjuhOjcqlSFLZWXaPaWOHceXGDej\n\tGBofXn91M05+GPfhXzbzYkYe1+eOAx/uOOiyy0ds="],"Authentication-Results":"lancelot.ideasonboard.com; dkim=pass (1024-bit key; \n\tunprotected) header.d=ideasonboard.com\n\theader.i=@ideasonboard.com\n\theader.b=\"fRb/fNsA\"; dkim-atps=neutral","Message-ID":"<5e774804-3b15-4e20-588b-b1a745465e6a@ideasonboard.com>","Date":"Mon, 27 Jun 2022 10:11:22 +0300","MIME-Version":"1.0","User-Agent":"Mozilla/5.0 (X11; Linux x86_64; rv:91.0) Gecko/20100101\n\tThunderbird/91.9.1","Content-Language":"en-US","To":"Kieran Bingham <kieran.bingham@ideasonboard.com>,\n\tDavid Plowman <david.plowman@raspberrypi.com>,\n\tJacopo Mondi <jacopo@jmondi.org>,\n\tLaurent Pinchart <laurent.pinchart@ideasonboard.com>,\n\tlibcamera-devel@lists.libcamera.org","References":"<20220623144736.78537-1-tomi.valkeinen@ideasonboard.com>\n\t<20220623144736.78537-4-tomi.valkeinen@ideasonboard.com>\n\t<165605893776.1149771.3323508296523593025@Monstersaurus>","In-Reply-To":"<165605893776.1149771.3323508296523593025@Monstersaurus>","Content-Type":"text/plain; charset=UTF-8; format=flowed","Content-Transfer-Encoding":"7bit","Subject":"Re: [libcamera-devel] [RFC v1 3/7] py: Move ControlValue helpers to\n\tpy_helpers.cpp","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>","From":"Tomi Valkeinen via libcamera-devel\n\t<libcamera-devel@lists.libcamera.org>","Reply-To":"Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>","Errors-To":"libcamera-devel-bounces@lists.libcamera.org","Sender":"\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"}}]