mirror of
https://repo.dec05eba.com/gpu-screen-recorder
synced 2026-04-07 03:45:32 +09:00
Compare commits
10 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2290f0641c | ||
|
|
f9e93467b2 | ||
|
|
7d7f986668 | ||
|
|
1b957d5b40 | ||
|
|
8ad6a1f4cb | ||
|
|
0cf0a9abf5 | ||
|
|
bc58e382b7 | ||
|
|
630c504241 | ||
|
|
0528bc6f31 | ||
|
|
a8b3e38082 |
@@ -78,7 +78,6 @@ GPU Screen Recorder uses meson build system so you need to install `meson` to bu
|
||||
## Build dependencies
|
||||
These are the dependencies needed to build GPU Screen Recorder:
|
||||
|
||||
* libglvnd (which provides libgl, libglx and libegl)
|
||||
* vulkan-headers
|
||||
* ffmpeg (libavcodec, libavformat, libavutil, libswresample, libavfilter)
|
||||
* x11 (libx11, libxcomposite, libxrandr, libxfixes, libxdamage)
|
||||
@@ -89,6 +88,8 @@ These are the dependencies needed to build GPU Screen Recorder:
|
||||
* wayland (wayland-client, wayland-egl, wayland-scanner)
|
||||
|
||||
## Runtime dependencies
|
||||
* libglvnd (which provides libgl, libglx and libegl) is needed. Your system needs to support at least OpenGL ES 3.0 (released in 2012)
|
||||
|
||||
There are also additional dependencies needed at runtime depending on your GPU vendor:
|
||||
|
||||
### AMD
|
||||
@@ -97,7 +98,7 @@ There are also additional dependencies needed at runtime depending on your GPU v
|
||||
|
||||
### Intel
|
||||
* mesa
|
||||
* vaapi (intel-media-driver/libva-intel-driver/linux-firmware, depending on which intel iGPU you have)
|
||||
* vaapi (intel-media-driver/libva-intel-driver/linux-firmware-intel, depending on which intel iGPU you have)
|
||||
|
||||
### NVIDIA
|
||||
* cuda runtime (libcuda.so.1) (libnvidia-compute)
|
||||
|
||||
4
TODO
4
TODO
@@ -302,3 +302,7 @@ Allow medium, high, very_high and ultra quality for -bm cbr. If that is used the
|
||||
Maybe do this in the ui instead (or both?), to show estimated file size.
|
||||
|
||||
Maybe remove shader compute code. It doesn't seem necessary anymore now that glSwapBuffer/glFinish isn't used. dbus server isn't needed anymore either, the code can be moved back to the gpu screen recorder process.
|
||||
|
||||
Add proper check if opengl functions are supported. dlsym for the symbol will return a no-op function if it's not supported, so it silently fails if used.
|
||||
|
||||
Colors are offset to bottom left by 1 pixel or so on steam deck in landscape mode.
|
||||
|
||||
@@ -48,6 +48,8 @@ typedef void(*__GLXextFuncPtr)(void);
|
||||
#define EGL_OPENGL_ES_API 0x30A0
|
||||
#define EGL_OPENGL_BIT 0x0008
|
||||
#define EGL_OPENGL_ES_BIT 0x0001
|
||||
#define EGL_OPENGL_ES2_BIT 0x0004
|
||||
#define EGL_OPENGL_ES3_BIT 0x00000040
|
||||
#define EGL_NONE 0x3038
|
||||
#define EGL_CONTEXT_CLIENT_VERSION 0x3098
|
||||
#define EGL_BACK_BUFFER 0x3084
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
#include <spa/param/video/format.h>
|
||||
|
||||
#define GSR_PIPEWIRE_VIDEO_MAX_MODIFIERS 1024
|
||||
#define GSR_PIPEWIRE_VIDEO_MAX_VIDEO_FORMATS 12
|
||||
#define GSR_PIPEWIRE_VIDEO_MAX_VIDEO_FORMATS 6
|
||||
#define GSR_PIPEWIRE_VIDEO_DMABUF_MAX_PLANES 4
|
||||
|
||||
typedef struct gsr_egl gsr_egl;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
project('gpu-screen-recorder', ['c', 'cpp'], version : '5.5.8', default_options : ['warning_level=2'])
|
||||
project('gpu-screen-recorder', ['c', 'cpp'], version : '5.5.10', default_options : ['warning_level=2'])
|
||||
|
||||
add_project_arguments('-Wshadow', language : ['c', 'cpp'])
|
||||
if get_option('buildtype') == 'debug'
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
[package]
|
||||
name = "gpu-screen-recorder"
|
||||
type = "executable"
|
||||
version = "5.5.8"
|
||||
version = "5.5.10"
|
||||
platforms = ["posix"]
|
||||
|
||||
[config]
|
||||
|
||||
6
scripts/toggle-recording.sh
Executable file
6
scripts/toggle-recording.sh
Executable file
@@ -0,0 +1,6 @@
|
||||
#!/bin/sh -e
|
||||
|
||||
killall -SIGINT gpu-screen-recorder && sleep 0.5 && notify-send -t 1500 -u low 'GPU Screen Recorder' 'Stopped recording' && exit 0;
|
||||
video="$HOME/Videos/$(date +"Video_%Y-%m-%d_%H-%M-%S.mp4")"
|
||||
notify-send -t 1500 -u low 'GPU Screen Recorder' "Started recording video to $video"
|
||||
gpu-screen-recorder -w screen -f 60 -a "default_output" -o "$video"
|
||||
@@ -12,7 +12,7 @@
|
||||
#include <fcntl.h>
|
||||
|
||||
#include <xf86drm.h>
|
||||
#include <libdrm/drm_fourcc.h>
|
||||
#include <drm_fourcc.h>
|
||||
|
||||
#include <libavutil/mastering_display_metadata.h>
|
||||
|
||||
|
||||
@@ -23,6 +23,12 @@ typedef struct {
|
||||
vec2i capture_size;
|
||||
gsr_pipewire_video_dmabuf_data dmabuf_data[GSR_PIPEWIRE_VIDEO_DMABUF_MAX_PLANES];
|
||||
int num_dmabuf_data;
|
||||
|
||||
gsr_pipewire_video_region region;
|
||||
gsr_pipewire_video_region cursor_region;
|
||||
uint32_t pipewire_fourcc;
|
||||
uint64_t pipewire_modifiers;
|
||||
bool using_external_image;
|
||||
} gsr_capture_portal;
|
||||
|
||||
static void gsr_capture_portal_cleanup_plane_fds(gsr_capture_portal *self) {
|
||||
@@ -216,19 +222,13 @@ static int gsr_capture_portal_setup_dbus(gsr_capture_portal *self, int *pipewire
|
||||
}
|
||||
|
||||
static bool gsr_capture_portal_get_frame_dimensions(gsr_capture_portal *self) {
|
||||
gsr_pipewire_video_region region = {0, 0, 0, 0};
|
||||
gsr_pipewire_video_region cursor_region = {0, 0, 0, 0};
|
||||
fprintf(stderr, "gsr info: gsr_capture_portal_start: waiting for pipewire negotiation\n");
|
||||
|
||||
const double start_time = clock_get_monotonic_seconds();
|
||||
while(clock_get_monotonic_seconds() - start_time < 5.0) {
|
||||
bool uses_external_image = false;
|
||||
uint32_t fourcc = 0;
|
||||
uint64_t modifiers = 0;
|
||||
if(gsr_pipewire_video_map_texture(&self->pipewire, self->texture_map, ®ion, &cursor_region, self->dmabuf_data, &self->num_dmabuf_data, &fourcc, &modifiers, &uses_external_image)) {
|
||||
gsr_capture_portal_cleanup_plane_fds(self);
|
||||
self->capture_size.x = region.width;
|
||||
self->capture_size.y = region.height;
|
||||
if(gsr_pipewire_video_map_texture(&self->pipewire, self->texture_map, &self->region, &self->cursor_region, self->dmabuf_data, &self->num_dmabuf_data, &self->pipewire_fourcc, &self->pipewire_modifiers, &self->using_external_image)) {
|
||||
self->capture_size.x = self->region.width;
|
||||
self->capture_size.y = self->region.height;
|
||||
fprintf(stderr, "gsr info: gsr_capture_portal_start: pipewire negotiation finished\n");
|
||||
return true;
|
||||
}
|
||||
@@ -300,20 +300,17 @@ static int gsr_capture_portal_capture(gsr_capture *cap, gsr_capture_metadata *ca
|
||||
(void)color_conversion;
|
||||
gsr_capture_portal *self = cap->priv;
|
||||
|
||||
/* TODO: Handle formats other than RGB(a) */
|
||||
gsr_pipewire_video_region region = {0, 0, 0, 0};
|
||||
gsr_pipewire_video_region cursor_region = {0, 0, 0, 0};
|
||||
uint32_t pipewire_fourcc = 0;
|
||||
uint64_t pipewire_modifiers = 0;
|
||||
bool using_external_image = false;
|
||||
if(gsr_pipewire_video_map_texture(&self->pipewire, self->texture_map, ®ion, &cursor_region, self->dmabuf_data, &self->num_dmabuf_data, &pipewire_fourcc, &pipewire_modifiers, &using_external_image)) {
|
||||
if(region.width != self->capture_size.x || region.height != self->capture_size.y) {
|
||||
self->capture_size.x = region.width;
|
||||
self->capture_size.y = region.height;
|
||||
gsr_color_conversion_clear(color_conversion);
|
||||
/* TODO: Handle formats other than RGB(A) */
|
||||
if(self->num_dmabuf_data == 0) {
|
||||
if(gsr_pipewire_video_map_texture(&self->pipewire, self->texture_map, &self->region, &self->cursor_region, self->dmabuf_data, &self->num_dmabuf_data, &self->pipewire_fourcc, &self->pipewire_modifiers, &self->using_external_image)) {
|
||||
if(self->region.width != self->capture_size.x || self->region.height != self->capture_size.y) {
|
||||
self->capture_size.x = self->region.width;
|
||||
self->capture_size.y = self->region.height;
|
||||
gsr_color_conversion_clear(color_conversion);
|
||||
}
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
|
||||
const bool is_scaled = self->params.output_resolution.x > 0 && self->params.output_resolution.y > 0;
|
||||
@@ -327,27 +324,27 @@ static int gsr_capture_portal_capture(gsr_capture *cap, gsr_capture_metadata *ca
|
||||
|
||||
// TODO: Handle region crop
|
||||
|
||||
gsr_color_conversion_draw(color_conversion, using_external_image ? self->texture_map.external_texture_id : self->texture_map.texture_id,
|
||||
gsr_color_conversion_draw(color_conversion, self->using_external_image ? self->texture_map.external_texture_id : self->texture_map.texture_id,
|
||||
target_pos, output_size,
|
||||
(vec2i){region.x, region.y}, self->capture_size, self->capture_size,
|
||||
GSR_ROT_0, GSR_SOURCE_COLOR_RGB, using_external_image, false);
|
||||
(vec2i){self->region.x, self->region.y}, self->capture_size, self->capture_size,
|
||||
GSR_ROT_0, GSR_SOURCE_COLOR_RGB, self->using_external_image, false);
|
||||
|
||||
if(self->params.record_cursor && self->texture_map.cursor_texture_id > 0 && cursor_region.width > 0) {
|
||||
if(self->params.record_cursor && self->texture_map.cursor_texture_id > 0 && self->cursor_region.width > 0) {
|
||||
const vec2d scale = {
|
||||
self->capture_size.x == 0 ? 0 : (double)output_size.x / (double)self->capture_size.x,
|
||||
self->capture_size.y == 0 ? 0 : (double)output_size.y / (double)self->capture_size.y
|
||||
};
|
||||
|
||||
const vec2i cursor_pos = {
|
||||
target_pos.x + (cursor_region.x * scale.x),
|
||||
target_pos.y + (cursor_region.y * scale.y)
|
||||
target_pos.x + (self->cursor_region.x * scale.x),
|
||||
target_pos.y + (self->cursor_region.y * scale.y)
|
||||
};
|
||||
|
||||
self->params.egl->glEnable(GL_SCISSOR_TEST);
|
||||
self->params.egl->glScissor(target_pos.x, target_pos.y, output_size.x, output_size.y);
|
||||
gsr_color_conversion_draw(color_conversion, self->texture_map.cursor_texture_id,
|
||||
(vec2i){cursor_pos.x, cursor_pos.y}, (vec2i){cursor_region.width * scale.x, cursor_region.height * scale.y},
|
||||
(vec2i){0, 0}, (vec2i){cursor_region.width, cursor_region.height}, (vec2i){cursor_region.width, cursor_region.height},
|
||||
(vec2i){cursor_pos.x, cursor_pos.y}, (vec2i){self->cursor_region.width * scale.x, self->cursor_region.height * scale.y},
|
||||
(vec2i){0, 0}, (vec2i){self->cursor_region.width, self->cursor_region.height}, (vec2i){self->cursor_region.width, self->cursor_region.height},
|
||||
GSR_ROT_0, GSR_SOURCE_COLOR_RGB, false, true);
|
||||
self->params.egl->glDisable(GL_SCISSOR_TEST);
|
||||
}
|
||||
|
||||
@@ -35,7 +35,7 @@ static bool gsr_egl_create_window(gsr_egl *self) {
|
||||
|
||||
const int32_t attr[] = {
|
||||
EGL_BUFFER_SIZE, 24,
|
||||
EGL_RENDERABLE_TYPE, EGL_OPENGL_ES_BIT,
|
||||
EGL_RENDERABLE_TYPE, EGL_OPENGL_ES3_BIT,
|
||||
EGL_NONE, EGL_NONE
|
||||
};
|
||||
|
||||
@@ -459,9 +459,9 @@ bool gsr_egl_load(gsr_egl *self, gsr_window *window, bool is_monitor_capture, bo
|
||||
/* This fixes nvenc codecs unable to load on openSUSE tumbleweed because of a cuda error. Don't ask me why */
|
||||
const bool inside_flatpak = getenv("FLATPAK_ID") != NULL;
|
||||
if(inside_flatpak)
|
||||
system("flatpak-spawn --host -- nvidia-smi -f /dev/null");
|
||||
system("flatpak-spawn --host -- sh -c 'grep -q openSUSE /etc/os-release && nvidia-smi -f /dev/null'");
|
||||
else
|
||||
system("nvidia-smi -f /dev/null");
|
||||
system("sh -c 'grep -q openSUSE /etc/os-release && nvidia-smi -f /dev/null'");
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
#include <spa/param/video/format-utils.h>
|
||||
#include <spa/debug/types.h>
|
||||
|
||||
#include <libdrm/drm_fourcc.h>
|
||||
#include <drm_fourcc.h>
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
@@ -346,17 +346,17 @@ static int64_t spa_video_format_to_drm_format(const enum spa_video_format format
|
||||
switch(format) {
|
||||
case SPA_VIDEO_FORMAT_RGBx: return DRM_FORMAT_XBGR8888;
|
||||
case SPA_VIDEO_FORMAT_BGRx: return DRM_FORMAT_XRGB8888;
|
||||
case SPA_VIDEO_FORMAT_RGBA: return DRM_FORMAT_ABGR8888;
|
||||
case SPA_VIDEO_FORMAT_BGRA: return DRM_FORMAT_ARGB8888;
|
||||
// case SPA_VIDEO_FORMAT_RGBA: return DRM_FORMAT_ABGR8888;
|
||||
//case SPA_VIDEO_FORMAT_BGRA: return DRM_FORMAT_ARGB8888;
|
||||
case SPA_VIDEO_FORMAT_RGB: return DRM_FORMAT_XBGR8888;
|
||||
case SPA_VIDEO_FORMAT_BGR: return DRM_FORMAT_XRGB8888;
|
||||
case SPA_VIDEO_FORMAT_ARGB: return DRM_FORMAT_XRGB8888;
|
||||
case SPA_VIDEO_FORMAT_ABGR: return DRM_FORMAT_XRGB8888;
|
||||
//case SPA_VIDEO_FORMAT_ARGB: return DRM_FORMAT_XRGB8888;
|
||||
//case SPA_VIDEO_FORMAT_ABGR: return DRM_FORMAT_XRGB8888;
|
||||
#if PW_CHECK_VERSION(0, 3, 41)
|
||||
case SPA_VIDEO_FORMAT_xRGB_210LE: return DRM_FORMAT_XRGB2101010;
|
||||
case SPA_VIDEO_FORMAT_xBGR_210LE: return DRM_FORMAT_XBGR2101010;
|
||||
case SPA_VIDEO_FORMAT_ARGB_210LE: return DRM_FORMAT_ARGB2101010;
|
||||
case SPA_VIDEO_FORMAT_ABGR_210LE: return DRM_FORMAT_ABGR2101010;
|
||||
// case SPA_VIDEO_FORMAT_ARGB_210LE: return DRM_FORMAT_ARGB2101010;
|
||||
// case SPA_VIDEO_FORMAT_ABGR_210LE: return DRM_FORMAT_ABGR2101010;
|
||||
#endif
|
||||
default: break;
|
||||
}
|
||||
@@ -366,23 +366,23 @@ static int64_t spa_video_format_to_drm_format(const enum spa_video_format format
|
||||
#if PW_CHECK_VERSION(0, 3, 41)
|
||||
#define GSR_PIPEWIRE_VIDEO_NUM_VIDEO_FORMATS GSR_PIPEWIRE_VIDEO_MAX_VIDEO_FORMATS
|
||||
#else
|
||||
#define GSR_PIPEWIRE_VIDEO_NUM_VIDEO_FORMATS 8
|
||||
#define GSR_PIPEWIRE_VIDEO_NUM_VIDEO_FORMATS 4
|
||||
#endif
|
||||
|
||||
static const enum spa_video_format video_formats[GSR_PIPEWIRE_VIDEO_MAX_VIDEO_FORMATS] = {
|
||||
SPA_VIDEO_FORMAT_BGRA,
|
||||
// SPA_VIDEO_FORMAT_BGRA,
|
||||
SPA_VIDEO_FORMAT_BGRx,
|
||||
SPA_VIDEO_FORMAT_BGR,
|
||||
SPA_VIDEO_FORMAT_RGBx,
|
||||
SPA_VIDEO_FORMAT_RGBA,
|
||||
// SPA_VIDEO_FORMAT_RGBA,
|
||||
SPA_VIDEO_FORMAT_RGB,
|
||||
SPA_VIDEO_FORMAT_ARGB,
|
||||
SPA_VIDEO_FORMAT_ABGR,
|
||||
// SPA_VIDEO_FORMAT_ARGB,
|
||||
// SPA_VIDEO_FORMAT_ABGR,
|
||||
#if PW_CHECK_VERSION(0, 3, 41)
|
||||
SPA_VIDEO_FORMAT_xRGB_210LE,
|
||||
SPA_VIDEO_FORMAT_xBGR_210LE,
|
||||
SPA_VIDEO_FORMAT_ARGB_210LE,
|
||||
SPA_VIDEO_FORMAT_ABGR_210LE
|
||||
// SPA_VIDEO_FORMAT_ARGB_210LE,
|
||||
// SPA_VIDEO_FORMAT_ABGR_210LE
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user