[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