diff --git a/spa/plugins/videoconvert/videoadapter.c b/spa/plugins/videoconvert/videoadapter.c index 57bd8391f..0f13230c5 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 @@ -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; @@ -132,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; @@ -150,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) @@ -176,15 +229,15 @@ 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); + // 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) { @@ -201,9 +254,9 @@ next: return 0; } } else { - if (this->convert == NULL) - return 0; - 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: @@ -247,9 +300,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 +568,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 +591,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 +620,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 +657,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 +680,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 +717,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 +798,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 +934,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 +1107,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 +1429,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 +1472,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 +1656,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 +1688,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 +1752,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 +1812,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 +1918,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 +1943,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);