[libcamera-devel,RFC,v1,3/7] py: Move ControlValue helpers to py_helpers.cpp
diff mbox series

Message ID 20220623144736.78537-4-tomi.valkeinen@ideasonboard.com
State Superseded
Headers show
Series
  • Python bindings event handling
Related show

Commit Message

Tomi Valkeinen June 23, 2022, 2:47 p.m. UTC
Clean up the py_main.cpp a bit by moving the ControlValue helpers to a
separate file.

Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>
---
 src/py/libcamera/meson.build    |  1 +
 src/py/libcamera/py_helpers.cpp | 98 +++++++++++++++++++++++++++++++++
 src/py/libcamera/py_helpers.h   | 13 +++++
 src/py/libcamera/py_main.cpp    | 83 +---------------------------
 4 files changed, 114 insertions(+), 81 deletions(-)
 create mode 100644 src/py/libcamera/py_helpers.cpp
 create mode 100644 src/py/libcamera/py_helpers.h

Comments

Kieran Bingham June 24, 2022, 8:22 a.m. UTC | #1
Quoting Tomi Valkeinen (2022-06-23 15:47:32)
> Clean up the py_main.cpp a bit by moving the ControlValue helpers to a
> separate file.
> 
> Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>
> ---
>  src/py/libcamera/meson.build    |  1 +
>  src/py/libcamera/py_helpers.cpp | 98 +++++++++++++++++++++++++++++++++
>  src/py/libcamera/py_helpers.h   | 13 +++++
>  src/py/libcamera/py_main.cpp    | 83 +---------------------------
>  4 files changed, 114 insertions(+), 81 deletions(-)
>  create mode 100644 src/py/libcamera/py_helpers.cpp
>  create mode 100644 src/py/libcamera/py_helpers.h
> 
> diff --git a/src/py/libcamera/meson.build b/src/py/libcamera/meson.build
> index eb884538..04578bac 100644
> --- a/src/py/libcamera/meson.build
> +++ b/src/py/libcamera/meson.build
> @@ -15,6 +15,7 @@ pybind11_dep = pybind11_proj.get_variable('pybind11_dep')
>  pycamera_sources = files([
>      'py_enums.cpp',
>      'py_geometry.cpp',
> +    'py_helpers.cpp',

Should this be called py_controls? Or do you expect other support code
to go in here too. Or maybe it's more about types, 'py_types' ..


>      'py_main.cpp',
>  ])
>  
> diff --git a/src/py/libcamera/py_helpers.cpp b/src/py/libcamera/py_helpers.cpp
> new file mode 100644
> index 00000000..d0a8b5c4
> --- /dev/null
> +++ b/src/py/libcamera/py_helpers.cpp
> @@ -0,0 +1,98 @@
> +/* SPDX-License-Identifier: LGPL-2.1-or-later */
> +/*
> + * Copyright (C) 2022, Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>
> + */
> +
> +#include "py_helpers.h"
> +
> +#include <libcamera/libcamera.h>
> +
> +#include <pybind11/functional.h>
> +#include <pybind11/smart_holder.h>

You have this in the py_helpers header too, so I don't think it needs to
be duplicated here.

What's it used for? I thought it was just for the Camera destructor or
something, I don't see Camera used here ?

Anyway, the code move to it's own component file makes sense to me.


Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com>

> +#include <pybind11/stl.h>
> +#include <pybind11/stl_bind.h>
> +
> +namespace py = pybind11;
> +
> +using namespace libcamera;
> +
> +template<typename T>
> +static py::object valueOrTuple(const ControlValue &cv)
> +{
> +       if (cv.isArray()) {
> +               const T *v = reinterpret_cast<const T *>(cv.data().data());
> +               auto t = py::tuple(cv.numElements());
> +
> +               for (size_t i = 0; i < cv.numElements(); ++i)
> +                       t[i] = v[i];
> +
> +               return std::move(t);
> +       }
> +
> +       return py::cast(cv.get<T>());
> +}
> +
> +py::object controlValueToPy(const ControlValue &cv)
> +{
> +       switch (cv.type()) {
> +       case ControlTypeBool:
> +               return valueOrTuple<bool>(cv);
> +       case ControlTypeByte:
> +               return valueOrTuple<uint8_t>(cv);
> +       case ControlTypeInteger32:
> +               return valueOrTuple<int32_t>(cv);
> +       case ControlTypeInteger64:
> +               return valueOrTuple<int64_t>(cv);
> +       case ControlTypeFloat:
> +               return valueOrTuple<float>(cv);
> +       case ControlTypeString:
> +               return py::cast(cv.get<std::string>());
> +       case ControlTypeRectangle: {
> +               const Rectangle *v = reinterpret_cast<const Rectangle *>(cv.data().data());
> +               return py::cast(v);
> +       }
> +       case ControlTypeSize: {
> +               const Size *v = reinterpret_cast<const Size *>(cv.data().data());
> +               return py::cast(v);
> +       }
> +       case ControlTypeNone:
> +       default:
> +               throw std::runtime_error("Unsupported ControlValue type");
> +       }
> +}
> +
> +template<typename T>
> +static ControlValue controlValueMaybeArray(const py::object &ob)
> +{
> +       if (py::isinstance<py::list>(ob) || py::isinstance<py::tuple>(ob)) {
> +               std::vector<T> vec = ob.cast<std::vector<T>>();
> +               return ControlValue(Span<const T>(vec));
> +       }
> +
> +       return ControlValue(ob.cast<T>());
> +}
> +
> +ControlValue pyToControlValue(const py::object &ob, ControlType type)
> +{
> +       switch (type) {
> +       case ControlTypeBool:
> +               return ControlValue(ob.cast<bool>());
> +       case ControlTypeByte:
> +               return controlValueMaybeArray<uint8_t>(ob);
> +       case ControlTypeInteger32:
> +               return controlValueMaybeArray<int32_t>(ob);
> +       case ControlTypeInteger64:
> +               return controlValueMaybeArray<int64_t>(ob);
> +       case ControlTypeFloat:
> +               return controlValueMaybeArray<float>(ob);
> +       case ControlTypeString:
> +               return ControlValue(ob.cast<std::string>());
> +       case ControlTypeRectangle:
> +               return ControlValue(ob.cast<Rectangle>());
> +       case ControlTypeSize:
> +               return ControlValue(ob.cast<Size>());
> +       case ControlTypeNone:
> +       default:
> +               throw std::runtime_error("Control type not implemented");
> +       }
> +}
> diff --git a/src/py/libcamera/py_helpers.h b/src/py/libcamera/py_helpers.h
> new file mode 100644
> index 00000000..cd31e2cc
> --- /dev/null
> +++ b/src/py/libcamera/py_helpers.h
> @@ -0,0 +1,13 @@
> +/* SPDX-License-Identifier: LGPL-2.1-or-later */
> +/*
> + * Copyright (C) 2022, Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>
> + */
> +
> +#pragma once
> +
> +#include <libcamera/libcamera.h>
> +
> +#include <pybind11/smart_holder.h>
> +
> +pybind11::object controlValueToPy(const libcamera::ControlValue &cv);
> +libcamera::ControlValue pyToControlValue(const pybind11::object &ob, libcamera::ControlType type);
> diff --git a/src/py/libcamera/py_main.cpp b/src/py/libcamera/py_main.cpp
> index 17b17f60..5a423ece 100644
> --- a/src/py/libcamera/py_main.cpp
> +++ b/src/py/libcamera/py_main.cpp
> @@ -21,93 +21,14 @@
>  #include <pybind11/stl.h>
>  #include <pybind11/stl_bind.h>
>  
> +#include "py_helpers.h"
> +
>  namespace py = pybind11;
>  
>  using namespace libcamera;
>  
>  LOG_DEFINE_CATEGORY(Python)
>  
> -template<typename T>
> -static py::object valueOrTuple(const ControlValue &cv)
> -{
> -       if (cv.isArray()) {
> -               const T *v = reinterpret_cast<const T *>(cv.data().data());
> -               auto t = py::tuple(cv.numElements());
> -
> -               for (size_t i = 0; i < cv.numElements(); ++i)
> -                       t[i] = v[i];
> -
> -               return std::move(t);
> -       }
> -
> -       return py::cast(cv.get<T>());
> -}
> -
> -static py::object controlValueToPy(const ControlValue &cv)
> -{
> -       switch (cv.type()) {
> -       case ControlTypeBool:
> -               return valueOrTuple<bool>(cv);
> -       case ControlTypeByte:
> -               return valueOrTuple<uint8_t>(cv);
> -       case ControlTypeInteger32:
> -               return valueOrTuple<int32_t>(cv);
> -       case ControlTypeInteger64:
> -               return valueOrTuple<int64_t>(cv);
> -       case ControlTypeFloat:
> -               return valueOrTuple<float>(cv);
> -       case ControlTypeString:
> -               return py::cast(cv.get<std::string>());
> -       case ControlTypeRectangle: {
> -               const Rectangle *v = reinterpret_cast<const Rectangle *>(cv.data().data());
> -               return py::cast(v);
> -       }
> -       case ControlTypeSize: {
> -               const Size *v = reinterpret_cast<const Size *>(cv.data().data());
> -               return py::cast(v);
> -       }
> -       case ControlTypeNone:
> -       default:
> -               throw std::runtime_error("Unsupported ControlValue type");
> -       }
> -}
> -
> -template<typename T>
> -static ControlValue controlValueMaybeArray(const py::object &ob)
> -{
> -       if (py::isinstance<py::list>(ob) || py::isinstance<py::tuple>(ob)) {
> -               std::vector<T> vec = ob.cast<std::vector<T>>();
> -               return ControlValue(Span<const T>(vec));
> -       }
> -
> -       return ControlValue(ob.cast<T>());
> -}
> -
> -static ControlValue pyToControlValue(const py::object &ob, ControlType type)
> -{
> -       switch (type) {
> -       case ControlTypeBool:
> -               return ControlValue(ob.cast<bool>());
> -       case ControlTypeByte:
> -               return controlValueMaybeArray<uint8_t>(ob);
> -       case ControlTypeInteger32:
> -               return controlValueMaybeArray<int32_t>(ob);
> -       case ControlTypeInteger64:
> -               return controlValueMaybeArray<int64_t>(ob);
> -       case ControlTypeFloat:
> -               return controlValueMaybeArray<float>(ob);
> -       case ControlTypeString:
> -               return ControlValue(ob.cast<std::string>());
> -       case ControlTypeRectangle:
> -               return ControlValue(ob.cast<Rectangle>());
> -       case ControlTypeSize:
> -               return ControlValue(ob.cast<Size>());
> -       case ControlTypeNone:
> -       default:
> -               throw std::runtime_error("Control type not implemented");
> -       }
> -}
> -
>  static std::weak_ptr<CameraManager> gCameraManager;
>  static int gEventfd;
>  static std::mutex gReqlistMutex;
> -- 
> 2.34.1
>
Laurent Pinchart June 24, 2022, 12:37 p.m. UTC | #2
On Fri, Jun 24, 2022 at 09:22:17AM +0100, Kieran Bingham wrote:
> Quoting Tomi Valkeinen (2022-06-23 15:47:32)
> > Clean up the py_main.cpp a bit by moving the ControlValue helpers to a
> > separate file.
> > 
> > Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>
> > ---
> >  src/py/libcamera/meson.build    |  1 +
> >  src/py/libcamera/py_helpers.cpp | 98 +++++++++++++++++++++++++++++++++
> >  src/py/libcamera/py_helpers.h   | 13 +++++
> >  src/py/libcamera/py_main.cpp    | 83 +---------------------------
> >  4 files changed, 114 insertions(+), 81 deletions(-)
> >  create mode 100644 src/py/libcamera/py_helpers.cpp
> >  create mode 100644 src/py/libcamera/py_helpers.h
> > 
> > diff --git a/src/py/libcamera/meson.build b/src/py/libcamera/meson.build
> > index eb884538..04578bac 100644
> > --- a/src/py/libcamera/meson.build
> > +++ b/src/py/libcamera/meson.build
> > @@ -15,6 +15,7 @@ pybind11_dep = pybind11_proj.get_variable('pybind11_dep')
> >  pycamera_sources = files([
> >      'py_enums.cpp',
> >      'py_geometry.cpp',
> > +    'py_helpers.cpp',
> 
> Should this be called py_controls? Or do you expect other support code
> to go in here too. Or maybe it's more about types, 'py_types' ..
> 
> >      'py_main.cpp',
> >  ])
> >  
> > diff --git a/src/py/libcamera/py_helpers.cpp b/src/py/libcamera/py_helpers.cpp
> > new file mode 100644
> > index 00000000..d0a8b5c4
> > --- /dev/null
> > +++ b/src/py/libcamera/py_helpers.cpp
> > @@ -0,0 +1,98 @@
> > +/* SPDX-License-Identifier: LGPL-2.1-or-later */
> > +/*
> > + * Copyright (C) 2022, Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>
> > + */
> > +
> > +#include "py_helpers.h"
> > +
> > +#include <libcamera/libcamera.h>
> > +
> > +#include <pybind11/functional.h>
> > +#include <pybind11/smart_holder.h>
> 
> You have this in the py_helpers header too, so I don't think it needs to
> be duplicated here.
> 
> What's it used for? I thought it was just for the Camera destructor or
> something, I don't see Camera used here ?
> 
> Anyway, the code move to it's own component file makes sense to me.
> 
> 
> Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com>

Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>

> > +#include <pybind11/stl.h>
> > +#include <pybind11/stl_bind.h>
> > +
> > +namespace py = pybind11;
> > +
> > +using namespace libcamera;
> > +
> > +template<typename T>
> > +static py::object valueOrTuple(const ControlValue &cv)
> > +{
> > +       if (cv.isArray()) {
> > +               const T *v = reinterpret_cast<const T *>(cv.data().data());
> > +               auto t = py::tuple(cv.numElements());
> > +
> > +               for (size_t i = 0; i < cv.numElements(); ++i)
> > +                       t[i] = v[i];
> > +
> > +               return std::move(t);
> > +       }
> > +
> > +       return py::cast(cv.get<T>());
> > +}
> > +
> > +py::object controlValueToPy(const ControlValue &cv)
> > +{
> > +       switch (cv.type()) {
> > +       case ControlTypeBool:
> > +               return valueOrTuple<bool>(cv);
> > +       case ControlTypeByte:
> > +               return valueOrTuple<uint8_t>(cv);
> > +       case ControlTypeInteger32:
> > +               return valueOrTuple<int32_t>(cv);
> > +       case ControlTypeInteger64:
> > +               return valueOrTuple<int64_t>(cv);
> > +       case ControlTypeFloat:
> > +               return valueOrTuple<float>(cv);
> > +       case ControlTypeString:
> > +               return py::cast(cv.get<std::string>());
> > +       case ControlTypeRectangle: {
> > +               const Rectangle *v = reinterpret_cast<const Rectangle *>(cv.data().data());
> > +               return py::cast(v);
> > +       }
> > +       case ControlTypeSize: {
> > +               const Size *v = reinterpret_cast<const Size *>(cv.data().data());
> > +               return py::cast(v);
> > +       }
> > +       case ControlTypeNone:
> > +       default:
> > +               throw std::runtime_error("Unsupported ControlValue type");
> > +       }
> > +}
> > +
> > +template<typename T>
> > +static ControlValue controlValueMaybeArray(const py::object &ob)
> > +{
> > +       if (py::isinstance<py::list>(ob) || py::isinstance<py::tuple>(ob)) {
> > +               std::vector<T> vec = ob.cast<std::vector<T>>();
> > +               return ControlValue(Span<const T>(vec));
> > +       }
> > +
> > +       return ControlValue(ob.cast<T>());
> > +}
> > +
> > +ControlValue pyToControlValue(const py::object &ob, ControlType type)
> > +{
> > +       switch (type) {
> > +       case ControlTypeBool:
> > +               return ControlValue(ob.cast<bool>());
> > +       case ControlTypeByte:
> > +               return controlValueMaybeArray<uint8_t>(ob);
> > +       case ControlTypeInteger32:
> > +               return controlValueMaybeArray<int32_t>(ob);
> > +       case ControlTypeInteger64:
> > +               return controlValueMaybeArray<int64_t>(ob);
> > +       case ControlTypeFloat:
> > +               return controlValueMaybeArray<float>(ob);
> > +       case ControlTypeString:
> > +               return ControlValue(ob.cast<std::string>());
> > +       case ControlTypeRectangle:
> > +               return ControlValue(ob.cast<Rectangle>());
> > +       case ControlTypeSize:
> > +               return ControlValue(ob.cast<Size>());
> > +       case ControlTypeNone:
> > +       default:
> > +               throw std::runtime_error("Control type not implemented");
> > +       }
> > +}
> > diff --git a/src/py/libcamera/py_helpers.h b/src/py/libcamera/py_helpers.h
> > new file mode 100644
> > index 00000000..cd31e2cc
> > --- /dev/null
> > +++ b/src/py/libcamera/py_helpers.h
> > @@ -0,0 +1,13 @@
> > +/* SPDX-License-Identifier: LGPL-2.1-or-later */
> > +/*
> > + * Copyright (C) 2022, Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>
> > + */
> > +
> > +#pragma once
> > +
> > +#include <libcamera/libcamera.h>
> > +
> > +#include <pybind11/smart_holder.h>
> > +
> > +pybind11::object controlValueToPy(const libcamera::ControlValue &cv);
> > +libcamera::ControlValue pyToControlValue(const pybind11::object &ob, libcamera::ControlType type);
> > diff --git a/src/py/libcamera/py_main.cpp b/src/py/libcamera/py_main.cpp
> > index 17b17f60..5a423ece 100644
> > --- a/src/py/libcamera/py_main.cpp
> > +++ b/src/py/libcamera/py_main.cpp
> > @@ -21,93 +21,14 @@
> >  #include <pybind11/stl.h>
> >  #include <pybind11/stl_bind.h>
> >  
> > +#include "py_helpers.h"
> > +
> >  namespace py = pybind11;
> >  
> >  using namespace libcamera;
> >  
> >  LOG_DEFINE_CATEGORY(Python)
> >  
> > -template<typename T>
> > -static py::object valueOrTuple(const ControlValue &cv)
> > -{
> > -       if (cv.isArray()) {
> > -               const T *v = reinterpret_cast<const T *>(cv.data().data());
> > -               auto t = py::tuple(cv.numElements());
> > -
> > -               for (size_t i = 0; i < cv.numElements(); ++i)
> > -                       t[i] = v[i];
> > -
> > -               return std::move(t);
> > -       }
> > -
> > -       return py::cast(cv.get<T>());
> > -}
> > -
> > -static py::object controlValueToPy(const ControlValue &cv)
> > -{
> > -       switch (cv.type()) {
> > -       case ControlTypeBool:
> > -               return valueOrTuple<bool>(cv);
> > -       case ControlTypeByte:
> > -               return valueOrTuple<uint8_t>(cv);
> > -       case ControlTypeInteger32:
> > -               return valueOrTuple<int32_t>(cv);
> > -       case ControlTypeInteger64:
> > -               return valueOrTuple<int64_t>(cv);
> > -       case ControlTypeFloat:
> > -               return valueOrTuple<float>(cv);
> > -       case ControlTypeString:
> > -               return py::cast(cv.get<std::string>());
> > -       case ControlTypeRectangle: {
> > -               const Rectangle *v = reinterpret_cast<const Rectangle *>(cv.data().data());
> > -               return py::cast(v);
> > -       }
> > -       case ControlTypeSize: {
> > -               const Size *v = reinterpret_cast<const Size *>(cv.data().data());
> > -               return py::cast(v);
> > -       }
> > -       case ControlTypeNone:
> > -       default:
> > -               throw std::runtime_error("Unsupported ControlValue type");
> > -       }
> > -}
> > -
> > -template<typename T>
> > -static ControlValue controlValueMaybeArray(const py::object &ob)
> > -{
> > -       if (py::isinstance<py::list>(ob) || py::isinstance<py::tuple>(ob)) {
> > -               std::vector<T> vec = ob.cast<std::vector<T>>();
> > -               return ControlValue(Span<const T>(vec));
> > -       }
> > -
> > -       return ControlValue(ob.cast<T>());
> > -}
> > -
> > -static ControlValue pyToControlValue(const py::object &ob, ControlType type)
> > -{
> > -       switch (type) {
> > -       case ControlTypeBool:
> > -               return ControlValue(ob.cast<bool>());
> > -       case ControlTypeByte:
> > -               return controlValueMaybeArray<uint8_t>(ob);
> > -       case ControlTypeInteger32:
> > -               return controlValueMaybeArray<int32_t>(ob);
> > -       case ControlTypeInteger64:
> > -               return controlValueMaybeArray<int64_t>(ob);
> > -       case ControlTypeFloat:
> > -               return controlValueMaybeArray<float>(ob);
> > -       case ControlTypeString:
> > -               return ControlValue(ob.cast<std::string>());
> > -       case ControlTypeRectangle:
> > -               return ControlValue(ob.cast<Rectangle>());
> > -       case ControlTypeSize:
> > -               return ControlValue(ob.cast<Size>());
> > -       case ControlTypeNone:
> > -       default:
> > -               throw std::runtime_error("Control type not implemented");
> > -       }
> > -}
> > -
> >  static std::weak_ptr<CameraManager> gCameraManager;
> >  static int gEventfd;
> >  static std::mutex gReqlistMutex;
Tomi Valkeinen June 27, 2022, 7:11 a.m. UTC | #3
On 24/06/2022 11:22, Kieran Bingham wrote:
> Quoting Tomi Valkeinen (2022-06-23 15:47:32)
>> Clean up the py_main.cpp a bit by moving the ControlValue helpers to a
>> separate file.
>>
>> Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>
>> ---
>>   src/py/libcamera/meson.build    |  1 +
>>   src/py/libcamera/py_helpers.cpp | 98 +++++++++++++++++++++++++++++++++
>>   src/py/libcamera/py_helpers.h   | 13 +++++
>>   src/py/libcamera/py_main.cpp    | 83 +---------------------------
>>   4 files changed, 114 insertions(+), 81 deletions(-)
>>   create mode 100644 src/py/libcamera/py_helpers.cpp
>>   create mode 100644 src/py/libcamera/py_helpers.h
>>
>> diff --git a/src/py/libcamera/meson.build b/src/py/libcamera/meson.build
>> index eb884538..04578bac 100644
>> --- a/src/py/libcamera/meson.build
>> +++ b/src/py/libcamera/meson.build
>> @@ -15,6 +15,7 @@ pybind11_dep = pybind11_proj.get_variable('pybind11_dep')
>>   pycamera_sources = files([
>>       'py_enums.cpp',
>>       'py_geometry.cpp',
>> +    'py_helpers.cpp',
> 
> Should this be called py_controls? Or do you expect other support code
> to go in here too. Or maybe it's more about types, 'py_types' ..

I felt that a dedicated file for just these controlvalue related 
functions is a bit too much, so I thought the file can be a holder of 
misc small things needed for the bindings.

>>       'py_main.cpp',
>>   ])
>>   
>> diff --git a/src/py/libcamera/py_helpers.cpp b/src/py/libcamera/py_helpers.cpp
>> new file mode 100644
>> index 00000000..d0a8b5c4
>> --- /dev/null
>> +++ b/src/py/libcamera/py_helpers.cpp
>> @@ -0,0 +1,98 @@
>> +/* SPDX-License-Identifier: LGPL-2.1-or-later */
>> +/*
>> + * Copyright (C) 2022, Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>
>> + */
>> +
>> +#include "py_helpers.h"
>> +
>> +#include <libcamera/libcamera.h>
>> +
>> +#include <pybind11/functional.h>
>> +#include <pybind11/smart_holder.h>
> 
> You have this in the py_helpers header too, so I don't think it needs to
> be duplicated here.

Ok.

> What's it used for? I thought it was just for the Camera destructor or
> something, I don't see Camera used here ?

It's the main pybind11 header file, when using the smart_holder branch. 
Although... Now that I think about it, we're using the "always use smart 
holder" mode, which probably means we don't need to include 
smart_holder.h but pybind11.h would be fine. Well, it doesn't really 
matter here which one we include to get the pybind11::object.

   Tomi

Patch
diff mbox series

diff --git a/src/py/libcamera/meson.build b/src/py/libcamera/meson.build
index eb884538..04578bac 100644
--- a/src/py/libcamera/meson.build
+++ b/src/py/libcamera/meson.build
@@ -15,6 +15,7 @@  pybind11_dep = pybind11_proj.get_variable('pybind11_dep')
 pycamera_sources = files([
     'py_enums.cpp',
     'py_geometry.cpp',
+    'py_helpers.cpp',
     'py_main.cpp',
 ])
 
diff --git a/src/py/libcamera/py_helpers.cpp b/src/py/libcamera/py_helpers.cpp
new file mode 100644
index 00000000..d0a8b5c4
--- /dev/null
+++ b/src/py/libcamera/py_helpers.cpp
@@ -0,0 +1,98 @@ 
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+/*
+ * Copyright (C) 2022, Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>
+ */
+
+#include "py_helpers.h"
+
+#include <libcamera/libcamera.h>
+
+#include <pybind11/functional.h>
+#include <pybind11/smart_holder.h>
+#include <pybind11/stl.h>
+#include <pybind11/stl_bind.h>
+
+namespace py = pybind11;
+
+using namespace libcamera;
+
+template<typename T>
+static py::object valueOrTuple(const ControlValue &cv)
+{
+	if (cv.isArray()) {
+		const T *v = reinterpret_cast<const T *>(cv.data().data());
+		auto t = py::tuple(cv.numElements());
+
+		for (size_t i = 0; i < cv.numElements(); ++i)
+			t[i] = v[i];
+
+		return std::move(t);
+	}
+
+	return py::cast(cv.get<T>());
+}
+
+py::object controlValueToPy(const ControlValue &cv)
+{
+	switch (cv.type()) {
+	case ControlTypeBool:
+		return valueOrTuple<bool>(cv);
+	case ControlTypeByte:
+		return valueOrTuple<uint8_t>(cv);
+	case ControlTypeInteger32:
+		return valueOrTuple<int32_t>(cv);
+	case ControlTypeInteger64:
+		return valueOrTuple<int64_t>(cv);
+	case ControlTypeFloat:
+		return valueOrTuple<float>(cv);
+	case ControlTypeString:
+		return py::cast(cv.get<std::string>());
+	case ControlTypeRectangle: {
+		const Rectangle *v = reinterpret_cast<const Rectangle *>(cv.data().data());
+		return py::cast(v);
+	}
+	case ControlTypeSize: {
+		const Size *v = reinterpret_cast<const Size *>(cv.data().data());
+		return py::cast(v);
+	}
+	case ControlTypeNone:
+	default:
+		throw std::runtime_error("Unsupported ControlValue type");
+	}
+}
+
+template<typename T>
+static ControlValue controlValueMaybeArray(const py::object &ob)
+{
+	if (py::isinstance<py::list>(ob) || py::isinstance<py::tuple>(ob)) {
+		std::vector<T> vec = ob.cast<std::vector<T>>();
+		return ControlValue(Span<const T>(vec));
+	}
+
+	return ControlValue(ob.cast<T>());
+}
+
+ControlValue pyToControlValue(const py::object &ob, ControlType type)
+{
+	switch (type) {
+	case ControlTypeBool:
+		return ControlValue(ob.cast<bool>());
+	case ControlTypeByte:
+		return controlValueMaybeArray<uint8_t>(ob);
+	case ControlTypeInteger32:
+		return controlValueMaybeArray<int32_t>(ob);
+	case ControlTypeInteger64:
+		return controlValueMaybeArray<int64_t>(ob);
+	case ControlTypeFloat:
+		return controlValueMaybeArray<float>(ob);
+	case ControlTypeString:
+		return ControlValue(ob.cast<std::string>());
+	case ControlTypeRectangle:
+		return ControlValue(ob.cast<Rectangle>());
+	case ControlTypeSize:
+		return ControlValue(ob.cast<Size>());
+	case ControlTypeNone:
+	default:
+		throw std::runtime_error("Control type not implemented");
+	}
+}
diff --git a/src/py/libcamera/py_helpers.h b/src/py/libcamera/py_helpers.h
new file mode 100644
index 00000000..cd31e2cc
--- /dev/null
+++ b/src/py/libcamera/py_helpers.h
@@ -0,0 +1,13 @@ 
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+/*
+ * Copyright (C) 2022, Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>
+ */
+
+#pragma once
+
+#include <libcamera/libcamera.h>
+
+#include <pybind11/smart_holder.h>
+
+pybind11::object controlValueToPy(const libcamera::ControlValue &cv);
+libcamera::ControlValue pyToControlValue(const pybind11::object &ob, libcamera::ControlType type);
diff --git a/src/py/libcamera/py_main.cpp b/src/py/libcamera/py_main.cpp
index 17b17f60..5a423ece 100644
--- a/src/py/libcamera/py_main.cpp
+++ b/src/py/libcamera/py_main.cpp
@@ -21,93 +21,14 @@ 
 #include <pybind11/stl.h>
 #include <pybind11/stl_bind.h>
 
+#include "py_helpers.h"
+
 namespace py = pybind11;
 
 using namespace libcamera;
 
 LOG_DEFINE_CATEGORY(Python)
 
-template<typename T>
-static py::object valueOrTuple(const ControlValue &cv)
-{
-	if (cv.isArray()) {
-		const T *v = reinterpret_cast<const T *>(cv.data().data());
-		auto t = py::tuple(cv.numElements());
-
-		for (size_t i = 0; i < cv.numElements(); ++i)
-			t[i] = v[i];
-
-		return std::move(t);
-	}
-
-	return py::cast(cv.get<T>());
-}
-
-static py::object controlValueToPy(const ControlValue &cv)
-{
-	switch (cv.type()) {
-	case ControlTypeBool:
-		return valueOrTuple<bool>(cv);
-	case ControlTypeByte:
-		return valueOrTuple<uint8_t>(cv);
-	case ControlTypeInteger32:
-		return valueOrTuple<int32_t>(cv);
-	case ControlTypeInteger64:
-		return valueOrTuple<int64_t>(cv);
-	case ControlTypeFloat:
-		return valueOrTuple<float>(cv);
-	case ControlTypeString:
-		return py::cast(cv.get<std::string>());
-	case ControlTypeRectangle: {
-		const Rectangle *v = reinterpret_cast<const Rectangle *>(cv.data().data());
-		return py::cast(v);
-	}
-	case ControlTypeSize: {
-		const Size *v = reinterpret_cast<const Size *>(cv.data().data());
-		return py::cast(v);
-	}
-	case ControlTypeNone:
-	default:
-		throw std::runtime_error("Unsupported ControlValue type");
-	}
-}
-
-template<typename T>
-static ControlValue controlValueMaybeArray(const py::object &ob)
-{
-	if (py::isinstance<py::list>(ob) || py::isinstance<py::tuple>(ob)) {
-		std::vector<T> vec = ob.cast<std::vector<T>>();
-		return ControlValue(Span<const T>(vec));
-	}
-
-	return ControlValue(ob.cast<T>());
-}
-
-static ControlValue pyToControlValue(const py::object &ob, ControlType type)
-{
-	switch (type) {
-	case ControlTypeBool:
-		return ControlValue(ob.cast<bool>());
-	case ControlTypeByte:
-		return controlValueMaybeArray<uint8_t>(ob);
-	case ControlTypeInteger32:
-		return controlValueMaybeArray<int32_t>(ob);
-	case ControlTypeInteger64:
-		return controlValueMaybeArray<int64_t>(ob);
-	case ControlTypeFloat:
-		return controlValueMaybeArray<float>(ob);
-	case ControlTypeString:
-		return ControlValue(ob.cast<std::string>());
-	case ControlTypeRectangle:
-		return ControlValue(ob.cast<Rectangle>());
-	case ControlTypeSize:
-		return ControlValue(ob.cast<Size>());
-	case ControlTypeNone:
-	default:
-		throw std::runtime_error("Control type not implemented");
-	}
-}
-
 static std::weak_ptr<CameraManager> gCameraManager;
 static int gEventfd;
 static std::mutex gReqlistMutex;