summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorTomi Valkeinen <tomi.valkeinen@ideasonboard.com>2022-08-19 14:16:11 +0300
committerLaurent Pinchart <laurent.pinchart@ideasonboard.com>2022-08-19 15:44:18 +0300
commitf814b1b6a9f3d091982b42f117630f4dc1300404 (patch)
tree306c675142a208ad3cca9dc2d39dc886c7ea4f5e /src
parent418cbde04b8b21a7b9392808a0144dadcd56d268 (diff)
py: Create PyCameraManager
Wrap the CameraManager with a PyCameraManager class and move the related code inside the new class. This helps understanding the life times of the used-to-be global variables, gets rid of static handleRequestCompleted function, and allows us to simplify the binding code as the more complex pieces are inside the class. There should be no user visible functional changes. Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ideasonboard.com> Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Diffstat (limited to 'src')
-rw-r--r--src/py/libcamera/meson.build1
-rw-r--r--src/py/libcamera/py_camera_manager.cpp127
-rw-r--r--src/py/libcamera/py_camera_manager.h44
-rw-r--r--src/py/libcamera/py_main.cpp120
4 files changed, 198 insertions, 94 deletions
diff --git a/src/py/libcamera/meson.build b/src/py/libcamera/meson.build
index 99c2a8c0..af19ffdd 100644
--- a/src/py/libcamera/meson.build
+++ b/src/py/libcamera/meson.build
@@ -13,6 +13,7 @@ pybind11_proj = subproject('pybind11')
pybind11_dep = pybind11_proj.get_variable('pybind11_dep')
pycamera_sources = files([
+ 'py_camera_manager.cpp',
'py_enums.cpp',
'py_geometry.cpp',
'py_helpers.cpp',
diff --git a/src/py/libcamera/py_camera_manager.cpp b/src/py/libcamera/py_camera_manager.cpp
new file mode 100644
index 00000000..228fb212
--- /dev/null
+++ b/src/py/libcamera/py_camera_manager.cpp
@@ -0,0 +1,127 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+/*
+ * Copyright (C) 2022, Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>
+ */
+
+#include "py_camera_manager.h"
+
+#include <errno.h>
+#include <memory>
+#include <sys/eventfd.h>
+#include <system_error>
+#include <unistd.h>
+#include <vector>
+
+#include "py_main.h"
+
+namespace py = pybind11;
+
+using namespace libcamera;
+
+PyCameraManager::PyCameraManager()
+{
+ LOG(Python, Debug) << "PyCameraManager()";
+
+ cameraManager_ = std::make_unique<CameraManager>();
+
+ int fd = eventfd(0, 0);
+ if (fd == -1)
+ throw std::system_error(errno, std::generic_category(),
+ "Failed to create eventfd");
+
+ eventFd_ = fd;
+
+ int ret = cameraManager_->start();
+ if (ret) {
+ close(fd);
+ eventFd_ = -1;
+ throw std::system_error(-ret, std::generic_category(),
+ "Failed to start CameraManager");
+ }
+}
+
+PyCameraManager::~PyCameraManager()
+{
+ LOG(Python, Debug) << "~PyCameraManager()";
+
+ if (eventFd_ != -1) {
+ close(eventFd_);
+ eventFd_ = -1;
+ }
+}
+
+py::list PyCameraManager::cameras()
+{
+ /*
+ * Create a list of Cameras, where each camera has a keep-alive to
+ * CameraManager.
+ */
+ py::list l;
+
+ for (auto &camera : cameraManager_->cameras()) {
+ py::object py_cm = py::cast(this);
+ py::object py_cam = py::cast(camera);
+ py::detail::keep_alive_impl(py_cam, py_cm);
+ l.append(py_cam);
+ }
+
+ return l;
+}
+
+std::vector<py::object> PyCameraManager::getReadyRequests()
+{
+ readFd();
+
+ std::vector<py::object> py_reqs;
+
+ for (Request *request : getCompletedRequests()) {
+ py::object o = py::cast(request);
+ /* Decrease the ref increased in Camera.queue_request() */
+ o.dec_ref();
+ py_reqs.push_back(o);
+ }
+
+ return py_reqs;
+}
+
+/* Note: Called from another thread */
+void PyCameraManager::handleRequestCompleted(Request *req)
+{
+ pushRequest(req);
+ writeFd();
+}
+
+void PyCameraManager::writeFd()
+{
+ uint64_t v = 1;
+
+ size_t s = write(eventFd_, &v, 8);
+ /*
+ * We should never fail, and have no simple means to manage the error,
+ * so let's log a fatal error.
+ */
+ if (s != 8)
+ LOG(Python, Fatal) << "Unable to write to eventfd";
+}
+
+void PyCameraManager::readFd()
+{
+ uint8_t buf[8];
+
+ if (read(eventFd_, buf, 8) != 8)
+ throw std::system_error(errno, std::generic_category());
+}
+
+void PyCameraManager::pushRequest(Request *req)
+{
+ std::lock_guard guard(completedRequestsMutex_);
+ completedRequests_.push_back(req);
+}
+
+std::vector<Request *> PyCameraManager::getCompletedRequests()
+{
+ std::vector<Request *> v;
+ std::lock_guard guard(completedRequestsMutex_);
+ swap(v, completedRequests_);
+ return v;
+}
diff --git a/src/py/libcamera/py_camera_manager.h b/src/py/libcamera/py_camera_manager.h
new file mode 100644
index 00000000..9c15f814
--- /dev/null
+++ b/src/py/libcamera/py_camera_manager.h
@@ -0,0 +1,44 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+/*
+ * Copyright (C) 2022, Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>
+ */
+
+#pragma once
+
+#include <mutex>
+
+#include <libcamera/libcamera.h>
+
+#include <pybind11/smart_holder.h>
+
+using namespace libcamera;
+
+class PyCameraManager
+{
+public:
+ PyCameraManager();
+ ~PyCameraManager();
+
+ pybind11::list cameras();
+ std::shared_ptr<Camera> get(const std::string &name) { return cameraManager_->get(name); }
+
+ static const std::string &version() { return CameraManager::version(); }
+
+ int eventFd() const { return eventFd_; }
+
+ std::vector<pybind11::object> getReadyRequests();
+
+ void handleRequestCompleted(Request *req);
+
+private:
+ std::unique_ptr<CameraManager> cameraManager_;
+
+ int eventFd_ = -1;
+ std::mutex completedRequestsMutex_;
+ std::vector<Request *> completedRequests_;
+
+ void writeFd();
+ void readFd();
+ void pushRequest(Request *req);
+ std::vector<Request *> getCompletedRequests();
+};
diff --git a/src/py/libcamera/py_main.cpp b/src/py/libcamera/py_main.cpp
index e652837f..7e613a3f 100644
--- a/src/py/libcamera/py_main.cpp
+++ b/src/py/libcamera/py_main.cpp
@@ -7,10 +7,10 @@
#include "py_main.h"
-#include <mutex>
+#include <memory>
#include <stdexcept>
-#include <sys/eventfd.h>
-#include <unistd.h>
+#include <string>
+#include <vector>
#include <libcamera/base/log.h>
@@ -21,6 +21,7 @@
#include <pybind11/stl.h>
#include <pybind11/stl_bind.h>
+#include "py_camera_manager.h"
#include "py_helpers.h"
namespace py = pybind11;
@@ -33,27 +34,11 @@ LOG_DEFINE_CATEGORY(Python)
}
-static std::weak_ptr<CameraManager> gCameraManager;
-static int gEventfd;
-static std::mutex gReqlistMutex;
-static std::vector<Request *> gReqList;
-
-static void handleRequestCompleted(Request *req)
-{
- {
- std::lock_guard guard(gReqlistMutex);
- gReqList.push_back(req);
- }
-
- uint64_t v = 1;
- size_t s = write(gEventfd, &v, 8);
- /*
- * We should never fail, and have no simple means to manage the error,
- * so let's log a fatal error.
- */
- if (s != 8)
- LOG(Python, Fatal) << "Unable to write to eventfd";
-}
+/*
+ * Note: global C++ destructors can be ran on this before the py module is
+ * destructed.
+ */
+static std::weak_ptr<PyCameraManager> gCameraManager;
void init_py_enums(py::module &m);
void init_py_controls_generated(py::module &m);
@@ -76,7 +61,7 @@ PYBIND11_MODULE(_libcamera, m)
* https://pybind11.readthedocs.io/en/latest/advanced/misc.html#avoiding-c-types-in-docstrings
*/
- auto pyCameraManager = py::class_<CameraManager>(m, "CameraManager");
+ auto pyCameraManager = py::class_<PyCameraManager>(m, "CameraManager");
auto pyCamera = py::class_<Camera>(m, "Camera");
auto pyCameraConfiguration = py::class_<CameraConfiguration>(m, "CameraConfiguration");
auto pyCameraConfigurationStatus = py::enum_<CameraConfiguration::Status>(pyCameraConfiguration, "Status");
@@ -110,78 +95,22 @@ PYBIND11_MODULE(_libcamera, m)
/* Classes */
pyCameraManager
.def_static("singleton", []() {
- std::shared_ptr<CameraManager> cm = gCameraManager.lock();
- if (cm)
- return cm;
-
- int fd = eventfd(0, 0);
- if (fd == -1)
- throw std::system_error(errno, std::generic_category(),
- "Failed to create eventfd");
-
- cm = std::shared_ptr<CameraManager>(new CameraManager, [](auto p) {
- close(gEventfd);
- gEventfd = -1;
- delete p;
- });
-
- gEventfd = fd;
- gCameraManager = cm;
-
- int ret = cm->start();
- if (ret)
- throw std::system_error(-ret, std::generic_category(),
- "Failed to start CameraManager");
-
- return cm;
- })
-
- .def_property_readonly("version", &CameraManager::version)
+ std::shared_ptr<PyCameraManager> cm = gCameraManager.lock();
- .def_property_readonly("event_fd", [](CameraManager &) {
- return gEventfd;
- })
-
- .def("get_ready_requests", [](CameraManager &) {
- uint8_t buf[8];
-
- if (read(gEventfd, buf, 8) != 8)
- throw std::system_error(errno, std::generic_category());
-
- std::vector<Request *> v;
-
- {
- std::lock_guard guard(gReqlistMutex);
- swap(v, gReqList);
+ if (!cm) {
+ cm = std::make_shared<PyCameraManager>();
+ gCameraManager = cm;
}
- std::vector<py::object> ret;
-
- for (Request *req : v) {
- py::object o = py::cast(req);
- /* Decrease the ref increased in Camera.queue_request() */
- o.dec_ref();
- ret.push_back(o);
- }
-
- return ret;
+ return cm;
})
- .def("get", py::overload_cast<const std::string &>(&CameraManager::get), py::keep_alive<0, 1>())
-
- /* Create a list of Cameras, where each camera has a keep-alive to CameraManager */
- .def_property_readonly("cameras", [](CameraManager &self) {
- py::list l;
-
- for (auto &c : self.cameras()) {
- py::object py_cm = py::cast(self);
- py::object py_cam = py::cast(c);
- py::detail::keep_alive_impl(py_cam, py_cm);
- l.append(py_cam);
- }
+ .def_property_readonly("version", &PyCameraManager::version)
+ .def("get", &PyCameraManager::get, py::keep_alive<0, 1>())
+ .def_property_readonly("cameras", &PyCameraManager::cameras)
- return l;
- });
+ .def_property_readonly("event_fd", &PyCameraManager::eventFd)
+ .def("get_ready_requests", &PyCameraManager::getReadyRequests);
pyCamera
.def_property_readonly("id", &Camera::id)
@@ -191,7 +120,10 @@ PYBIND11_MODULE(_libcamera, m)
const std::unordered_map<const ControlId *, py::object> &controls) {
/* \todo What happens if someone calls start() multiple times? */
- self.requestCompleted.connect(handleRequestCompleted);
+ auto cm = gCameraManager.lock();
+ ASSERT(cm);
+
+ self.requestCompleted.connect(cm.get(), &PyCameraManager::handleRequestCompleted);
ControlList controlList(self.controls());
@@ -202,7 +134,7 @@ PYBIND11_MODULE(_libcamera, m)
int ret = self.start(&controlList);
if (ret) {
- self.requestCompleted.disconnect(handleRequestCompleted);
+ self.requestCompleted.disconnect();
return ret;
}
@@ -214,7 +146,7 @@ PYBIND11_MODULE(_libcamera, m)
if (ret)
return ret;
- self.requestCompleted.disconnect(handleRequestCompleted);
+ self.requestCompleted.disconnect();
return 0;
})