aboutsummaryrefslogtreecommitdiff
path: root/src/GsrInfo.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/GsrInfo.cpp')
-rw-r--r--src/GsrInfo.cpp179
1 files changed, 179 insertions, 0 deletions
diff --git a/src/GsrInfo.cpp b/src/GsrInfo.cpp
new file mode 100644
index 0000000..1534363
--- /dev/null
+++ b/src/GsrInfo.cpp
@@ -0,0 +1,179 @@
+#include "../include/GsrInfo.hpp"
+#include <string.h>
+#include <functional>
+
+namespace gsr {
+ using StringSplitCallback = std::function<bool(std::string_view line)>;
+
+ static void string_split_char(const std::string &str, char delimiter, StringSplitCallback callback_func) {
+ size_t index = 0;
+ while(index < str.size()) {
+ size_t new_index = str.find(delimiter, index);
+ if(new_index == std::string::npos)
+ new_index = str.size();
+
+ if(!callback_func({str.data() + index, new_index - index}))
+ break;
+
+ index = new_index + 1;
+ }
+ }
+
+ static void parse_system_info_line(GsrInfo *gsr_info, const std::string &line) {
+ const size_t space_index = line.find(' ');
+ if(space_index == std::string::npos)
+ return;
+
+ const std::string_view attribute_name = {line.c_str(), space_index};
+ const std::string_view attribute_value = {line.c_str() + space_index + 1, line.size() - (space_index + 1)};
+ if(attribute_name == "display_server") {
+ if(attribute_value == "x11")
+ gsr_info->system_info.display_server = DisplayServer::X11;
+ else if(attribute_value == "wayland")
+ gsr_info->system_info.display_server = DisplayServer::WAYLAND;
+ }
+ }
+
+ static void parse_gpu_info_line(GsrInfo *gsr_info, const std::string &line) {
+ const size_t space_index = line.find(' ');
+ if(space_index == std::string::npos)
+ return;
+
+ const std::string_view attribute_name = {line.c_str(), space_index};
+ const std::string_view attribute_value = {line.c_str() + space_index + 1, line.size() - (space_index + 1)};
+ if(attribute_name == "vendor") {
+ if(attribute_value == "amd")
+ gsr_info->gpu_info.vendor = GpuVendor::AMD;
+ else if(attribute_value == "intel")
+ gsr_info->gpu_info.vendor = GpuVendor::INTEL;
+ else if(attribute_value == "nvidia")
+ gsr_info->gpu_info.vendor = GpuVendor::NVIDIA;
+ }
+ }
+
+ static void parse_video_codecs_line(GsrInfo *gsr_info, const std::string &line) {
+ if(line == "h264")
+ gsr_info->supported_video_codecs.h264 = true;
+ else if(line == "hevc")
+ gsr_info->supported_video_codecs.hevc = true;
+ else if(line == "av1")
+ gsr_info->supported_video_codecs.av1 = true;
+ else if(line == "vp8")
+ gsr_info->supported_video_codecs.vp8 = true;
+ else if(line == "vp9")
+ gsr_info->supported_video_codecs.vp9 = true;
+ }
+
+ static GsrMonitor capture_option_line_to_monitor(const std::string &line) {
+ size_t space_index = line.find(' ');
+ if(space_index == std::string::npos)
+ return { line, {0, 0} };
+
+ mgl::vec2i size = {0, 0};
+ if(sscanf(line.c_str() + space_index + 1, "%dx%d", &size.x, &size.y) != 2)
+ size = {0, 0};
+
+ return { line.substr(0, space_index), size };
+ }
+
+ static void parse_capture_options_line(GsrInfo *gsr_info, const std::string &line) {
+ if(line == "window")
+ gsr_info->supported_capture_options.window = true;
+ else if(line == "focused")
+ gsr_info->supported_capture_options.focused = true;
+ else if(line == "screen")
+ gsr_info->supported_capture_options.screen = true;
+ else if(line == "portal")
+ gsr_info->supported_capture_options.portal = true;
+ else
+ gsr_info->supported_capture_options.monitors.push_back(capture_option_line_to_monitor(line));
+ }
+
+ enum class GsrInfoSection {
+ UNKNOWN,
+ SYSTEM_INFO,
+ GPU_INFO,
+ VIDEO_CODECS,
+ CAPTURE_OPTIONS
+ };
+
+ static bool starts_with(const std::string &str, const char *substr) {
+ size_t len = strlen(substr);
+ return str.size() >= len && memcmp(str.data(), substr, len) == 0;
+ }
+
+ GsrInfoExitStatus get_gpu_screen_recorder_info(GsrInfo *gsr_info) {
+ *gsr_info = GsrInfo{};
+
+ FILE *f = popen("gpu-screen-recorder --info", "r");
+ if(!f) {
+ fprintf(stderr, "error: 'gpu-screen-recorder --info' failed\n");
+ return GsrInfoExitStatus::FAILED_TO_RUN_COMMAND;
+ }
+
+ char output[8192];
+ ssize_t bytes_read = fread(output, 1, sizeof(output) - 1, f);
+ if(bytes_read < 0 || ferror(f)) {
+ fprintf(stderr, "error: failed to read 'gpu-screen-recorder --info' output\n");
+ pclose(f);
+ return GsrInfoExitStatus::FAILED_TO_RUN_COMMAND;
+ }
+ output[bytes_read] = '\0';
+
+ GsrInfoSection section = GsrInfoSection::UNKNOWN;
+ string_split_char(output, '\n', [&](std::string_view line) {
+ const std::string line_str(line.data(), line.size());
+
+ if(starts_with(line_str, "section=")) {
+ const char *section_name = line_str.c_str() + 8;
+ if(strcmp(section_name, "system_info") == 0)
+ section = GsrInfoSection::SYSTEM_INFO;
+ else if(strcmp(section_name, "gpu_info") == 0)
+ section = GsrInfoSection::GPU_INFO;
+ else if(strcmp(section_name, "video_codecs") == 0)
+ section = GsrInfoSection::VIDEO_CODECS;
+ else if(strcmp(section_name, "capture_options") == 0)
+ section = GsrInfoSection::CAPTURE_OPTIONS;
+ else
+ section = GsrInfoSection::UNKNOWN;
+ return true;
+ }
+
+ switch(section) {
+ case GsrInfoSection::UNKNOWN: {
+ break;
+ }
+ case GsrInfoSection::SYSTEM_INFO: {
+ parse_system_info_line(gsr_info, line_str);
+ break;
+ }
+ case GsrInfoSection::GPU_INFO: {
+ parse_gpu_info_line(gsr_info, line_str);
+ break;
+ }
+ case GsrInfoSection::VIDEO_CODECS: {
+ parse_video_codecs_line(gsr_info, line_str);
+ break;
+ }
+ case GsrInfoSection::CAPTURE_OPTIONS: {
+ parse_capture_options_line(gsr_info, line_str);
+ break;
+ }
+ }
+
+ return true;
+ });
+
+ int status = pclose(f);
+ if(WIFEXITED(status)) {
+ switch(WEXITSTATUS(status)) {
+ case 0: return GsrInfoExitStatus::OK;
+ case 22: return GsrInfoExitStatus::OPENGL_FAILED;
+ case 23: return GsrInfoExitStatus::NO_DRM_CARD;
+ default: return GsrInfoExitStatus::FAILED_TO_RUN_COMMAND;
+ }
+ }
+
+ return GsrInfoExitStatus::FAILED_TO_RUN_COMMAND;
+ }
+} \ No newline at end of file