[libcamera-devel] [PATCH v4 15/15] py: Hack for different event enable mechanism
Tomi Valkeinen
tomi.valkeinen at ideasonboard.com
Thu Mar 9 16:40:10 CET 2023
On 09/03/2023 16:26, Tomi Valkeinen wrote:
> Instead of connecting all the event signals automatically (except
> bufferCompletedEvent), add properties to Camera object to enable/disable
> the events. E.g.
>
> cam.requestCompletedEnabled = True
>
> would enable the delivery of request completed events.
>
> Also, as (I think) almost everyone wants request completed events,
> subscribe to them automatically for all cameras when creating the
> PyCameraManager singleton. If someone doesn't want request completed
> events, they can set the cam.requestCompletedEnabled to False.
>
> This is just a quick hack, a proper implementation would need a bit more
> abstraction functionality to the PyCameraManager.
Also, the Camera Manager events (camera added/removed) are still always
connected. We could add similar properties to enable/disable those.
Tomi
> Signed-off-by: Tomi Valkeinen <tomi.valkeinen at ideasonboard.com>
> ---
> src/py/libcamera/py_camera_manager.cpp | 3 -
> src/py/libcamera/py_camera_manager.h | 5 +-
> src/py/libcamera/py_main.cpp | 113 ++++++++++++++++++++-----
> 3 files changed, 96 insertions(+), 25 deletions(-)
>
> diff --git a/src/py/libcamera/py_camera_manager.cpp b/src/py/libcamera/py_camera_manager.cpp
> index c3b9646f..ca0f6f7a 100644
> --- a/src/py/libcamera/py_camera_manager.cpp
> +++ b/src/py/libcamera/py_camera_manager.cpp
> @@ -182,9 +182,6 @@ std::vector<PyCameraEvent> PyCameraManager::getPyCameraEvents(std::shared_ptr<Ca
> /* Note: Called from another thread */
> void PyCameraManager::handleBufferCompleted(std::shared_ptr<Camera> cam, Request *req, FrameBuffer *fb)
> {
> - if (!bufferCompletedEventActive_)
> - return;
> -
> CameraEvent ev(CameraEventType::BufferCompleted, cam, req, fb);
>
> pushEvent(ev);
> diff --git a/src/py/libcamera/py_camera_manager.h b/src/py/libcamera/py_camera_manager.h
> index 648d78af..41105de7 100644
> --- a/src/py/libcamera/py_camera_manager.h
> +++ b/src/py/libcamera/py_camera_manager.h
> @@ -77,10 +77,11 @@ public:
> void handleCameraAdded(std::shared_ptr<Camera> cam);
> void handleCameraRemoved(std::shared_ptr<Camera> cam);
>
> - bool bufferCompletedEventActive_ = false;
> + uint32_t event_mask_;
> + std::map<std::shared_ptr<Camera>, uint32_t> camera_event_masks_;
> + std::unique_ptr<CameraManager> cameraManager_;
>
> private:
> - std::unique_ptr<CameraManager> cameraManager_;
>
> UniqueFD eventFd_;
> libcamera::Mutex eventsMutex_;
> diff --git a/src/py/libcamera/py_main.cpp b/src/py/libcamera/py_main.cpp
> index cb7088b1..54b58366 100644
> --- a/src/py/libcamera/py_main.cpp
> +++ b/src/py/libcamera/py_main.cpp
> @@ -48,6 +48,57 @@ void init_py_geometry(py::module &m);
> void init_py_properties_generated(py::module &m);
> void init_py_transform(py::module &m);
>
> +static bool py_camera_get_event_flag(std::shared_ptr<Camera> camera, CameraEventType event_type)
> +{
> + const uint32_t evbit = 1 << (uint32_t)event_type;
> +
> + auto cm = gCameraManager.lock();
> + ASSERT(cm);
> +
> + auto it = cm->camera_event_masks_.find(camera);
> +
> + uint32_t mask = 0;
> +
> + if (it != cm->camera_event_masks_.end())
> + mask = it->second;
> +
> + return !!(mask & evbit);
> +}
> +
> +static void py_camera_set_event_flag(std::shared_ptr<Camera> camera, CameraEventType event_type, bool value)
> +{
> + const uint32_t evbit = 1 << (uint32_t)event_type;
> +
> + auto cm = gCameraManager.lock();
> + ASSERT(cm);
> +
> + uint32_t mask = 0;
> +
> + auto it = cm->camera_event_masks_.find(camera);
> + if (it != cm->camera_event_masks_.end())
> + mask = it->second;
> +
> + bool old_val = !!(mask & evbit);
> +
> + if (old_val == value)
> + return;
> +
> + if (value)
> + mask |= evbit;
> + else
> + mask &= ~evbit;
> +
> + cm->camera_event_masks_[camera] = mask;
> +
> + if (value) {
> + camera->requestCompleted.connect(camera.get(), [cm, camera](Request *req) {
> + cm->handleRequestCompleted(camera, req);
> + });
> + } else {
> + camera->requestCompleted.disconnect();
> + }
> +}
> +
> PYBIND11_MODULE(_libcamera, m)
> {
> init_py_enums(m);
> @@ -121,6 +172,10 @@ PYBIND11_MODULE(_libcamera, m)
> if (!cm) {
> cm = std::make_shared<PyCameraManager>();
> gCameraManager = cm;
> +
> + /* Always enable RequestCompleted for all cameras */
> + for (auto cam : cm->cameraManager_->cameras())
> + py_camera_set_event_flag(cam, CameraEventType::RequestCompleted, true);
> }
>
> return cm;
> @@ -132,12 +187,47 @@ PYBIND11_MODULE(_libcamera, m)
>
> .def_property_readonly("event_fd", &PyCameraManager::eventFd)
>
> - .def("get_events", &PyCameraManager::getPyEvents)
> -
> - .def_readwrite("buffer_completed_active", &PyCameraManager::bufferCompletedEventActive_);
> + .def("get_events", &PyCameraManager::getPyEvents);
>
> pyCamera
> .def_property_readonly("id", &Camera::id)
> +
> + .def_property(
> + "requestCompletedEnabled",
> + [](Camera &self) {
> + return py_camera_get_event_flag(self.shared_from_this(),
> + CameraEventType::RequestCompleted);
> + },
> + [](Camera &self, bool val) {
> + py_camera_set_event_flag(self.shared_from_this(),
> + CameraEventType::RequestCompleted,
> + val);
> + })
> +
> + .def_property(
> + "bufferCompletedEnabled",
> + [](Camera &self) {
> + return py_camera_get_event_flag(self.shared_from_this(),
> + CameraEventType::BufferCompleted);
> + },
> + [](Camera &self, bool val) {
> + py_camera_set_event_flag(self.shared_from_this(),
> + CameraEventType::BufferCompleted,
> + val);
> + })
> +
> + .def_property(
> + "disconnectEnabled",
> + [](Camera &self) {
> + return py_camera_get_event_flag(self.shared_from_this(),
> + CameraEventType::Disconnect);
> + },
> + [](Camera &self, bool val) {
> + py_camera_set_event_flag(self.shared_from_this(),
> + CameraEventType::Disconnect,
> + val);
> + })
> +
> .def("acquire", [](Camera &self) {
> int ret = self.acquire();
> if (ret)
> @@ -157,18 +247,6 @@ PYBIND11_MODULE(_libcamera, m)
> auto cm = gCameraManager.lock();
> ASSERT(cm);
>
> - self.requestCompleted.connect(&self, [cm, camera=self.shared_from_this()](Request *req) {
> - cm->handleRequestCompleted(camera, req);
> - });
> -
> - self.bufferCompleted.connect(&self, [cm, camera=self.shared_from_this()](Request *req, FrameBuffer *fb) {
> - cm->handleBufferCompleted(camera, req, fb);
> - });
> -
> - self.disconnected.connect(&self, [cm, camera=self.shared_from_this()]() {
> - cm->handleDisconnected(camera);
> - });
> -
> ControlList controlList(self.controls());
>
> for (const auto& [id, obj]: controls) {
> @@ -178,7 +256,6 @@ PYBIND11_MODULE(_libcamera, m)
>
> int ret = self.start(&controlList);
> if (ret) {
> - self.requestCompleted.disconnect();
> throw std::system_error(-ret, std::generic_category(),
> "Failed to start camera");
> }
> @@ -187,10 +264,6 @@ PYBIND11_MODULE(_libcamera, m)
> .def("stop", [](Camera &self) {
> int ret = self.stop();
>
> - self.requestCompleted.disconnect();
> - self.bufferCompleted.disconnect();
> - self.disconnected.disconnect();
> -
> auto cm = gCameraManager.lock();
> ASSERT(cm);
>
More information about the libcamera-devel
mailing list