diff --git a/include/screencast_common.h b/include/screencast_common.h index 14d9de2..a196761 100644 --- a/include/screencast_common.h +++ b/include/screencast_common.h @@ -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); diff --git a/src/screencast/pipewire_screencast.c b/src/screencast/pipewire_screencast.c index 4b4b794..425bc80 100644 --- a/src/screencast/pipewire_screencast.c +++ b/src/screencast/pipewire_screencast.c @@ -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<screencopy_frame_info.size, - cast->screencopy_frame_info.stride, 1<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; diff --git a/src/screencast/screencast.c b/src/screencast/screencast.c index b382156..f5f6003 100644 --- a/src/screencast/screencast.c +++ b/src/screencast/screencast.c @@ -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; diff --git a/src/screencast/screencast_common.c b/src/screencast/screencast_common.c index 09f8452..0b1ecfe 100644 --- a/src/screencast/screencast_common.c +++ b/src/screencast/screencast_common.c @@ -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; diff --git a/src/screencast/wlr_screencast.c b/src/screencast/wlr_screencast.c index 152fa7e..e41143f 100644 --- a/src/screencast/wlr_screencast.c +++ b/src/screencast/wlr_screencast.c @@ -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);