mirror of
https://github.com/hyprwm/xdg-desktop-portal-hyprland.git
synced 2024-12-22 17:59:47 +01:00
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:
parent
88a8a9cb7e
commit
12de0cd144
5 changed files with 70 additions and 42 deletions
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in a new issue