mirror of
https://gitlab.freedesktop.org/pipewire/pipewire.git
synced 2025-11-02 09:01:50 -05:00
videoconvert: add PeerFormats support
Make a new PeerFormats param that can be set on ports to let it know about the possible peer formats. This can be used by converters to calculate an optimum conversion. make the videoadpter query the follower formats, simplify them and then set them as PeerFormats on the converter. Implement peerformats in videoconvert. This makes EnumFormat on the port depend on the negotiated format of the peer. It will suggest a Format that most closely matches the current negotiated format with the available PeerFormats. This then makes it possible to negotiate to the format that would require the least amount of conversions.
This commit is contained in:
parent
46d376cb78
commit
1904521a4d
5 changed files with 643 additions and 108 deletions
|
|
@ -41,6 +41,7 @@ static const struct spa_type_info spa_type_param[] = {
|
|||
{ SPA_PARAM_Latency, SPA_TYPE_OBJECT_ParamLatency, SPA_TYPE_INFO_PARAM_ID_BASE "Latency", NULL },
|
||||
{ SPA_PARAM_ProcessLatency, SPA_TYPE_OBJECT_ParamProcessLatency, SPA_TYPE_INFO_PARAM_ID_BASE "ProcessLatency", NULL },
|
||||
{ SPA_PARAM_Tag, SPA_TYPE_OBJECT_ParamTag, SPA_TYPE_INFO_PARAM_ID_BASE "Tag", NULL },
|
||||
{ SPA_PARAM_PeerFormats, SPA_TYPE_Struct, SPA_TYPE_INFO_PARAM_ID_BASE "PeerFormats", NULL },
|
||||
{ 0, 0, NULL, NULL },
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -40,6 +40,7 @@ enum spa_param_type {
|
|||
SPA_PARAM_Latency, /**< latency reporting, a SPA_TYPE_OBJECT_ParamLatency */
|
||||
SPA_PARAM_ProcessLatency, /**< processing latency, a SPA_TYPE_OBJECT_ParamProcessLatency */
|
||||
SPA_PARAM_Tag, /**< tag reporting, a SPA_TYPE_OBJECT_ParamTag. Since 0.3.79 */
|
||||
SPA_PARAM_PeerFormats, /**< peer formats, a SPA_TYPE_Struct of SPA_TYPE_OBJECT_Format. Since 1.5.0 */
|
||||
};
|
||||
|
||||
/** information about a parameter */
|
||||
|
|
|
|||
188
spa/include/spa/pod/simplify.h
Normal file
188
spa/include/spa/pod/simplify.h
Normal file
|
|
@ -0,0 +1,188 @@
|
|||
/* Simple Plugin API */
|
||||
/* SPDX-FileCopyrightText: Copyright © 2018 Wim Taymans */
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
|
||||
#ifndef SPA_POD_SIMPLIFY_H
|
||||
#define SPA_POD_SIMPLIFY_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <spa/param/props.h>
|
||||
#include <spa/pod/iter.h>
|
||||
#include <spa/pod/builder.h>
|
||||
#include <spa/pod/dynamic.h>
|
||||
#include <spa/pod/compare.h>
|
||||
#include <spa/debug/pod.h>
|
||||
|
||||
#ifndef SPA_API_POD_SIMPLIFY
|
||||
#ifdef SPA_API_IMPL
|
||||
#define SPA_API_POD_SIMPLIFY SPA_API_IMPL
|
||||
#else
|
||||
#define SPA_API_POD_SIMPLIFY static inline
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/**
|
||||
* \addtogroup spa_pod
|
||||
* \{
|
||||
*/
|
||||
|
||||
SPA_API_POD_SIMPLIFY int
|
||||
spa_pod_simplify_merge(struct spa_pod_builder *b, const struct spa_pod *pod1, const struct spa_pod *pod2)
|
||||
{
|
||||
const struct spa_pod_object *o1, *o2;
|
||||
const struct spa_pod_prop *p1, *p2;
|
||||
struct spa_pod_frame f[2];
|
||||
int res = 0, count = 0;
|
||||
|
||||
if (pod1->type != pod2->type)
|
||||
return -ENOTSUP;
|
||||
if (pod1->type != SPA_TYPE_Object)
|
||||
return -ENOTSUP;
|
||||
|
||||
o1 = (const struct spa_pod_object*) pod1;
|
||||
o2 = (const struct spa_pod_object*) pod2;
|
||||
|
||||
spa_pod_builder_push_object(b, &f[0], o1->body.type, o1->body.id);
|
||||
p2 = NULL;
|
||||
SPA_POD_OBJECT_FOREACH(o1, p1) {
|
||||
p2 = spa_pod_object_find_prop(o2, p2, p1->key);
|
||||
if (p2 == NULL)
|
||||
goto error_enoent;
|
||||
|
||||
if (spa_pod_compare(&p1->value, &p2->value) == 0) {
|
||||
spa_pod_builder_raw_padded(b, p1, SPA_POD_PROP_SIZE(p1));
|
||||
}
|
||||
else {
|
||||
uint32_t i, n_vals1, n_vals2, choice1, choice2, size;
|
||||
const struct spa_pod *vals1, *vals2;
|
||||
void *alt1, *alt2, *a1, *a2;
|
||||
|
||||
count++;
|
||||
if (count > 1)
|
||||
goto error_einval;
|
||||
|
||||
vals1 = spa_pod_get_values(&p1->value, &n_vals1, &choice1);
|
||||
vals2 = spa_pod_get_values(&p2->value, &n_vals2, &choice2);
|
||||
|
||||
if (vals1->type != vals2->type)
|
||||
goto error_einval;
|
||||
|
||||
size = vals1->size;
|
||||
|
||||
alt1 = SPA_POD_BODY(vals1);
|
||||
alt2 = SPA_POD_BODY(vals2);
|
||||
|
||||
if ((choice1 == SPA_CHOICE_None && choice2 == SPA_CHOICE_None) ||
|
||||
(choice1 == SPA_CHOICE_None && choice2 == SPA_CHOICE_Enum) ||
|
||||
(choice1 == SPA_CHOICE_Enum && choice2 == SPA_CHOICE_None) ||
|
||||
(choice1 == SPA_CHOICE_Enum && choice2 == SPA_CHOICE_Enum)) {
|
||||
spa_pod_builder_prop(b, p1->key, p1->flags);
|
||||
spa_pod_builder_push_choice(b, &f[1], SPA_CHOICE_Enum, 0);
|
||||
spa_pod_builder_child(b, size, vals1->type);
|
||||
for (i = 0, a1 = alt1; i < n_vals1; i++, a1 = SPA_PTROFF(a1,size,void)) {
|
||||
if (i == 0 && n_vals1 == 1)
|
||||
spa_pod_builder_raw(b, a1, size);
|
||||
spa_pod_builder_raw(b, a1, size);
|
||||
}
|
||||
for (i = 0, a2 = alt2; i < n_vals2; i++, a2 = SPA_PTROFF(a2,size,void)) {
|
||||
spa_pod_builder_raw(b, a2, size);
|
||||
}
|
||||
spa_pod_builder_pop(b, &f[1]);
|
||||
} else {
|
||||
goto error_einval;
|
||||
}
|
||||
}
|
||||
}
|
||||
p1 = NULL;
|
||||
SPA_POD_OBJECT_FOREACH(o2, p2) {
|
||||
p1 = spa_pod_object_find_prop(o1, p1, p2->key);
|
||||
if (p1 == NULL)
|
||||
goto error_enoent;
|
||||
}
|
||||
done:
|
||||
spa_pod_builder_pop(b, &f[0]);
|
||||
return res;
|
||||
|
||||
error_einval:
|
||||
res = -EINVAL;
|
||||
goto done;
|
||||
error_enoent:
|
||||
res = -ENOENT;
|
||||
goto done;
|
||||
}
|
||||
|
||||
SPA_API_POD_SIMPLIFY int
|
||||
spa_pod_simplify_struct(struct spa_pod_builder *b, const struct spa_pod *pod, uint32_t pod_size)
|
||||
{
|
||||
struct spa_pod *p1 = NULL, *p2;
|
||||
struct spa_pod_frame f;
|
||||
struct spa_pod_builder_state state;
|
||||
uint32_t p1offs;
|
||||
|
||||
spa_pod_builder_push_struct(b, &f);
|
||||
SPA_POD_STRUCT_FOREACH(pod, p2) {
|
||||
spa_pod_builder_get_state(b, &state);
|
||||
if (p1 == NULL || spa_pod_simplify_merge(b, p1, p2) < 0) {
|
||||
spa_pod_builder_reset(b, &state);
|
||||
spa_pod_builder_raw_padded(b, p2, SPA_POD_SIZE(p2));
|
||||
p1offs = state.offset;
|
||||
p1 = SPA_PTROFF(b->data, p1offs, struct spa_pod);
|
||||
} else {
|
||||
void *pnew = SPA_PTROFF(b->data, state.offset, void);
|
||||
p1 = SPA_PTROFF(b->data, p1offs, struct spa_pod);
|
||||
spa_pod_builder_remove(b, SPA_POD_SIZE(p1));
|
||||
memmove(p1, pnew, SPA_POD_SIZE(pnew));
|
||||
}
|
||||
}
|
||||
spa_pod_builder_pop(b, &f);
|
||||
return 0;
|
||||
}
|
||||
|
||||
SPA_API_POD_SIMPLIFY int
|
||||
spa_pod_simplify(struct spa_pod_builder *b, struct spa_pod **result, const struct spa_pod *pod)
|
||||
{
|
||||
int res = 0;
|
||||
struct spa_pod_builder_state state;
|
||||
|
||||
spa_return_val_if_fail(pod != NULL, -EINVAL);
|
||||
spa_return_val_if_fail(b != NULL, -EINVAL);
|
||||
|
||||
spa_pod_builder_get_state(b, &state);
|
||||
|
||||
if (!spa_pod_is_struct(pod)) {
|
||||
res = spa_pod_builder_raw_padded(b, pod, SPA_POD_SIZE(pod));
|
||||
} else {
|
||||
struct spa_pod_dynamic_builder db;
|
||||
spa_pod_dynamic_builder_continue(&db, b);
|
||||
res = spa_pod_simplify_struct(&db.b, pod, SPA_POD_SIZE(pod));
|
||||
if (res >= 0)
|
||||
res = spa_pod_builder_raw_padded(b, db.b.data, db.b.state.offset);
|
||||
spa_pod_dynamic_builder_clean(&db);
|
||||
}
|
||||
|
||||
if (res >= 0 && result) {
|
||||
*result = (struct spa_pod*)spa_pod_builder_deref(b, state.offset);
|
||||
if (*result == NULL)
|
||||
res = -ENOSPC;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* \}
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* SPA_POD_SIMPLIFY_H */
|
||||
Loading…
Add table
Add a link
Reference in a new issue