mirror of
https://gitlab.freedesktop.org/pipewire/pipewire.git
synced 2026-05-05 06:46:28 -04:00
Merge branch 'columbarius/fallback-videoconverter' into 'master'
Draft: videoconvert: Fallback to dummy converter See merge request pipewire/pipewire!1854
This commit is contained in:
commit
fb70408342
1 changed files with 119 additions and 50 deletions
|
|
@ -2,7 +2,7 @@
|
||||||
/* SPDX-FileCopyrightText: Copyright © 2019 Wim Taymans */
|
/* SPDX-FileCopyrightText: Copyright © 2019 Wim Taymans */
|
||||||
/* SPDX-License-Identifier: MIT */
|
/* SPDX-License-Identifier: MIT */
|
||||||
|
|
||||||
#include "spa/utils/dict.h"
|
#include <spa/utils/dict.h>
|
||||||
#include <spa/support/plugin.h>
|
#include <spa/support/plugin.h>
|
||||||
#include <spa/support/plugin-loader.h>
|
#include <spa/support/plugin-loader.h>
|
||||||
#include <spa/support/log.h>
|
#include <spa/support/log.h>
|
||||||
|
|
@ -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;
|
||||||
|
|
@ -132,8 +131,33 @@ static int follower_enum_params(struct impl *this,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int convert_enum_port_config(struct impl *this,
|
static void replace_mode(struct spa_pod *filter, enum spa_param_port_config_mode tmode, enum spa_param_port_config_mode rmode)
|
||||||
int seq, uint32_t id, uint32_t start, uint32_t num,
|
{
|
||||||
|
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)
|
const struct spa_pod *filter, struct spa_pod_builder *builder)
|
||||||
{
|
{
|
||||||
struct spa_pod *f1, *f2 = NULL;
|
struct spa_pod *f1, *f2 = NULL;
|
||||||
|
|
@ -150,9 +174,38 @@ static int convert_enum_port_config(struct impl *this,
|
||||||
else {
|
else {
|
||||||
f2 = f1;
|
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,
|
static int impl_node_enum_params(void *object, int seq,
|
||||||
uint32_t id, uint32_t start, uint32_t num,
|
uint32_t id, uint32_t start, uint32_t num,
|
||||||
const struct spa_pod *filter)
|
const struct spa_pod *filter)
|
||||||
|
|
@ -176,15 +229,15 @@ 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 convert_enum_port_config(this, seq, id, start, num, filter, &b.b);
|
||||||
return 0;
|
res = adapter_enum_port_config(this, id, &result, filter, &b.b);
|
||||||
return convert_enum_port_config(this, seq, id, start, num, filter, &b.b);
|
break;
|
||||||
case SPA_PARAM_PortConfig:
|
case SPA_PARAM_PortConfig:
|
||||||
if (this->passthrough) {
|
if (this->passthrough) {
|
||||||
switch (result.index) {
|
switch (result.index) {
|
||||||
|
|
@ -201,9 +254,9 @@ next:
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (this->convert == NULL)
|
// return convert_enum_port_config(this, seq, id, start, num, filter, &b.b);
|
||||||
return 0;
|
res = adapter_enum_port_config(this, id, &result, filter, &b.b);
|
||||||
return convert_enum_port_config(this, seq, id, start, num, filter, &b.b);
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case SPA_PARAM_PropInfo:
|
case SPA_PARAM_PropInfo:
|
||||||
|
|
@ -247,9 +300,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 +568,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 +591,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 +620,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 +657,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 +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,
|
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 +717,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 +798,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 +934,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 +1107,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 +1429,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 +1472,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 +1656,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 +1688,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 +1752,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 +1812,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 +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);
|
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 +1943,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)
|
spa_node_add_listener(this->convert,
|
||||||
if (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 {
|
} else {
|
||||||
reconfigure_mode(this, true, this->direction, NULL);
|
setup_convert(this, SPA_PARAM_PORT_CONFIG_MODE_convert);
|
||||||
}
|
}
|
||||||
|
|
||||||
link_io(this);
|
link_io(this);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue