From c5fbbfbd77aa96cc4fa9acb6d61c112d8c1cd51d Mon Sep 17 00:00:00 2001 From: columbarius Date: Thu, 4 Jan 2024 14:31:13 +0100 Subject: [PATCH 1/3] videoconvert: Fallback to dummy converter Videoadapter will fall back to the dummy converter if the configured converter fails to load. Assuming the existence of a converter allows removing all checks for the existence of the converter and simplifies the adapter to a single codepath. In case the videoadapter is not configured differently by the session manager the output port will run in passthrough mode and the input port will run in convert mode. --- spa/plugins/videoconvert/videoadapter.c | 99 ++++++++++++++----------- 1 file changed, 55 insertions(+), 44 deletions(-) diff --git a/spa/plugins/videoconvert/videoadapter.c b/spa/plugins/videoconvert/videoadapter.c index 57bd8391f..1bbc0f96f 100644 --- a/spa/plugins/videoconvert/videoadapter.c +++ b/spa/plugins/videoconvert/videoadapter.c @@ -114,8 +114,7 @@ static int follower_enum_params(struct impl *this, { int res; if (result->next < 0x100000) { - if (this->convert != NULL && - (res = spa_node_enum_params_sync(this->convert, + if ((res = spa_node_enum_params_sync(this->convert, id, &result->next, filter, &result->param, builder)) == 1) return res; result->next = 0x100000; @@ -176,14 +175,12 @@ static int impl_node_enum_params(void *object, int seq, next: result.index = result.next; - spa_log_debug(this->log, "%p: %d id:%u", this, seq, id); + spa_log_info(this->log, "%p: %d id:%u", this, seq, id); spa_pod_builder_reset(&b.b, &state); switch (id) { case SPA_PARAM_EnumPortConfig: - if (this->convert == NULL) - return 0; return convert_enum_port_config(this, seq, id, start, num, filter, &b.b); case SPA_PARAM_PortConfig: if (this->passthrough) { @@ -201,8 +198,6 @@ next: return 0; } } else { - if (this->convert == NULL) - return 0; return convert_enum_port_config(this, seq, id, start, num, filter, &b.b); } break; @@ -247,9 +242,6 @@ static int link_io(struct impl *this) struct spa_io_rate_match *rate_match; size_t rate_match_size; - if (this->convert == NULL) - return 0; - spa_log_debug(this->log, "%p: controls", this); spa_zero(this->io_rate_match); @@ -518,7 +510,7 @@ static int configure_format(struct impl *this, uint32_t flags, const struct spa_ format = fmt; } - if (this->convert && this->target != this->follower) { + if (this->target != this->follower) { if ((res = spa_node_port_set_param(this->convert, SPA_DIRECTION_REVERSE(this->direction), 0, SPA_PARAM_Format, flags, @@ -541,9 +533,6 @@ static int configure_convert(struct impl *this, uint32_t mode) uint8_t buffer[1024]; struct spa_pod *param; - if (this->convert == NULL) - return 0; - spa_pod_builder_init(&b, buffer, sizeof(buffer)); spa_log_debug(this->log, "%p: configure convert %p %d", this, this->target, mode); @@ -573,9 +562,6 @@ static int recalc_latency(struct impl *this, struct spa_node *src, enum spa_dire if (this->target == this->follower) return 0; - if (dst == NULL) - return 0; - while (true) { spa_pod_builder_init(&b, buffer, sizeof(buffer)); if ((res = spa_node_port_enum_params_sync(src, @@ -613,9 +599,6 @@ static int recalc_tag(struct impl *this, struct spa_node *src, enum spa_directio if (this->target == this->follower) return 0; - if (dst == NULL) - return 0; - spa_pod_dynamic_builder_init(&b, buffer, sizeof(buffer), 2048); spa_pod_builder_get_state(&b.b, &state); @@ -639,7 +622,8 @@ static int recalc_tag(struct impl *this, struct spa_node *src, enum spa_directio static int reconfigure_mode(struct impl *this, bool passthrough, - enum spa_direction direction, struct spa_pod *format) + enum spa_direction direction, enum spa_param_port_config_mode mode, + struct spa_pod *format) { int res = 0; struct spa_hook l; @@ -675,7 +659,7 @@ static int reconfigure_mode(struct impl *this, bool passthrough, spa_hook_remove(&l); } else { /* add converter ports */ - configure_convert(this, SPA_PARAM_PORT_CONFIG_MODE_dsp); + configure_convert(this, mode); } link_io(this); } @@ -756,14 +740,12 @@ static int impl_node_set_param(void *object, uint32_t id, uint32_t flags, case SPA_PARAM_PORT_CONFIG_MODE_none: return -ENOTSUP; case SPA_PARAM_PORT_CONFIG_MODE_passthrough: - if ((res = reconfigure_mode(this, true, dir, format)) < 0) + if ((res = reconfigure_mode(this, true, dir, mode, format)) < 0) return res; break; case SPA_PARAM_PORT_CONFIG_MODE_convert: case SPA_PARAM_PORT_CONFIG_MODE_dsp: - if (this->convert == NULL) - return -ENOTSUP; - if ((res = reconfigure_mode(this, false, dir, NULL)) < 0) + if ((res = reconfigure_mode(this, false, dir, mode, NULL)) < 0) return res; break; default: @@ -894,7 +876,7 @@ static int negotiate_format(struct impl *this) } } state = 0; - if (this->convert && (res = spa_node_port_enum_params_sync(this->convert, + if ((res = spa_node_port_enum_params_sync(this->convert, SPA_DIRECTION_REVERSE(this->direction), 0, SPA_PARAM_EnumFormat, &state, format, &format, &b)) != 1) { @@ -1067,7 +1049,7 @@ static void follower_convert_port_info(void *data, this->direction == SPA_DIRECTION_INPUT ? "Input" : "Output", info, info->change_mask); - if (this->convert && info->change_mask & SPA_PORT_CHANGE_MASK_PARAMS) { + if (info->change_mask & SPA_PORT_CHANGE_MASK_PARAMS) { for (i = 0; i < info->n_params; i++) { uint32_t idx; @@ -1389,7 +1371,7 @@ static int follower_reuse_buffer(void *data, uint32_t port_id, uint32_t buffer_i int res; struct impl *this = data; - if (this->convert && this->target != this->follower) + if (this->target != this->follower) res = spa_node_port_reuse_buffer(this->convert, port_id, buffer_id); else res = spa_node_call_reuse_buffer(&this->callbacks, port_id, buffer_id); @@ -1432,11 +1414,9 @@ static int impl_node_add_listener(void *object, spa_node_add_listener(this->follower, &l, &follower_node_events, this); spa_hook_remove(&l); - if (this->convert) { - spa_zero(l); - spa_node_add_listener(this->convert, &l, &convert_node_events, this); - spa_hook_remove(&l); - } + spa_zero(l); + spa_node_add_listener(this->convert, &l, &convert_node_events, this); + spa_hook_remove(&l); this->add_listener = false; @@ -1618,7 +1598,7 @@ static int impl_node_process(void *object) * First we run the converter to process the input for the follower * then if it produced data, we run the follower. */ while (retry--) { - status = this->convert ? spa_node_process(this->convert) : 0; + status = spa_node_process(this->convert); /* schedule the follower when the converter needed * a recycled buffer */ if (status == -EPIPE || status == 0) @@ -1650,7 +1630,7 @@ static int impl_node_process(void *object) /* output node (source). First run the converter to make * sure we push out any queued data. Then when it needs * more data, schedule the follower. */ - status = this->convert ? spa_node_process(this->convert) : 0; + status = spa_node_process(this->convert); if (status == 0) status = SPA_STATUS_NEED_DATA; else if (status < 0) @@ -1714,6 +1694,30 @@ static const struct spa_node_methods impl_node = { .process = impl_node_process, }; +static int setup_convert(struct impl *this, uint32_t mode) +{ + int res; + spa_log_debug(this->log, "%p: setup converter with mode %d", this, mode); + + if ((res = configure_convert(this, mode)) >= 0) { + reconfigure_mode(this, mode == SPA_PARAM_PORT_CONFIG_MODE_none, this->direction, mode, NULL); + return 0; + } + + spa_log_warn(this->log, "%p: set mode %d on convert failed %d %s", this, + mode, res, spa_strerror(res)); + + mode = SPA_PARAM_PORT_CONFIG_MODE_none; + this->passthrough = mode == SPA_PARAM_PORT_CONFIG_MODE_none; + if ((res = configure_convert(this, mode)) < 0) { + spa_log_warn(this->log, "%p: set mode %d on convert failed %d %s", this, + mode, res, spa_strerror(res)); + return res; + } + reconfigure_mode(this, true, this->direction, mode, NULL); + return 0; +} + static int load_plugin_from(struct impl *this, const struct spa_dict *info, const char *convertname, struct spa_handle **handle, struct spa_node **iface) { @@ -1750,7 +1754,12 @@ static int load_converter(struct impl *this, const struct spa_dict *info) return ret; } } - return 0; + ret = load_plugin_from(this, info, "video.convert.dummy", &this->hnd_convert, &this->convert); + if (ret >= 0) { + this->convertname = strdup(factory_name); + return ret; + } + return -EINVAL; } static int impl_get_interface(struct spa_handle *handle, const char *type, void **interface) @@ -1851,7 +1860,9 @@ impl_init(const struct spa_handle_factory *factory, spa_log_debug(this->log, "%p: loaded converter %s, hnd %p, convert %p", this, this->convertname, this->hnd_convert, this->convert); if (ret < 0) return ret; - this->target = this->convert; + this->target = this->direction == SPA_DIRECTION_OUTPUT + ? this->follower + : this->convert; this->info_all = SPA_NODE_CHANGE_MASK_FLAGS | SPA_NODE_CHANGE_MASK_PARAMS; @@ -1874,14 +1885,14 @@ impl_init(const struct spa_handle_factory *factory, &this->follower_listener, &follower_node_events, this); spa_node_set_callbacks(this->follower, &follower_node_callbacks, this); - // TODO: adapt port bootstrap for arbitrary converter (incl. dummy) - if (this->convert) { - spa_node_add_listener(this->convert, - &this->convert_listener, &convert_node_events, this); + spa_node_add_listener(this->convert, + &this->convert_listener, &convert_node_events, this); - configure_convert(this, SPA_PARAM_PORT_CONFIG_MODE_convert); + // TODO: adapt port bootstrap for arbitrary converter (incl. dummy) + if (this->direction == SPA_DIRECTION_OUTPUT) { + setup_convert(this, SPA_PARAM_PORT_CONFIG_MODE_none); } else { - reconfigure_mode(this, true, this->direction, NULL); + setup_convert(this, SPA_PARAM_PORT_CONFIG_MODE_convert); } link_io(this); From 085af17706621168f9006138a28c1e8c6bd0e356 Mon Sep 17 00:00:00 2001 From: columbarius Date: Mon, 22 Jan 2024 15:57:48 +0100 Subject: [PATCH 2/3] videoconverter: Fix include --- spa/plugins/videoconvert/videoadapter.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spa/plugins/videoconvert/videoadapter.c b/spa/plugins/videoconvert/videoadapter.c index 1bbc0f96f..d6c6c77c5 100644 --- a/spa/plugins/videoconvert/videoadapter.c +++ b/spa/plugins/videoconvert/videoadapter.c @@ -2,7 +2,7 @@ /* SPDX-FileCopyrightText: Copyright © 2019 Wim Taymans */ /* SPDX-License-Identifier: MIT */ -#include "spa/utils/dict.h" +#include #include #include #include From 969d0d4ac535b2868797269d51a5116486fdbc2c Mon Sep 17 00:00:00 2001 From: columbarius Date: Thu, 29 Feb 2024 03:13:04 +0100 Subject: [PATCH 3/3] videoadapter: Map PortConfigMode --- spa/plugins/videoconvert/videoadapter.c | 68 +++++++++++++++++++++++-- 1 file changed, 63 insertions(+), 5 deletions(-) diff --git a/spa/plugins/videoconvert/videoadapter.c b/spa/plugins/videoconvert/videoadapter.c index d6c6c77c5..0f13230c5 100644 --- a/spa/plugins/videoconvert/videoadapter.c +++ b/spa/plugins/videoconvert/videoadapter.c @@ -131,8 +131,33 @@ static int follower_enum_params(struct impl *this, return 0; } -static int convert_enum_port_config(struct impl *this, - int seq, uint32_t id, uint32_t start, uint32_t num, +static void replace_mode(struct spa_pod *filter, enum spa_param_port_config_mode tmode, enum spa_param_port_config_mode rmode) +{ + const struct spa_pod_prop *prop; + if ((prop = spa_pod_find_prop(filter, NULL, SPA_PARAM_PORT_CONFIG_mode)) != NULL) { + switch (SPA_POD_TYPE(&prop->value)) { + case SPA_TYPE_Choice:; + enum spa_param_port_config_mode *modes = SPA_POD_CHOICE_VALUES((struct spa_pod_choice *)&prop->value); + for (uint32_t i = 0; i < SPA_POD_CHOICE_N_VALUES((struct spa_pod_choice *)&prop->value); i++) { + if (modes[i] == tmode) + modes[i] = rmode; + } + break; + case SPA_TYPE_Id:; + struct spa_pod_id *p = (struct spa_pod_id*)&prop->value; + if (p->value == tmode) + p->value = rmode; + break; + default: + break; + + } + + } +} + +static int adapter_enum_port_config(struct impl *this, + uint32_t id, struct spa_result_node_params *result, const struct spa_pod *filter, struct spa_pod_builder *builder) { struct spa_pod *f1, *f2 = NULL; @@ -149,9 +174,38 @@ static int convert_enum_port_config(struct impl *this, else { f2 = f1; } - return spa_node_enum_params(this->convert, seq, id, start, num, f2); + + res = spa_node_enum_params_sync(this->convert, + id, &result->next, f2, &result->param, builder); + spa_log_info(this->log, "convert_enum_port_config"); + spa_debug_log_pod(this->log, SPA_LOG_LEVEL_INFO, 2, NULL, result->param); + replace_mode(result->param, SPA_PARAM_PORT_CONFIG_MODE_none, SPA_PARAM_PORT_CONFIG_MODE_passthrough); + spa_debug_log_pod(this->log, SPA_LOG_LEVEL_INFO, 2, NULL, result->param); + return res; } +// static int convert_enum_port_config(struct impl *this, +// int seq, uint32_t id, uint32_t start, uint32_t num, +// const struct spa_pod *filter, struct spa_pod_builder *builder) +// { +// struct spa_pod *f1, *f2 = NULL; +// int res; +// +// f1 = spa_pod_builder_add_object(builder, +// SPA_TYPE_OBJECT_ParamPortConfig, id, +// SPA_PARAM_PORT_CONFIG_direction, SPA_POD_Id(this->direction)); +// +// if (filter) { +// if ((res = spa_pod_filter(builder, &f2, f1, filter)) < 0) +// return res; +// } +// else { +// f2 = f1; +// } +// +// return spa_node_enum_params(this->convert, seq, id, start, num, f2); +// } + static int impl_node_enum_params(void *object, int seq, uint32_t id, uint32_t start, uint32_t num, const struct spa_pod *filter) @@ -181,7 +235,9 @@ next: switch (id) { case SPA_PARAM_EnumPortConfig: - return convert_enum_port_config(this, seq, id, start, num, filter, &b.b); + // return convert_enum_port_config(this, seq, id, start, num, filter, &b.b); + res = adapter_enum_port_config(this, id, &result, filter, &b.b); + break; case SPA_PARAM_PortConfig: if (this->passthrough) { switch (result.index) { @@ -198,7 +254,9 @@ next: return 0; } } else { - return convert_enum_port_config(this, seq, id, start, num, filter, &b.b); + // return convert_enum_port_config(this, seq, id, start, num, filter, &b.b); + res = adapter_enum_port_config(this, id, &result, filter, &b.b); + break; } break; case SPA_PARAM_PropInfo: