Message ID | 20231011140238.39058-1-david.plowman@raspberrypi.com |
---|---|
State | Accepted |
Commit | d05009d34c67dfb11e890eaee2858a7e99ed06e4 |
Headers | show |
Series |
|
Related | show |
Hi David, Quoting David Plowman via libcamera-devel (2023-10-11 15:02:38) > We provide access to the various fields of the new SensorConfiguration > class. The class also needs a constructor so that Python applications > can make one and put it into the CameraConfiguration. > > Signed-off-by: David Plowman <david.plowman@raspberrypi.com> > --- > src/py/libcamera/py_main.cpp | 36 ++++++++++++++++++++++++++++++++++++ > 1 file changed, 36 insertions(+) > > diff --git a/src/py/libcamera/py_main.cpp b/src/py/libcamera/py_main.cpp > index 01fb15a9..d2ce3722 100644 > --- a/src/py/libcamera/py_main.cpp > +++ b/src/py/libcamera/py_main.cpp > @@ -112,6 +112,7 @@ PYBIND11_MODULE(_libcamera, m) > > auto pyCameraManager = py::class_<PyCameraManager, std::shared_ptr<PyCameraManager>>(m, "CameraManager"); > auto pyCamera = py::class_<Camera, PyCameraSmartPtr<Camera>>(m, "Camera"); > + auto pySensorConfiguration = py::class_<SensorConfiguration>(m, "SensorConfiguration"); > auto pyCameraConfiguration = py::class_<CameraConfiguration>(m, "CameraConfiguration"); > auto pyCameraConfigurationStatus = py::enum_<CameraConfiguration::Status>(pyCameraConfiguration, "Status"); > auto pyStreamConfiguration = py::class_<StreamConfiguration>(m, "StreamConfiguration"); > @@ -281,6 +282,40 @@ PYBIND11_MODULE(_libcamera, m) > return ret; > }); > > + pySensorConfiguration > + .def(py::init<>()) > + .def_readwrite("bit_depth", &SensorConfiguration::bitDepth) > + .def_readwrite("analog_crop", &SensorConfiguration::analogCrop) > + .def_property( > + "binning", > + [](SensorConfiguration &self) { > + return py::make_tuple(self.binning.binX, self.binning.binY); > + }, > + [](SensorConfiguration &self, py::object value) { > + auto vec = value.cast<std::vector<unsigned int>>(); > + if (vec.size() != 2) > + throw std::runtime_error("binning requires iterable of 2 values"); > + self.binning.binX = vec[0]; > + self.binning.binY = vec[1]; This seems reasonable to me. Partially filling in either of binning or skipping would be invalid. Thanks for filling in the rest of the logic: Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com> Tomi - Are you happy with this? > + }) > + .def_property( > + "skipping", > + [](SensorConfiguration &self) { > + return py::make_tuple(self.skipping.xOddInc, self.skipping.xEvenInc, > + self.skipping.yOddInc, self.skipping.yEvenInc); > + }, > + [](SensorConfiguration &self, py::object value) { > + auto vec = value.cast<std::vector<unsigned int>>(); > + if (vec.size() != 4) > + throw std::runtime_error("skipping requires iterable of 4 values"); > + self.skipping.xOddInc = vec[0]; > + self.skipping.xEvenInc = vec[1]; > + self.skipping.yOddInc = vec[2]; > + self.skipping.yEvenInc = vec[3]; > + }) > + .def_readwrite("output_size", &SensorConfiguration::outputSize) > + .def("is_valid", &SensorConfiguration::isValid); > + > pyCameraConfiguration > .def("__iter__", [](CameraConfiguration &self) { > return py::make_iterator<py::return_value_policy::reference_internal>(self); > @@ -293,6 +328,7 @@ PYBIND11_MODULE(_libcamera, m) > py::return_value_policy::reference_internal) > .def_property_readonly("size", &CameraConfiguration::size) > .def_property_readonly("empty", &CameraConfiguration::empty) > + .def_readwrite("sensor_config", &CameraConfiguration::sensorConfig) > .def_readwrite("transform", &CameraConfiguration::transform); > > pyCameraConfigurationStatus > -- > 2.39.2 >
On 12/10/2023 11:29, Kieran Bingham via libcamera-devel wrote: > Hi David, > > Quoting David Plowman via libcamera-devel (2023-10-11 15:02:38) >> We provide access to the various fields of the new SensorConfiguration >> class. The class also needs a constructor so that Python applications >> can make one and put it into the CameraConfiguration. >> >> Signed-off-by: David Plowman <david.plowman@raspberrypi.com> >> --- >> src/py/libcamera/py_main.cpp | 36 ++++++++++++++++++++++++++++++++++++ >> 1 file changed, 36 insertions(+) >> >> diff --git a/src/py/libcamera/py_main.cpp b/src/py/libcamera/py_main.cpp >> index 01fb15a9..d2ce3722 100644 >> --- a/src/py/libcamera/py_main.cpp >> +++ b/src/py/libcamera/py_main.cpp >> @@ -112,6 +112,7 @@ PYBIND11_MODULE(_libcamera, m) >> >> auto pyCameraManager = py::class_<PyCameraManager, std::shared_ptr<PyCameraManager>>(m, "CameraManager"); >> auto pyCamera = py::class_<Camera, PyCameraSmartPtr<Camera>>(m, "Camera"); >> + auto pySensorConfiguration = py::class_<SensorConfiguration>(m, "SensorConfiguration"); >> auto pyCameraConfiguration = py::class_<CameraConfiguration>(m, "CameraConfiguration"); >> auto pyCameraConfigurationStatus = py::enum_<CameraConfiguration::Status>(pyCameraConfiguration, "Status"); >> auto pyStreamConfiguration = py::class_<StreamConfiguration>(m, "StreamConfiguration"); >> @@ -281,6 +282,40 @@ PYBIND11_MODULE(_libcamera, m) >> return ret; >> }); >> >> + pySensorConfiguration >> + .def(py::init<>()) >> + .def_readwrite("bit_depth", &SensorConfiguration::bitDepth) >> + .def_readwrite("analog_crop", &SensorConfiguration::analogCrop) >> + .def_property( >> + "binning", >> + [](SensorConfiguration &self) { >> + return py::make_tuple(self.binning.binX, self.binning.binY); >> + }, >> + [](SensorConfiguration &self, py::object value) { >> + auto vec = value.cast<std::vector<unsigned int>>(); >> + if (vec.size() != 2) >> + throw std::runtime_error("binning requires iterable of 2 values"); >> + self.binning.binX = vec[0]; >> + self.binning.binY = vec[1]; > > This seems reasonable to me. Partially filling in either of binning or > skipping would be invalid. > > Thanks for filling in the rest of the logic: > > Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com> > > Tomi - Are you happy with this? I think it's simpler and better to do: .def_property( "binning", [](SensorConfiguration &self) { return std::make_tuple(self.binning.binX, self.binning.binY); }, [](SensorConfiguration &self, std::tuple<uint32_t, uint32_t> value) { self.binning.binX = std::get<0>(value); self.binning.binY = std::get<1>(value); }) Tomi > > > >> + }) >> + .def_property( >> + "skipping", >> + [](SensorConfiguration &self) { >> + return py::make_tuple(self.skipping.xOddInc, self.skipping.xEvenInc, >> + self.skipping.yOddInc, self.skipping.yEvenInc); >> + }, >> + [](SensorConfiguration &self, py::object value) { >> + auto vec = value.cast<std::vector<unsigned int>>(); >> + if (vec.size() != 4) >> + throw std::runtime_error("skipping requires iterable of 4 values"); >> + self.skipping.xOddInc = vec[0]; >> + self.skipping.xEvenInc = vec[1]; >> + self.skipping.yOddInc = vec[2]; >> + self.skipping.yEvenInc = vec[3]; >> + }) >> + .def_readwrite("output_size", &SensorConfiguration::outputSize) >> + .def("is_valid", &SensorConfiguration::isValid); >> + >> pyCameraConfiguration >> .def("__iter__", [](CameraConfiguration &self) { >> return py::make_iterator<py::return_value_policy::reference_internal>(self); >> @@ -293,6 +328,7 @@ PYBIND11_MODULE(_libcamera, m) >> py::return_value_policy::reference_internal) >> .def_property_readonly("size", &CameraConfiguration::size) >> .def_property_readonly("empty", &CameraConfiguration::empty) >> + .def_readwrite("sensor_config", &CameraConfiguration::sensorConfig) >> .def_readwrite("transform", &CameraConfiguration::transform); >> >> pyCameraConfigurationStatus >> -- >> 2.39.2 >>
Hi Tomi Thanks for that. I had no idea you could write that... the joys of C++! Would folks like me to send another update? David On Fri, 20 Oct 2023 at 08:51, Tomi Valkeinen <tomi.valkeinen@ideasonboard.com> wrote: > > On 12/10/2023 11:29, Kieran Bingham via libcamera-devel wrote: > > Hi David, > > > > Quoting David Plowman via libcamera-devel (2023-10-11 15:02:38) > >> We provide access to the various fields of the new SensorConfiguration > >> class. The class also needs a constructor so that Python applications > >> can make one and put it into the CameraConfiguration. > >> > >> Signed-off-by: David Plowman <david.plowman@raspberrypi.com> > >> --- > >> src/py/libcamera/py_main.cpp | 36 ++++++++++++++++++++++++++++++++++++ > >> 1 file changed, 36 insertions(+) > >> > >> diff --git a/src/py/libcamera/py_main.cpp b/src/py/libcamera/py_main.cpp > >> index 01fb15a9..d2ce3722 100644 > >> --- a/src/py/libcamera/py_main.cpp > >> +++ b/src/py/libcamera/py_main.cpp > >> @@ -112,6 +112,7 @@ PYBIND11_MODULE(_libcamera, m) > >> > >> auto pyCameraManager = py::class_<PyCameraManager, std::shared_ptr<PyCameraManager>>(m, "CameraManager"); > >> auto pyCamera = py::class_<Camera, PyCameraSmartPtr<Camera>>(m, "Camera"); > >> + auto pySensorConfiguration = py::class_<SensorConfiguration>(m, "SensorConfiguration"); > >> auto pyCameraConfiguration = py::class_<CameraConfiguration>(m, "CameraConfiguration"); > >> auto pyCameraConfigurationStatus = py::enum_<CameraConfiguration::Status>(pyCameraConfiguration, "Status"); > >> auto pyStreamConfiguration = py::class_<StreamConfiguration>(m, "StreamConfiguration"); > >> @@ -281,6 +282,40 @@ PYBIND11_MODULE(_libcamera, m) > >> return ret; > >> }); > >> > >> + pySensorConfiguration > >> + .def(py::init<>()) > >> + .def_readwrite("bit_depth", &SensorConfiguration::bitDepth) > >> + .def_readwrite("analog_crop", &SensorConfiguration::analogCrop) > >> + .def_property( > >> + "binning", > >> + [](SensorConfiguration &self) { > >> + return py::make_tuple(self.binning.binX, self.binning.binY); > >> + }, > >> + [](SensorConfiguration &self, py::object value) { > >> + auto vec = value.cast<std::vector<unsigned int>>(); > >> + if (vec.size() != 2) > >> + throw std::runtime_error("binning requires iterable of 2 values"); > >> + self.binning.binX = vec[0]; > >> + self.binning.binY = vec[1]; > > > > This seems reasonable to me. Partially filling in either of binning or > > skipping would be invalid. > > > > Thanks for filling in the rest of the logic: > > > > Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com> > > > > Tomi - Are you happy with this? > > I think it's simpler and better to do: > > .def_property( > "binning", > [](SensorConfiguration &self) { > return std::make_tuple(self.binning.binX, self.binning.binY); > }, > [](SensorConfiguration &self, std::tuple<uint32_t, uint32_t> value) { > self.binning.binX = std::get<0>(value); > self.binning.binY = std::get<1>(value); > }) > > Tomi > > > > > > > > > >> + }) > >> + .def_property( > >> + "skipping", > >> + [](SensorConfiguration &self) { > >> + return py::make_tuple(self.skipping.xOddInc, self.skipping.xEvenInc, > >> + self.skipping.yOddInc, self.skipping.yEvenInc); > >> + }, > >> + [](SensorConfiguration &self, py::object value) { > >> + auto vec = value.cast<std::vector<unsigned int>>(); > >> + if (vec.size() != 4) > >> + throw std::runtime_error("skipping requires iterable of 4 values"); > >> + self.skipping.xOddInc = vec[0]; > >> + self.skipping.xEvenInc = vec[1]; > >> + self.skipping.yOddInc = vec[2]; > >> + self.skipping.yEvenInc = vec[3]; > >> + }) > >> + .def_readwrite("output_size", &SensorConfiguration::outputSize) > >> + .def("is_valid", &SensorConfiguration::isValid); > >> + > >> pyCameraConfiguration > >> .def("__iter__", [](CameraConfiguration &self) { > >> return py::make_iterator<py::return_value_policy::reference_internal>(self); > >> @@ -293,6 +328,7 @@ PYBIND11_MODULE(_libcamera, m) > >> py::return_value_policy::reference_internal) > >> .def_property_readonly("size", &CameraConfiguration::size) > >> .def_property_readonly("empty", &CameraConfiguration::empty) > >> + .def_readwrite("sensor_config", &CameraConfiguration::sensorConfig) > >> .def_readwrite("transform", &CameraConfiguration::transform); > >> > >> pyCameraConfigurationStatus > >> -- > >> 2.39.2 > >> >
On 20/10/2023 11:17, David Plowman wrote: > Hi Tomi > > Thanks for that. I had no idea you could write that... the joys of C++! I think usually with pybind11 you should think in terms of C++. Use the C++ types whenever possible, as they're more performant and specific than the Python types, and let pybind11 do the conversions between the Python and C++ types. Tomi > > Would folks like me to send another update? > > David > > On Fri, 20 Oct 2023 at 08:51, Tomi Valkeinen > <tomi.valkeinen@ideasonboard.com> wrote: >> >> On 12/10/2023 11:29, Kieran Bingham via libcamera-devel wrote: >>> Hi David, >>> >>> Quoting David Plowman via libcamera-devel (2023-10-11 15:02:38) >>>> We provide access to the various fields of the new SensorConfiguration >>>> class. The class also needs a constructor so that Python applications >>>> can make one and put it into the CameraConfiguration. >>>> >>>> Signed-off-by: David Plowman <david.plowman@raspberrypi.com> >>>> --- >>>> src/py/libcamera/py_main.cpp | 36 ++++++++++++++++++++++++++++++++++++ >>>> 1 file changed, 36 insertions(+) >>>> >>>> diff --git a/src/py/libcamera/py_main.cpp b/src/py/libcamera/py_main.cpp >>>> index 01fb15a9..d2ce3722 100644 >>>> --- a/src/py/libcamera/py_main.cpp >>>> +++ b/src/py/libcamera/py_main.cpp >>>> @@ -112,6 +112,7 @@ PYBIND11_MODULE(_libcamera, m) >>>> >>>> auto pyCameraManager = py::class_<PyCameraManager, std::shared_ptr<PyCameraManager>>(m, "CameraManager"); >>>> auto pyCamera = py::class_<Camera, PyCameraSmartPtr<Camera>>(m, "Camera"); >>>> + auto pySensorConfiguration = py::class_<SensorConfiguration>(m, "SensorConfiguration"); >>>> auto pyCameraConfiguration = py::class_<CameraConfiguration>(m, "CameraConfiguration"); >>>> auto pyCameraConfigurationStatus = py::enum_<CameraConfiguration::Status>(pyCameraConfiguration, "Status"); >>>> auto pyStreamConfiguration = py::class_<StreamConfiguration>(m, "StreamConfiguration"); >>>> @@ -281,6 +282,40 @@ PYBIND11_MODULE(_libcamera, m) >>>> return ret; >>>> }); >>>> >>>> + pySensorConfiguration >>>> + .def(py::init<>()) >>>> + .def_readwrite("bit_depth", &SensorConfiguration::bitDepth) >>>> + .def_readwrite("analog_crop", &SensorConfiguration::analogCrop) >>>> + .def_property( >>>> + "binning", >>>> + [](SensorConfiguration &self) { >>>> + return py::make_tuple(self.binning.binX, self.binning.binY); >>>> + }, >>>> + [](SensorConfiguration &self, py::object value) { >>>> + auto vec = value.cast<std::vector<unsigned int>>(); >>>> + if (vec.size() != 2) >>>> + throw std::runtime_error("binning requires iterable of 2 values"); >>>> + self.binning.binX = vec[0]; >>>> + self.binning.binY = vec[1]; >>> >>> This seems reasonable to me. Partially filling in either of binning or >>> skipping would be invalid. >>> >>> Thanks for filling in the rest of the logic: >>> >>> Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com> >>> >>> Tomi - Are you happy with this? >> >> I think it's simpler and better to do: >> >> .def_property( >> "binning", >> [](SensorConfiguration &self) { >> return std::make_tuple(self.binning.binX, self.binning.binY); >> }, >> [](SensorConfiguration &self, std::tuple<uint32_t, uint32_t> value) { >> self.binning.binX = std::get<0>(value); >> self.binning.binY = std::get<1>(value); >> }) >> >> Tomi >> >> >>> >>> >>> >>>> + }) >>>> + .def_property( >>>> + "skipping", >>>> + [](SensorConfiguration &self) { >>>> + return py::make_tuple(self.skipping.xOddInc, self.skipping.xEvenInc, >>>> + self.skipping.yOddInc, self.skipping.yEvenInc); >>>> + }, >>>> + [](SensorConfiguration &self, py::object value) { >>>> + auto vec = value.cast<std::vector<unsigned int>>(); >>>> + if (vec.size() != 4) >>>> + throw std::runtime_error("skipping requires iterable of 4 values"); >>>> + self.skipping.xOddInc = vec[0]; >>>> + self.skipping.xEvenInc = vec[1]; >>>> + self.skipping.yOddInc = vec[2]; >>>> + self.skipping.yEvenInc = vec[3]; >>>> + }) >>>> + .def_readwrite("output_size", &SensorConfiguration::outputSize) >>>> + .def("is_valid", &SensorConfiguration::isValid); >>>> + >>>> pyCameraConfiguration >>>> .def("__iter__", [](CameraConfiguration &self) { >>>> return py::make_iterator<py::return_value_policy::reference_internal>(self); >>>> @@ -293,6 +328,7 @@ PYBIND11_MODULE(_libcamera, m) >>>> py::return_value_policy::reference_internal) >>>> .def_property_readonly("size", &CameraConfiguration::size) >>>> .def_property_readonly("empty", &CameraConfiguration::empty) >>>> + .def_readwrite("sensor_config", &CameraConfiguration::sensorConfig) >>>> .def_readwrite("transform", &CameraConfiguration::transform); >>>> >>>> pyCameraConfigurationStatus >>>> -- >>>> 2.39.2 >>>> >>
Quoting Tomi Valkeinen (2023-10-20 08:51:08) > On 12/10/2023 11:29, Kieran Bingham via libcamera-devel wrote: > > Hi David, > > > > Quoting David Plowman via libcamera-devel (2023-10-11 15:02:38) > >> We provide access to the various fields of the new SensorConfiguration > >> class. The class also needs a constructor so that Python applications > >> can make one and put it into the CameraConfiguration. > >> > >> Signed-off-by: David Plowman <david.plowman@raspberrypi.com> > >> --- > >> src/py/libcamera/py_main.cpp | 36 ++++++++++++++++++++++++++++++++++++ > >> 1 file changed, 36 insertions(+) > >> > >> diff --git a/src/py/libcamera/py_main.cpp b/src/py/libcamera/py_main.cpp > >> index 01fb15a9..d2ce3722 100644 > >> --- a/src/py/libcamera/py_main.cpp > >> +++ b/src/py/libcamera/py_main.cpp > >> @@ -112,6 +112,7 @@ PYBIND11_MODULE(_libcamera, m) > >> > >> auto pyCameraManager = py::class_<PyCameraManager, std::shared_ptr<PyCameraManager>>(m, "CameraManager"); > >> auto pyCamera = py::class_<Camera, PyCameraSmartPtr<Camera>>(m, "Camera"); > >> + auto pySensorConfiguration = py::class_<SensorConfiguration>(m, "SensorConfiguration"); > >> auto pyCameraConfiguration = py::class_<CameraConfiguration>(m, "CameraConfiguration"); > >> auto pyCameraConfigurationStatus = py::enum_<CameraConfiguration::Status>(pyCameraConfiguration, "Status"); > >> auto pyStreamConfiguration = py::class_<StreamConfiguration>(m, "StreamConfiguration"); > >> @@ -281,6 +282,40 @@ PYBIND11_MODULE(_libcamera, m) > >> return ret; > >> }); > >> > >> + pySensorConfiguration > >> + .def(py::init<>()) > >> + .def_readwrite("bit_depth", &SensorConfiguration::bitDepth) > >> + .def_readwrite("analog_crop", &SensorConfiguration::analogCrop) > >> + .def_property( > >> + "binning", > >> + [](SensorConfiguration &self) { > >> + return py::make_tuple(self.binning.binX, self.binning.binY); > >> + }, > >> + [](SensorConfiguration &self, py::object value) { > >> + auto vec = value.cast<std::vector<unsigned int>>(); > >> + if (vec.size() != 2) > >> + throw std::runtime_error("binning requires iterable of 2 values"); > >> + self.binning.binX = vec[0]; > >> + self.binning.binY = vec[1]; > > > > This seems reasonable to me. Partially filling in either of binning or > > skipping would be invalid. > > > > Thanks for filling in the rest of the logic: > > > > Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com> > > > > Tomi - Are you happy with this? > > I think it's simpler and better to do: > > .def_property( > "binning", > [](SensorConfiguration &self) { > return std::make_tuple(self.binning.binX, self.binning.binY); > }, > [](SensorConfiguration &self, std::tuple<uint32_t, uint32_t> value) { > self.binning.binX = std::get<0>(value); > self.binning.binY = std::get<1>(value); Does the std::get<> add the bounds checking that allows the vec.size() check to be removed? > }) > I'm afraid I already merged this I think. If it's a cleanup/fixup - can you submit a patch please? -- Kieran > Tomi > > > > > > > > > >> + }) > >> + .def_property( > >> + "skipping", > >> + [](SensorConfiguration &self) { > >> + return py::make_tuple(self.skipping.xOddInc, self.skipping.xEvenInc, > >> + self.skipping.yOddInc, self.skipping.yEvenInc); > >> + }, > >> + [](SensorConfiguration &self, py::object value) { > >> + auto vec = value.cast<std::vector<unsigned int>>(); > >> + if (vec.size() != 4) > >> + throw std::runtime_error("skipping requires iterable of 4 values"); > >> + self.skipping.xOddInc = vec[0]; > >> + self.skipping.xEvenInc = vec[1]; > >> + self.skipping.yOddInc = vec[2]; > >> + self.skipping.yEvenInc = vec[3]; > >> + }) > >> + .def_readwrite("output_size", &SensorConfiguration::outputSize) > >> + .def("is_valid", &SensorConfiguration::isValid); > >> + > >> pyCameraConfiguration > >> .def("__iter__", [](CameraConfiguration &self) { > >> return py::make_iterator<py::return_value_policy::reference_internal>(self); > >> @@ -293,6 +328,7 @@ PYBIND11_MODULE(_libcamera, m) > >> py::return_value_policy::reference_internal) > >> .def_property_readonly("size", &CameraConfiguration::size) > >> .def_property_readonly("empty", &CameraConfiguration::empty) > >> + .def_readwrite("sensor_config", &CameraConfiguration::sensorConfig) > >> .def_readwrite("transform", &CameraConfiguration::transform); > >> > >> pyCameraConfigurationStatus > >> -- > >> 2.39.2 > >> >
On 20/10/2023 11:20, Kieran Bingham wrote: > Quoting Tomi Valkeinen (2023-10-20 08:51:08) >> On 12/10/2023 11:29, Kieran Bingham via libcamera-devel wrote: >>> Hi David, >>> >>> Quoting David Plowman via libcamera-devel (2023-10-11 15:02:38) >>>> We provide access to the various fields of the new SensorConfiguration >>>> class. The class also needs a constructor so that Python applications >>>> can make one and put it into the CameraConfiguration. >>>> >>>> Signed-off-by: David Plowman <david.plowman@raspberrypi.com> >>>> --- >>>> src/py/libcamera/py_main.cpp | 36 ++++++++++++++++++++++++++++++++++++ >>>> 1 file changed, 36 insertions(+) >>>> >>>> diff --git a/src/py/libcamera/py_main.cpp b/src/py/libcamera/py_main.cpp >>>> index 01fb15a9..d2ce3722 100644 >>>> --- a/src/py/libcamera/py_main.cpp >>>> +++ b/src/py/libcamera/py_main.cpp >>>> @@ -112,6 +112,7 @@ PYBIND11_MODULE(_libcamera, m) >>>> >>>> auto pyCameraManager = py::class_<PyCameraManager, std::shared_ptr<PyCameraManager>>(m, "CameraManager"); >>>> auto pyCamera = py::class_<Camera, PyCameraSmartPtr<Camera>>(m, "Camera"); >>>> + auto pySensorConfiguration = py::class_<SensorConfiguration>(m, "SensorConfiguration"); >>>> auto pyCameraConfiguration = py::class_<CameraConfiguration>(m, "CameraConfiguration"); >>>> auto pyCameraConfigurationStatus = py::enum_<CameraConfiguration::Status>(pyCameraConfiguration, "Status"); >>>> auto pyStreamConfiguration = py::class_<StreamConfiguration>(m, "StreamConfiguration"); >>>> @@ -281,6 +282,40 @@ PYBIND11_MODULE(_libcamera, m) >>>> return ret; >>>> }); >>>> >>>> + pySensorConfiguration >>>> + .def(py::init<>()) >>>> + .def_readwrite("bit_depth", &SensorConfiguration::bitDepth) >>>> + .def_readwrite("analog_crop", &SensorConfiguration::analogCrop) >>>> + .def_property( >>>> + "binning", >>>> + [](SensorConfiguration &self) { >>>> + return py::make_tuple(self.binning.binX, self.binning.binY); >>>> + }, >>>> + [](SensorConfiguration &self, py::object value) { >>>> + auto vec = value.cast<std::vector<unsigned int>>(); >>>> + if (vec.size() != 2) >>>> + throw std::runtime_error("binning requires iterable of 2 values"); >>>> + self.binning.binX = vec[0]; >>>> + self.binning.binY = vec[1]; >>> >>> This seems reasonable to me. Partially filling in either of binning or >>> skipping would be invalid. >>> >>> Thanks for filling in the rest of the logic: >>> >>> Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com> >>> >>> Tomi - Are you happy with this? >> >> I think it's simpler and better to do: >> >> .def_property( >> "binning", >> [](SensorConfiguration &self) { >> return std::make_tuple(self.binning.binX, self.binning.binY); >> }, >> [](SensorConfiguration &self, std::tuple<uint32_t, uint32_t> value) { >> self.binning.binX = std::get<0>(value); >> self.binning.binY = std::get<1>(value); > > Does the std::get<> add the bounds checking that allows the vec.size() > check to be removed? It's the "std::tuple<uint32_t, uint32_t> value" that forces the types and the size. Tomi > >> }) >> > > I'm afraid I already merged this I think. > > If it's a cleanup/fixup - can you submit a patch please? > > -- > Kieran > > >> Tomi >> >> >>> >>> >>> >>>> + }) >>>> + .def_property( >>>> + "skipping", >>>> + [](SensorConfiguration &self) { >>>> + return py::make_tuple(self.skipping.xOddInc, self.skipping.xEvenInc, >>>> + self.skipping.yOddInc, self.skipping.yEvenInc); >>>> + }, >>>> + [](SensorConfiguration &self, py::object value) { >>>> + auto vec = value.cast<std::vector<unsigned int>>(); >>>> + if (vec.size() != 4) >>>> + throw std::runtime_error("skipping requires iterable of 4 values"); >>>> + self.skipping.xOddInc = vec[0]; >>>> + self.skipping.xEvenInc = vec[1]; >>>> + self.skipping.yOddInc = vec[2]; >>>> + self.skipping.yEvenInc = vec[3]; >>>> + }) >>>> + .def_readwrite("output_size", &SensorConfiguration::outputSize) >>>> + .def("is_valid", &SensorConfiguration::isValid); >>>> + >>>> pyCameraConfiguration >>>> .def("__iter__", [](CameraConfiguration &self) { >>>> return py::make_iterator<py::return_value_policy::reference_internal>(self); >>>> @@ -293,6 +328,7 @@ PYBIND11_MODULE(_libcamera, m) >>>> py::return_value_policy::reference_internal) >>>> .def_property_readonly("size", &CameraConfiguration::size) >>>> .def_property_readonly("empty", &CameraConfiguration::empty) >>>> + .def_readwrite("sensor_config", &CameraConfiguration::sensorConfig) >>>> .def_readwrite("transform", &CameraConfiguration::transform); >>>> >>>> pyCameraConfigurationStatus >>>> -- >>>> 2.39.2 >>>> >>
diff --git a/src/py/libcamera/py_main.cpp b/src/py/libcamera/py_main.cpp index 01fb15a9..d2ce3722 100644 --- a/src/py/libcamera/py_main.cpp +++ b/src/py/libcamera/py_main.cpp @@ -112,6 +112,7 @@ PYBIND11_MODULE(_libcamera, m) auto pyCameraManager = py::class_<PyCameraManager, std::shared_ptr<PyCameraManager>>(m, "CameraManager"); auto pyCamera = py::class_<Camera, PyCameraSmartPtr<Camera>>(m, "Camera"); + auto pySensorConfiguration = py::class_<SensorConfiguration>(m, "SensorConfiguration"); auto pyCameraConfiguration = py::class_<CameraConfiguration>(m, "CameraConfiguration"); auto pyCameraConfigurationStatus = py::enum_<CameraConfiguration::Status>(pyCameraConfiguration, "Status"); auto pyStreamConfiguration = py::class_<StreamConfiguration>(m, "StreamConfiguration"); @@ -281,6 +282,40 @@ PYBIND11_MODULE(_libcamera, m) return ret; }); + pySensorConfiguration + .def(py::init<>()) + .def_readwrite("bit_depth", &SensorConfiguration::bitDepth) + .def_readwrite("analog_crop", &SensorConfiguration::analogCrop) + .def_property( + "binning", + [](SensorConfiguration &self) { + return py::make_tuple(self.binning.binX, self.binning.binY); + }, + [](SensorConfiguration &self, py::object value) { + auto vec = value.cast<std::vector<unsigned int>>(); + if (vec.size() != 2) + throw std::runtime_error("binning requires iterable of 2 values"); + self.binning.binX = vec[0]; + self.binning.binY = vec[1]; + }) + .def_property( + "skipping", + [](SensorConfiguration &self) { + return py::make_tuple(self.skipping.xOddInc, self.skipping.xEvenInc, + self.skipping.yOddInc, self.skipping.yEvenInc); + }, + [](SensorConfiguration &self, py::object value) { + auto vec = value.cast<std::vector<unsigned int>>(); + if (vec.size() != 4) + throw std::runtime_error("skipping requires iterable of 4 values"); + self.skipping.xOddInc = vec[0]; + self.skipping.xEvenInc = vec[1]; + self.skipping.yOddInc = vec[2]; + self.skipping.yEvenInc = vec[3]; + }) + .def_readwrite("output_size", &SensorConfiguration::outputSize) + .def("is_valid", &SensorConfiguration::isValid); + pyCameraConfiguration .def("__iter__", [](CameraConfiguration &self) { return py::make_iterator<py::return_value_policy::reference_internal>(self); @@ -293,6 +328,7 @@ PYBIND11_MODULE(_libcamera, m) py::return_value_policy::reference_internal) .def_property_readonly("size", &CameraConfiguration::size) .def_property_readonly("empty", &CameraConfiguration::empty) + .def_readwrite("sensor_config", &CameraConfiguration::sensorConfig) .def_readwrite("transform", &CameraConfiguration::transform); pyCameraConfigurationStatus
We provide access to the various fields of the new SensorConfiguration class. The class also needs a constructor so that Python applications can make one and put it into the CameraConfiguration. Signed-off-by: David Plowman <david.plowman@raspberrypi.com> --- src/py/libcamera/py_main.cpp | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+)