mirror of
				https://gitlab.freedesktop.org/pipewire/pipewire.git
				synced 2025-11-03 09:01:54 -05:00 
			
		
		
		
	Merge branch 'feature/libcamera-controls' into 'master'
propagate libcamera control as pipewire properties See merge request pipewire/pipewire!2355
This commit is contained in:
		
						commit
						b976d6cc8a
					
				
					 1 changed files with 101 additions and 8 deletions
				
			
		| 
						 | 
					@ -7,6 +7,7 @@
 | 
				
			||||||
#include <array>
 | 
					#include <array>
 | 
				
			||||||
#include <cstddef>
 | 
					#include <cstddef>
 | 
				
			||||||
#include <limits>
 | 
					#include <limits>
 | 
				
			||||||
 | 
					#include <mutex>
 | 
				
			||||||
#include <optional>
 | 
					#include <optional>
 | 
				
			||||||
#include <type_traits>
 | 
					#include <type_traits>
 | 
				
			||||||
#include <utility>
 | 
					#include <utility>
 | 
				
			||||||
| 
						 | 
					@ -34,6 +35,7 @@
 | 
				
			||||||
#include <spa/control/control.h>
 | 
					#include <spa/control/control.h>
 | 
				
			||||||
#include <spa/pod/dynamic.h>
 | 
					#include <spa/pod/dynamic.h>
 | 
				
			||||||
#include <spa/pod/filter.h>
 | 
					#include <spa/pod/filter.h>
 | 
				
			||||||
 | 
					#include <spa/pod/dynamic.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <libcamera/camera.h>
 | 
					#include <libcamera/camera.h>
 | 
				
			||||||
#include <libcamera/control_ids.h>
 | 
					#include <libcamera/control_ids.h>
 | 
				
			||||||
| 
						 | 
					@ -121,6 +123,7 @@ struct impl {
 | 
				
			||||||
	struct spa_node node = {};
 | 
						struct spa_node node = {};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct spa_log *log;
 | 
						struct spa_log *log;
 | 
				
			||||||
 | 
						struct spa_loop *main_loop;
 | 
				
			||||||
	struct spa_loop *data_loop;
 | 
						struct spa_loop *data_loop;
 | 
				
			||||||
	struct spa_system *system;
 | 
						struct spa_system *system;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -161,10 +164,12 @@ struct impl {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ControlList ctrls;
 | 
						ControlList ctrls;
 | 
				
			||||||
	ControlList initial_controls;
 | 
						ControlList initial_controls;
 | 
				
			||||||
 | 
						ControlList request_metadata;
 | 
				
			||||||
 | 
						std::mutex request_metadata_mutex;
 | 
				
			||||||
	bool active = false;
 | 
						bool active = false;
 | 
				
			||||||
	bool acquired = false;
 | 
						bool acquired = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	impl(spa_log *log, spa_loop *data_loop, spa_system *system,
 | 
						impl(spa_log *log, spa_loop *main_loop, spa_loop *data_loop, spa_system *system,
 | 
				
			||||||
	     std::shared_ptr<CameraManager> manager, std::shared_ptr<Camera> camera,
 | 
						     std::shared_ptr<CameraManager> manager, std::shared_ptr<Camera> camera,
 | 
				
			||||||
	     std::unique_ptr<CameraConfiguration> config);
 | 
						     std::unique_ptr<CameraConfiguration> config);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1037,6 +1042,23 @@ int spa_libcamera_apply_controls(struct impl *impl, libcamera::ControlList&& con
 | 
				
			||||||
	);
 | 
						);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void emit_node_info(struct impl *impl, bool full);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int do_emit_node_info(struct spa_loop *loop,
 | 
				
			||||||
 | 
								    bool async,
 | 
				
			||||||
 | 
								    uint32_t seq,
 | 
				
			||||||
 | 
								    const void *data,
 | 
				
			||||||
 | 
								    size_t size,
 | 
				
			||||||
 | 
								    void *user_data)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct impl *impl = (struct impl *)user_data;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						impl->info.change_mask |= SPA_NODE_CHANGE_MASK_PARAMS;
 | 
				
			||||||
 | 
						impl->params[NODE_Props].flags ^= SPA_PARAM_INFO_SERIAL;
 | 
				
			||||||
 | 
						emit_node_info(impl, true);
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void handle_completed_request(struct impl *impl, libcamera::Request *request)
 | 
					void handle_completed_request(struct impl *impl, libcamera::Request *request)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	const auto request_id = request->cookie();
 | 
						const auto request_id = request->cookie();
 | 
				
			||||||
| 
						 | 
					@ -1111,6 +1133,34 @@ void handle_completed_request(struct impl *impl, libcamera::Request *request)
 | 
				
			||||||
			d->chunk->flags |= SPA_CHUNK_FLAG_CORRUPTED;
 | 
								d->chunk->flags |= SPA_CHUNK_FLAG_CORRUPTED;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// update stored metadata from request metadata
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							const auto lock_guard = std::lock_guard{impl->request_metadata_mutex};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							auto update = false;
 | 
				
			||||||
 | 
							for (const auto& [id, value] : request->metadata())
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								const auto prop_id = control_to_prop_id(id);
 | 
				
			||||||
 | 
								if (prop_id >= SPA_PROP_START_CUSTOM)
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									continue;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								const auto it = std::find_if(impl->request_metadata.begin(), impl->request_metadata.end(), [id](const auto& entry)
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									return id == entry.first;
 | 
				
			||||||
 | 
								});
 | 
				
			||||||
 | 
								if ((it == impl->request_metadata.end()) || (value != it->second))
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									impl->request_metadata.set(id, value);
 | 
				
			||||||
 | 
									update = true;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if (update)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								spa_loop_invoke(impl->main_loop, do_emit_node_info, 0, nullptr, 0, false, impl);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	request->reuse(libcamera::Request::ReuseFlag::ReuseBuffers);
 | 
						request->reuse(libcamera::Request::ReuseFlag::ReuseBuffers);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	spa_list_append(&port->queue, &b->link);
 | 
						spa_list_append(&port->queue, &b->link);
 | 
				
			||||||
| 
						 | 
					@ -1305,7 +1355,6 @@ spa_libcamera_alloc_buffers(struct impl *impl, struct port *port,
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
void impl::requestComplete(libcamera::Request *request)
 | 
					void impl::requestComplete(libcamera::Request *request)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct impl *impl = this;
 | 
						struct impl *impl = this;
 | 
				
			||||||
| 
						 | 
					@ -1451,7 +1500,8 @@ int impl_node_enum_params(void *object, int seq,
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct impl *impl = (struct impl*)object;
 | 
						struct impl *impl = (struct impl*)object;
 | 
				
			||||||
	struct spa_pod *param;
 | 
						struct spa_pod *param;
 | 
				
			||||||
	struct spa_pod_builder b = { 0 };
 | 
						spa_auto(spa_pod_dynamic_builder) b = { 0 };
 | 
				
			||||||
 | 
						struct spa_pod_builder_state state;
 | 
				
			||||||
	uint8_t buffer[1024];
 | 
						uint8_t buffer[1024];
 | 
				
			||||||
	struct spa_result_node_params result;
 | 
						struct spa_result_node_params result;
 | 
				
			||||||
	uint32_t count = 0;
 | 
						uint32_t count = 0;
 | 
				
			||||||
| 
						 | 
					@ -1460,12 +1510,15 @@ int impl_node_enum_params(void *object, int seq,
 | 
				
			||||||
	spa_return_val_if_fail(impl != nullptr, -EINVAL);
 | 
						spa_return_val_if_fail(impl != nullptr, -EINVAL);
 | 
				
			||||||
	spa_return_val_if_fail(num != 0, -EINVAL);
 | 
						spa_return_val_if_fail(num != 0, -EINVAL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						spa_pod_dynamic_builder_init(&b, buffer, sizeof(buffer), 4096);
 | 
				
			||||||
 | 
						spa_pod_builder_get_state(&b.b, &state);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	result.id = id;
 | 
						result.id = id;
 | 
				
			||||||
	result.next = start;
 | 
						result.next = start;
 | 
				
			||||||
next:
 | 
					next:
 | 
				
			||||||
	result.index = result.next++;
 | 
						result.index = result.next++;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	spa_pod_builder_init(&b, buffer, sizeof(buffer));
 | 
						spa_pod_builder_reset(&b.b, &state);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	switch (id) {
 | 
						switch (id) {
 | 
				
			||||||
	case SPA_PARAM_PropInfo:
 | 
						case SPA_PARAM_PropInfo:
 | 
				
			||||||
| 
						 | 
					@ -1481,6 +1534,39 @@ next:
 | 
				
			||||||
	case SPA_PARAM_Props:
 | 
						case SPA_PARAM_Props:
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		switch (result.index) {
 | 
							switch (result.index) {
 | 
				
			||||||
 | 
							case 0: {
 | 
				
			||||||
 | 
								const auto add_property = [&b, &impl](unsigned int controlId, const libcamera::ControlValue& value) {
 | 
				
			||||||
 | 
									const auto id = control_to_prop_id(controlId);
 | 
				
			||||||
 | 
									if (id >= SPA_PROP_START_CUSTOM) {
 | 
				
			||||||
 | 
										return;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									if (value.isArray()) {
 | 
				
			||||||
 | 
										return; // not yet supported
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									spa_pod_builder_prop(&b.b, id, 0);
 | 
				
			||||||
 | 
									control_value_to_pod(b.b, value);
 | 
				
			||||||
 | 
								};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								struct spa_pod_frame f;
 | 
				
			||||||
 | 
								spa_pod_builder_push_object(&b.b, &f, SPA_TYPE_OBJECT_Props, id);
 | 
				
			||||||
 | 
								const auto metadata = [&]()
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									const auto lock_guard = std::lock_guard{impl->request_metadata_mutex};
 | 
				
			||||||
 | 
									auto metadata = impl->request_metadata;
 | 
				
			||||||
 | 
									return metadata;
 | 
				
			||||||
 | 
								}();
 | 
				
			||||||
 | 
								for (const auto& [id, value] : metadata)
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									add_property(id, value);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								for (const auto& [id, info] : impl->camera->controls()) {
 | 
				
			||||||
 | 
									if (!metadata.contains(id->id())) {
 | 
				
			||||||
 | 
										add_property(id->id(), info.def());
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								param = (spa_pod*)spa_pod_builder_pop(&b.b, &f);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
		default:
 | 
							default:
 | 
				
			||||||
			return 0;
 | 
								return 0;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
| 
						 | 
					@ -1490,14 +1576,14 @@ next:
 | 
				
			||||||
		return spa_libcamera_enum_format(impl, GET_OUT_PORT(impl, 0),
 | 
							return spa_libcamera_enum_format(impl, GET_OUT_PORT(impl, 0),
 | 
				
			||||||
				seq, start, num, filter);
 | 
									seq, start, num, filter);
 | 
				
			||||||
	case SPA_PARAM_Format:
 | 
						case SPA_PARAM_Format:
 | 
				
			||||||
		if ((res = port_get_format(impl, GET_OUT_PORT(impl, 0), result.index, filter, ¶m, &b)) <= 0)
 | 
							if ((res = port_get_format(impl, GET_OUT_PORT(impl, 0), result.index, filter, ¶m, &b.b)) <= 0)
 | 
				
			||||||
			return res;
 | 
								return res;
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
	default:
 | 
						default:
 | 
				
			||||||
		return -ENOENT;
 | 
							return -ENOENT;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (spa_pod_filter(&b, &result.param, param, filter) < 0)
 | 
						if (spa_pod_filter(&b.b, &result.param, param, filter) < 0)
 | 
				
			||||||
		goto next;
 | 
							goto next;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	spa_node_emit_result(&impl->hooks, seq, 0, SPA_RESULT_TYPE_NODE_PARAMS, &result);
 | 
						spa_node_emit_result(&impl->hooks, seq, 0, SPA_RESULT_TYPE_NODE_PARAMS, &result);
 | 
				
			||||||
| 
						 | 
					@ -2144,11 +2230,12 @@ int impl_clear(struct spa_handle *handle)
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl::impl(spa_log *log, spa_loop *data_loop, spa_system *system,
 | 
					impl::impl(spa_log *log, spa_loop *main_loop, spa_loop *data_loop, spa_system *system,
 | 
				
			||||||
	   std::shared_ptr<CameraManager> manager, std::shared_ptr<Camera> camera,
 | 
						   std::shared_ptr<CameraManager> manager, std::shared_ptr<Camera> camera,
 | 
				
			||||||
	   std::unique_ptr<CameraConfiguration> config)
 | 
						   std::unique_ptr<CameraConfiguration> config)
 | 
				
			||||||
	: handle({ SPA_VERSION_HANDLE, impl_get_interface, impl_clear }),
 | 
						: handle({ SPA_VERSION_HANDLE, impl_get_interface, impl_clear }),
 | 
				
			||||||
	  log(log),
 | 
						  log(log),
 | 
				
			||||||
 | 
						  main_loop(main_loop),
 | 
				
			||||||
	  data_loop(data_loop),
 | 
						  data_loop(data_loop),
 | 
				
			||||||
	  system(system),
 | 
						  system(system),
 | 
				
			||||||
	  out_ports{{this}},
 | 
						  out_ports{{this}},
 | 
				
			||||||
| 
						 | 
					@ -2200,9 +2287,15 @@ impl_init(const struct spa_handle_factory *factory,
 | 
				
			||||||
	spa_return_val_if_fail(handle != nullptr, -EINVAL);
 | 
						spa_return_val_if_fail(handle != nullptr, -EINVAL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	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 main_loop = static_cast<spa_loop *>(spa_support_find(support, n_support, SPA_TYPE_INTERFACE_Loop));
 | 
				
			||||||
	auto data_loop = static_cast<spa_loop *>(spa_support_find(support, n_support, SPA_TYPE_INTERFACE_DataLoop));
 | 
						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));
 | 
						auto system = static_cast<spa_system *>(spa_support_find(support, n_support, SPA_TYPE_INTERFACE_System));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!main_loop) {
 | 
				
			||||||
 | 
							spa_log_error(log, "a main_loop is needed");
 | 
				
			||||||
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!data_loop) {
 | 
						if (!data_loop) {
 | 
				
			||||||
		spa_log_error(log, "a data_loop is needed");
 | 
							spa_log_error(log, "a data_loop is needed");
 | 
				
			||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
| 
						 | 
					@ -2235,7 +2328,7 @@ impl_init(const struct spa_handle_factory *factory,
 | 
				
			||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	new (handle) impl(log, data_loop, system,
 | 
						new (handle) impl(log, main_loop, data_loop, system,
 | 
				
			||||||
			  std::move(manager), std::move(camera),
 | 
								  std::move(manager), std::move(camera),
 | 
				
			||||||
			  std::move(config));
 | 
								  std::move(config));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue