Merge branch 'columbarius/fallback-videoconverter' into 'master'

Draft: videoconvert: Fallback to dummy converter

See merge request pipewire/pipewire!1854
This commit is contained in:
columbarius 2024-08-26 16:47:40 +00:00
commit fb70408342

View file

@ -2,7 +2,7 @@
/* SPDX-FileCopyrightText: Copyright © 2019 Wim Taymans */
/* SPDX-License-Identifier: MIT */
#include "spa/utils/dict.h"
#include <spa/utils/dict.h>
#include <spa/support/plugin.h>
#include <spa/support/plugin-loader.h>
#include <spa/support/log.h>
@ -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);