aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--include/recorder/windowing.h1
-rw-r--r--src/cli/commands.c40
-rw-r--r--src/cli/main.c200
-rw-r--r--src/pipewire_audio.c5
-rw-r--r--src/recorder/recorder.c140
-rw-r--r--src/recorder/screenshot.c18
-rw-r--r--src/recorder/windowing.c18
-rw-r--r--src/window/window.c5
8 files changed, 237 insertions, 190 deletions
diff --git a/include/recorder/windowing.h b/include/recorder/windowing.h
index 6bc5f5f..630f3fe 100644
--- a/include/recorder/windowing.h
+++ b/include/recorder/windowing.h
@@ -25,6 +25,7 @@ typedef struct {
int gsr_windowing_init(gsr_windowing *self, const gsr_windowing_params *params);
/* Returns a |gsr_error| value. Loads opengl and finds the drm card to use */
int gsr_windowing_load_egl(gsr_windowing *self, const gsr_windowing_params *params);
+void gsr_windowing_deinit(gsr_windowing *self);
bool gsr_windowing_is_wayland(const gsr_windowing *self);
bool gsr_windowing_is_using_prime_run(void);
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);