mirror of
https://gitlab.freedesktop.org/pipewire/pipewire.git
synced 2025-10-29 05:40:27 -04: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 <cstddef>
|
||||
#include <limits>
|
||||
#include <mutex>
|
||||
#include <optional>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
|
@ -34,6 +35,7 @@
|
|||
#include <spa/control/control.h>
|
||||
#include <spa/pod/dynamic.h>
|
||||
#include <spa/pod/filter.h>
|
||||
#include <spa/pod/dynamic.h>
|
||||
|
||||
#include <libcamera/camera.h>
|
||||
#include <libcamera/control_ids.h>
|
||||
|
|
@ -121,6 +123,7 @@ struct impl {
|
|||
struct spa_node node = {};
|
||||
|
||||
struct spa_log *log;
|
||||
struct spa_loop *main_loop;
|
||||
struct spa_loop *data_loop;
|
||||
struct spa_system *system;
|
||||
|
||||
|
|
@ -161,10 +164,12 @@ struct impl {
|
|||
|
||||
ControlList ctrls;
|
||||
ControlList initial_controls;
|
||||
ControlList request_metadata;
|
||||
std::mutex request_metadata_mutex;
|
||||
bool active = 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::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)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
// 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);
|
||||
|
||||
spa_list_append(&port->queue, &b->link);
|
||||
|
|
@ -1305,7 +1355,6 @@ spa_libcamera_alloc_buffers(struct impl *impl, struct port *port,
|
|||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void impl::requestComplete(libcamera::Request *request)
|
||||
{
|
||||
struct impl *impl = this;
|
||||
|
|
@ -1451,7 +1500,8 @@ int impl_node_enum_params(void *object, int seq,
|
|||
{
|
||||
struct impl *impl = (struct impl*)object;
|
||||
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];
|
||||
struct spa_result_node_params result;
|
||||
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(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.next = start;
|
||||
next:
|
||||
result.index = result.next++;
|
||||
|
||||
spa_pod_builder_init(&b, buffer, sizeof(buffer));
|
||||
spa_pod_builder_reset(&b.b, &state);
|
||||
|
||||
switch (id) {
|
||||
case SPA_PARAM_PropInfo:
|
||||
|
|
@ -1481,6 +1534,39 @@ next:
|
|||
case SPA_PARAM_Props:
|
||||
{
|
||||
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:
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1490,14 +1576,14 @@ next:
|
|||
return spa_libcamera_enum_format(impl, GET_OUT_PORT(impl, 0),
|
||||
seq, start, num, filter);
|
||||
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;
|
||||
break;
|
||||
default:
|
||||
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;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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::unique_ptr<CameraConfiguration> config)
|
||||
: handle({ SPA_VERSION_HANDLE, impl_get_interface, impl_clear }),
|
||||
log(log),
|
||||
main_loop(main_loop),
|
||||
data_loop(data_loop),
|
||||
system(system),
|
||||
out_ports{{this}},
|
||||
|
|
@ -2200,9 +2287,15 @@ impl_init(const struct spa_handle_factory *factory,
|
|||
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 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 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) {
|
||||
spa_log_error(log, "a data_loop is needed");
|
||||
return -EINVAL;
|
||||
|
|
@ -2235,7 +2328,7 @@ impl_init(const struct spa_handle_factory *factory,
|
|||
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(config));
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue