From c5fbbfbd77aa96cc4fa9acb6d61c112d8c1cd51d Mon Sep 17 00:00:00 2001 From: columbarius Date: Thu, 4 Jan 2024 14:31:13 +0100 Subject: [PATCH] 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);