diff options
Diffstat (limited to 'src/args_parser.c')
| -rw-r--r-- | src/args_parser.c | 354 |
1 files changed, 178 insertions, 176 deletions
diff --git a/src/args_parser.c b/src/args_parser.c index c37712a..d10da67 100644 --- a/src/args_parser.c +++ b/src/args_parser.c @@ -1,4 +1,5 @@ #include "../include/args_parser.h" +#include "../include/log.h" #include "../include/defs.h" #include "../include/egl.h" #include "../include/window/window.h" @@ -116,17 +117,18 @@ static bool arg_get_enum_value_by_name(const Arg *arg, const char *name, int *en return false; } -static void arg_print_expected_enum_names(const Arg *arg) { +static void arg_get_expected_enum_names(const Arg *arg, char *buf, size_t buf_size) { assert(arg->type == ARG_TYPE_ENUM); assert(arg->enum_values); + buf[0] = '\0'; + size_t offset = 0; for(int i = 0; i < arg->num_enum_values; ++i) { - if(i > 0) { - if(i == arg->num_enum_values -1) - fprintf(stderr, " or "); - else - fprintf(stderr, ", "); - } - fprintf(stderr, "'%s'", arg->enum_values[i].name); + const char *separator = ""; + if(i > 0) + separator = i == arg->num_enum_values - 1 ? " or " : ", "; + const int written = snprintf(buf + offset, offset < buf_size ? buf_size - offset : 0, "%s'%s'", separator, arg->enum_values[i].name); + if(written > 0) + offset += written; } } @@ -204,7 +206,7 @@ static void usage_header(void) { "[-cursor yes|no] [-keyint <value>] [-restore-portal-session yes|no] [-portal-session-token-filepath filepath] [-encoder gpu|cpu] " "[-fallback-cpu-encoding yes|no] [-o <output_file>] [-ro <output_directory>] [-ffmpeg-opts <options>] [--list-capture-options [card_path]] " "[--list-monitors] [--list-audio-devices] [--list-application-audio] [--list-v4l2-devices] [-write-first-frame-ts yes|no] [-low-power yes|no] " - "[-v yes|no] [-gl-debug yes|no] [-exclude-metadata yes|no] [--version] [-h|--help]\n", program_name); + "[-ipc <socket_path>] [-v yes|no] [-gl-debug yes|no] [-exclude-metadata yes|no] [--version] [-h|--help]\n", program_name); fflush(stdout); } @@ -251,283 +253,283 @@ static bool file_is_pipe_or_char_device(const char *filepath) { } static bool args_parser_set_values(args_parser *self) { - self->video_encoder = (gsr_video_encoder_hardware)args_get_enum_by_key(self->args, NUM_ARGS, "-encoder", GSR_VIDEO_ENCODER_HW_GPU); - self->pixel_format = (gsr_pixel_format)args_get_enum_by_key(self->args, NUM_ARGS, "-pixfmt", GSR_PIXEL_FORMAT_YUV420); - self->framerate_mode = (gsr_framerate_mode)args_get_enum_by_key(self->args, NUM_ARGS, "-fm", GSR_FRAMERATE_MODE_VARIABLE); - self->color_range = (gsr_color_range)args_get_enum_by_key(self->args, NUM_ARGS, "-cr", GSR_COLOR_RANGE_LIMITED); - self->tune = (gsr_tune)args_get_enum_by_key(self->args, NUM_ARGS, "-tune", GSR_TUNE_PERFORMANCE); - self->video_codec = (gsr_video_codec)args_get_enum_by_key(self->args, NUM_ARGS, "-k", GSR_VIDEO_CODEC_AUTO); - self->audio_codec = (gsr_audio_codec)args_get_enum_by_key(self->args, NUM_ARGS, "-ac", GSR_AUDIO_CODEC_OPUS); - self->bitrate_mode = (gsr_bitrate_mode)args_get_enum_by_key(self->args, NUM_ARGS, "-bm", GSR_BITRATE_MODE_AUTO); - self->replay_storage = (gsr_replay_storage)args_get_enum_by_key(self->args, NUM_ARGS, "-replay-storage", GSR_REPLAY_STORAGE_RAM); - - self->capture_source = args_get_value_by_key(self->args, NUM_ARGS, "-w"); - self->verbose = args_get_boolean_by_key(self->args, NUM_ARGS, "-v", true); - self->gl_debug = args_get_boolean_by_key(self->args, NUM_ARGS, "-gl-debug", false); - self->record_cursor = args_get_boolean_by_key(self->args, NUM_ARGS, "-cursor", true); - self->date_folders = args_get_boolean_by_key(self->args, NUM_ARGS, "-df", false); - self->restore_portal_session = args_get_boolean_by_key(self->args, NUM_ARGS, "-restore-portal-session", false); - self->restart_replay_on_save = args_get_boolean_by_key(self->args, NUM_ARGS, "-restart-replay-on-save", false); + self->settings.video_encoder = (gsr_video_encoder_hardware)args_get_enum_by_key(self->args, NUM_ARGS, "-encoder", GSR_VIDEO_ENCODER_HW_GPU); + self->settings.pixel_format = (gsr_pixel_format)args_get_enum_by_key(self->args, NUM_ARGS, "-pixfmt", GSR_PIXEL_FORMAT_YUV420); + self->settings.framerate_mode = (gsr_framerate_mode)args_get_enum_by_key(self->args, NUM_ARGS, "-fm", GSR_FRAMERATE_MODE_VARIABLE); + self->settings.color_range = (gsr_color_range)args_get_enum_by_key(self->args, NUM_ARGS, "-cr", GSR_COLOR_RANGE_LIMITED); + self->settings.tune = (gsr_tune)args_get_enum_by_key(self->args, NUM_ARGS, "-tune", GSR_TUNE_PERFORMANCE); + self->settings.video_codec = (gsr_video_codec)args_get_enum_by_key(self->args, NUM_ARGS, "-k", GSR_VIDEO_CODEC_AUTO); + self->settings.audio_codec = (gsr_audio_codec)args_get_enum_by_key(self->args, NUM_ARGS, "-ac", GSR_AUDIO_CODEC_OPUS); + self->settings.bitrate_mode = (gsr_bitrate_mode)args_get_enum_by_key(self->args, NUM_ARGS, "-bm", GSR_BITRATE_MODE_AUTO); + self->settings.replay_storage = (gsr_replay_storage)args_get_enum_by_key(self->args, NUM_ARGS, "-replay-storage", GSR_REPLAY_STORAGE_RAM); + + self->settings.capture_source = args_get_value_by_key(self->args, NUM_ARGS, "-w"); + self->settings.verbose = args_get_boolean_by_key(self->args, NUM_ARGS, "-v", true); + self->settings.gl_debug = args_get_boolean_by_key(self->args, NUM_ARGS, "-gl-debug", false); + self->settings.record_cursor = args_get_boolean_by_key(self->args, NUM_ARGS, "-cursor", true); + self->settings.date_folders = args_get_boolean_by_key(self->args, NUM_ARGS, "-df", false); + self->settings.restore_portal_session = args_get_boolean_by_key(self->args, NUM_ARGS, "-restore-portal-session", false); + self->settings.restart_replay_on_save = args_get_boolean_by_key(self->args, NUM_ARGS, "-restart-replay-on-save", false); const bool overclock = args_get_boolean_by_key(self->args, NUM_ARGS, "-oc", false); - self->fallback_cpu_encoding = args_get_boolean_by_key(self->args, NUM_ARGS, "-fallback-cpu-encoding", false); - self->write_first_frame_ts = args_get_boolean_by_key(self->args, NUM_ARGS, "-write-first-frame-ts", false); - self->low_power = args_get_boolean_by_key(self->args, NUM_ARGS, "-low-power", false); - self->exclude_metadata = args_get_boolean_by_key(self->args, NUM_ARGS, "-exclude-metadata", false); + self->settings.fallback_cpu_encoding = args_get_boolean_by_key(self->args, NUM_ARGS, "-fallback-cpu-encoding", false); + self->settings.write_first_frame_ts = args_get_boolean_by_key(self->args, NUM_ARGS, "-write-first-frame-ts", false); + self->settings.low_power = args_get_boolean_by_key(self->args, NUM_ARGS, "-low-power", false); + self->settings.exclude_metadata = args_get_boolean_by_key(self->args, NUM_ARGS, "-exclude-metadata", false); - self->audio_bitrate = args_get_i64_by_key(self->args, NUM_ARGS, "-ab", 0); - self->audio_bitrate *= 1000LL; + self->settings.audio_bitrate = args_get_i64_by_key(self->args, NUM_ARGS, "-ab", 0); + self->settings.audio_bitrate *= 1000LL; - self->keyint = args_get_double_by_key(self->args, NUM_ARGS, "-keyint", 2.0); + self->settings.keyint = args_get_double_by_key(self->args, NUM_ARGS, "-keyint", 2.0); if(overclock) { - fprintf(stderr, "gsr info: the overclock option (-oc) is deprecated and no longer has any effect as it's no longer needed (on GPUs that are 12 years old or younger)\n"); + gsr_log(GSR_LOG_LEVEL_INFO, "the overclock option (-oc) is deprecated and no longer has any effect as it's no longer needed (on GPUs that are 12 years old or younger)"); } - if(self->audio_codec == GSR_AUDIO_CODEC_FLAC) { - fprintf(stderr, "gsr warning: flac audio codec is temporary disabled, using opus audio codec instead\n"); - self->audio_codec = GSR_AUDIO_CODEC_OPUS; + if(self->settings.audio_codec == GSR_AUDIO_CODEC_FLAC) { + gsr_log(GSR_LOG_LEVEL_WARNING, "flac audio codec is temporary disabled, using opus audio codec instead"); + self->settings.audio_codec = GSR_AUDIO_CODEC_OPUS; } - self->portal_session_token_filepath = args_get_value_by_key(self->args, NUM_ARGS, "-portal-session-token-filepath"); - if(self->portal_session_token_filepath) { - int len = strlen(self->portal_session_token_filepath); - if(len > 0 && self->portal_session_token_filepath[len - 1] == '/') { - fprintf(stderr, "gsr error: -portal-session-token-filepath should be a path to a file but it ends with a /: %s\n", self->portal_session_token_filepath); + self->settings.portal_session_token_filepath = args_get_value_by_key(self->args, NUM_ARGS, "-portal-session-token-filepath"); + if(self->settings.portal_session_token_filepath) { + int len = strlen(self->settings.portal_session_token_filepath); + if(len > 0 && self->settings.portal_session_token_filepath[len - 1] == '/') { + gsr_log(GSR_LOG_LEVEL_ERROR, "-portal-session-token-filepath should be a path to a file but it ends with a /: %s", self->settings.portal_session_token_filepath); return false; } } - self->recording_saved_script = args_get_value_by_key(self->args, NUM_ARGS, "-sc"); - if(self->recording_saved_script) { + self->settings.recording_saved_script = args_get_value_by_key(self->args, NUM_ARGS, "-sc"); + if(self->settings.recording_saved_script) { struct stat buf; - if(stat(self->recording_saved_script, &buf) == -1 || !S_ISREG(buf.st_mode)) { - fprintf(stderr, "gsr error: Script \"%s\" either doesn't exist or it's not a file\n", self->recording_saved_script); + if(stat(self->settings.recording_saved_script, &buf) == -1 || !S_ISREG(buf.st_mode)) { + gsr_log(GSR_LOG_LEVEL_ERROR, "Script \"%s\" either doesn't exist or it's not a file", self->settings.recording_saved_script); usage(); return false; } if(!(buf.st_mode & S_IXUSR)) { - fprintf(stderr, "gsr error: Script \"%s\" is not executable\n", self->recording_saved_script); + gsr_log(GSR_LOG_LEVEL_ERROR, "Script \"%s\" is not executable", self->settings.recording_saved_script); usage(); return false; } } const char *quality_str = args_get_value_by_key(self->args, NUM_ARGS, "-q"); - self->video_quality = GSR_VIDEO_QUALITY_VERY_HIGH; - self->video_bitrate = 0; + self->settings.video_quality = GSR_VIDEO_QUALITY_VERY_HIGH; + self->settings.video_bitrate = 0; - if(self->bitrate_mode == GSR_BITRATE_MODE_CBR) { + if(self->settings.bitrate_mode == GSR_BITRATE_MODE_CBR) { if(!quality_str) { - fprintf(stderr, "gsr error: option '-q' is required when using '-bm cbr' option\n"); + gsr_log(GSR_LOG_LEVEL_ERROR, "option '-q' is required when using '-bm cbr' option"); usage(); return false; } - if(sscanf(quality_str, "%" PRIi64, &self->video_bitrate) != 1) { - fprintf(stderr, "gsr error: -q argument \"%s\" is not an integer value. When using '-bm cbr' option '-q' is expected to be an integer value\n", quality_str); + if(sscanf(quality_str, "%" PRIi64, &self->settings.video_bitrate) != 1) { + gsr_log(GSR_LOG_LEVEL_ERROR, "-q argument \"%s\" is not an integer value. When using '-bm cbr' option '-q' is expected to be an integer value", quality_str); usage(); return false; } - if(self->video_bitrate < 0) { - fprintf(stderr, "gsr error: -q is expected to be 0 or larger, got %" PRIi64 "\n", self->video_bitrate); + if(self->settings.video_bitrate < 0) { + gsr_log(GSR_LOG_LEVEL_ERROR, "-q is expected to be 0 or larger, got %" PRIi64, self->settings.video_bitrate); usage(); return false; } - self->video_bitrate *= 1000LL; + self->settings.video_bitrate *= 1000LL; } else { if(!quality_str) quality_str = "very_high"; if(strcmp(quality_str, "medium") == 0) { - self->video_quality = GSR_VIDEO_QUALITY_MEDIUM; + self->settings.video_quality = GSR_VIDEO_QUALITY_MEDIUM; } else if(strcmp(quality_str, "high") == 0) { - self->video_quality = GSR_VIDEO_QUALITY_HIGH; + self->settings.video_quality = GSR_VIDEO_QUALITY_HIGH; } else if(strcmp(quality_str, "very_high") == 0) { - self->video_quality = GSR_VIDEO_QUALITY_VERY_HIGH; + self->settings.video_quality = GSR_VIDEO_QUALITY_VERY_HIGH; } else if(strcmp(quality_str, "ultra") == 0) { - self->video_quality = GSR_VIDEO_QUALITY_ULTRA; + self->settings.video_quality = GSR_VIDEO_QUALITY_ULTRA; } else { - fprintf(stderr, "gsr error: -q should either be 'medium', 'high', 'very_high' or 'ultra', got: '%s'\n", quality_str); + gsr_log(GSR_LOG_LEVEL_ERROR, "-q should either be 'medium', 'high', 'very_high' or 'ultra', got: '%s'", quality_str); usage(); return false; } } - self->output_resolution = (vec2i){0, 0}; + self->settings.output_resolution = (vec2i){0, 0}; const char *output_resolution_str = args_get_value_by_key(self->args, NUM_ARGS, "-s"); if(output_resolution_str) { - if(sscanf(output_resolution_str, "%dx%d", &self->output_resolution.x, &self->output_resolution.y) != 2) { - fprintf(stderr, "gsr error: invalid value for option -s '%s', expected a value in format WxH\n", output_resolution_str); + if(sscanf(output_resolution_str, "%dx%d", &self->settings.output_resolution.x, &self->settings.output_resolution.y) != 2) { + gsr_log(GSR_LOG_LEVEL_ERROR, "invalid value for option -s '%s', expected a value in format WxH", output_resolution_str); usage(); return false; } - if(self->output_resolution.x < 0 || self->output_resolution.y < 0) { - fprintf(stderr, "gsr error: invalid value for option -s '%s', expected width and height to be greater or equal to 0\n", output_resolution_str); + if(self->settings.output_resolution.x < 0 || self->settings.output_resolution.y < 0) { + gsr_log(GSR_LOG_LEVEL_ERROR, "invalid value for option -s '%s', expected width and height to be greater or equal to 0", output_resolution_str); usage(); return false; } } - self->region_size = (vec2i){0, 0}; - self->region_position = (vec2i){0, 0}; + self->settings.region_size = (vec2i){0, 0}; + self->settings.region_position = (vec2i){0, 0}; const char *region_str = args_get_value_by_key(self->args, NUM_ARGS, "-region"); if(region_str) { - if(sscanf(region_str, "%dx%d+%d+%d", &self->region_size.x, &self->region_size.y, &self->region_position.x, &self->region_position.y) != 4) { - fprintf(stderr, "gsr error: invalid value for option -region '%s', expected a value in format WxH+X+Y\n", region_str); + if(sscanf(region_str, "%dx%d+%d+%d", &self->settings.region_size.x, &self->settings.region_size.y, &self->settings.region_position.x, &self->settings.region_position.y) != 4) { + gsr_log(GSR_LOG_LEVEL_ERROR, "invalid value for option -region '%s', expected a value in format WxH+X+Y", region_str); usage(); return false; } - if(self->region_size.x < 0 || self->region_size.y < 0) { - fprintf(stderr, "gsr error: invalid value for option -region '%s', expected width and height to be greater or equal to 0\n", region_str); + if(self->settings.region_size.x < 0 || self->settings.region_size.y < 0) { + gsr_log(GSR_LOG_LEVEL_ERROR, "invalid value for option -region '%s', expected width and height to be greater or equal to 0", region_str); usage(); return false; } } - self->fps = args_get_i64_by_key(self->args, NUM_ARGS, "-f", 60); - self->replay_buffer_size_secs = args_get_i64_by_key(self->args, NUM_ARGS, "-r", -1); - if(self->replay_buffer_size_secs != -1) - self->replay_buffer_size_secs += (int64_t)(self->keyint + 0.5); // Add a few seconds to account of lost packets because of non-keyframe packets skipped + self->settings.fps = args_get_i64_by_key(self->args, NUM_ARGS, "-f", 60); + self->settings.replay_buffer_size_secs = args_get_i64_by_key(self->args, NUM_ARGS, "-r", -1); + if(self->settings.replay_buffer_size_secs != -1) + self->settings.replay_buffer_size_secs += (int64_t)(self->settings.keyint + 0.5); // Add a few seconds to account of lost packets because of non-keyframe packets skipped - self->container_format = args_get_value_by_key(self->args, NUM_ARGS, "-c"); - if(self->container_format && strcmp(self->container_format, "mkv") == 0) - self->container_format = "matroska"; + self->settings.container_format = args_get_value_by_key(self->args, NUM_ARGS, "-c"); + if(self->settings.container_format && strcmp(self->settings.container_format, "mkv") == 0) + self->settings.container_format = "matroska"; - self->is_replaying = self->replay_buffer_size_secs != -1; - self->is_livestream = false; - self->filename = args_get_value_by_key(self->args, NUM_ARGS, "-o"); - if(self->filename) { - self->is_livestream = is_livestream_path(self->filename); - if(self->is_livestream) { - if(self->is_replaying) { - fprintf(stderr, "gsr error: replay mode is not applicable to live streaming\n"); + self->settings.is_replaying = self->settings.replay_buffer_size_secs != -1; + self->settings.is_livestream = false; + self->settings.filename = args_get_value_by_key(self->args, NUM_ARGS, "-o"); + if(self->settings.filename) { + self->settings.is_livestream = is_livestream_path(self->settings.filename); + if(self->settings.is_livestream) { + if(self->settings.is_replaying) { + gsr_log(GSR_LOG_LEVEL_ERROR, "replay mode is not applicable to live streaming"); return false; } } else { - if(!self->is_replaying) { + if(!self->settings.is_replaying) { char directory_buf[PATH_MAX]; - snprintf(directory_buf, sizeof(directory_buf), "%s", self->filename); + snprintf(directory_buf, sizeof(directory_buf), "%s", self->settings.filename); char *directory = dirname(directory_buf); if(strcmp(directory, ".") != 0 && strcmp(directory, "/") != 0) { if(create_directory_recursive(directory) != 0) { - fprintf(stderr, "gsr error: failed to create directory for output file: %s\n", self->filename); + gsr_log(GSR_LOG_LEVEL_ERROR, "failed to create directory for output file: %s", self->settings.filename); return false; } } } else { - if(!self->container_format) { - fprintf(stderr, "gsr error: option -c is required when using option -r\n"); + if(!self->settings.container_format) { + gsr_log(GSR_LOG_LEVEL_ERROR, "option -c is required when using option -r"); usage(); return false; } struct stat buf; - if(stat(self->filename, &buf) != -1 && !S_ISDIR(buf.st_mode)) { - fprintf(stderr, "gsr error: File \"%s\" exists but it's not a directory\n", self->filename); + if(stat(self->settings.filename, &buf) != -1 && !S_ISDIR(buf.st_mode)) { + gsr_log(GSR_LOG_LEVEL_ERROR, "File \"%s\" exists but it's not a directory", self->settings.filename); usage(); return false; } } } } else { - if(!self->is_replaying) { - self->filename = "/dev/stdout"; + if(!self->settings.is_replaying) { + self->settings.filename = "/dev/stdout"; } else { - fprintf(stderr, "gsr error: Option -o is required when using option -r\n"); + gsr_log(GSR_LOG_LEVEL_ERROR, "Option -o is required when using option -r"); usage(); return false; } - if(!self->container_format) { - fprintf(stderr, "gsr error: option -c is required when not using option -o\n"); + if(!self->settings.container_format) { + gsr_log(GSR_LOG_LEVEL_ERROR, "option -c is required when not using option -o"); usage(); return false; } } - self->is_output_piped = file_is_pipe_or_char_device(self->filename); - self->low_latency_recording = self->is_livestream || self->is_output_piped; - if(self->write_first_frame_ts && (self->is_livestream || self->is_output_piped)) { - fprintf(stderr, "gsr warning: -write-first-frame-ts is ignored for livestreaming or when output is piped\n"); - self->write_first_frame_ts = false; + self->settings.is_output_piped = file_is_pipe_or_char_device(self->settings.filename); + self->settings.low_latency_recording = self->settings.is_livestream || self->settings.is_output_piped; + if(self->settings.write_first_frame_ts && (self->settings.is_livestream || self->settings.is_output_piped)) { + gsr_log(GSR_LOG_LEVEL_WARNING, "-write-first-frame-ts is ignored for livestreaming or when output is piped"); + self->settings.write_first_frame_ts = false; } - self->replay_recording_directory = args_get_value_by_key(self->args, NUM_ARGS, "-ro"); + self->settings.replay_recording_directory = args_get_value_by_key(self->args, NUM_ARGS, "-ro"); - if(self->is_livestream && self->recording_saved_script) { - fprintf(stderr, "gsr warning: live stream detected, -sc script is ignored\n"); - self->recording_saved_script = NULL; + if(self->settings.is_livestream && self->settings.recording_saved_script) { + gsr_log(GSR_LOG_LEVEL_WARNING, "live stream detected, -sc script is ignored"); + self->settings.recording_saved_script = NULL; } - self->ffmpeg_opts = args_get_value_by_key(self->args, NUM_ARGS, "-ffmpeg-opts"); - self->ffmpeg_video_opts = args_get_value_by_key(self->args, NUM_ARGS, "-ffmpeg-video-opts"); - self->ffmpeg_audio_opts = args_get_value_by_key(self->args, NUM_ARGS, "-ffmpeg-audio-opts"); + self->settings.ffmpeg_opts = args_get_value_by_key(self->args, NUM_ARGS, "-ffmpeg-opts"); + self->settings.ffmpeg_video_opts = args_get_value_by_key(self->args, NUM_ARGS, "-ffmpeg-video-opts"); + self->settings.ffmpeg_audio_opts = args_get_value_by_key(self->args, NUM_ARGS, "-ffmpeg-audio-opts"); return true; } -bool args_parser_parse(args_parser *self, int argc, char **argv, const args_handlers *arg_handlers, void *userdata) { +args_parse_result args_parser_parse(args_parser *self, int argc, char **argv, const args_handlers *arg_handlers, void *userdata, int *command_exit_code) { assert(arg_handlers); memset(self, 0, sizeof(*self)); if(argc <= 1) { usage_full(); - return false; + return ARGS_PARSE_RESULT_ERROR; } if(argc == 2 && (strcmp(argv[1], "-h") == 0 || strcmp(argv[1], "--help") == 0)) { usage_full(); - return false; + return ARGS_PARSE_RESULT_ERROR; } if(argc == 2 && strcmp(argv[1], "--info") == 0) { - arg_handlers->info(userdata); - return true; + *command_exit_code = arg_handlers->info(userdata); + return ARGS_PARSE_RESULT_COMMAND_HANDLED; } if(argc == 2 && strcmp(argv[1], "--list-audio-devices") == 0) { - arg_handlers->list_audio_devices(userdata); - return true; + *command_exit_code = arg_handlers->list_audio_devices(userdata); + return ARGS_PARSE_RESULT_COMMAND_HANDLED; } if(argc == 2 && strcmp(argv[1], "--list-application-audio") == 0) { - arg_handlers->list_application_audio(userdata); - return true; + *command_exit_code = arg_handlers->list_application_audio(userdata); + return ARGS_PARSE_RESULT_COMMAND_HANDLED; } if(argc == 2 && strcmp(argv[1], "--list-v4l2-devices") == 0) { - arg_handlers->list_v4l2_devices(userdata); - return true; + *command_exit_code = arg_handlers->list_v4l2_devices(userdata); + return ARGS_PARSE_RESULT_COMMAND_HANDLED; } if(strcmp(argv[1], "--list-capture-options") == 0) { if(argc == 2) { - arg_handlers->list_capture_options(NULL, userdata); - return true; + *command_exit_code = arg_handlers->list_capture_options(NULL, userdata); + return ARGS_PARSE_RESULT_COMMAND_HANDLED; } else if(argc == 3 || argc == 4) { const char *card_path = argv[2]; - arg_handlers->list_capture_options(card_path, userdata); - return true; + *command_exit_code = arg_handlers->list_capture_options(card_path, userdata); + return ARGS_PARSE_RESULT_COMMAND_HANDLED; } else { - fprintf(stderr, "gsr error: expected --list-capture-options to be called with either no extra arguments or 1 extra argument (card path)\n"); - return false; + gsr_log(GSR_LOG_LEVEL_ERROR, "expected --list-capture-options to be called with either no extra arguments or 1 extra argument (card path)"); + return ARGS_PARSE_RESULT_ERROR; } } if(strcmp(argv[1], "--list-monitors") == 0) { - arg_handlers->list_monitors(userdata); - return true; + *command_exit_code = arg_handlers->list_monitors(userdata); + return ARGS_PARSE_RESULT_COMMAND_HANDLED; } if(argc == 2 && strcmp(argv[1], "--version") == 0) { - arg_handlers->version(userdata); - return true; + *command_exit_code = arg_handlers->version(userdata); + return ARGS_PARSE_RESULT_COMMAND_HANDLED; } int arg_index = 0; @@ -569,27 +571,28 @@ bool args_parser_parse(args_parser *self, int argc, char **argv, const args_hand self->args[arg_index++] = (Arg){ .key = "-write-first-frame-ts", .optional = true, .list = false, .type = ARG_TYPE_BOOLEAN }; self->args[arg_index++] = (Arg){ .key = "-low-power", .optional = true, .list = false, .type = ARG_TYPE_BOOLEAN }; self->args[arg_index++] = (Arg){ .key = "-exclude-metadata", .optional = true, .list = false, .type = ARG_TYPE_BOOLEAN }; + self->args[arg_index++] = (Arg){ .key = "-ipc", .optional = true, .list = false, .type = ARG_TYPE_STRING }; assert(arg_index == NUM_ARGS); for(int i = 1; i < argc; i += 2) { const char *arg_name = argv[i]; Arg *arg = args_get_by_key(self->args, NUM_ARGS, arg_name); if(!arg) { - fprintf(stderr, "gsr error: invalid argument '%s'\n", arg_name); + gsr_log(GSR_LOG_LEVEL_ERROR, "invalid argument '%s'", arg_name); usage(); - return false; + return ARGS_PARSE_RESULT_ERROR; } if(arg->num_values > 0 && !arg->list) { - fprintf(stderr, "gsr error: expected argument '%s' to only be specified once\n", arg_name); + gsr_log(GSR_LOG_LEVEL_ERROR, "expected argument '%s' to only be specified once", arg_name); usage(); - return false; + return ARGS_PARSE_RESULT_ERROR; } if(i + 1 >= argc) { - fprintf(stderr, "gsr error: missing value for argument '%s'\n", arg_name); + gsr_log(GSR_LOG_LEVEL_ERROR, "missing value for argument '%s'", arg_name); usage(); - return false; + return ARGS_PARSE_RESULT_ERROR; } const char *arg_value = argv[i + 1]; @@ -603,80 +606,80 @@ bool args_parser_parse(args_parser *self, int argc, char **argv, const args_hand } else if(strcmp(arg_value, "no") == 0) { arg->typed_value.boolean = false; } else { - fprintf(stderr, "gsr error: %s should either be 'yes' or 'no', got: '%s'\n", arg_name, arg_value); + gsr_log(GSR_LOG_LEVEL_ERROR, "%s should either be 'yes' or 'no', got: '%s'", arg_name, arg_value); usage(); - return false; + return ARGS_PARSE_RESULT_ERROR; } break; } case ARG_TYPE_ENUM: { if(!arg_get_enum_value_by_name(arg, arg_value, &arg->typed_value.enum_value)) { - fprintf(stderr, "gsr error: %s should either be ", arg_name); - arg_print_expected_enum_names(arg); - fprintf(stderr, ", got: '%s'\n", arg_value); + char expected_enum_names[512]; + arg_get_expected_enum_names(arg, expected_enum_names, sizeof(expected_enum_names)); + gsr_log(GSR_LOG_LEVEL_ERROR, "%s should either be %s, got: '%s'", arg_name, expected_enum_names, arg_value); usage(); - return false; + return ARGS_PARSE_RESULT_ERROR; } break; } case ARG_TYPE_I64: { if(sscanf(arg_value, "%" PRIi64, &arg->typed_value.i64_value) != 1) { - fprintf(stderr, "gsr error: %s argument \"%s\" is not an integer\n", arg_name, arg_value); + gsr_log(GSR_LOG_LEVEL_ERROR, "%s argument \"%s\" is not an integer", arg_name, arg_value); usage(); - return false; + return ARGS_PARSE_RESULT_ERROR; } if(arg->typed_value.i64_value < arg->integer_value_min) { - fprintf(stderr, "gsr error: %s argument is expected to be larger than %" PRIi64 ", got %" PRIi64 "\n", arg_name, arg->integer_value_min, arg->typed_value.i64_value); + gsr_log(GSR_LOG_LEVEL_ERROR, "%s argument is expected to be larger than %" PRIi64 ", got %" PRIi64, arg_name, arg->integer_value_min, arg->typed_value.i64_value); usage(); - return false; + return ARGS_PARSE_RESULT_ERROR; } if(arg->typed_value.i64_value > arg->integer_value_max) { - fprintf(stderr, "gsr error: %s argument is expected to be less than %" PRIi64 ", got %" PRIi64 "\n", arg_name, arg->integer_value_max, arg->typed_value.i64_value); + gsr_log(GSR_LOG_LEVEL_ERROR, "%s argument is expected to be less than %" PRIi64 ", got %" PRIi64, arg_name, arg->integer_value_max, arg->typed_value.i64_value); usage(); - return false; + return ARGS_PARSE_RESULT_ERROR; } break; } case ARG_TYPE_DOUBLE: { if(sscanf(arg_value, "%lf", &arg->typed_value.d_value) != 1) { - fprintf(stderr, "gsr error: %s argument \"%s\" is not an floating-point number\n", arg_name, arg_value); + gsr_log(GSR_LOG_LEVEL_ERROR, "%s argument \"%s\" is not an floating-point number", arg_name, arg_value); usage(); - return false; + return ARGS_PARSE_RESULT_ERROR; } if(arg->typed_value.d_value < arg->integer_value_min) { - fprintf(stderr, "gsr error: %s argument is expected to be larger than %" PRIi64 ", got %lf\n", arg_name, arg->integer_value_min, arg->typed_value.d_value); + gsr_log(GSR_LOG_LEVEL_ERROR, "%s argument is expected to be larger than %" PRIi64 ", got %lf", arg_name, arg->integer_value_min, arg->typed_value.d_value); usage(); - return false; + return ARGS_PARSE_RESULT_ERROR; } if(arg->typed_value.d_value > arg->integer_value_max) { - fprintf(stderr, "gsr error: %s argument is expected to be less than %" PRIi64 ", got %lf\n", arg_name, arg->integer_value_max, arg->typed_value.d_value); + gsr_log(GSR_LOG_LEVEL_ERROR, "%s argument is expected to be less than %" PRIi64 ", got %lf", arg_name, arg->integer_value_max, arg->typed_value.d_value); usage(); - return false; + return ARGS_PARSE_RESULT_ERROR; } break; } } if(!arg_append_value(arg, arg_value)) { - fprintf(stderr, "gsr error: failed to append argument, out of memory\n"); - return false; + gsr_log(GSR_LOG_LEVEL_ERROR, "failed to append argument, out of memory"); + return ARGS_PARSE_RESULT_ERROR; } } for(int i = 0; i < NUM_ARGS; ++i) { const Arg *arg = &self->args[i]; if(!arg->optional && arg->num_values == 0) { - fprintf(stderr, "gsr error: missing argument '%s'\n", arg->key); + gsr_log(GSR_LOG_LEVEL_ERROR, "missing argument '%s'", arg->key); usage(); - return false; + return ARGS_PARSE_RESULT_ERROR; } } - return args_parser_set_values(self); + return args_parser_set_values(self) ? ARGS_PARSE_RESULT_OK : ARGS_PARSE_RESULT_ERROR; } void args_parser_deinit(args_parser *self) { @@ -688,34 +691,33 @@ void args_parser_deinit(args_parser *self) { bool args_parser_validate_with_gl_info(args_parser *self, gsr_egl *egl) { const bool wayland = gsr_window_get_display_server(egl->window) == GSR_DISPLAY_SERVER_WAYLAND; - if(self->bitrate_mode == (gsr_bitrate_mode)GSR_BITRATE_MODE_AUTO) { + if(self->settings.bitrate_mode == (gsr_bitrate_mode)GSR_BITRATE_MODE_AUTO) { // QP is broken on steam deck, see https://github.com/ValveSoftware/SteamOS/issues/1609 - self->bitrate_mode = egl->gpu_info.is_steam_deck ? GSR_BITRATE_MODE_VBR : GSR_BITRATE_MODE_QP; + self->settings.bitrate_mode = egl->gpu_info.is_steam_deck ? GSR_BITRATE_MODE_VBR : GSR_BITRATE_MODE_QP; } - if(egl->gpu_info.is_steam_deck && self->bitrate_mode == GSR_BITRATE_MODE_QP) { - fprintf(stderr, "gsr warning: qp bitrate mode is not supported on Steam Deck because of Steam Deck driver bugs. Using vbr instead\n"); - self->bitrate_mode = GSR_BITRATE_MODE_VBR; + if(egl->gpu_info.is_steam_deck && self->settings.bitrate_mode == GSR_BITRATE_MODE_QP) { + gsr_log(GSR_LOG_LEVEL_WARNING, "qp bitrate mode is not supported on Steam Deck because of Steam Deck driver bugs. Using vbr instead"); + self->settings.bitrate_mode = GSR_BITRATE_MODE_VBR; } - if(self->video_encoder == GSR_VIDEO_ENCODER_HW_CPU && self->bitrate_mode == GSR_BITRATE_MODE_VBR) { - fprintf(stderr, "gsr warning: bitrate mode has been forcefully set to qp because software encoding option doesn't support vbr option\n"); - self->bitrate_mode = GSR_BITRATE_MODE_QP; + if(self->settings.video_encoder == GSR_VIDEO_ENCODER_HW_CPU && self->settings.bitrate_mode == GSR_BITRATE_MODE_VBR) { + gsr_log(GSR_LOG_LEVEL_WARNING, "bitrate mode has been forcefully set to qp because software encoding option doesn't support vbr option"); + self->settings.bitrate_mode = GSR_BITRATE_MODE_QP; } if(egl->gpu_info.is_steam_deck) { - fprintf(stderr, "gsr warning: steam deck has multiple driver issues. One of them has been reported here: https://github.com/ValveSoftware/SteamOS/issues/1609\n" - "If you have issues with GPU Screen Recorder on steam deck that you don't have on a desktop computer then report the issue to Valve and/or AMD.\n"); + gsr_log(GSR_LOG_LEVEL_WARNING, "steam deck has multiple driver issues. One of them has been reported here: https://github.com/ValveSoftware/SteamOS/issues/1609\nIf you have issues with GPU Screen Recorder on steam deck that you don't have on a desktop computer then report the issue to Valve and/or AMD."); } - self->very_old_gpu = false; + self->settings.very_old_gpu = false; if(egl->gpu_info.vendor == GSR_GPU_VENDOR_NVIDIA && egl->gpu_info.gpu_version != 0 && egl->gpu_info.gpu_version < 900) { - fprintf(stderr, "gsr info: your gpu appears to be very old (older than maxwell architecture). Switching to lower preset\n"); - self->very_old_gpu = true; + gsr_log(GSR_LOG_LEVEL_INFO, "your gpu appears to be very old (older than maxwell architecture). Switching to lower preset"); + self->settings.very_old_gpu = true; } - if(video_codec_is_hdr(self->video_codec) && !wayland) { - fprintf(stderr, "gsr error: hdr video codec option %s is not available on X11\n", video_codec_to_string(self->video_codec)); + if(video_codec_is_hdr(self->settings.video_codec) && !wayland) { + gsr_log(GSR_LOG_LEVEL_ERROR, "hdr video codec option %s is not available on X11", video_codec_to_string(self->settings.video_codec)); usage(); return false; } |
