From a629c0bfb3ff14199e503bfc3f88cd7630bd6d02 Mon Sep 17 00:00:00 2001 From: dec05eba Date: Fri, 17 Nov 2023 10:09:51 +0100 Subject: [PATCH] Make amd/intel nvidia/wayland capture display match x11 connector name, allow screen capture on amd/intel nvidia/wayland (select the first output for now) --- TODO | 2 +- src/main.cpp | 31 ++++++++++++++++++++++++++++++- src/utils.c | 10 +++++----- 3 files changed, 36 insertions(+), 7 deletions(-) diff --git a/TODO b/TODO index 4054ba9..e2111d1 100644 --- a/TODO +++ b/TODO @@ -56,7 +56,7 @@ Intel is a bit weird with monitor capture and multiple monitors. If one of the m Support vp8/vp9. This is especially important on amd which on some distros (such as Manjaro) where hardware accelerated h264/hevc is disabled in the mesa package. -Support screen (all monitors) capture on amd/intel when no combined plane is found. +Support screen (all monitors) capture on amd/intel and nvidia wayland when no combined plane is found. Right now screen just takes the first output. Use separate plane (which has offset and pitch) from combined plane instead of the combined plane. Both twitch and youtube support variable bitrate but twitch recommends constant bitrate to reduce stream buffering/dropped frames when going from low motion to high motion: https://help.twitch.tv/s/article/broadcasting-guidelines?language=en_US. Info for youtube: https://support.google.com/youtube/answer/2853702?hl=en#zippy=%2Cvariable-bitrate-with-custom-stream-keys-in-live-control-room%2Ck-p-fps%2Cp-fps. diff --git a/src/main.cpp b/src/main.cpp index c9f793e..797c290 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -52,6 +52,16 @@ static void monitor_output_callback_print(const gsr_monitor *monitor, void *user fprintf(stderr, " \"%.*s\" (%dx%d+%d+%d)\n", monitor->name_len, monitor->name, monitor->size.x, monitor->size.y, monitor->pos.x, monitor->pos.y); } +typedef struct { + const char *output_name; +} FirstOutputCallback; + +static void get_first_output(const gsr_monitor *monitor, void *userdata) { + FirstOutputCallback *first_output = (FirstOutputCallback*)userdata; + if(!first_output->output_name) + first_output->output_name = strndup(monitor->name, monitor->name_len + 1); +} + static char* av_error_to_string(int err) { if(av_strerror(err, av_error_buffer, sizeof(av_error_buffer)) < 0) strcpy(av_error_buffer, "Unknown error"); @@ -1557,7 +1567,7 @@ int main(int argc, char **argv) { } const char *screen_region = args["-s"].value(); - const char *window_str = args["-w"].value(); + const char *window_str = strdup(args["-w"].value()); if(screen_region && strcmp(window_str, "focused") != 0) { fprintf(stderr, "Error: option -s is only available when using -w focused\n"); @@ -1593,10 +1603,27 @@ int main(int argc, char **argv) { follow_focused = true; } else if(contains_non_hex_number(window_str)) { if(wayland || gpu_inf.vendor != GSR_GPU_VENDOR_NVIDIA) { + if(strcmp(window_str, "screen") == 0) { + FirstOutputCallback first_output; + first_output.output_name = NULL; + if(gsr_egl_supports_wayland_capture(&egl)) { + for_each_active_monitor_output(&egl, GSR_CONNECTION_WAYLAND, get_first_output, &first_output); + } else { + for_each_active_monitor_output(card_path, GSR_CONNECTION_DRM, get_first_output, &first_output); + } + + if(first_output.output_name) { + window_str = first_output.output_name; + } else { + fprintf(stderr, "Error: no available output found\n"); + } + } + if(gsr_egl_supports_wayland_capture(&egl)) { gsr_monitor gmon; if(!get_monitor_by_name(&egl, GSR_CONNECTION_WAYLAND, window_str, &gmon)) { fprintf(stderr, "gsr error: display \"%s\" not found, expected one of:\n", window_str); + fprintf(stderr, " \"screen\"\n"); for_each_active_monitor_output(&egl, GSR_CONNECTION_WAYLAND, monitor_output_callback_print, NULL); _exit(1); } @@ -1604,6 +1631,7 @@ int main(int argc, char **argv) { gsr_monitor gmon; if(!get_monitor_by_name(card_path, GSR_CONNECTION_DRM, window_str, &gmon)) { fprintf(stderr, "gsr error: display \"%s\" not found, expected one of:\n", window_str); + fprintf(stderr, " \"screen\"\n"); for_each_active_monitor_output(card_path, GSR_CONNECTION_DRM, monitor_output_callback_print, NULL); _exit(1); } @@ -2357,6 +2385,7 @@ int main(int argc, char **argv) { //XCloseDisplay(dpy); } + free((void*)window_str); free(empty_audio); // We do an _exit here because cuda uses at_exit to do _something_ that causes the program to freeze, // but only on some nvidia driver versions on some gpus (RTX?), and _exit exits the program without calling diff --git a/src/utils.c b/src/utils.c index db0bd6f..94b0037 100644 --- a/src/utils.c +++ b/src/utils.c @@ -137,17 +137,17 @@ static void for_each_active_monitor_output_drm(const char *drm_card_path, active if(!connector) continue; - if(connector->connection != DRM_MODE_CONNECTED) { - drmModeFreeConnector(connector); - continue; - } - drm_connector_type_count *connector_type = drm_connector_types_get_index(type_counts, &num_type_counts, connector->connector_type); const char *connection_name = drmModeGetConnectorTypeName(connector->connector_type); const int connection_name_len = strlen(connection_name); if(connector_type) ++connector_type->count; + if(connector->connection != DRM_MODE_CONNECTED) { + drmModeFreeConnector(connector); + continue; + } + uint64_t crtc_id = 0; connector_get_property_by_name(fd, connector, "CRTC_ID", &crtc_id);