diff --git a/spa/plugins/libcamera/libcamera-source.cpp b/spa/plugins/libcamera/libcamera-source.cpp index f92ced043..2db7edbb1 100644 --- a/spa/plugins/libcamera/libcamera-source.cpp +++ b/spa/plugins/libcamera/libcamera-source.cpp @@ -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 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; - FrameBufferAllocator *allocator; + FrameBufferAllocator *allocator = nullptr; std::vector> requestPool; std::deque pendingRequests; @@ -157,13 +172,16 @@ struct impl { unsigned int have_config; std::unique_ptr 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, 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(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, 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_support_find(support, n_support, SPA_TYPE_INTERFACE_Log)); + auto data_loop = static_cast(spa_support_find(support, n_support, SPA_TYPE_INTERFACE_DataLoop)); + auto system = static_cast(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; } diff --git a/spa/plugins/libcamera/libcamera-utils.cpp b/spa/plugins/libcamera/libcamera-utils.cpp index 8cf7ff427..582e06e83 100644 --- a/spa/plugins/libcamera/libcamera-utils.cpp +++ b/spa/plugins/libcamera/libcamera-utils.cpp @@ -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)