[libcamera-devel] [PATCH v4 15/15] py: Hack for different event enable mechanism

Tomi Valkeinen tomi.valkeinen at ideasonboard.com
Thu Mar 9 15:26:01 CET 2023


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 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);
 
-- 
2.34.1



More information about the libcamera-devel mailing list