diff options
| author | dec05eba <dec05eba@protonmail.com> | 2026-08-02 00:04:45 +0200 |
|---|---|---|
| committer | dec05eba <dec05eba@protonmail.com> | 2026-08-02 00:04:45 +0200 |
| commit | 06be2c8a12cd021083670d304a72f93907c8b22e (patch) | |
| tree | 53b69ef77c54ac46e269acb26a51b5f582cc8803 /src | |
| parent | 68d5c511d105650c9d0a5e920f77b0f19fabbfe0 (diff) | |
Add resource cleanup on all paths
The recorder, screenshot and cli now free everything they create, also
when setup fails. Adds gsr_windowing_deinit, implements the missing
gsr_window_destroy and destroys the pipewire registry proxy.
Diffstat (limited to 'src')
| -rw-r--r-- | src/cli/commands.c | 40 | ||||
| -rw-r--r-- | src/cli/main.c | 200 | ||||
| -rw-r--r-- | src/pipewire_audio.c | 5 | ||||
| -rw-r--r-- | src/recorder/recorder.c | 140 | ||||
| -rw-r--r-- | src/recorder/screenshot.c | 18 | ||||
| -rw-r--r-- | src/recorder/windowing.c | 18 | ||||
| -rw-r--r-- | src/window/window.c | 5 |
7 files changed, 236 insertions, 190 deletions
diff --git a/src/cli/commands.c b/src/cli/commands.c index 38342ec..12de13b 100644 --- a/src/cli/commands.c +++ b/src/cli/commands.c @@ -238,8 +238,12 @@ int info_command(void *userdata) { const gsr_windowing_params windowing_params = {false, false, false}; if(gsr_windowing_init(&windowing, &windowing_params) != GSR_ERROR_OK) return 1; - if(gsr_windowing_load_egl(&windowing, &windowing_params) != GSR_ERROR_OK) + + if(gsr_windowing_load_egl(&windowing, &windowing_params) != GSR_ERROR_OK) { + gsr_windowing_deinit(&windowing); return 22; + } + const bool wayland = gsr_windowing_is_wayland(&windowing); av_log_set_level(AV_LOG_FATAL); @@ -262,13 +266,7 @@ int info_command(void *userdata) { list_supported_capture_options(windowing.window, windowing.egl.card_path, windowing.card_path_found); fflush(stdout); - - // Not needed as this will just slow down shutdown - //gsr_egl_unload(&egl); - //gsr_window_destroy(&window); - //if(dpy) - // XCloseDisplay(dpy); - + gsr_windowing_deinit(&windowing); return 0; } @@ -328,8 +326,11 @@ int list_capture_options_command(const char *card_path, void *userdata) { const gsr_windowing_params windowing_params = {false, false, false}; if(gsr_windowing_init(&windowing, &windowing_params) != GSR_ERROR_OK) return 1; - if(!card_path && gsr_windowing_load_egl(&windowing, &windowing_params) != GSR_ERROR_OK) + + if(!card_path && gsr_windowing_load_egl(&windowing, &windowing_params) != GSR_ERROR_OK) { + gsr_windowing_deinit(&windowing); return 22; + } if(card_path) list_supported_capture_options(windowing.window, card_path, true); @@ -337,13 +338,7 @@ int list_capture_options_command(const char *card_path, void *userdata) { list_supported_capture_options(windowing.window, windowing.egl.card_path, windowing.card_path_found); fflush(stdout); - - // Not needed as this will just slow down shutdown - //gsr_egl_unload(&egl); - //gsr_window_destroy(&window); - //if(dpy) - // XCloseDisplay(dpy); - + gsr_windowing_deinit(&windowing); return 0; } @@ -353,19 +348,16 @@ int list_monitors_command(void *userdata) { const gsr_windowing_params windowing_params = {false, false, false}; if(gsr_windowing_init(&windowing, &windowing_params) != GSR_ERROR_OK) return 1; - if(gsr_windowing_load_egl(&windowing, &windowing_params) != GSR_ERROR_OK) + + if(gsr_windowing_load_egl(&windowing, &windowing_params) != GSR_ERROR_OK) { + gsr_windowing_deinit(&windowing); return 22; + } if(windowing.card_path_found) list_monitors(windowing.window, windowing.egl.card_path); fflush(stdout); - - // Not needed as this will just slow down shutdown - //gsr_egl_unload(&egl); - //gsr_window_destroy(&window); - //if(dpy) - // XCloseDisplay(dpy); - + gsr_windowing_deinit(&windowing); return 0; } diff --git a/src/cli/main.c b/src/cli/main.c index 563ab19..9d5f7e2 100644 --- a/src/cli/main.c +++ b/src/cli/main.c @@ -405,99 +405,75 @@ static int record(args_parser *arg_parser, gsr_windowing *windowing, gsr_capture return run_result; } -int main(int argc, char **argv) { - setlocale(LC_ALL, "C"); /* Sigh... stupid C */ -#ifdef __GLIBC__ - mallopt(M_MMAP_THRESHOLD, 65536); -#endif - - install_signal_handlers(); - set_environment_variables(); - install_cuda_no_stable_perf_limit(); - - if(geteuid() == 0) { - gsr_log(GSR_LOG_LEVEL_ERROR, "don't run gpu-screen-recorder as the root user"); - _exit(1); - } - - args_handlers arg_handlers; - arg_handlers.version = version_command; - arg_handlers.info = info_command; - arg_handlers.list_audio_devices = list_audio_devices_command; - arg_handlers.list_application_audio = list_application_audio_command; - arg_handlers.list_v4l2_devices = list_v4l2_devices; - arg_handlers.list_capture_options = list_capture_options_command; - arg_handlers.list_monitors = list_monitors_command; +static int run(args_parser *arg_parser) { + int exit_code = 0; - args_parser arg_parser; - int command_exit_code = 0; - switch(args_parser_parse(&arg_parser, argc, argv, &arg_handlers, NULL, &command_exit_code)) { - case ARGS_PARSE_RESULT_ERROR: - _exit(1); - case ARGS_PARSE_RESULT_COMMAND_HANDLED: - _exit(command_exit_code); - case ARGS_PARSE_RESULT_OK: - break; - } + gsr_capture_sources capture_sources; + gsr_audio_input_tracks audio_input_tracks; + gsr_app_audio_names app_audio_names; + gsr_windowing windowing; + gsr_capture_deps capture_deps; + memset(&audio_input_tracks, 0, sizeof(audio_input_tracks)); + memset(&app_audio_names, 0, sizeof(app_audio_names)); + memset(&windowing, 0, sizeof(windowing)); + gsr_capture_deps_init(&capture_deps); - if(!arg_parser.settings.low_power) { - /* Forces low latency encoding mode. Use this environment variable until vaapi supports setting this as a parameter. - The downside of this is that it always uses maximum power, which is not ideal for replay mode that runs on system startup. - This option was added in mesa 24.1.4, released in july 17, 2024. - Seems like the performance issue is not in encoding, but rendering the frame. - Some frames end up taking 10 times longer. Seems to be an issue with amd gpu power management when letting the application sleep on the cpu side? */ - setenv("AMD_DEBUG", "lowlatencyenc", true); + const int parse_capture_sources_result = gsr_capture_sources_parse(&capture_sources, arg_parser->settings.capture_source, arg_parser->settings.region_position, arg_parser->settings.region_size); + if(parse_capture_sources_result != GSR_ERROR_OK) { + exit_code = gsr_error_to_exit_code(parse_capture_sources_result); + goto done; } - gsr_capture_sources capture_sources; - const int parse_capture_sources_result = gsr_capture_sources_parse(&capture_sources, arg_parser.settings.capture_source, arg_parser.settings.region_position, arg_parser.settings.region_size); - if(parse_capture_sources_result != GSR_ERROR_OK) - _exit(gsr_error_to_exit_code(parse_capture_sources_result)); - if(capture_sources.num_items == 0) { gsr_log(GSR_LOG_LEVEL_ERROR, "option -w can't be empty. You need to capture video from at least one source"); args_parser_print_usage(); - _exit(1); + exit_code = 1; + goto done; } - const int validate_args_result = validate_args_with_capture_sources(&arg_parser, &capture_sources); - if(validate_args_result != GSR_ERROR_OK) - _exit(gsr_error_to_exit_code(validate_args_result)); + const int validate_args_result = validate_args_with_capture_sources(arg_parser, &capture_sources); + if(validate_args_result != GSR_ERROR_OK) { + exit_code = gsr_error_to_exit_code(validate_args_result); + goto done; + } - gsr_audio_input_tracks audio_input_tracks; - const int parse_audio_inputs_result = parse_audio_inputs(&arg_parser, &audio_input_tracks); - if(parse_audio_inputs_result != GSR_ERROR_OK) - _exit(gsr_error_to_exit_code(parse_audio_inputs_result)); + const int parse_audio_inputs_result = parse_audio_inputs(arg_parser, &audio_input_tracks); + if(parse_audio_inputs_result != GSR_ERROR_OK) { + exit_code = gsr_error_to_exit_code(parse_audio_inputs_result); + goto done; + } const bool uses_app_audio = gsr_audio_input_tracks_has_app_audio(&audio_input_tracks); - gsr_app_audio_names app_audio_names; - memset(&app_audio_names, 0, sizeof(app_audio_names)); - #ifdef GSR_APP_AUDIO if(uses_app_audio) { const int app_audio_result = setup_app_audio(&app_audio_names); - if(app_audio_result != GSR_ERROR_OK) - _exit(gsr_error_to_exit_code(app_audio_result)); + if(app_audio_result != GSR_ERROR_OK) { + exit_code = gsr_error_to_exit_code(app_audio_result); + goto done; + } } #else if(uses_app_audio) { gsr_log(GSR_LOG_LEVEL_ERROR, "application audio can't be recorded because GPU Screen Recorder is built without application audio support (-Dapp_audio option)"); - _exit(2); + exit_code = 2; + goto done; } #endif const int validate_app_audio_result = gsr_audio_input_tracks_validate_app_audio(&audio_input_tracks, &app_audio_names); - gsr_app_audio_names_deinit(&app_audio_names); - if(validate_app_audio_result != GSR_ERROR_OK) - _exit(gsr_error_to_exit_code(validate_app_audio_result)); + if(validate_app_audio_result != GSR_ERROR_OK) { + exit_code = gsr_error_to_exit_code(validate_app_audio_result); + goto done; + } - gsr_windowing windowing; gsr_windowing_params windowing_params; windowing_params.monitor_capture = gsr_capture_sources_has_monitor_or_region(&capture_sources); - windowing_params.gl_debug = arg_parser.settings.gl_debug; + windowing_params.gl_debug = arg_parser->settings.gl_debug; windowing_params.listen_to_x11_events = true; - if(gsr_windowing_init(&windowing, &windowing_params) != GSR_ERROR_OK) - _exit(1); + if(gsr_windowing_init(&windowing, &windowing_params) != GSR_ERROR_OK) { + exit_code = 1; + goto done; + } if(gsr_capture_sources_has_type(&capture_sources, GSR_CAPTURE_SOURCE_TYPE_PORTAL)) { if(gsr_windowing_is_using_prime_run()) { @@ -505,56 +481,114 @@ int main(int argc, char **argv) { gsr_windowing_disable_prime_run(); } - if(video_codec_is_hdr(arg_parser.settings.video_codec)) { + if(video_codec_is_hdr(arg_parser->settings.video_codec)) { gsr_log(GSR_LOG_LEVEL_WARNING, "portal capture option doesn't support hdr yet (PipeWire doesn't support hdr), the video will be tonemapped from hdr to sdr"); - arg_parser.settings.video_codec = hdr_video_codec_to_sdr_video_codec(arg_parser.settings.video_codec); + arg_parser->settings.video_codec = hdr_video_codec_to_sdr_video_codec(arg_parser->settings.video_codec); } } - if(gsr_windowing_load_egl(&windowing, &windowing_params) != GSR_ERROR_OK) - _exit(1); + if(gsr_windowing_load_egl(&windowing, &windowing_params) != GSR_ERROR_OK) { + exit_code = 1; + goto done; + } - gsr_shader_enable_debug_output(arg_parser.settings.gl_debug); + gsr_shader_enable_debug_output(arg_parser->settings.gl_debug); #ifndef NDEBUG gsr_shader_enable_debug_output(true); #endif - if(!args_parser_validate_with_gl_info(&arg_parser, &windowing.egl)) - _exit(1); + if(!args_parser_validate_with_gl_info(arg_parser, &windowing.egl)) { + exit_code = 1; + goto done; + } if(!windowing.card_path_found) { gsr_log(GSR_LOG_LEVEL_ERROR, "no /dev/dri/cardX device found. Make sure that you have at least one monitor connected or record a single window instead on X11 or record with the -w portal option"); - _exit(2); + exit_code = 2; + goto done; } - gsr_capture_deps capture_deps; - gsr_capture_deps_init(&capture_deps); - gsr_capture_deps_init_cursor(&capture_deps, &windowing.egl, arg_parser.settings.record_cursor); + gsr_capture_deps_init_cursor(&capture_deps, &windowing.egl, arg_parser->settings.record_cursor); - int result = GSR_ERROR_OK; gsr_image_format image_format; - if(get_image_format_from_filename(arg_parser.settings.filename, &image_format)) { + if(get_image_format_from_filename(arg_parser->settings.filename, &image_format)) { if(audio_input_tracks.num_items > 0) { gsr_log(GSR_LOG_LEVEL_ERROR, "can't record audio (-a) when taking a screenshot"); - _exit(1); + exit_code = 1; + goto done; } - result = take_screenshot(&arg_parser, &windowing, &capture_deps, &capture_sources, image_format); + exit_code = gsr_error_to_exit_code(take_screenshot(arg_parser, &windowing, &capture_deps, &capture_sources, image_format)); } else { - result = record(&arg_parser, &windowing, &capture_deps, &capture_sources, &audio_input_tracks); + exit_code = gsr_error_to_exit_code(record(arg_parser, &windowing, &capture_deps, &capture_sources, &audio_input_tracks)); } + done: gsr_capture_deps_deinit(&capture_deps); + gsr_windowing_deinit(&windowing); #ifdef GSR_APP_AUDIO gsr_pipewire_audio_deinit(&pipewire_audio); #endif + gsr_app_audio_names_deinit(&app_audio_names); gsr_audio_input_tracks_deinit(&audio_input_tracks); gsr_capture_sources_deinit(&capture_sources); + return exit_code; +} + +int main(int argc, char **argv) { + setlocale(LC_ALL, "C"); /* Sigh... stupid C */ +#ifdef __GLIBC__ + mallopt(M_MMAP_THRESHOLD, 65536); +#endif + + install_signal_handlers(); + set_environment_variables(); + install_cuda_no_stable_perf_limit(); + + if(geteuid() == 0) { + gsr_log(GSR_LOG_LEVEL_ERROR, "don't run gpu-screen-recorder as the root user"); + _exit(1); + } + + args_handlers arg_handlers; + arg_handlers.version = version_command; + arg_handlers.info = info_command; + arg_handlers.list_audio_devices = list_audio_devices_command; + arg_handlers.list_application_audio = list_application_audio_command; + arg_handlers.list_v4l2_devices = list_v4l2_devices; + arg_handlers.list_capture_options = list_capture_options_command; + arg_handlers.list_monitors = list_monitors_command; + + args_parser arg_parser; + int exit_code = 0; + int command_exit_code = 0; + switch(args_parser_parse(&arg_parser, argc, argv, &arg_handlers, NULL, &command_exit_code)) { + case ARGS_PARSE_RESULT_ERROR: + exit_code = 1; + break; + case ARGS_PARSE_RESULT_COMMAND_HANDLED: + exit_code = command_exit_code; + break; + case ARGS_PARSE_RESULT_OK: { + if(!arg_parser.settings.low_power) { + /* Forces low latency encoding mode. Use this environment variable until vaapi supports setting this as a parameter. + The downside of this is that it always uses maximum power, which is not ideal for replay mode that runs on system startup. + This option was added in mesa 24.1.4, released in july 17, 2024. + Seems like the performance issue is not in encoding, but rendering the frame. + Some frames end up taking 10 times longer. Seems to be an issue with amd gpu power management when letting the application sleep on the cpu side? */ + setenv("AMD_DEBUG", "lowlatencyenc", true); + } + + exit_code = run(&arg_parser); + break; + } + } + args_parser_deinit(&arg_parser); /* 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 the at_exit registered functions. Cuda (nvenc) is loaded in a separate process, but this still happens. */ - _exit(gsr_error_to_exit_code(result)); + _exit(exit_code); } diff --git a/src/pipewire_audio.c b/src/pipewire_audio.c index 73192a9..8f40695 100644 --- a/src/pipewire_audio.c +++ b/src/pipewire_audio.c @@ -797,6 +797,11 @@ void gsr_pipewire_audio_deinit(gsr_pipewire_audio *self) { spa_hook_remove(&self->registry_listener); spa_hook_remove(&self->core_listener); + if(self->registry) { + pw_proxy_destroy((struct pw_proxy*)self->registry); + self->registry = NULL; + } + if(self->core) { pw_core_disconnect(self->core); self->core = NULL; diff --git a/src/recorder/recorder.c b/src/recorder/recorder.c index 7ace350..2fc62d5 100644 --- a/src/recorder/recorder.c +++ b/src/recorder/recorder.c @@ -273,106 +273,97 @@ static int recorder_setup_video_encoder(gsr_recorder *self) { return GSR_ERROR_OK; } -static int recorder_setup_audio(gsr_recorder *self) { - if(gsr_audio_capture_init(&self->audio_capture, &self->encoder, self->recording_clock, &self->running) != GSR_ERROR_OK) { +static int recorder_setup_audio_track(gsr_recorder *self, const gsr_merged_audio_inputs *merged_audio_inputs, int audio_stream_index, gsr_audio_track *audio_track) { + const bool use_amix = gsr_audio_inputs_should_use_amix(merged_audio_inputs); + + memset(audio_track, 0, sizeof(*audio_track)); + audio_track->stream_index = audio_stream_index; + audio_track->codec_context = create_audio_codec_context(self->settings.fps, self->settings.audio_codec, use_amix, self->settings.audio_bitrate); + if(!audio_track->codec_context) return GSR_ERROR_GENERIC; + AVStream *audio_stream = NULL; + if(!self->settings.is_replaying) { + audio_stream = create_stream(self->av_format_context, audio_track->codec_context); + if(!audio_stream) + return GSR_ERROR_GENERIC; + + if(gsr_encoder_add_recording_destination(&self->encoder, audio_track->codec_context, self->av_format_context, audio_stream, 0) == (size_t)-1) + gsr_log(GSR_LOG_LEVEL_ERROR, "added too many audio sources"); } - - int audio_stream_index = GSR_VIDEO_STREAM_INDEX + 1; - for(size_t audio_track_index = 0; audio_track_index < self->audio_input_tracks->num_items; ++audio_track_index) { - const gsr_merged_audio_inputs *merged_audio_inputs = &self->audio_input_tracks->items[audio_track_index]; - const bool use_amix = gsr_audio_inputs_should_use_amix(merged_audio_inputs); - AVCodecContext *audio_codec_context = create_audio_codec_context(self->settings.fps, self->settings.audio_codec, use_amix, self->settings.audio_bitrate); - if(!audio_codec_context) { - return GSR_ERROR_GENERIC; - } + snprintf(audio_track->name, sizeof(audio_track->name), "%s", merged_audio_inputs->track_name); + if(audio_stream && audio_track->name[0] != '\0' && !self->settings.exclude_metadata) + av_dict_set(&audio_stream->metadata, "title", audio_track->name, 0); - AVStream *audio_stream = NULL; - if(!self->settings.is_replaying) { - audio_stream = create_stream(self->av_format_context, audio_codec_context); - if(gsr_encoder_add_recording_destination(&self->encoder, audio_codec_context, self->av_format_context, audio_stream, 0) == (size_t)-1) - gsr_log(GSR_LOG_LEVEL_ERROR, "added too many audio sources"); - } + if(!open_audio(audio_track->codec_context, self->settings.ffmpeg_audio_opts)) + return GSR_ERROR_GENERIC; - if(audio_stream && merged_audio_inputs->track_name[0] != '\0' && !self->settings.exclude_metadata) - av_dict_set(&audio_stream->metadata, "title", merged_audio_inputs->track_name, 0); + if(audio_stream) + avcodec_parameters_from_context(audio_stream->codecpar, audio_track->codec_context); - if(!open_audio(audio_codec_context, self->settings.ffmpeg_audio_opts)) { - return GSR_ERROR_GENERIC; + #if LIBAVCODEC_VERSION_MAJOR < 60 + const int num_channels = audio_track->codec_context->channels; + #else + const int num_channels = audio_track->codec_context->ch_layout.nb_channels; + #endif + AVFilterContext *src_filter_ctx[GSR_MAX_AUDIO_SOURCES_PER_TRACK]; + if(use_amix) { + if(merged_audio_inputs->num_items > GSR_MAX_AUDIO_SOURCES_PER_TRACK) { + gsr_log(GSR_LOG_LEVEL_ERROR, "too many audio sources for one audio track, the maximum is %d", GSR_MAX_AUDIO_SOURCES_PER_TRACK); + return GSR_ERROR_GENERIC; } - if(audio_stream) - avcodec_parameters_from_context(audio_stream->codecpar, audio_codec_context); - - #if LIBAVCODEC_VERSION_MAJOR < 60 - const int num_channels = audio_codec_context->channels; - #else - const int num_channels = audio_codec_context->ch_layout.nb_channels; - #endif - - //audio_frame->sample_rate = audio_codec_context->sample_rate; - - AVFilterContext *src_filter_ctx[GSR_MAX_AUDIO_SOURCES_PER_TRACK]; - AVFilterGraph *graph = NULL; - AVFilterContext *sink = NULL; - if(use_amix) { - if(merged_audio_inputs->num_items > GSR_MAX_AUDIO_SOURCES_PER_TRACK) { - gsr_log(GSR_LOG_LEVEL_ERROR, "too many audio sources for one audio track, the maximum is %d", GSR_MAX_AUDIO_SOURCES_PER_TRACK); - return GSR_ERROR_GENERIC; - } - if(gsr_audio_init_filter_graph(audio_codec_context, &graph, &sink, src_filter_ctx, merged_audio_inputs->num_items) < 0) { - gsr_log(GSR_LOG_LEVEL_ERROR, "failed to create audio filter"); - return GSR_ERROR_GENERIC; - } + if(gsr_audio_init_filter_graph(audio_track->codec_context, &audio_track->graph, &audio_track->sink, src_filter_ctx, merged_audio_inputs->num_items) < 0) { + gsr_log(GSR_LOG_LEVEL_ERROR, "failed to create audio filter"); + return GSR_ERROR_GENERIC; } + } - // TODO: Cleanup above - - const double audio_fps = (double)audio_codec_context->sample_rate / (double)audio_codec_context->frame_size; - const double timeout_sec = 1000.0 / audio_fps / 1000.0; + const double audio_fps = (double)audio_track->codec_context->sample_rate / (double)audio_track->codec_context->frame_size; + const double timeout_sec = 1000.0 / audio_fps / 1000.0; - const double audio_startup_time_seconds = self->force_no_audio_offset ? 0 : audio_codec_get_desired_delay(self->settings.audio_codec, self->settings.fps);// * ((double)audio_codec_context->frame_size / 1024.0); - const double num_audio_frames_shift = audio_startup_time_seconds / timeout_sec; + const double audio_startup_time_seconds = self->force_no_audio_offset ? 0 : audio_codec_get_desired_delay(self->settings.audio_codec, self->settings.fps); + const double num_audio_frames_shift = audio_startup_time_seconds / timeout_sec; + audio_track->pts = -audio_track->codec_context->frame_size * num_audio_frames_shift; - gsr_audio_track audio_track; - memset(&audio_track, 0, sizeof(audio_track)); - snprintf(audio_track.name, sizeof(audio_track.name), "%s", merged_audio_inputs->track_name); - audio_track.codec_context = audio_codec_context; - audio_track.graph = graph; - audio_track.sink = sink; - audio_track.stream_index = audio_stream_index; - audio_track.pts = -audio_codec_context->frame_size * num_audio_frames_shift; - - int audio_track_result = GSR_ERROR_OK; - if(gsr_audio_inputs_has_app_audio(merged_audio_inputs)) { - assert(!use_amix); + if(gsr_audio_inputs_has_app_audio(merged_audio_inputs)) { + assert(!use_amix); #ifdef GSR_APP_AUDIO - audio_track_result = gsr_audio_track_init_application_input(&audio_track, merged_audio_inputs, audio_codec_context, num_channels, num_audio_frames_shift, self->pipewire_audio); + return gsr_audio_track_init_application_input(audio_track, merged_audio_inputs, audio_track->codec_context, num_channels, num_audio_frames_shift, self->pipewire_audio); +#else + return GSR_ERROR_UNSUPPORTED; #endif - } else { - audio_track_result = gsr_audio_track_init_device_inputs(&audio_track, merged_audio_inputs, audio_codec_context, num_channels, num_audio_frames_shift, src_filter_ctx, use_amix); - } + } + + return gsr_audio_track_init_device_inputs(audio_track, merged_audio_inputs, audio_track->codec_context, num_channels, num_audio_frames_shift, src_filter_ctx, use_amix); +} + +static int recorder_setup_audio(gsr_recorder *self) { + if(gsr_audio_capture_init(&self->audio_capture, &self->encoder, self->recording_clock, &self->running) != GSR_ERROR_OK) + return GSR_ERROR_GENERIC; + int audio_stream_index = GSR_VIDEO_STREAM_INDEX + 1; + for(size_t i = 0; i < self->audio_input_tracks->num_items; ++i) { + gsr_audio_track audio_track; + const int audio_track_result = recorder_setup_audio_track(self, &self->audio_input_tracks->items[i], audio_stream_index, &audio_track); if(audio_track_result != GSR_ERROR_OK) { + gsr_audio_track_deinit(&audio_track); return audio_track_result; - } if(!gsr_audio_capture_add_track(&self->audio_capture, &audio_track)) { + gsr_audio_track_deinit(&audio_track); return GSR_ERROR_GENERIC; - } + ++audio_stream_index; - if(audio_codec_context->frame_size > self->audio_max_frame_size) - self->audio_max_frame_size = audio_codec_context->frame_size; + if(audio_track.codec_context->frame_size > self->audio_max_frame_size) + self->audio_max_frame_size = audio_track.codec_context->frame_size; } - //av_dump_format(self->av_format_context, 0, filename, 1); - return GSR_ERROR_OK; } @@ -768,8 +759,11 @@ int gsr_recorder_run(gsr_recorder *self) { gsr_recording_clock_start(self->recording_clock); self->record_start_time = gsr_recording_clock_get_start_time(self->recording_clock); - if(gsr_audio_capture_start(&self->audio_capture, self->audio_max_frame_size, self->uses_amix) != GSR_ERROR_OK) + if(gsr_audio_capture_start(&self->audio_capture, self->audio_max_frame_size, self->uses_amix) != GSR_ERROR_OK) { + /* The audio threads that did start have to stop before they can be joined */ + self->running = 0; return GSR_ERROR_GENERIC; + } // Set update_fps to 24 to test if duplicate/delayed frames cause video/audio desync or too fast/slow video. //const double update_fps = fps + 190; diff --git a/src/recorder/screenshot.c b/src/recorder/screenshot.c index 45155b4..7611270 100644 --- a/src/recorder/screenshot.c +++ b/src/recorder/screenshot.c @@ -88,12 +88,15 @@ int gsr_screenshot_take(const gsr_screenshot_params *params) { return load_plugins_result; } + int result = GSR_ERROR_GENERIC; gsr_image_writer image_writer; + memset(&image_writer, 0, sizeof(image_writer)); + gsr_color_conversion color_conversion; + memset(&color_conversion, 0, sizeof(color_conversion)); + if(!gsr_image_writer_init_opengl(&image_writer, egl, video_size.x, video_size.y)) { gsr_log(GSR_LOG_LEVEL_ERROR, "gsr_screenshot_take: gsr_image_write_gl_init failed"); - gsr_plugins_deinit(&plugins); - gsr_video_sources_deinit(video_sources); - return GSR_ERROR_GENERIC; + goto done; } gsr_color_conversion_params color_conversion_params; @@ -107,13 +110,9 @@ int gsr_screenshot_take(const gsr_screenshot_params *params) { color_conversion_params.num_destination_textures = 1; color_conversion_params.destination_color = GSR_DESTINATION_COLOR_RGB; - gsr_color_conversion color_conversion; if(gsr_color_conversion_init(&color_conversion, &color_conversion_params) != 0) { gsr_log(GSR_LOG_LEVEL_ERROR, "gsr_screenshot_take: failed to create color conversion"); - gsr_image_writer_deinit(&image_writer); - gsr_plugins_deinit(&plugins); - gsr_video_sources_deinit(video_sources); - return GSR_ERROR_GENERIC; + goto done; } gsr_color_conversion_clear(&color_conversion); @@ -190,7 +189,7 @@ int gsr_screenshot_take(const gsr_screenshot_params *params) { gsr_egl_swap_buffers(egl); - int result = should_stop_error ? GSR_ERROR_CAPTURE_FAILED : GSR_ERROR_OK; + result = should_stop_error ? GSR_ERROR_CAPTURE_FAILED : GSR_ERROR_OK; if(!should_stop_error) { if(!gsr_image_writer_write_to_file(&image_writer, settings->filename, params->image_format, image_quality)) { gsr_log(GSR_LOG_LEVEL_ERROR, "gsr_screenshot_take: failed to write opengl texture to image output file %s", settings->filename); @@ -201,6 +200,7 @@ int gsr_screenshot_take(const gsr_screenshot_params *params) { params->screenshot_saved(settings->filename, params->userdata); } + done: gsr_color_conversion_deinit(&color_conversion); gsr_plugins_deinit(&plugins); gsr_image_writer_deinit(&image_writer); diff --git a/src/recorder/windowing.c b/src/recorder/windowing.c index 6671898..0bd1de6 100644 --- a/src/recorder/windowing.c +++ b/src/recorder/windowing.c @@ -117,6 +117,24 @@ int gsr_windowing_load_egl(gsr_windowing *self, const gsr_windowing_params *para return GSR_ERROR_OK; } +void gsr_windowing_deinit(gsr_windowing *self) { + if(self->egl_loaded) { + gsr_egl_unload(&self->egl); + self->egl_loaded = false; + } + + if(self->window) { + gsr_window_destroy(self->window); + self->window = NULL; + } + + if(self->display) { + /* TODO: XCloseDisplay causes a crash, why? maybe some other library dlclose xlib and that also happened to unload this??? */ + //XCloseDisplay(self->display); + self->display = NULL; + } +} + bool gsr_windowing_is_wayland(const gsr_windowing *self) { return gsr_window_get_display_server(self->window) == GSR_DISPLAY_SERVER_WAYLAND; } diff --git a/src/window/window.c b/src/window/window.c index 5ede9fd..460ff7f 100644 --- a/src/window/window.c +++ b/src/window/window.c @@ -1,7 +1,10 @@ #include "../../include/window/window.h" #include <stddef.h> -void gsr_window_destroy(gsr_window *self); +void gsr_window_destroy(gsr_window *self) { + if(self) + self->destroy(self); +} bool gsr_window_process_event(gsr_window *self) { return self->process_event(self); |
