@@ -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_;
@@ -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);
@@ -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) {
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@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(-)