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>
This commit is contained in:
Tomi Valkeinen
2022-08-19 14:16:11 +03:00
committed by Laurent Pinchart
parent 418cbde04b
commit f814b1b6a9
4 changed files with 198 additions and 94 deletions
+26 -94
View File
@@ -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;
std::shared_ptr<PyCameraManager> cm = gCameraManager.lock();
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");
if (!cm) {
cm = std::make_shared<PyCameraManager>();
gCameraManager = cm;
}
return cm;
})
.def_property_readonly("version", &CameraManager::version)
.def_property_readonly("version", &PyCameraManager::version)
.def("get", &PyCameraManager::get, py::keep_alive<0, 1>())
.def_property_readonly("cameras", &PyCameraManager::cameras)
.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);
}
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;
})
.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);
}
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;
})