mirror of
https://gitlab.freedesktop.org/pipewire/pipewire.git
synced 2025-10-31 22:25:38 -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 <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