screencast: introduce buffer_type

We want to support WL_SHM and DMABUFS based buffers. The buffer_type
member tracks the type of a xdpw_buffer and screencopy_frame_info of the
screencast_instance will be an array with an element for each buffer type
indexed by the value of the buffer_type enum. Only members of the
xdpw_screencopy_frame_info relevant to the buffer type should be used.
This commit is contained in:
columbarius 2021-06-17 21:51:16 +02:00
parent 88a8a9cb7e
commit 12de0cd144
5 changed files with 70 additions and 42 deletions

View file

@ -22,6 +22,11 @@ enum source_types {
WINDOW = 2,
};
enum buffer_type {
WL_SHM = 0,
DMABUF = 1,
};
enum xdpw_chooser_types {
XDPW_CHOOSER_DEFAULT,
XDPW_CHOOSER_NONE,
@ -68,6 +73,7 @@ struct xdpw_screencopy_frame_info {
struct xdpw_buffer {
struct wl_list link;
enum buffer_type buffer_type;
uint32_t width;
uint32_t height;
@ -127,11 +133,12 @@ struct xdpw_screencast_instance {
struct xdpw_wlr_output *target_output;
uint32_t max_framerate;
struct zwlr_screencopy_frame_v1 *wlr_frame;
struct xdpw_screencopy_frame_info screencopy_frame_info;
struct xdpw_screencopy_frame_info screencopy_frame_info[2];
bool with_cursor;
int err;
bool quit;
bool need_buffer;
enum buffer_type buffer_type;
// fps limit
struct fps_limit_state fps_limit;
@ -152,7 +159,7 @@ struct xdpw_wlr_output {
void randname(char *buf);
struct xdpw_buffer *xdpw_buffer_create(struct xdpw_screencast_instance *cast,
struct xdpw_screencopy_frame_info *frame_info);
enum buffer_type buffer_type, struct xdpw_screencopy_frame_info *frame_info);
void xdpw_buffer_destroy(struct xdpw_buffer *buffer);
enum wl_shm_format xdpw_format_wl_shm_from_drm_fourcc(uint32_t format);
uint32_t xdpw_format_drm_fourcc_from_wl_shm(enum wl_shm_format format);

View file

@ -68,8 +68,8 @@ static struct spa_pod *build_format(struct spa_pod_builder *b, enum spa_video_fo
static uint32_t build_formats(struct spa_pod_builder *b, struct xdpw_screencast_instance *cast,
const struct spa_pod *params[static 1]) {
uint32_t param_count = 1;
params[0] = build_format(b, xdpw_format_pw_from_drm_fourcc(cast->screencopy_frame_info.format),
cast->screencopy_frame_info.width, cast->screencopy_frame_info.height, cast->framerate);
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);
return param_count;
}
@ -122,6 +122,8 @@ static void pwr_handle_stream_param_changed(void *data, uint32_t id,
struct spa_pod_builder b =
SPA_POD_BUILDER_INIT(params_buffer, sizeof(params_buffer));
const struct spa_pod *params[2];
uint32_t blocks;
uint32_t data_type;
if (!param || id != SPA_PARAM_Format) {
return;
@ -130,9 +132,16 @@ static void pwr_handle_stream_param_changed(void *data, uint32_t id,
spa_format_video_raw_parse(param, &cast->pwr_format);
cast->framerate = (uint32_t)(cast->pwr_format.max_framerate.num / cast->pwr_format.max_framerate.denom);
if (spa_pod_find_prop(param, NULL, SPA_FORMAT_VIDEO_modifier) != NULL) {
abort();
} else {
cast->buffer_type = WL_SHM;
blocks = 1;
data_type = 1<<SPA_DATA_MemFd;
}
params[0] = build_buffer(&b, 1, cast->screencopy_frame_info.size,
cast->screencopy_frame_info.stride, 1<<SPA_DATA_MemFd);
params[0] = build_buffer(&b, blocks, cast->screencopy_frame_info[cast->buffer_type].size,
cast->screencopy_frame_info[cast->buffer_type].stride, data_type);
params[1] = spa_pod_builder_add_object(&b,
SPA_TYPE_OBJECT_ParamMeta, SPA_PARAM_Meta,
@ -152,6 +161,7 @@ static void pwr_handle_stream_add_buffer(void *data, struct pw_buffer *buffer) {
// Select buffer type from negotiation result
if ((d[0].type & (1u << SPA_DATA_MemFd)) > 0) {
assert(cast->buffer_type == WL_SHM);
d[0].type = SPA_DATA_MemFd;
} else {
logprint(ERROR, "pipewire: unsupported buffer type");
@ -161,7 +171,7 @@ static void pwr_handle_stream_add_buffer(void *data, struct pw_buffer *buffer) {
logprint(TRACE, "pipewire: selected buffertype %u", d[0].type);
struct xdpw_buffer *xdpw_buffer = xdpw_buffer_create(cast, &cast->screencopy_frame_info);
struct xdpw_buffer *xdpw_buffer = xdpw_buffer_create(cast, cast->buffer_type, &cast->screencopy_frame_info[cast->buffer_type]);
if (xdpw_buffer == NULL) {
logprint(ERROR, "pipewire: failed to create xdpw buffer");
cast->err = 1;

View file

@ -455,7 +455,7 @@ static int method_screencast_start(sd_bus_message *msg, void *data,
"streams", "a(ua{sv})", 1,
cast->node_id, 2,
"position", "(ii)", 0, 0,
"size", "(ii)", cast->screencopy_frame_info.width, cast->screencopy_frame_info.height);
"size", "(ii)", cast->screencopy_frame_info[WL_SHM].width, cast->screencopy_frame_info[WL_SHM].height);
if (ret < 0) {
return ret;

View file

@ -57,35 +57,43 @@ static struct wl_buffer *import_wl_shm_buffer(struct xdpw_screencast_instance *c
}
struct xdpw_buffer *xdpw_buffer_create(struct xdpw_screencast_instance *cast,
struct xdpw_screencopy_frame_info *frame_info) {
enum buffer_type buffer_type, struct xdpw_screencopy_frame_info *frame_info) {
struct xdpw_buffer *buffer = calloc(1, sizeof(struct xdpw_buffer));
buffer->width = frame_info->width;
buffer->height = frame_info->height;
buffer->format = frame_info->format;
buffer->size = frame_info->size;
buffer->stride = frame_info->stride;
buffer->offset = 0;
buffer->fd = anonymous_shm_open();
if (buffer->fd == -1) {
logprint(ERROR, "xdpw: unable to create anonymous filedescriptor");
free(buffer);
return NULL;
}
buffer->buffer_type = buffer_type;
if (ftruncate(buffer->fd, buffer->size) < 0) {
logprint(ERROR, "xdpw: unable to truncate filedescriptor");
close(buffer->fd);
free(buffer);
return NULL;
}
switch (buffer_type) {
case WL_SHM:
buffer->size = frame_info->size;
buffer->stride = frame_info->stride;
buffer->offset = 0;
buffer->fd = anonymous_shm_open();
if (buffer->fd == -1) {
logprint(ERROR, "xdpw: unable to create anonymous filedescriptor");
free(buffer);
return NULL;
}
buffer->buffer = import_wl_shm_buffer(cast, buffer->fd, xdpw_format_wl_shm_from_drm_fourcc(frame_info->format),
frame_info->width, frame_info->height, frame_info->stride);
if (buffer->buffer == NULL) {
logprint(ERROR, "xdpw: unable to create wl_buffer");
close(buffer->fd);
free(buffer);
return NULL;
if (ftruncate(buffer->fd, buffer->size) < 0) {
logprint(ERROR, "xdpw: unable to truncate filedescriptor");
close(buffer->fd);
free(buffer);
return NULL;
}
buffer->buffer = import_wl_shm_buffer(cast, buffer->fd, xdpw_format_wl_shm_from_drm_fourcc(frame_info->format),
frame_info->width, frame_info->height, frame_info->stride);
if (buffer->buffer == NULL) {
logprint(ERROR, "xdpw: unable to create wl_buffer");
close(buffer->fd);
free(buffer);
return NULL;
}
break;
case DMABUF:
abort();
}
return buffer;

View file

@ -87,11 +87,11 @@ static void wlr_frame_buffer(void *data, struct zwlr_screencopy_frame_v1 *frame,
logprint(TRACE, "wlroots: buffer event handler");
cast->wlr_frame = frame;
cast->screencopy_frame_info.width = width;
cast->screencopy_frame_info.height = height;
cast->screencopy_frame_info.stride = stride;
cast->screencopy_frame_info.size = stride * height;
cast->screencopy_frame_info.format = xdpw_format_drm_fourcc_from_wl_shm(format);
cast->screencopy_frame_info[WL_SHM].width = width;
cast->screencopy_frame_info[WL_SHM].height = height;
cast->screencopy_frame_info[WL_SHM].stride = stride;
cast->screencopy_frame_info[WL_SHM].size = stride * height;
cast->screencopy_frame_info[WL_SHM].format = xdpw_format_drm_fourcc_from_wl_shm(format);
if (zwlr_screencopy_manager_v1_get_version(cast->ctx->screencopy_manager) < 3) {
wlr_frame_buffer_done(cast, frame);
@ -116,10 +116,10 @@ static void wlr_frame_buffer_done(void *data,
}
// Check if announced screencopy information is compatible with pipewire meta
if ((cast->pwr_format.format != xdpw_format_pw_from_drm_fourcc(cast->screencopy_frame_info.format) &&
cast->pwr_format.format != xdpw_format_pw_strip_alpha(xdpw_format_pw_from_drm_fourcc(cast->screencopy_frame_info.format))) ||
cast->pwr_format.size.width != cast->screencopy_frame_info.width ||
cast->pwr_format.size.height != cast->screencopy_frame_info.height) {
if ((cast->pwr_format.format != xdpw_format_pw_from_drm_fourcc(cast->screencopy_frame_info[cast->buffer_type].format) &&
cast->pwr_format.format != xdpw_format_pw_strip_alpha(xdpw_format_pw_from_drm_fourcc(cast->screencopy_frame_info[cast->buffer_type].format))) ||
cast->pwr_format.size.width != cast->screencopy_frame_info[cast->buffer_type].width ||
cast->pwr_format.size.height != cast->screencopy_frame_info[cast->buffer_type].height) {
logprint(DEBUG, "wlroots: pipewire and wlroots metadata are incompatible. Renegotiate stream");
cast->frame_state = XDPW_FRAME_STATE_RENEG;
xdpw_wlr_frame_finish(cast);
@ -140,8 +140,11 @@ static void wlr_frame_buffer_done(void *data,
assert(cast->current_frame.xdpw_buffer);
// Check if dequeued buffer is compatible with announced buffer
if (cast->current_frame.xdpw_buffer->size != cast->screencopy_frame_info.size ||
cast->current_frame.xdpw_buffer->stride != cast->screencopy_frame_info.stride) {
if (( cast->buffer_type == WL_SHM &&
(cast->current_frame.xdpw_buffer->size != cast->screencopy_frame_info[cast->buffer_type].size ||
cast->current_frame.xdpw_buffer->stride != cast->screencopy_frame_info[cast->buffer_type].stride)) ||
cast->current_frame.xdpw_buffer->width != cast->screencopy_frame_info[cast->buffer_type].width ||
cast->current_frame.xdpw_buffer->height != cast->screencopy_frame_info[cast->buffer_type].height) {
logprint(DEBUG, "wlroots: pipewire buffer has wrong dimensions");
cast->frame_state = XDPW_FRAME_STATE_FAILED;
xdpw_wlr_frame_finish(cast);