Message ID | 20230309142601.70556-16-tomi.valkeinen@ideasonboard.com |
---|---|
State | Superseded |
Headers | show |
Series |
|
Related | show |
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@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); >
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);
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. Signed-off-by: Tomi Valkeinen <tomi.valkeinen@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(-)