screencast: support modifiers in build_format

When announcing support for dmabufs via PipeWire this is done by adding
the SPA_FORMAT_VIDEO_modifier property to an EnumFormat. Producers can
choose between two different ways [1]:

* Supporting only implicit modifiers by adding the property as a sigle
  value together with the SPA_POD_PROP_FLAG_MANDATORY flag
* Support for multiple modifiers. This is done by announcing a
  SPA_CHOICE_ENUM array together with the use of the
  SPA_POD_PROP_FLAG_MANDATORY and SPA_POD_PROP_FLAG_DONT_FIXATE flag

[1] https://docs.pipewire.org/page_dma_buf.html
This commit is contained in:
columbarius 2021-06-17 23:27:07 +02:00
parent 6630525b7a
commit bae393a684

View file

@ -8,6 +8,7 @@
#include <sys/mman.h> #include <sys/mman.h>
#include <unistd.h> #include <unistd.h>
#include <assert.h> #include <assert.h>
#include <libdrm/drm_fourcc.h>
#include "wlr_screencast.h" #include "wlr_screencast.h"
#include "xdpw.h" #include "xdpw.h"
@ -35,8 +36,10 @@ static struct spa_pod *build_buffer(struct spa_pod_builder *b, uint32_t blocks,
} }
static struct spa_pod *build_format(struct spa_pod_builder *b, enum spa_video_format format, static struct spa_pod *build_format(struct spa_pod_builder *b, enum spa_video_format format,
uint32_t width, uint32_t height, uint32_t framerate) { uint32_t width, uint32_t height, uint32_t framerate,
struct spa_pod_frame f[1]; uint64_t *modifiers, int modifier_count) {
struct spa_pod_frame f[2];
int i, c;
enum spa_video_format format_without_alpha = xdpw_format_pw_strip_alpha(format); enum spa_video_format format_without_alpha = xdpw_format_pw_strip_alpha(format);
@ -44,12 +47,31 @@ static struct spa_pod *build_format(struct spa_pod_builder *b, enum spa_video_fo
spa_pod_builder_add(b, SPA_FORMAT_mediaType, SPA_POD_Id(SPA_MEDIA_TYPE_video), 0); spa_pod_builder_add(b, SPA_FORMAT_mediaType, SPA_POD_Id(SPA_MEDIA_TYPE_video), 0);
spa_pod_builder_add(b, SPA_FORMAT_mediaSubtype, SPA_POD_Id(SPA_MEDIA_SUBTYPE_raw), 0); spa_pod_builder_add(b, SPA_FORMAT_mediaSubtype, SPA_POD_Id(SPA_MEDIA_SUBTYPE_raw), 0);
/* format */ /* format */
if (format_without_alpha == SPA_VIDEO_FORMAT_UNKNOWN) { if (modifier_count > 0 || format_without_alpha == SPA_VIDEO_FORMAT_UNKNOWN) {
// modifiers are defined only in combinations with their format
// we should not announce the format without alpha
spa_pod_builder_add(b, SPA_FORMAT_VIDEO_format, SPA_POD_Id(format), 0); spa_pod_builder_add(b, SPA_FORMAT_VIDEO_format, SPA_POD_Id(format), 0);
} else { } else {
spa_pod_builder_add(b, SPA_FORMAT_VIDEO_format, spa_pod_builder_add(b, SPA_FORMAT_VIDEO_format,
SPA_POD_CHOICE_ENUM_Id(3, format, format, format_without_alpha), 0); SPA_POD_CHOICE_ENUM_Id(3, format, format, format_without_alpha), 0);
} }
/* modifiers */
if (modifier_count == 1 && modifiers[0] == DRM_FORMAT_MOD_INVALID) {
// we only support implicit modifiers, use shortpath to skip fixation phase
spa_pod_builder_prop(b, SPA_FORMAT_VIDEO_modifier, SPA_POD_PROP_FLAG_MANDATORY);
spa_pod_builder_long(b, modifiers[0]);
} else if (modifier_count > 0) {
// build an enumeration of modifiers
spa_pod_builder_prop(b, SPA_FORMAT_VIDEO_modifier, SPA_POD_PROP_FLAG_MANDATORY | SPA_POD_PROP_FLAG_DONT_FIXATE);
spa_pod_builder_push_choice(b, &f[1], SPA_CHOICE_Enum, 0);
// modifiers from the array
for (i = 0, c = 0; i < modifier_count; i++) {
spa_pod_builder_long(b, modifiers[i]);
if (c++ == 0)
spa_pod_builder_long(b, modifiers[i]);
}
spa_pod_builder_pop(b, &f[1]);
}
spa_pod_builder_add(b, SPA_FORMAT_VIDEO_size, spa_pod_builder_add(b, SPA_FORMAT_VIDEO_size,
SPA_POD_Rectangle(&SPA_RECTANGLE(width, height)), SPA_POD_Rectangle(&SPA_RECTANGLE(width, height)),
0); 0);
@ -69,7 +91,8 @@ static uint32_t build_formats(struct spa_pod_builder *b, struct xdpw_screencast_
const struct spa_pod *params[static 1]) { const struct spa_pod *params[static 1]) {
uint32_t param_count = 1; uint32_t param_count = 1;
params[0] = build_format(b, xdpw_format_pw_from_drm_fourcc(cast->screencopy_frame_info[WL_SHM].format), params[0] = build_format(b, xdpw_format_pw_from_drm_fourcc(cast->screencopy_frame_info[WL_SHM].format),
cast->screencopy_frame_info[WL_SHM].width, cast->screencopy_frame_info[WL_SHM].height, cast->framerate); cast->screencopy_frame_info[WL_SHM].width, cast->screencopy_frame_info[WL_SHM].height, cast->framerate,
NULL, 0);
return param_count; return param_count;
} }