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.
This commit is contained in:
columbarius 2024-01-04 14:31:13 +01:00
parent 66792c1e77
commit c5fbbfbd77

View file

@ -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);