Compare commits

...

6 Commits
5.3.0 ... 5.3.3

Author SHA1 Message Date
dec05eba
e7a95f830a 5.3.3 2025-03-16 01:22:35 +01:00
dec05eba
1e0e24c818 todo 2025-03-16 01:16:18 +01:00
dec05eba
22c76fb8c3 Ffmpeg changes the api YET AGAIN, breaking recording on nvidia 2025-03-16 00:48:38 +01:00
dec05eba
77b60a03b2 5.3.2 2025-03-15 13:23:09 +01:00
dec05eba
1280a5ed0c Fix application audio not working correctly after a recent update 2025-03-15 13:22:42 +01:00
dec05eba
190c775a08 Fix screenshot of window not working after latest change 2025-03-14 08:54:12 +01:00
7 changed files with 48 additions and 59 deletions

2
TODO
View File

@@ -250,3 +250,5 @@ Support high quality scaling with -s by using lanczos.
Support spanning multiple monitors with region capture. This would also allow the user to record multiple monitors at the same time, the same way screen-direct works on nvidia x11.
When webcam support is added also support v4l2loopback? this is done by using avdevice_register_all(); and -c v4l2 -o /dev/video0; but it needs to output raw data as well instead of h264 and possibly yuv420p. Maybe add a -k yuv420p option to do that.
Do proper exit, to call gsr_capture_destroy which will properly stop gsr-kms-server. Otherwise there can be zombie gsr-kms-server on error.

View File

@@ -8,8 +8,6 @@ typedef struct {
gsr_egl *egl;
const char *display_to_capture; /* if this is "screen", then the entire x11 screen is captured (all displays). A copy is made of this */
int fps;
vec2i pos;
vec2i size;
bool direct_capture;
bool record_cursor;
vec2i output_resolution;

View File

@@ -1,4 +1,4 @@
project('gpu-screen-recorder', ['c', 'cpp'], version : '5.3.0', default_options : ['warning_level=2'])
project('gpu-screen-recorder', ['c', 'cpp'], version : '5.3.3', 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.3.0"
version = "5.3.3"
platforms = ["posix"]
[config]

View File

@@ -27,7 +27,7 @@ typedef struct {
NVFBC_TOGL_SETUP_PARAMS setup_params;
bool supports_direct_cursor;
uint32_t x, y, width, height;
uint32_t width, height;
NVFBC_TRACKING_TYPE tracking_type;
uint32_t output_id;
uint32_t tracking_width, tracking_height;
@@ -285,11 +285,6 @@ static int gsr_capture_nvfbc_start(gsr_capture *cap, gsr_capture_metadata *captu
if(!gsr_capture_nvfbc_load_library(cap))
return -1;
self->x = max_int(self->params.pos.x, 0);
self->y = max_int(self->params.pos.y, 0);
self->width = max_int(self->params.size.x, 0);
self->height = max_int(self->params.size.y, 0);
self->supports_direct_cursor = false;
int driver_major_version = 0;
int driver_minor_version = 0;

View File

@@ -777,7 +777,7 @@ static void dict_set_profile(AVCodecContext *codec_context, gsr_gpu_vendor vendo
//if(color_depth == GSR_COLOR_DEPTH_10_BITS)
// av_dict_set_int(options, "profile", AV_PROFILE_H264_HIGH_10, 0);
//else
av_dict_set_int(options, "profile", AV_PROFILE_H264_HIGH, 0);
av_dict_set_int(options, "profile", vendor == GSR_GPU_VENDOR_NVIDIA ? 2 : AV_PROFILE_H264_HIGH, 0);
} else if(codec_context->codec_id == AV_CODEC_ID_AV1) {
if(vendor == GSR_GPU_VENDOR_NVIDIA) {
if(color_depth == GSR_COLOR_DEPTH_10_BITS)
@@ -787,9 +787,9 @@ static void dict_set_profile(AVCodecContext *codec_context, gsr_gpu_vendor vendo
}
} else if(codec_context->codec_id == AV_CODEC_ID_HEVC) {
if(color_depth == GSR_COLOR_DEPTH_10_BITS)
av_dict_set_int(options, "profile", AV_PROFILE_HEVC_MAIN_10, 0);
av_dict_set_int(options, "profile", vendor == GSR_GPU_VENDOR_NVIDIA ? 1 : AV_PROFILE_HEVC_MAIN_10, 0);
else
av_dict_set_int(options, "profile", AV_PROFILE_HEVC_MAIN, 0);
av_dict_set_int(options, "profile", vendor == GSR_GPU_VENDOR_NVIDIA ? 0 : AV_PROFILE_HEVC_MAIN, 0);
}
#endif
}
@@ -1224,7 +1224,8 @@ static void usage_full() {
printf(" By default this value is set to 2.0.\n");
printf("\n");
printf(" -restore-portal-session\n");
printf(" If GPU Screen Recorder should use the same capture option as the last time. Using this option removes the popup asking what you want to record the next time you record with '-w portal' if you selected the option to save session (token) in the desktop portal screencast popup.\n");
printf(" If GPU Screen Recorder should use the same capture option as the last time. Using this option removes the popup asking what you want to record the next time you record with '-w portal'\n");
printf(" if you selected the option to save session (token) in the desktop portal screencast popup.\n");
printf(" This option may not have any effect on your Wayland compositor and your systems desktop portal needs to support ScreenCast version 5 or later. Optional, set to 'no' by default.\n");
printf("\n");
printf(" -portal-session-token-filepath\n");
@@ -2428,8 +2429,30 @@ static std::string get_monitor_by_region_center(const gsr_egl *egl, vec2i region
return result;
}
static gsr_capture* create_monitor_capture(const std::string &window_str, vec2i output_resolution, vec2i region_size, vec2i region_position, gsr_egl *egl, int fps, bool hdr, bool record_cursor) {
if(!monitor_capture_use_drm(egl->window, egl->gpu_info.vendor)) {
static gsr_capture* create_monitor_capture(const std::string &window_str, vec2i output_resolution, vec2i region_size, vec2i region_position, gsr_egl *egl, int fps, bool hdr, bool record_cursor, bool prefer_ximage) {
if(gsr_window_get_display_server(egl->window) == GSR_DISPLAY_SERVER_X11 && prefer_ximage) {
gsr_capture_ximage_params ximage_params;
ximage_params.egl = egl;
ximage_params.display_to_capture = window_str.c_str();
ximage_params.record_cursor = record_cursor;
ximage_params.output_resolution = output_resolution;
ximage_params.region_size = region_size;
ximage_params.region_position = region_position;
return gsr_capture_ximage_create(&ximage_params);
}
if(monitor_capture_use_drm(egl->window, egl->gpu_info.vendor)) {
gsr_capture_kms_params kms_params;
kms_params.egl = egl;
kms_params.display_to_capture = window_str.c_str();
kms_params.record_cursor = record_cursor;
kms_params.hdr = hdr;
kms_params.fps = fps;
kms_params.output_resolution = output_resolution;
kms_params.region_size = region_size;
kms_params.region_position = region_position;
return gsr_capture_kms_create(&kms_params);
} else {
const char *capture_target = window_str.c_str();
const bool direct_capture = strcmp(window_str.c_str(), "screen-direct") == 0 || strcmp(window_str.c_str(), "screen-direct-force") == 0;
if(direct_capture) {
@@ -2441,25 +2464,12 @@ static gsr_capture* create_monitor_capture(const std::string &window_str, vec2i
nvfbc_params.egl = egl;
nvfbc_params.display_to_capture = capture_target;
nvfbc_params.fps = fps;
nvfbc_params.pos = { 0, 0 };
nvfbc_params.size = { 0, 0 };
nvfbc_params.direct_capture = direct_capture;
nvfbc_params.record_cursor = record_cursor;
nvfbc_params.output_resolution = output_resolution;
nvfbc_params.region_size = region_size;
nvfbc_params.region_position = region_position;
return gsr_capture_nvfbc_create(&nvfbc_params);
} else {
gsr_capture_kms_params kms_params;
kms_params.egl = egl;
kms_params.display_to_capture = window_str.c_str();
kms_params.record_cursor = record_cursor;
kms_params.hdr = hdr;
kms_params.fps = fps;
kms_params.output_resolution = output_resolution;
kms_params.region_size = region_size;
kms_params.region_position = region_position;
return gsr_capture_kms_create(&kms_params);
}
}
@@ -2489,7 +2499,7 @@ static void region_get_data(std::string &window_str, gsr_egl *egl, vec2i *region
}
static gsr_capture* create_capture_impl(std::string &window_str, vec2i output_resolution, vec2i region_size, vec2i region_position, bool wayland, gsr_egl *egl, int fps, bool hdr,
bool record_cursor, bool restore_portal_session, const char *portal_session_token_filepath)
bool record_cursor, bool restore_portal_session, const char *portal_session_token_filepath, bool prefer_ximage)
{
Window src_window_id = None;
bool follow_focused = false;
@@ -2530,12 +2540,12 @@ static gsr_capture* create_capture_impl(std::string &window_str, vec2i output_re
#endif
} else if(strcmp(window_str.c_str(), "region") == 0) {
region_get_data(window_str, egl, &region_size, &region_position);
capture = create_monitor_capture(window_str, output_resolution, region_size, region_position, egl, fps, hdr, record_cursor);
capture = create_monitor_capture(window_str, output_resolution, region_size, region_position, egl, fps, hdr, record_cursor, prefer_ximage);
if(!capture)
_exit(1);
} else if(contains_non_hex_number(window_str.c_str())) {
validate_monitor_get_valid(egl, window_str);
capture = create_monitor_capture(window_str, output_resolution, region_size, region_position, egl, fps, hdr, record_cursor);
capture = create_monitor_capture(window_str, output_resolution, region_size, region_position, egl, fps, hdr, record_cursor, prefer_ximage);
if(!capture)
_exit(1);
} else {
@@ -2596,29 +2606,8 @@ static void capture_image_to_file(const char *filepath, std::string &window_str,
bool record_cursor, bool restore_portal_session, const char *portal_session_token_filepath, VideoQuality video_quality) {
const gsr_color_range color_range = image_format_to_color_range(image_format);
const int fps = 60;
gsr_capture *capture = nullptr;
switch(gsr_window_get_display_server(egl->window)) {
case GSR_DISPLAY_SERVER_X11: {
if(window_str == "region")
region_get_data(window_str, egl, &region_size, &region_position);
else
validate_monitor_get_valid(egl, window_str);
gsr_capture_ximage_params ximage_params;
ximage_params.egl = egl;
ximage_params.display_to_capture = window_str.c_str();
ximage_params.record_cursor = record_cursor;
ximage_params.output_resolution = output_resolution;
ximage_params.region_size = region_size;
ximage_params.region_position = region_position;
capture = gsr_capture_ximage_create(&ximage_params);
break;
}
case GSR_DISPLAY_SERVER_WAYLAND: {
capture = create_capture_impl(window_str, output_resolution, region_size, region_position, wayland, egl, fps, false, record_cursor, restore_portal_session, portal_session_token_filepath);
break;
}
}
const bool prefer_ximage = true;
gsr_capture *capture = create_capture_impl(window_str, output_resolution, region_size, region_position, wayland, egl, fps, false, record_cursor, restore_portal_session, portal_session_token_filepath, prefer_ximage);
gsr_capture_metadata capture_metadata;
capture_metadata.width = 0;
@@ -3958,7 +3947,7 @@ int main(int argc, char **argv) {
const AVCodec *video_codec_f = select_video_codec_with_fallback(&video_codec, video_codec_to_use, file_extension.c_str(), use_software_video_encoder, &egl, &low_power);
const gsr_color_depth color_depth = video_codec_to_bit_depth(video_codec);
gsr_capture *capture = create_capture_impl(window_str, output_resolution, region_size, region_position, wayland, &egl, fps, video_codec_is_hdr(video_codec), record_cursor, restore_portal_session, portal_session_token_filepath);
gsr_capture *capture = create_capture_impl(window_str, output_resolution, region_size, region_position, wayland, &egl, fps, video_codec_is_hdr(video_codec), record_cursor, restore_portal_session, portal_session_token_filepath, false);
// (Some?) livestreaming services require at least one audio track to work.
// If not audio is provided then create one silent audio track.

View File

@@ -365,6 +365,8 @@ static bool gsr_pipewire_audio_listen_on_metadata(gsr_pipewire_audio *self, uint
pw_proxy_add_object_listener(self->metadata_proxy, &self->metadata_listener, &metadata_events, self);
pw_proxy_add_listener(self->metadata_proxy, &self->metadata_proxy_listener, &metadata_proxy_events, self);
self->server_version_sync = pw_core_sync(self->core, PW_ID_CORE, self->server_version_sync);
return true;
}
@@ -562,12 +564,12 @@ bool gsr_pipewire_audio_init(gsr_pipewire_audio *self) {
// TODO: Error check
pw_core_add_listener(self->core, &self->core_listener, &core_events, self);
self->server_version_sync = pw_core_sync(self->core, PW_ID_CORE, 0);
pw_thread_loop_wait(self->thread_loop);
self->registry = pw_core_get_registry(self->core, PW_VERSION_REGISTRY, 0);
pw_registry_add_listener(self->registry, &self->registry_listener, &registry_events, self);
self->server_version_sync = pw_core_sync(self->core, PW_ID_CORE, self->server_version_sync);
pw_thread_loop_wait(self->thread_loop);
pw_thread_loop_unlock(self->thread_loop);
return true;
}
@@ -595,6 +597,9 @@ void gsr_pipewire_audio_deinit(gsr_pipewire_audio *self) {
self->metadata_proxy = NULL;
}
spa_hook_remove(&self->registry_listener);
spa_hook_remove(&self->core_listener);
if(self->core) {
pw_core_disconnect(self->core);
self->core = NULL;