mirror of
https://gitlab.freedesktop.org/pipewire/pipewire.git
synced 2025-11-01 22:58:50 -04:00
spa: libcamera: rework construction/destruction of libcamera source impl
Move some things into constructors and try not to depend on the fact that the storage is zero initialized, try to initialize everything properly.
This commit is contained in:
parent
98193f7d67
commit
330686d3aa
2 changed files with 130 additions and 118 deletions
|
|
@ -60,15 +60,7 @@
|
|||
#include "libcamera.h"
|
||||
#include "libcamera-manager.hpp"
|
||||
|
||||
struct props {
|
||||
char device[128];
|
||||
char device_name[128];
|
||||
};
|
||||
|
||||
static void reset_props(struct props *props)
|
||||
{
|
||||
spa_zero(*props);
|
||||
}
|
||||
namespace {
|
||||
|
||||
#define MAX_BUFFERS 32
|
||||
#define MASK_BUFFERS 31
|
||||
|
|
@ -97,58 +89,81 @@ struct control {
|
|||
struct port {
|
||||
struct impl *impl;
|
||||
|
||||
bool have_format;
|
||||
bool have_format = false;
|
||||
struct spa_video_info current_format;
|
||||
struct spa_fraction rate;
|
||||
|
||||
struct spa_fraction rate = {};
|
||||
StreamConfiguration streamConfig;
|
||||
|
||||
uint32_t memtype;
|
||||
uint32_t memtype = 0;
|
||||
|
||||
struct control controls[MAX_CONTROLS];
|
||||
uint32_t n_controls;
|
||||
uint32_t n_controls = 0;
|
||||
|
||||
struct buffer buffers[MAX_BUFFERS];
|
||||
uint32_t n_buffers;
|
||||
uint32_t n_buffers = 0;
|
||||
struct spa_list queue;
|
||||
struct spa_ringbuffer ring;
|
||||
struct spa_ringbuffer ring = SPA_RINGBUFFER_INIT();
|
||||
uint32_t ring_ids[MAX_BUFFERS];
|
||||
|
||||
uint64_t info_all;
|
||||
struct spa_port_info info;
|
||||
struct spa_io_buffers *io;
|
||||
struct spa_io_sequence *control;
|
||||
static constexpr uint64_t info_all = SPA_PORT_CHANGE_MASK_FLAGS | SPA_PORT_CHANGE_MASK_PARAMS;
|
||||
struct spa_port_info info = SPA_PORT_INFO_INIT();
|
||||
struct spa_io_buffers *io = nullptr;
|
||||
struct spa_io_sequence *control = nullptr;
|
||||
struct spa_param_info params[8];
|
||||
|
||||
uint32_t fmt_index;
|
||||
uint32_t fmt_index = 0;
|
||||
PixelFormat enum_fmt;
|
||||
uint32_t size_index;
|
||||
uint32_t size_index = 0;
|
||||
|
||||
port(struct impl *impl)
|
||||
: impl(impl)
|
||||
{
|
||||
spa_list_init(&queue);
|
||||
|
||||
params[0] = SPA_PARAM_INFO(SPA_PARAM_PropInfo, SPA_PARAM_INFO_READ);
|
||||
params[1] = SPA_PARAM_INFO(SPA_PARAM_EnumFormat, SPA_PARAM_INFO_READ);
|
||||
params[2] = SPA_PARAM_INFO(SPA_PARAM_Meta, SPA_PARAM_INFO_READ);
|
||||
params[3] = SPA_PARAM_INFO(SPA_PARAM_IO, SPA_PARAM_INFO_READ);
|
||||
params[4] = SPA_PARAM_INFO(SPA_PARAM_Format, SPA_PARAM_INFO_WRITE);
|
||||
params[5] = SPA_PARAM_INFO(SPA_PARAM_Buffers, 0);
|
||||
|
||||
info.flags = SPA_PORT_FLAG_LIVE | SPA_PORT_FLAG_PHYSICAL | SPA_PORT_FLAG_TERMINAL;
|
||||
info.params = params;
|
||||
info.n_params = 6;
|
||||
}
|
||||
};
|
||||
|
||||
struct impl {
|
||||
typedef struct impl {
|
||||
struct spa_handle handle;
|
||||
struct spa_node node;
|
||||
struct spa_node node = {};
|
||||
|
||||
struct spa_log *log;
|
||||
struct spa_loop *data_loop;
|
||||
struct spa_system *system;
|
||||
|
||||
uint64_t info_all;
|
||||
struct spa_node_info info;
|
||||
static constexpr uint64_t info_all =
|
||||
SPA_NODE_CHANGE_MASK_FLAGS |
|
||||
SPA_NODE_CHANGE_MASK_PROPS |
|
||||
SPA_NODE_CHANGE_MASK_PARAMS;
|
||||
struct spa_node_info info = SPA_NODE_INFO_INIT();
|
||||
struct spa_param_info params[8];
|
||||
struct props props;
|
||||
|
||||
std::string device_id;
|
||||
std::string device_name;
|
||||
|
||||
struct spa_hook_list hooks;
|
||||
struct spa_callbacks callbacks;
|
||||
struct spa_callbacks callbacks = {};
|
||||
|
||||
struct port out_ports[1];
|
||||
std::array<port, 1> out_ports;
|
||||
|
||||
struct spa_io_position *position;
|
||||
struct spa_io_clock *clock;
|
||||
struct spa_io_position *position = nullptr;
|
||||
struct spa_io_clock *clock = nullptr;
|
||||
|
||||
CameraManager *manager;
|
||||
std::shared_ptr<Camera> camera;
|
||||
|
||||
FrameBufferAllocator *allocator;
|
||||
FrameBufferAllocator *allocator = nullptr;
|
||||
std::vector<std::unique_ptr<libcamera::Request>> requestPool;
|
||||
std::deque<libcamera::Request *> pendingRequests;
|
||||
|
||||
|
|
@ -157,13 +172,16 @@ struct impl {
|
|||
unsigned int have_config;
|
||||
std::unique_ptr<CameraConfiguration> config;
|
||||
|
||||
struct spa_source source;
|
||||
struct spa_source source = {};
|
||||
|
||||
unsigned int active:1;
|
||||
unsigned int acquired:1;
|
||||
};
|
||||
bool active = false;
|
||||
bool acquired = false;
|
||||
|
||||
typedef struct impl Impl;
|
||||
impl(spa_log *log, spa_loop *data_loop, spa_system *system,
|
||||
CameraManager *manager, std::shared_ptr<Camera> camera, std::string device_id);
|
||||
} Impl;
|
||||
|
||||
}
|
||||
|
||||
#define CHECK_PORT(impl,direction,port_id) ((direction) == SPA_DIRECTION_OUTPUT && (port_id) == 0)
|
||||
|
||||
|
|
@ -196,22 +214,20 @@ next:
|
|||
switch (id) {
|
||||
case SPA_PARAM_PropInfo:
|
||||
{
|
||||
struct props *p = &impl->props;
|
||||
|
||||
switch (result.index) {
|
||||
case 0:
|
||||
param = (struct spa_pod*)spa_pod_builder_add_object(&b,
|
||||
SPA_TYPE_OBJECT_PropInfo, id,
|
||||
SPA_PROP_INFO_id, SPA_POD_Id(SPA_PROP_device),
|
||||
SPA_PROP_INFO_description, SPA_POD_String("The libcamera device"),
|
||||
SPA_PROP_INFO_type, SPA_POD_String(p->device));
|
||||
SPA_PROP_INFO_type, SPA_POD_String(impl->device_id.c_str()));
|
||||
break;
|
||||
case 1:
|
||||
param = (struct spa_pod*)spa_pod_builder_add_object(&b,
|
||||
SPA_TYPE_OBJECT_PropInfo, id,
|
||||
SPA_PROP_INFO_id, SPA_POD_Id(SPA_PROP_deviceName),
|
||||
SPA_PROP_INFO_description, SPA_POD_String("The libcamera device name"),
|
||||
SPA_PROP_INFO_type, SPA_POD_String(p->device_name));
|
||||
SPA_PROP_INFO_type, SPA_POD_String(impl->device_name.c_str()));
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
|
|
@ -220,14 +236,12 @@ next:
|
|||
}
|
||||
case SPA_PARAM_Props:
|
||||
{
|
||||
struct props *p = &impl->props;
|
||||
|
||||
switch (result.index) {
|
||||
case 0:
|
||||
param = (struct spa_pod*)spa_pod_builder_add_object(&b,
|
||||
SPA_TYPE_OBJECT_Props, id,
|
||||
SPA_PROP_device, SPA_POD_String(p->device),
|
||||
SPA_PROP_deviceName, SPA_POD_String(p->device_name));
|
||||
SPA_PROP_device, SPA_POD_String(impl->device_id.c_str()),
|
||||
SPA_PROP_deviceName, SPA_POD_String(impl->device_name.c_str()));
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
|
|
@ -260,15 +274,22 @@ static int impl_node_set_param(void *object,
|
|||
switch (id) {
|
||||
case SPA_PARAM_Props:
|
||||
{
|
||||
struct props *p = &impl->props;
|
||||
|
||||
if (param == NULL) {
|
||||
reset_props(p);
|
||||
impl->device_id.clear();
|
||||
impl->device_name.clear();
|
||||
return 0;
|
||||
}
|
||||
spa_pod_parse_object(param,
|
||||
|
||||
char device[128];
|
||||
int res = spa_pod_parse_object(param,
|
||||
SPA_TYPE_OBJECT_Props, NULL,
|
||||
SPA_PROP_device, SPA_POD_OPT_Stringn(p->device, sizeof(p->device)));
|
||||
SPA_PROP_device, SPA_POD_OPT_Stringn(device, sizeof(device)));
|
||||
|
||||
if (res < 0)
|
||||
return res;
|
||||
|
||||
impl->device_id = device;
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
|
|
@ -894,13 +915,44 @@ static int impl_get_interface(struct spa_handle *handle, const char *type, void
|
|||
|
||||
static int impl_clear(struct spa_handle *handle)
|
||||
{
|
||||
struct impl *impl;
|
||||
auto impl = reinterpret_cast<struct impl *>(handle);
|
||||
auto manager = impl->manager;
|
||||
|
||||
std::destroy_at(impl);
|
||||
libcamera_manager_release(manager);
|
||||
|
||||
impl = (struct impl *) handle;
|
||||
impl->~Impl();
|
||||
return 0;
|
||||
}
|
||||
|
||||
impl::impl(spa_log *log, spa_loop *data_loop, spa_system *system,
|
||||
CameraManager *manager, std::shared_ptr<Camera> camera, std::string device_id)
|
||||
: handle({ SPA_VERSION_HANDLE, impl_get_interface, impl_clear }),
|
||||
log(log),
|
||||
data_loop(data_loop),
|
||||
system(system),
|
||||
device_id(std::move(device_id)),
|
||||
out_ports{{this}},
|
||||
manager(manager),
|
||||
camera(std::move(camera))
|
||||
{
|
||||
libcamera_log_topic_init(log);
|
||||
|
||||
spa_hook_list_init(&hooks);
|
||||
|
||||
node.iface = SPA_INTERFACE_INIT(
|
||||
SPA_TYPE_INTERFACE_Node,
|
||||
SPA_VERSION_NODE,
|
||||
&impl_node, this);
|
||||
|
||||
params[0] = SPA_PARAM_INFO(SPA_PARAM_PropInfo, SPA_PARAM_INFO_READ);
|
||||
params[1] = SPA_PARAM_INFO(SPA_PARAM_Props, SPA_PARAM_INFO_READWRITE);
|
||||
|
||||
info.max_output_ports = 1;
|
||||
info.flags = SPA_NODE_FLAG_RT;
|
||||
info.params = params;
|
||||
info.n_params = 2;
|
||||
}
|
||||
|
||||
static size_t
|
||||
impl_get_size(const struct spa_handle_factory *factory,
|
||||
const struct spa_dict *params)
|
||||
|
|
@ -915,87 +967,47 @@ impl_init(const struct spa_handle_factory *factory,
|
|||
const struct spa_support *support,
|
||||
uint32_t n_support)
|
||||
{
|
||||
struct impl *impl;
|
||||
const char *str;
|
||||
struct port *port;
|
||||
int res;
|
||||
|
||||
spa_return_val_if_fail(factory != NULL, -EINVAL);
|
||||
spa_return_val_if_fail(handle != NULL, -EINVAL);
|
||||
|
||||
impl = new(handle) Impl();
|
||||
auto log = static_cast<spa_log *>(spa_support_find(support, n_support, SPA_TYPE_INTERFACE_Log));
|
||||
auto data_loop = static_cast<spa_loop *>(spa_support_find(support, n_support, SPA_TYPE_INTERFACE_DataLoop));
|
||||
auto system = static_cast<spa_system *>(spa_support_find(support, n_support, SPA_TYPE_INTERFACE_System));
|
||||
|
||||
handle->get_interface = impl_get_interface;
|
||||
handle->clear = impl_clear;
|
||||
|
||||
impl->log = (struct spa_log*)spa_support_find(support, n_support, SPA_TYPE_INTERFACE_Log);
|
||||
libcamera_log_topic_init(impl->log);
|
||||
|
||||
impl->data_loop = (struct spa_loop*)spa_support_find(support, n_support, SPA_TYPE_INTERFACE_DataLoop);
|
||||
impl->system = (struct spa_system*)spa_support_find(support, n_support, SPA_TYPE_INTERFACE_System);
|
||||
|
||||
if (impl->data_loop == NULL) {
|
||||
spa_log_error(impl->log, "a data_loop is needed");
|
||||
if (!data_loop) {
|
||||
spa_log_error(log, "a data_loop is needed");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (impl->system == NULL) {
|
||||
spa_log_error(impl->log, "a system is needed");
|
||||
if (!system) {
|
||||
spa_log_error(log, "a system is needed");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
impl->node.iface = SPA_INTERFACE_INIT(
|
||||
SPA_TYPE_INTERFACE_Node,
|
||||
SPA_VERSION_NODE,
|
||||
&impl_node, impl);
|
||||
spa_hook_list_init(&impl->hooks);
|
||||
|
||||
impl->info_all = SPA_NODE_CHANGE_MASK_FLAGS |
|
||||
SPA_NODE_CHANGE_MASK_PROPS |
|
||||
SPA_NODE_CHANGE_MASK_PARAMS;
|
||||
impl->info = SPA_NODE_INFO_INIT();
|
||||
impl->info.max_output_ports = 1;
|
||||
impl->info.flags = SPA_NODE_FLAG_RT;
|
||||
impl->params[0] = SPA_PARAM_INFO(SPA_PARAM_PropInfo, SPA_PARAM_INFO_READ);
|
||||
impl->params[1] = SPA_PARAM_INFO(SPA_PARAM_Props, SPA_PARAM_INFO_READWRITE);
|
||||
impl->info.params = impl->params;
|
||||
impl->info.n_params = 2;
|
||||
reset_props(&impl->props);
|
||||
|
||||
port = GET_OUT_PORT(impl, 0);
|
||||
port->impl = impl;
|
||||
spa_list_init(&port->queue);
|
||||
port->info_all = SPA_PORT_CHANGE_MASK_FLAGS |
|
||||
SPA_PORT_CHANGE_MASK_PARAMS;
|
||||
port->info = SPA_PORT_INFO_INIT();
|
||||
port->info.flags = SPA_PORT_FLAG_LIVE |
|
||||
SPA_PORT_FLAG_PHYSICAL |
|
||||
SPA_PORT_FLAG_TERMINAL;
|
||||
port->params[0] = SPA_PARAM_INFO(SPA_PARAM_PropInfo, SPA_PARAM_INFO_READ);
|
||||
port->params[1] = SPA_PARAM_INFO(SPA_PARAM_EnumFormat, SPA_PARAM_INFO_READ);
|
||||
port->params[2] = SPA_PARAM_INFO(SPA_PARAM_Meta, SPA_PARAM_INFO_READ);
|
||||
port->params[3] = SPA_PARAM_INFO(SPA_PARAM_IO, SPA_PARAM_INFO_READ);
|
||||
port->params[4] = SPA_PARAM_INFO(SPA_PARAM_Format, SPA_PARAM_INFO_WRITE);
|
||||
port->params[5] = SPA_PARAM_INFO(SPA_PARAM_Buffers, 0);
|
||||
port->info.params = port->params;
|
||||
port->info.n_params = 6;
|
||||
|
||||
if (info && (str = spa_dict_lookup(info, SPA_KEY_API_LIBCAMERA_PATH)))
|
||||
strncpy(impl->props.device, str, sizeof(impl->props.device));
|
||||
|
||||
impl->manager = libcamera_manager_acquire();
|
||||
if (impl->manager == NULL) {
|
||||
auto manager = libcamera_manager_acquire();
|
||||
if (!manager) {
|
||||
res = -errno;
|
||||
spa_log_error(impl->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;
|
||||
}
|
||||
|
||||
impl->camera = impl->manager->get(impl->props.device);
|
||||
if (impl->camera == NULL) {
|
||||
spa_log_error(impl->log, "unknown camera id %s", impl->props.device);
|
||||
libcamera_manager_release(impl->manager);
|
||||
std::string device_id;
|
||||
if (info && (str = spa_dict_lookup(info, SPA_KEY_API_LIBCAMERA_PATH)))
|
||||
device_id = str;
|
||||
|
||||
auto camera = manager->get(device_id);
|
||||
if (!camera) {
|
||||
spa_log_error(log, "unknown camera id %s", device_id.c_str());
|
||||
libcamera_manager_release(manager);
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
new (handle) impl(log, data_loop, system,
|
||||
manager, std::move(camera), std::move(device_id));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ int spa_libcamera_open(struct impl *impl)
|
|||
if (impl->acquired)
|
||||
return 0;
|
||||
|
||||
spa_log_info(impl->log, "open camera %s", impl->props.device);
|
||||
spa_log_info(impl->log, "open camera %s", impl->device_id.c_str());
|
||||
impl->camera->acquire();
|
||||
|
||||
impl->allocator = new FrameBufferAllocator(impl->camera);
|
||||
|
|
@ -57,7 +57,7 @@ int spa_libcamera_close(struct impl *impl)
|
|||
if (impl->active || port->have_format)
|
||||
return 0;
|
||||
|
||||
spa_log_info(impl->log, "close camera %s", impl->props.device);
|
||||
spa_log_info(impl->log, "close camera %s", impl->device_id.c_str());
|
||||
delete impl->allocator;
|
||||
impl->allocator = nullptr;
|
||||
|
||||
|
|
@ -674,7 +674,7 @@ static int spa_libcamera_stream_on(struct impl *impl)
|
|||
|
||||
impl->camera->requestCompleted.connect(impl, &impl::requestComplete);
|
||||
|
||||
spa_log_info(impl->log, "starting camera %s", impl->props.device);
|
||||
spa_log_info(impl->log, "starting camera %s", impl->device_id.c_str());
|
||||
if ((res = impl->camera->start()) < 0)
|
||||
return res == -EACCES ? -EBUSY : res;
|
||||
|
||||
|
|
@ -724,7 +724,7 @@ static int spa_libcamera_stream_off(struct impl *impl)
|
|||
return 0;
|
||||
}
|
||||
|
||||
spa_log_info(impl->log, "stopping camera %s", impl->props.device);
|
||||
spa_log_info(impl->log, "stopping camera %s", impl->device_id.c_str());
|
||||
impl->pendingRequests.clear();
|
||||
|
||||
if ((res = impl->camera->stop()) < 0)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue