spa: libcamera: manage libcamera::CameraManager via a shared_ptr

Using a shared_ptr removes the need for manually calling
`libcamera_manager_release()` to drop the reference as it is done
automatically whenever the shared_ptr is destroyed or reset.
This commit is contained in:
Barnabás Pőcze 2022-09-03 22:10:50 +02:00 committed by Wim Taymans
parent 330686d3aa
commit 13357fec20
4 changed files with 38 additions and 78 deletions

View file

@ -66,11 +66,11 @@ struct impl {
struct spa_hook_list hooks; struct spa_hook_list hooks;
CameraManager *manager; std::shared_ptr<CameraManager> manager;
std::shared_ptr<Camera> camera; std::shared_ptr<Camera> camera;
impl(spa_log *log, impl(spa_log *log,
CameraManager *manager, std::shared_ptr<CameraManager> manager,
std::shared_ptr<Camera> camera, std::shared_ptr<Camera> camera,
std::string device_id); std::string device_id);
}; };
@ -234,20 +234,18 @@ static int impl_get_interface(struct spa_handle *handle, const char *type, void
static int impl_clear(struct spa_handle *handle) static int impl_clear(struct spa_handle *handle)
{ {
auto impl = reinterpret_cast<struct impl *>(handle); std::destroy_at(reinterpret_cast<impl *>(handle));
auto manager = impl->manager;
std::destroy_at(impl);
libcamera_manager_release(manager);
return 0; return 0;
} }
impl::impl(spa_log *log, CameraManager *manager, std::shared_ptr<Camera> camera, std::string device_id) impl::impl(spa_log *log,
std::shared_ptr<CameraManager> manager,
std::shared_ptr<Camera> camera,
std::string device_id)
: handle({ SPA_VERSION_HANDLE, impl_get_interface, impl_clear }), : handle({ SPA_VERSION_HANDLE, impl_get_interface, impl_clear }),
log(log), log(log),
device_id(std::move(device_id)), device_id(std::move(device_id)),
manager(manager), manager(std::move(manager)),
camera(std::move(camera)) camera(std::move(camera))
{ {
libcamera_log_topic_init(log); libcamera_log_topic_init(log);
@ -282,9 +280,8 @@ impl_init(const struct spa_handle_factory *factory,
auto log = static_cast<spa_log *>(spa_support_find(support, n_support, SPA_TYPE_INTERFACE_Log)); auto log = static_cast<spa_log *>(spa_support_find(support, n_support, SPA_TYPE_INTERFACE_Log));
auto manager = libcamera_manager_acquire(); auto manager = libcamera_manager_acquire(res);
if (!manager) { if (!manager) {
res = -errno;
spa_log_error(log, "can't start camera manager: %s", spa_strerror(res)); spa_log_error(log, "can't start camera manager: %s", spa_strerror(res));
return res; return res;
} }
@ -296,11 +293,10 @@ impl_init(const struct spa_handle_factory *factory,
auto camera = manager->get(device_id); auto camera = manager->get(device_id);
if (!camera) { if (!camera) {
spa_log_error(log, "unknown camera id %s", device_id.c_str()); spa_log_error(log, "unknown camera id %s", device_id.c_str());
libcamera_manager_release(manager);
return -ENOENT; return -ENOENT;
} }
new (handle) impl(log, manager, std::move(camera), std::move(device_id)); new (handle) impl(log, std::move(manager), std::move(camera), std::move(device_id));
return 0; return 0;
} }

View file

@ -56,13 +56,6 @@ using namespace libcamera;
namespace { namespace {
struct global {
int ref;
CameraManager *manager;
};
static struct global global;
struct device { struct device {
uint32_t id; uint32_t id;
std::shared_ptr<Camera> camera; std::shared_ptr<Camera> camera;
@ -79,7 +72,7 @@ typedef struct impl {
static constexpr uint64_t info_all = SPA_DEVICE_CHANGE_MASK_FLAGS | SPA_DEVICE_CHANGE_MASK_PROPS; static constexpr uint64_t info_all = SPA_DEVICE_CHANGE_MASK_FLAGS | SPA_DEVICE_CHANGE_MASK_PROPS;
struct spa_device_info info = SPA_DEVICE_INFO_INIT(); struct spa_device_info info = SPA_DEVICE_INFO_INIT();
CameraManager *manager = nullptr; std::shared_ptr<CameraManager> manager;
void addCamera(std::shared_ptr<libcamera::Camera> camera); void addCamera(std::shared_ptr<libcamera::Camera> camera);
void removeCamera(std::shared_ptr<libcamera::Camera> camera); void removeCamera(std::shared_ptr<libcamera::Camera> camera);
@ -91,35 +84,20 @@ typedef struct impl {
} }
int libcamera_manager_release(CameraManager *manager) static std::weak_ptr<CameraManager> global_manager;
std::shared_ptr<CameraManager> libcamera_manager_acquire(int& res)
{ {
if (global.manager != manager) if (auto manager = global_manager.lock())
return -EINVAL; return manager;
if (--global.ref == 0) { auto manager = std::make_shared<CameraManager>();
global.manager->stop(); if ((res = manager->start()) < 0)
delete global.manager; return {};
global.manager = NULL;
}
return 0;
}
CameraManager *libcamera_manager_acquire(void) global_manager = manager;
{
int res;
if (global.ref++ == 0) { return manager;
global.manager = new CameraManager();
if (global.manager == NULL)
return NULL;
if ((res = global.manager->start()) < 0) {
libcamera_manager_release(global.manager);
errno = -res;
return NULL;
}
}
return global.manager;
} }
static struct device *add_device(struct impl *impl, std::shared_ptr<Camera> camera) static struct device *add_device(struct impl *impl, std::shared_ptr<Camera> camera)
@ -227,7 +205,7 @@ static int start_monitor(struct impl *impl)
static int stop_monitor(struct impl *impl) static int stop_monitor(struct impl *impl)
{ {
if (impl->manager != NULL) { if (impl->manager) {
impl->manager->cameraAdded.disconnect(impl, &Impl::addCamera); impl->manager->cameraAdded.disconnect(impl, &Impl::addCamera);
impl->manager->cameraRemoved.disconnect(impl, &Impl::removeCamera); impl->manager->cameraRemoved.disconnect(impl, &Impl::removeCamera);
} }
@ -269,9 +247,7 @@ static void impl_hook_removed(struct spa_hook *hook)
struct impl *impl = (struct impl*)hook->priv; struct impl *impl = (struct impl*)hook->priv;
if (spa_hook_list_is_empty(&impl->hooks)) { if (spa_hook_list_is_empty(&impl->hooks)) {
stop_monitor(impl); stop_monitor(impl);
if (impl->manager) impl->manager.reset();
libcamera_manager_release(impl->manager);
impl->manager = NULL;
} }
} }
@ -286,9 +262,9 @@ impl_device_add_listener(void *object, struct spa_hook *listener,
spa_return_val_if_fail(impl != NULL, -EINVAL); spa_return_val_if_fail(impl != NULL, -EINVAL);
spa_return_val_if_fail(events != NULL, -EINVAL); spa_return_val_if_fail(events != NULL, -EINVAL);
impl->manager = libcamera_manager_acquire(); impl->manager = libcamera_manager_acquire(res);
if (impl->manager == NULL) if (!impl->manager)
return -errno; return res;
spa_hook_list_isolate(&impl->hooks, &save, listener, events, data); spa_hook_list_isolate(&impl->hooks, &save, listener, events, data);
@ -333,14 +309,10 @@ static int impl_get_interface(struct spa_handle *handle, const char *type, void
static int impl_clear(struct spa_handle *handle) static int impl_clear(struct spa_handle *handle)
{ {
auto impl = reinterpret_cast<struct impl *>(handle); auto impl = reinterpret_cast<struct impl *>(handle);
auto manager = impl->manager;
stop_monitor(impl); stop_monitor(impl);
std::destroy_at(impl); std::destroy_at(impl);
if (manager)
libcamera_manager_release(manager);
return 0; return 0;
} }

View file

@ -22,11 +22,8 @@
* DEALINGS IN THE SOFTWARE. * DEALINGS IN THE SOFTWARE.
*/ */
#include <memory>
#include <libcamera/camera_manager.h> #include <libcamera/camera_manager.h>
#include <linux/media.h> std::shared_ptr<libcamera::CameraManager> libcamera_manager_acquire(int& res);
using namespace libcamera;
CameraManager *libcamera_manager_acquire(void);
int libcamera_manager_release(CameraManager *manager);

View file

@ -60,6 +60,8 @@
#include "libcamera.h" #include "libcamera.h"
#include "libcamera-manager.hpp" #include "libcamera-manager.hpp"
using namespace libcamera;
namespace { namespace {
#define MAX_BUFFERS 32 #define MAX_BUFFERS 32
@ -160,7 +162,7 @@ typedef struct impl {
struct spa_io_position *position = nullptr; struct spa_io_position *position = nullptr;
struct spa_io_clock *clock = nullptr; struct spa_io_clock *clock = nullptr;
CameraManager *manager; std::shared_ptr<CameraManager> manager;
std::shared_ptr<Camera> camera; std::shared_ptr<Camera> camera;
FrameBufferAllocator *allocator = nullptr; FrameBufferAllocator *allocator = nullptr;
@ -178,7 +180,7 @@ typedef struct impl {
bool acquired = false; bool acquired = false;
impl(spa_log *log, spa_loop *data_loop, spa_system *system, impl(spa_log *log, spa_loop *data_loop, spa_system *system,
CameraManager *manager, std::shared_ptr<Camera> camera, std::string device_id); std::shared_ptr<CameraManager> manager, std::shared_ptr<Camera> camera, std::string device_id);
} Impl; } Impl;
} }
@ -915,24 +917,19 @@ static int impl_get_interface(struct spa_handle *handle, const char *type, void
static int impl_clear(struct spa_handle *handle) static int impl_clear(struct spa_handle *handle)
{ {
auto impl = reinterpret_cast<struct impl *>(handle); std::destroy_at(reinterpret_cast<impl *>(handle));
auto manager = impl->manager;
std::destroy_at(impl);
libcamera_manager_release(manager);
return 0; return 0;
} }
impl::impl(spa_log *log, spa_loop *data_loop, spa_system *system, impl::impl(spa_log *log, spa_loop *data_loop, spa_system *system,
CameraManager *manager, std::shared_ptr<Camera> camera, std::string device_id) std::shared_ptr<CameraManager> manager, std::shared_ptr<Camera> camera, std::string device_id)
: handle({ SPA_VERSION_HANDLE, impl_get_interface, impl_clear }), : handle({ SPA_VERSION_HANDLE, impl_get_interface, impl_clear }),
log(log), log(log),
data_loop(data_loop), data_loop(data_loop),
system(system), system(system),
device_id(std::move(device_id)), device_id(std::move(device_id)),
out_ports{{this}}, out_ports{{this}},
manager(manager), manager(std::move(manager)),
camera(std::move(camera)) camera(std::move(camera))
{ {
libcamera_log_topic_init(log); libcamera_log_topic_init(log);
@ -987,9 +984,8 @@ impl_init(const struct spa_handle_factory *factory,
return -EINVAL; return -EINVAL;
} }
auto manager = libcamera_manager_acquire(); auto manager = libcamera_manager_acquire(res);
if (!manager) { if (!manager) {
res = -errno;
spa_log_error(log, "can't start camera manager: %s", spa_strerror(res)); spa_log_error(log, "can't start camera manager: %s", spa_strerror(res));
return res; return res;
} }
@ -1001,12 +997,11 @@ impl_init(const struct spa_handle_factory *factory,
auto camera = manager->get(device_id); auto camera = manager->get(device_id);
if (!camera) { if (!camera) {
spa_log_error(log, "unknown camera id %s", device_id.c_str()); spa_log_error(log, "unknown camera id %s", device_id.c_str());
libcamera_manager_release(manager);
return -ENOENT; return -ENOENT;
} }
new (handle) impl(log, data_loop, system, new (handle) impl(log, data_loop, system,
manager, std::move(camera), std::move(device_id)); std::move(manager), std::move(camera), std::move(device_id));
return 0; return 0;
} }