diff options
Diffstat (limited to 'src/recorder')
| -rw-r--r-- | src/recorder/recorder.c | 140 | ||||
| -rw-r--r-- | src/recorder/screenshot.c | 18 | ||||
| -rw-r--r-- | src/recorder/windowing.c | 18 |
3 files changed, 94 insertions, 82 deletions
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; } |
