xdg-desktop-portal-hyprland/src/screencast/screencast_common.c

194 lines
5.2 KiB
C
Raw Normal View History

2020-01-24 23:31:01 +01:00
#include "screencast_common.h"
#include <assert.h>
#include <fcntl.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <unistd.h>
2020-01-24 23:31:01 +01:00
#include "logger.h"
void randname(char *buf) {
struct timespec ts;
clock_gettime(CLOCK_REALTIME, &ts);
long r = ts.tv_nsec;
for (int i = 0; i < 6; ++i) {
assert(buf[i] == 'X');
buf[i] = 'A'+(r&15)+(r&16)*2;
r >>= 5;
}
}
static int anonymous_shm_open(void) {
char name[] = "/xdpw-shm-XXXXXX";
int retries = 100;
do {
randname(name + strlen(name) - 6);
--retries;
// shm_open guarantees that O_CLOEXEC is set
int fd = shm_open(name, O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR);
if (fd >= 0) {
shm_unlink(name);
return fd;
}
} while (retries > 0 && errno == EEXIST);
return -1;
}
static struct wl_buffer *import_wl_shm_buffer(struct xdpw_screencast_instance *cast, int fd,
enum wl_shm_format fmt, int width, int height, int stride) {
struct xdpw_screencast_context *ctx = cast->ctx;
int size = stride * height;
if (fd < 0) {
return NULL;
}
struct wl_shm_pool *pool = wl_shm_create_pool(ctx->shm, fd, size);
struct wl_buffer *buffer =
wl_shm_pool_create_buffer(pool, 0, width, height, stride, fmt);
wl_shm_pool_destroy(pool);
return buffer;
}
struct xdpw_buffer *xdpw_buffer_create(struct xdpw_screencast_instance *cast,
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;
}
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, 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;
}
return buffer;
}
void xdpw_buffer_destroy(struct xdpw_buffer *buffer) {
wl_buffer_destroy(buffer->buffer);
close(buffer->fd);
wl_list_remove(&buffer->link);
free(buffer);
}
enum spa_video_format xdpw_format_pw_from_wl_shm(enum wl_shm_format format) {
switch (format) {
case WL_SHM_FORMAT_ARGB8888:
return SPA_VIDEO_FORMAT_BGRA;
case WL_SHM_FORMAT_XRGB8888:
return SPA_VIDEO_FORMAT_BGRx;
case WL_SHM_FORMAT_RGBA8888:
return SPA_VIDEO_FORMAT_ABGR;
case WL_SHM_FORMAT_RGBX8888:
return SPA_VIDEO_FORMAT_xBGR;
case WL_SHM_FORMAT_ABGR8888:
return SPA_VIDEO_FORMAT_RGBA;
case WL_SHM_FORMAT_XBGR8888:
return SPA_VIDEO_FORMAT_RGBx;
case WL_SHM_FORMAT_BGRA8888:
return SPA_VIDEO_FORMAT_ARGB;
case WL_SHM_FORMAT_BGRX8888:
return SPA_VIDEO_FORMAT_xRGB;
case WL_SHM_FORMAT_NV12:
return SPA_VIDEO_FORMAT_NV12;
case WL_SHM_FORMAT_XRGB2101010:
return SPA_VIDEO_FORMAT_xRGB_210LE;
case WL_SHM_FORMAT_XBGR2101010:
return SPA_VIDEO_FORMAT_xBGR_210LE;
case WL_SHM_FORMAT_RGBX1010102:
return SPA_VIDEO_FORMAT_RGBx_102LE;
case WL_SHM_FORMAT_BGRX1010102:
return SPA_VIDEO_FORMAT_BGRx_102LE;
case WL_SHM_FORMAT_ARGB2101010:
return SPA_VIDEO_FORMAT_ARGB_210LE;
case WL_SHM_FORMAT_ABGR2101010:
return SPA_VIDEO_FORMAT_ABGR_210LE;
case WL_SHM_FORMAT_RGBA1010102:
return SPA_VIDEO_FORMAT_RGBA_102LE;
case WL_SHM_FORMAT_BGRA1010102:
return SPA_VIDEO_FORMAT_BGRA_102LE;
default:
logprint(ERROR, "xdg-desktop-portal-wlr: failed to convert wl_shm "
"format 0x%08x to spa_video_format", format);
abort();
2020-01-24 23:31:01 +01:00
}
}
enum spa_video_format xdpw_format_pw_strip_alpha(enum spa_video_format format) {
switch (format) {
case SPA_VIDEO_FORMAT_BGRA:
return SPA_VIDEO_FORMAT_BGRx;
case SPA_VIDEO_FORMAT_ABGR:
return SPA_VIDEO_FORMAT_xBGR;
case SPA_VIDEO_FORMAT_RGBA:
return SPA_VIDEO_FORMAT_RGBx;
case SPA_VIDEO_FORMAT_ARGB:
return SPA_VIDEO_FORMAT_xRGB;
case SPA_VIDEO_FORMAT_ARGB_210LE:
return SPA_VIDEO_FORMAT_xRGB_210LE;
case SPA_VIDEO_FORMAT_ABGR_210LE:
return SPA_VIDEO_FORMAT_xBGR_210LE;
case SPA_VIDEO_FORMAT_RGBA_102LE:
return SPA_VIDEO_FORMAT_RGBx_102LE;
case SPA_VIDEO_FORMAT_BGRA_102LE:
return SPA_VIDEO_FORMAT_BGRx_102LE;
default:
return SPA_VIDEO_FORMAT_UNKNOWN;
}
}
enum xdpw_chooser_types get_chooser_type(const char *chooser_type) {
if (!chooser_type || strcmp(chooser_type, "default") == 0) {
return XDPW_CHOOSER_DEFAULT;
} else if (strcmp(chooser_type, "none") == 0) {
return XDPW_CHOOSER_NONE;
} else if (strcmp(chooser_type, "simple") == 0) {
return XDPW_CHOOSER_SIMPLE;
} else if (strcmp(chooser_type, "dmenu") == 0) {
return XDPW_CHOOSER_DMENU;
}
fprintf(stderr, "Could not understand chooser type %s\n", chooser_type);
exit(1);
}
const char *chooser_type_str(enum xdpw_chooser_types chooser_type) {
switch (chooser_type) {
case XDPW_CHOOSER_DEFAULT:
return "default";
case XDPW_CHOOSER_NONE:
return "none";
case XDPW_CHOOSER_SIMPLE:
return "simple";
case XDPW_CHOOSER_DMENU:
return "dmenu";
}
fprintf(stderr, "Could not find chooser type %d\n", chooser_type);
abort();
}