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; int res;
if (result->next < 0x100000) { if (result->next < 0x100000) {
if (this->convert != NULL && if ((res = spa_node_enum_params_sync(this->convert,
(res = spa_node_enum_params_sync(this->convert,
id, &result->next, filter, &result->param, builder)) == 1) id, &result->next, filter, &result->param, builder)) == 1)
return res; return res;
result->next = 0x100000; result->next = 0x100000;
@ -176,14 +175,12 @@ static int impl_node_enum_params(void *object, int seq,
next: next:
result.index = result.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); spa_pod_builder_reset(&b.b, &state);
switch (id) { switch (id) {
case SPA_PARAM_EnumPortConfig: 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);
case SPA_PARAM_PortConfig: case SPA_PARAM_PortConfig:
if (this->passthrough) { if (this->passthrough) {
@ -201,8 +198,6 @@ next:
return 0; return 0;
} }
} else { } 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);
} }
break; break;
@ -247,9 +242,6 @@ static int link_io(struct impl *this)
struct spa_io_rate_match *rate_match; struct spa_io_rate_match *rate_match;
size_t rate_match_size; size_t rate_match_size;
if (this->convert == NULL)
return 0;
spa_log_debug(this->log, "%p: controls", this); spa_log_debug(this->log, "%p: controls", this);
spa_zero(this->io_rate_match); 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; format = fmt;
} }
if (this->convert && this->target != this->follower) { if (this->target != this->follower) {
if ((res = spa_node_port_set_param(this->convert, if ((res = spa_node_port_set_param(this->convert,
SPA_DIRECTION_REVERSE(this->direction), 0, SPA_DIRECTION_REVERSE(this->direction), 0,
SPA_PARAM_Format, flags, SPA_PARAM_Format, flags,
@ -541,9 +533,6 @@ static int configure_convert(struct impl *this, uint32_t mode)
uint8_t buffer[1024]; uint8_t buffer[1024];
struct spa_pod *param; struct spa_pod *param;
if (this->convert == NULL)
return 0;
spa_pod_builder_init(&b, buffer, sizeof(buffer)); spa_pod_builder_init(&b, buffer, sizeof(buffer));
spa_log_debug(this->log, "%p: configure convert %p %d", this, this->target, mode); 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) if (this->target == this->follower)
return 0; return 0;
if (dst == NULL)
return 0;
while (true) { while (true) {
spa_pod_builder_init(&b, buffer, sizeof(buffer)); spa_pod_builder_init(&b, buffer, sizeof(buffer));
if ((res = spa_node_port_enum_params_sync(src, 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) if (this->target == this->follower)
return 0; return 0;
if (dst == NULL)
return 0;
spa_pod_dynamic_builder_init(&b, buffer, sizeof(buffer), 2048); spa_pod_dynamic_builder_init(&b, buffer, sizeof(buffer), 2048);
spa_pod_builder_get_state(&b.b, &state); 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, 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; int res = 0;
struct spa_hook l; struct spa_hook l;
@ -675,7 +659,7 @@ static int reconfigure_mode(struct impl *this, bool passthrough,
spa_hook_remove(&l); spa_hook_remove(&l);
} else { } else {
/* add converter ports */ /* add converter ports */
configure_convert(this, SPA_PARAM_PORT_CONFIG_MODE_dsp); configure_convert(this, mode);
} }
link_io(this); 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: case SPA_PARAM_PORT_CONFIG_MODE_none:
return -ENOTSUP; return -ENOTSUP;
case SPA_PARAM_PORT_CONFIG_MODE_passthrough: 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; return res;
break; break;
case SPA_PARAM_PORT_CONFIG_MODE_convert: case SPA_PARAM_PORT_CONFIG_MODE_convert:
case SPA_PARAM_PORT_CONFIG_MODE_dsp: case SPA_PARAM_PORT_CONFIG_MODE_dsp:
if (this->convert == NULL) if ((res = reconfigure_mode(this, false, dir, mode, NULL)) < 0)
return -ENOTSUP;
if ((res = reconfigure_mode(this, false, dir, NULL)) < 0)
return res; return res;
break; break;
default: default:
@ -894,7 +876,7 @@ static int negotiate_format(struct impl *this)
} }
} }
state = 0; 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_DIRECTION_REVERSE(this->direction), 0,
SPA_PARAM_EnumFormat, &state, SPA_PARAM_EnumFormat, &state,
format, &format, &b)) != 1) { format, &format, &b)) != 1) {
@ -1067,7 +1049,7 @@ static void follower_convert_port_info(void *data,
this->direction == SPA_DIRECTION_INPUT ? this->direction == SPA_DIRECTION_INPUT ?
"Input" : "Output", info, info->change_mask); "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++) { for (i = 0; i < info->n_params; i++) {
uint32_t idx; uint32_t idx;
@ -1389,7 +1371,7 @@ static int follower_reuse_buffer(void *data, uint32_t port_id, uint32_t buffer_i
int res; int res;
struct impl *this = data; 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); res = spa_node_port_reuse_buffer(this->convert, port_id, buffer_id);
else else
res = spa_node_call_reuse_buffer(&this->callbacks, port_id, buffer_id); 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_node_add_listener(this->follower, &l, &follower_node_events, this);
spa_hook_remove(&l); spa_hook_remove(&l);
if (this->convert) {
spa_zero(l); spa_zero(l);
spa_node_add_listener(this->convert, &l, &convert_node_events, this); spa_node_add_listener(this->convert, &l, &convert_node_events, this);
spa_hook_remove(&l); spa_hook_remove(&l);
}
this->add_listener = false; 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 * First we run the converter to process the input for the follower
* then if it produced data, we run the follower. */ * then if it produced data, we run the follower. */
while (retry--) { while (retry--) {
status = this->convert ? spa_node_process(this->convert) : 0; status = spa_node_process(this->convert);
/* schedule the follower when the converter needed /* schedule the follower when the converter needed
* a recycled buffer */ * a recycled buffer */
if (status == -EPIPE || status == 0) 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 /* output node (source). First run the converter to make
* sure we push out any queued data. Then when it needs * sure we push out any queued data. Then when it needs
* more data, schedule the follower. */ * more data, schedule the follower. */
status = this->convert ? spa_node_process(this->convert) : 0; status = spa_node_process(this->convert);
if (status == 0) if (status == 0)
status = SPA_STATUS_NEED_DATA; status = SPA_STATUS_NEED_DATA;
else if (status < 0) else if (status < 0)
@ -1714,6 +1694,30 @@ static const struct spa_node_methods impl_node = {
.process = impl_node_process, .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, static int load_plugin_from(struct impl *this, const struct spa_dict *info,
const char *convertname, struct spa_handle **handle, struct spa_node **iface) 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 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) 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); spa_log_debug(this->log, "%p: loaded converter %s, hnd %p, convert %p", this, this->convertname, this->hnd_convert, this->convert);
if (ret < 0) if (ret < 0)
return ret; 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 | this->info_all = SPA_NODE_CHANGE_MASK_FLAGS |
SPA_NODE_CHANGE_MASK_PARAMS; SPA_NODE_CHANGE_MASK_PARAMS;
@ -1874,14 +1885,14 @@ impl_init(const struct spa_handle_factory *factory,
&this->follower_listener, &follower_node_events, this); &this->follower_listener, &follower_node_events, this);
spa_node_set_callbacks(this->follower, &follower_node_callbacks, 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, spa_node_add_listener(this->convert,
&this->convert_listener, &convert_node_events, this); &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 { } else {
reconfigure_mode(this, true, this->direction, NULL); setup_convert(this, SPA_PARAM_PORT_CONFIG_MODE_convert);
} }
link_io(this); link_io(this);