[libcamera-devel] [PATCH v2 13/14] py: Discard/Dispatch Request events on camera.stop()
Tomi Valkeinen
tomi.valkeinen at ideasonboard.com
Wed Jun 29 09:04:15 CEST 2022
To prevent old Request related events from being left in the event
queue, messing up the next camera.start(), force the events to be either
discarded or dispatched when camera.stop() is called.
camera.stop() will discard all Request events (RequestCompleted and
BufferCompleted) for that camera. camera.stop(dispatch_events=True) will
instead dispatch all events, also for other cameras.
The dispatch version dispatches all events instead of just the Request
events for one camera so that the event ordering stays the same.
Signed-off-by: Tomi Valkeinen <tomi.valkeinen at ideasonboard.com>
---
src/py/libcamera/py_camera_manager.cpp | 30 ++++++++++++++++++++++++++
src/py/libcamera/py_camera_manager.h | 1 +
src/py/libcamera/py_main.cpp | 12 +++++++++--
3 files changed, 41 insertions(+), 2 deletions(-)
diff --git a/src/py/libcamera/py_camera_manager.cpp b/src/py/libcamera/py_camera_manager.cpp
index 599a9f7e..dfd43a09 100644
--- a/src/py/libcamera/py_camera_manager.cpp
+++ b/src/py/libcamera/py_camera_manager.cpp
@@ -218,6 +218,36 @@ void PyCameraManager::discardEvents()
}
}
+void PyCameraManager::discardRequests(std::shared_ptr<Camera> camera)
+{
+ MutexLocker guard(cameraEventsMutex_);
+
+ size_t oldSize = cameraEvents_.size();
+
+ for (const auto &ev : cameraEvents_) {
+ if (ev.type_ != CameraEvent::Type::RequestCompleted)
+ continue;
+
+ if (ev.camera_ != camera)
+ continue;
+
+ /* Decrease the ref increased in Camera.queue_request() */
+ py::object o = py::cast(ev.request_);
+ o.dec_ref();
+ }
+
+ cameraEvents_.erase(std::remove_if(cameraEvents_.begin(), cameraEvents_.end(),
+ [&camera](const CameraEvent &ev) {
+ return ev.camera_ == camera &&
+ (ev.type_ == CameraEvent::Type::RequestCompleted ||
+ ev.type_ == CameraEvent::Type::BufferCompleted);
+ }),
+ cameraEvents_.end());
+
+ LOG(Python, Debug) << "Discarded " << oldSize - cameraEvents_.size()
+ << " request events";
+}
+
std::function<void(std::shared_ptr<Camera>)> PyCameraManager::getCameraAdded() const
{
return cameraAddedHandler_;
diff --git a/src/py/libcamera/py_camera_manager.h b/src/py/libcamera/py_camera_manager.h
index aa51a6bc..9c8d6ca8 100644
--- a/src/py/libcamera/py_camera_manager.h
+++ b/src/py/libcamera/py_camera_manager.h
@@ -38,6 +38,7 @@ public:
void dispatchEvents();
void discardEvents();
+ void discardRequests(std::shared_ptr<Camera> camera);
std::function<void(std::shared_ptr<Camera>)> getCameraAdded() const;
void setCameraAdded(std::function<void(std::shared_ptr<Camera>)> func);
diff --git a/src/py/libcamera/py_main.cpp b/src/py/libcamera/py_main.cpp
index a07f06c4..c4755bea 100644
--- a/src/py/libcamera/py_main.cpp
+++ b/src/py/libcamera/py_main.cpp
@@ -168,16 +168,24 @@ PYBIND11_MODULE(_libcamera, m)
}
}, py::arg("controls") = std::unordered_map<const ControlId *, py::object>())
- .def("stop", [](Camera &self) {
+ .def("stop", [](Camera &self, bool dispatchEvents) {
int ret = self.stop();
self.requestCompleted.disconnect();
+ auto cm = gCameraManager.lock();
+ ASSERT(cm);
+
+ if (dispatchEvents)
+ cm->dispatchEvents();
+ else
+ cm->discardRequests(self.shared_from_this());
+
/* \todo Should we just ignore the error? */
if (ret)
throw std::system_error(-ret, std::generic_category(),
"Failed to start camera");
- })
+ }, py::arg("dispatch_events") = false)
.def_property("request_completed",
[](Camera &self) {
--
2.34.1
More information about the libcamera-devel
mailing list