Compare commits

...

10 Commits

Author SHA1 Message Date
dec05eba
4ed04830c1 Add void linux to README, update pkill command 2026-03-18 15:39:41 +01:00
dec05eba
755340454d Poll reset revents 2026-03-11 11:32:45 +01:00
dec05eba
2f8212b122 5.12.5 2026-03-02 00:00:38 +01:00
dec05eba
23782889be Minor check 2026-03-01 23:52:59 +01:00
dec05eba
fd08cdb9b4 pipewire video: fail video map texture if state is not streaming
Fixes portal capture failing on some systems
2026-03-01 19:30:17 +01:00
dec05eba
6079a0162d Portal capture: test disable modifier recheck same 2026-03-01 18:12:00 +01:00
dec05eba
eff5d619eb Fix incorrect manpage 2026-02-25 01:08:05 +01:00
dec05eba
309c4e5f2e Update info about reporting bugs in the manpage, move gpu-screen-recorder.env to ~/.config/gpu-screen-recorder but keep old path as well 2026-02-23 23:15:09 +01:00
dec05eba
0555cfde58 FAQ browser av1 2026-02-19 22:29:55 +01:00
p0358
ff030ba63f don't show microphone indicator on KDE 2026-02-19 20:04:55 +01:00
13 changed files with 50 additions and 34 deletions

View File

@@ -48,6 +48,7 @@ Here are some known unofficial packages:
* Solus: [gpu-screen-recorder](https://github.com/getsolus/packages/tree/main/packages/g/gpu-screen-recorder)
* Nobara: [Nobara wiki](https://wiki.nobaraproject.org/en/general-usage/additional-software/GPU-Screen-Recorder)
* AppImage [AppImage GitHub releases](https://github.com/pkgforge-dev/gpu-screen-recorder-AppImage/releases)
* Void Linux: [gpu-screen-recorder](https://voidlinux.org/packages/?arch=x86_64&q=gpu-screen-recorder) (Make sure to read the README in the package)
# Dependencies
GPU Screen Recorder uses meson build system so you need to install `meson` to build GPU Screen Recorder.
@@ -96,7 +97,7 @@ There is also a gui for the gpu screen recorder called [GPU Screen Recorder GTK]
There is also a new alternative UI for GPU Screen Recorder in the style of ShadowPlay called [GPU Screen Recorder UI](https://git.dec05eba.com/gpu-screen-recorder-ui/).
## Recording
Here is an example of how to record your monitor and the default audio output: `gpu-screen-recorder -w screen -f 60 -a default_output -o ~/Videos/test_video.mp4`.
Yyou can stop and save the recording with `Ctrl+C` or by running `pkill -SIGINT -f gpu-screen-recorder`.
Yyou can stop and save the recording with `Ctrl+C` or by running `pkill -SIGINT -f "^gpu-screen-recorder"`.
You can see a list of capture options to record if you run `gpu-screen-recorder --list-capture-options`. This will list possible capture options and monitor names, for example:\
```
window
@@ -122,12 +123,12 @@ GPU Screen Recorder uses Ffmpeg so GPU Screen Recorder supports all protocols th
If you want to reduce latency one thing you can do is to use the `-keyint` option, for example `-keyint 0.5`. Lower value means lower latency at the cost of increased bitrate/decreased quality.
## Recording while using replay/streaming
You can record a regular video while using replay/streaming by launching GPU Screen Recorder with the `-ro` option to specify a directory where to save the recording (for example: `gpu-screen-recorder -w screen -c mp4 -r 60 -o "$HOME/Videos/replays" -ro "$HOME/Videos/recordings"`).\
To start/stop (and save) recording use the SIGRTMIN signal, for example `pkill -SIGRTMIN -f gpu-screen-recorder`. The path to the video will be displayed in stdout when saving the video.\
To start/stop (and save) recording use the SIGRTMIN signal, for example `pkill -SIGRTMIN -f "^gpu-screen-recorder"`. The path to the video will be displayed in stdout when saving the video.\
This way of recording while using replay/streaming is more efficient than running GPU Screen Recorder multiple times since this way it only records the screen and encodes the video once.
## Controlling GPU Screen Recorder remotely
To save a video in replay mode, you need to send signal SIGUSR1 to gpu screen recorder. You can do this by running `pkill -SIGUSR1 -f gpu-screen-recorder`.\
To stop recording send SIGINT to gpu screen recorder. You can do this by running `pkill -SIGINT -f gpu-screen-recorder` or pressing `Ctrl-C` in the terminal that runs gpu screen recorder. When recording a regular non-replay video this will also save the video.\
To pause/unpause recording send SIGUSR2 to gpu screen recorder. You can do this by running `pkill -SIGUSR2 -f gpu-screen-recorder`. This is only applicable and useful when recording (not streaming nor replay).\
To save a video in replay mode, you need to send signal SIGUSR1 to gpu screen recorder. You can do this by running `pkill -SIGUSR1 -f "^gpu-screen-recorder"`.\
To stop recording send SIGINT to gpu screen recorder. You can do this by running `pkill -SIGINT -f "^gpu-screen-recorder"` or pressing `Ctrl-C` in the terminal that runs gpu screen recorder. When recording a regular non-replay video this will also save the video.\
To pause/unpause recording send SIGUSR2 to gpu screen recorder. You can do this by running `pkill -SIGUSR2 -f "^gpu-screen-recorder"`. This is only applicable and useful when recording (not streaming nor replay).\
There are more signals to control GPU Screen Recorder. Run `gpu-screen-recorder --help` to list them all (under `NOTES` section).
## Simple way to run replay without gui
Run the script `scripts/start-replay.sh` to start replay and then `scripts/save-replay.sh` to save a replay and `scripts/stop-replay.sh` to stop the replay. The videos are saved to `$HOME/Videos`.
@@ -135,7 +136,7 @@ You can use these scripts to start replay at system startup if you add `scripts/
hotkey settings on your system and choose a hotkey to run the script `scripts/save-replay.sh`. Modify `scripts/start-replay.sh` if you want to use other replay options.
## Run replay on system startup
If you installed GPU Screen Recorder from AUR or from source and you are running a distro that uses systemd then you will have a systemd service installed that can be started with `systemctl enable --now --user gpu-screen-recorder`. This systemd service runs GPU Screen Recorder on system startup.\
It's configured with `$HOME/.config/gpu-screen-recorder.env` (create it if it doesn't exist). You can look at [extra/gpu-screen-recorder.env](https://git.dec05eba.com/gpu-screen-recorder/plain/extra/gpu-screen-recorder.env) to see an example.
It's configured with `$HOME/.config/gpu-screen-recorder/gpu-screen-recorder.env` (create it if it doesn't exist). You can look at [extra/gpu-screen-recorder.env](https://git.dec05eba.com/gpu-screen-recorder/plain/extra/gpu-screen-recorder.env) to see an example.
You can see which variables that you can use in the `gpu-screen-recorder.env` file by looking at the `extra/gpu-screen-recorder.service` file. Note that all of the variables are optional, you only have to set the ones that are you interested in.
You can use the `scripts/save-replay.sh` script to save a replay and by default the systemd service saves videos in `$HOME/Videos`.
## Run a script when a video is saved
@@ -209,7 +210,7 @@ Newer ffmpeg versions don't support older nvidia cards. Try installing GPU Scree
## I get a black screen/glitches while live streaming
It seems like ffmpeg earlier than version 6.1 has some type of bug. Install ffmpeg version 6.1 or later and then reinstall GPU Screen Recorder to fix this issue. The flatpak version of GPU Screen Recorder comes with a newer version of ffmpeg so no extra steps are needed.
## I can't play the video in my browser directly or in discord
Browsers and discord don't support hevc video codec at the moment. Choose h264 video codec instead with the -k h264 option.
Browsers and discord don't support hevc video codec at the moment. You can instead choose h264 video codec with the -k h264 option or av1 video codec with the -k av1 option.
Note that websites such as youtube support hevc so there is no need to choose h264 video codec if you intend to upload the video to youtube or if you want to play the video locally or if you intend to
edit the video with a video editor. Hevc allows for better video quality (especially at lower file sizes) so hevc (or av1) is recommended for source videos.
## I get a black bar/distorted colors on the sides in the video

10
TODO
View File

@@ -312,8 +312,6 @@ Check if region capture works properly with fractional scaling on wayland.
Add option to specify medium/high/very high/ultra for -bm cbr as well, which should automatically pick bitrate based on resolution and framerate.
This should also be reflected in gsr ui.
Implement webcam support by using mjpeg with v4l2 and use ffmpeg mjpeg decoder.
After adding rpc, making recording while in replay/streaming work differently. Start recording should take audio as an argument, to optionally specify different audio for recording than replay/stream.
After adding rpc, make it possible to add/remove audio and video. The same number of audio tracks should remain, but the audio devices/app should be possible to configure. You should be able to configure the capture sources however you want.
@@ -398,8 +396,12 @@ Should -low-power option also use vaapi/vulkan low power, if available?
Should capture option x=bla;y=bla be scaled by -s (output resolution scale)? width and height is.
Certain webcam resolutions yuyv resolutions dont work (on amd at least), such as 800x600. Maybe it's because of alignment issue, 600 isn't divisible by 16.
Add option to capture all monitors automatically.
Make -w optional, to only capture audio.
Use GL_RGBA16F or GL_RGBA32F for hdr, that allows color values to be outside the 0.0 to 1.0 range.
https://registry.khronos.org/EGL/extensions/EXT/EGL_EXT_surface_SMPTE2086_metadata.txt
Doesn't work: sibs run --args -w "/dev/video0;camera_width=800;camera_height=600;pixfmt=yuyv" -fm content -o video.mp4

View File

@@ -3,6 +3,7 @@ Description=GPU Screen Recorder Service
[Service]
EnvironmentFile=-%h/.config/gpu-screen-recorder.env
EnvironmentFile=-%h/.config/gpu-screen-recorder/gpu-screen-recorder.env
Environment=WINDOW=screen
Environment=CONTAINER=mp4
Environment=QUALITY=40000

View File

@@ -209,7 +209,7 @@ A value of 0 means to use the best option available.
.BI \-region " WxH+X+Y"
Specify region to capture when using
.BR \-w " region."
Format is width x height + X offset + Y offset. Use 0x0 for full monitor.
Format is width x height + X offset + Y offset. Set width and height to 0 to capture the whole monitor that contains the position.
It is compatible with tools such as slop (X11) and slurp (Wayland).
.TP
@@ -450,7 +450,7 @@ Save last 30 minutes (replay mode).
Use
.B pkill
to send signals (e.g.,
.BR "pkill -SIGUSR1 -f gpu-screen-recorder" ).
.BR "pkill -SIGUSR1 -f ""^gpu-screen-recorder""" ).
.SH EXAMPLES
Record monitor at 60 FPS with desktop audio:
.PP
@@ -549,7 +549,7 @@ gpu-screen-recorder -w "DP-1|DP-2;x=1920" -o video.mp4
.fi
.SH FILES
.TP
.I ~/.config/gpu-screen-recorder.env
.I ~/.config/gpu-screen-recorder/gpu-screen-recorder.env
Environment variables for systemd service (optional).
.TP
.I /usr/lib/modprobe.d/gsr-nvidia.conf
@@ -606,8 +606,16 @@ ShadowPlay-style UI
Developed by dec05eba and contributors.
.SH COPYRIGHT
Copyright © dec05eba. Licensed under GPL3-only.
.SH BUGS
.SH REPORTING BUGS
Report bugs at
.UR mailto:dec05eba@protonmail.com
dec05eba@protonmail.com
.UE .
.UR https://git.dec05eba.com/?p=about
See more information about reporting bugs at the gpu-screen-recorder website
.UE .
.br
.UR https://git.dec05eba.com/gpu-screen-recorder/about/
Before reporting a bug or an issue, please take a look at FAQ part of the README
.UE .
The bug or issue may have been previously reported or may not be related to gpu-screen-recorder.

View File

@@ -106,13 +106,13 @@ typedef struct {
bool no_modifiers_fallback;
bool external_texture_fallback;
uint64_t renegotiated_modifier;
uint64_t modifiers[GSR_PIPEWIRE_VIDEO_MAX_MODIFIERS];
size_t num_modifiers;
bool paused;
double paused_start_secs;
bool streaming;
gsr_monitor_rotation rotation;
} gsr_pipewire_video;

View File

@@ -378,6 +378,7 @@ int gsr_kms_client_init(gsr_kms_client *self, const char *card_path) {
goto err;
}
}
poll_fd.revents = 0;
}
fprintf(stderr, "gsr info: gsr_kms_client_init: server connected\n");

View File

@@ -1,4 +1,4 @@
project('gpu-screen-recorder', ['c', 'cpp'], version : '5.12.4', default_options : ['warning_level=2'])
project('gpu-screen-recorder', ['c', 'cpp'], version : '5.12.5', default_options : ['warning_level=2'])
add_project_arguments('-Wshadow', language : ['c', 'cpp'])
if get_option('buildtype') == 'debug'

View File

@@ -1,7 +1,7 @@
[package]
name = "gpu-screen-recorder"
type = "executable"
version = "5.12.4"
version = "5.12.5"
platforms = ["posix"]
[config]

View File

@@ -458,6 +458,7 @@ static bool gsr_capture_v4l2_map_buffer(gsr_capture_v4l2 *self, const struct v4l
if(!self->dma_image[i]) {
self->yuyv_conversion_fallback = true;
// This doesn't work for everybody on nvidia. On pop os 24.04 when egl_display is NULL (when capturing monitor on x11) then this fails with EGL_BAD_DISPLAY
self->dma_image[i] = self->params.egl->eglCreateImage(self->params.egl->egl_display, 0, EGL_LINUX_DMA_BUF_EXT, NULL, (intptr_t[]) {
EGL_WIDTH, fmt->fmt.pix.width,
EGL_HEIGHT, fmt->fmt.pix.height,

View File

@@ -187,6 +187,7 @@ static void gsr_capture_xcomposite_on_event(gsr_capture *cap, gsr_egl *egl) {
break;
}
case ConfigureNotify: {
// TODO: Use PresentConfigureNotify instead
self->window_pos.x = xev->xconfigure.x;
self->window_pos.y = xev->xconfigure.y;

View File

@@ -3267,7 +3267,7 @@ static const AVCodec* pick_video_codec(gsr_egl *egl, args_parser *args_parser, b
if(!video_codec_f && use_fallback_codec && args_parser->video_encoder != GSR_VIDEO_ENCODER_HW_CPU) {
switch(args_parser->video_codec) {
case GSR_VIDEO_CODEC_H264: {
fprintf(stderr, "gsr error: selected video codec h264 is not supported\n");
fprintf(stderr, "gsr error: selected video codec h264 is not supported by your hardware\n");
if(args_parser->fallback_cpu_encoding) {
fprintf(stderr, "gsr warning: gpu encoding is not available on your system, trying cpu encoding instead because -fallback-cpu-encoding is enabled. Install the proper vaapi drivers on your system (if supported) if you experience performance issues\n");
force_cpu_encoding(args_parser);
@@ -3277,14 +3277,14 @@ static const AVCodec* pick_video_codec(gsr_egl *egl, args_parser *args_parser, b
case GSR_VIDEO_CODEC_HEVC:
case GSR_VIDEO_CODEC_HEVC_HDR:
case GSR_VIDEO_CODEC_HEVC_10BIT: {
fprintf(stderr, "gsr warning: selected video codec hevc is not supported, trying h264 instead\n");
fprintf(stderr, "gsr warning: selected video codec hevc is not supported by your hardware, trying h264 instead\n");
args_parser->video_codec = GSR_VIDEO_CODEC_H264;
return pick_video_codec(egl, args_parser, true, low_power, supported_video_codecs);
}
case GSR_VIDEO_CODEC_AV1:
case GSR_VIDEO_CODEC_AV1_HDR:
case GSR_VIDEO_CODEC_AV1_10BIT: {
fprintf(stderr, "gsr warning: selected video codec av1 is not supported, trying h264 instead\n");
fprintf(stderr, "gsr warning: selected video codec av1 is not supported by your hardware, trying h264 instead\n");
args_parser->video_codec = GSR_VIDEO_CODEC_H264;
return pick_video_codec(egl, args_parser, true, low_power, supported_video_codecs);
}
@@ -3293,7 +3293,7 @@ static const AVCodec* pick_video_codec(gsr_egl *egl, args_parser *args_parser, b
// TODO: Cant fallback to other codec because webm only supports vp8/vp9
break;
case GSR_VIDEO_CODEC_H264_VULKAN: {
fprintf(stderr, "gsr warning: selected video codec h264_vulkan is not supported, trying h264 instead\n");
fprintf(stderr, "gsr warning: selected video codec h264_vulkan is not supported by your hardware, trying h264 instead\n");
args_parser->video_codec = GSR_VIDEO_CODEC_H264;
// Need to do a query again because this time it's without vulkan
if(!get_supported_video_codecs(egl, args_parser->video_codec, false, true, supported_video_codecs)) {
@@ -3304,7 +3304,7 @@ static const AVCodec* pick_video_codec(gsr_egl *egl, args_parser *args_parser, b
return pick_video_codec(egl, args_parser, true, low_power, supported_video_codecs);
}
case GSR_VIDEO_CODEC_HEVC_VULKAN: {
fprintf(stderr, "gsr warning: selected video codec hevc_vulkan is not supported, trying hevc instead\n");
fprintf(stderr, "gsr warning: selected video codec hevc_vulkan is not supported by your hardware, trying hevc instead\n");
args_parser->video_codec = GSR_VIDEO_CODEC_HEVC;
// Need to do a query again because this time it's without vulkan
if(!get_supported_video_codecs(egl, args_parser->video_codec, false, true, supported_video_codecs)) {
@@ -3564,7 +3564,7 @@ static void set_display_server_environment_variables() {
const char *wayland_display = getenv("WAYLAND_DISPLAY");
if(!wayland_display) {
wayland_display = "wayland-1";
wayland_display = "wayland-0";
setenv("WAYLAND_DISPLAY", wayland_display, true);
}
}

View File

@@ -134,7 +134,7 @@ static void on_process_cb(void *user_data) {
}
struct spa_buffer *buffer = pw_buf->buffer;
const bool has_buffer = buffer->datas[0].chunk->size != 0;
const bool has_buffer = buffer->n_datas > 0 && buffer->datas[0].chunk->size != 0;
pthread_mutex_lock(&self->mutex);
@@ -348,6 +348,7 @@ static void on_state_changed_cb(void *user_data, enum pw_stream_state prev_state
} else {
self->paused = false;
}
self->streaming = (new_state == PW_STREAM_STATE_STREAMING);
pthread_mutex_unlock(&self->mutex);
}
@@ -692,7 +693,6 @@ bool gsr_pipewire_video_init(gsr_pipewire_video *self, int pipewire_fd, uint32_t
self->video_info.fps_num = fps;
self->video_info.fps_den = 1;
self->cursor.visible = capture_cursor;
self->renegotiated_modifier = DRM_FORMAT_MOD_INVALID;
if(!gsr_pipewire_video_setup_stream(self)) {
gsr_pipewire_video_deinit(self);
@@ -798,14 +798,8 @@ static EGLImage gsr_pipewire_video_create_egl_image_with_fallback(gsr_pipewire_v
fprintf(stderr, "gsr error: gsr_pipewire_video_create_egl_image_with_fallback: failed to create egl image with modifiers, trying without modifiers\n");
self->no_modifiers_fallback = true;
image = gsr_pipewire_video_create_egl_image(self, fds, offsets, pitches, modifiers, false);
} else if(self->renegotiated_modifier == self->format.info.raw.modifier) {
fprintf(stderr, "gsr error: gsr_pipewire_video_create_egl_image_with_fallback: modifier 0x%" PRIx64 " failed again after renegotiation, trying without modifiers as last resort\n", self->format.info.raw.modifier);
image = gsr_pipewire_video_create_egl_image(self, fds, offsets, pitches, modifiers, false);
if(image)
self->no_modifiers_fallback = true;
} else {
fprintf(stderr, "gsr error: gsr_pipewire_video_create_egl_image_with_fallback: failed to create egl image with modifier 0x%" PRIx64 ", renegotiating with a different modifier\n", self->format.info.raw.modifier);
self->renegotiated_modifier = self->format.info.raw.modifier;
self->negotiated = false;
pw_thread_loop_lock(self->thread_loop);
gsr_pipewire_video_remove_modifier(self, self->format.info.raw.modifier);
@@ -865,7 +859,7 @@ bool gsr_pipewire_video_map_texture(gsr_pipewire_video *self, gsr_texture_map te
output->rotation = GSR_MONITOR_ROT_0;
pthread_mutex_lock(&self->mutex);
if(!self->negotiated || self->dmabuf_data[0].fd <= 0) {
if(!self->negotiated || !self->streaming || self->dmabuf_data[0].fd <= 0) {
pthread_mutex_unlock(&self->mutex);
return false;
}

View File

@@ -340,11 +340,18 @@ static bool pa_sound_device_handle_reconnect(pa_handle *p, char *device_name, si
return false;
}
if(!(p->stream = pa_stream_new(p->context, p->stream_name, &p->ss, NULL))) {
pa_proplist *proplist = pa_proplist_new();
// This prevents microphone recording indicator from being shown on KDE
pa_proplist_sets(proplist, "node.virtual", "true");
if(!(p->stream = pa_stream_new_with_proplist(p->context, p->stream_name, &p->ss, NULL, proplist))) {
//pa_context_errno(p->context);
pa_proplist_free(proplist);
return false;
}
pa_proplist_free(proplist);
const int r = pa_stream_connect_record(p->stream, device_name, &p->attr,
(pa_stream_flags_t)(PA_STREAM_INTERPOLATE_TIMING|PA_STREAM_ADJUST_LATENCY|PA_STREAM_AUTO_TIMING_UPDATE|PA_STREAM_DONT_MOVE));