diff options
-rw-r--r-- | include/encoder/encoder.h | 44 | ||||
-rw-r--r-- | include/encoder/video/video.h | 28 | ||||
-rw-r--r-- | meson.build | 1 | ||||
-rw-r--r-- | src/encoder/encoder.c | 152 | ||||
-rw-r--r-- | src/encoder/video/video.c | 151 | ||||
-rw-r--r-- | src/main.cpp | 36 |
6 files changed, 223 insertions, 189 deletions
diff --git a/include/encoder/encoder.h b/include/encoder/encoder.h new file mode 100644 index 0000000..8f03149 --- /dev/null +++ b/include/encoder/encoder.h @@ -0,0 +1,44 @@ +#ifndef GSR_ENCODER_H +#define GSR_ENCODER_H + +#include "../replay_buffer.h" +#include <stdbool.h> +#include <stdint.h> +#include <stddef.h> +#include <pthread.h> + +#define GSR_MAX_RECORDING_DESTINATIONS 128 + +typedef struct AVCodecContext AVCodecContext; +typedef struct AVFormatContext AVFormatContext; +typedef struct AVStream AVStream; + +typedef struct { + size_t id; + AVCodecContext *codec_context; + AVFormatContext *format_context; + AVStream *stream; + int64_t start_pts; + bool has_received_keyframe; +} gsr_encoder_recording_destination; + +typedef struct { + gsr_replay_buffer replay_buffer; + bool has_replay_buffer; + pthread_mutex_t file_write_mutex; + bool mutex_created; + + gsr_encoder_recording_destination recording_destinations[GSR_MAX_RECORDING_DESTINATIONS]; + size_t num_recording_destinations; + size_t recording_destination_id_counter; +} gsr_encoder; + +bool gsr_encoder_init(gsr_encoder *self, size_t replay_buffer_num_packets); +void gsr_encoder_deinit(gsr_encoder *self); + +void gsr_encoder_receive_packets(gsr_encoder *self, AVCodecContext *codec_context, int64_t pts, int stream_index); +/* Returns the id to the recording destination, or -1 on error */ +size_t gsr_encoder_add_recording_destination(gsr_encoder *self, AVCodecContext *codec_context, AVFormatContext *format_context, AVStream *stream, int64_t start_pts); +bool gsr_encoder_remove_recording_destination(gsr_encoder *self, size_t id); + +#endif /* GSR_ENCODER_H */ diff --git a/include/encoder/video/video.h b/include/encoder/video/video.h index 97f63e8..7a706b5 100644 --- a/include/encoder/video/video.h +++ b/include/encoder/video/video.h @@ -2,27 +2,13 @@ #define GSR_ENCODER_VIDEO_H #include "../../color_conversion.h" -#include "../../replay_buffer.h" #include <stdbool.h> -#include <stdint.h> -#include <pthread.h> #define GSR_MAX_RECORDING_DESTINATIONS 128 typedef struct gsr_video_encoder gsr_video_encoder; typedef struct AVCodecContext AVCodecContext; -typedef struct AVFormatContext AVFormatContext; typedef struct AVFrame AVFrame; -typedef struct AVStream AVStream; - -typedef struct { - size_t id; - AVCodecContext *codec_context; - AVFormatContext *format_context; - AVStream *stream; - int64_t start_pts; - bool has_received_keyframe; -} gsr_video_encoder_recording_destination; struct gsr_video_encoder { bool (*start)(gsr_video_encoder *encoder, AVCodecContext *video_codec_context, AVFrame *frame); @@ -33,24 +19,12 @@ struct gsr_video_encoder { void *priv; bool started; - gsr_replay_buffer replay_buffer; - bool has_replay_buffer; - pthread_mutex_t file_write_mutex; - - gsr_video_encoder_recording_destination recording_destinations[GSR_MAX_RECORDING_DESTINATIONS]; - size_t num_recording_destinations; - size_t recording_destination_id; }; /* Set |replay_buffer_time_seconds| and |fps| to 0 to disable replay buffer */ -bool gsr_video_encoder_start(gsr_video_encoder *encoder, AVCodecContext *video_codec_context, AVFrame *frame, size_t replay_buffer_num_packets); +bool gsr_video_encoder_start(gsr_video_encoder *encoder, AVCodecContext *video_codec_context, AVFrame *frame); void gsr_video_encoder_destroy(gsr_video_encoder *encoder, AVCodecContext *video_codec_context); void gsr_video_encoder_copy_textures_to_frame(gsr_video_encoder *encoder, AVFrame *frame, gsr_color_conversion *color_conversion); void gsr_video_encoder_get_textures(gsr_video_encoder *encoder, unsigned int *textures, int *num_textures, gsr_destination_color *destination_color); -void gsr_video_encoder_receive_packets(gsr_video_encoder *encoder, AVCodecContext *codec_context, int64_t pts, int stream_index); -/* Returns the id to the recording destination, or -1 on error */ -size_t gsr_video_encoder_add_recording_destination(gsr_video_encoder *encoder, AVCodecContext *codec_context, AVFormatContext *format_context, AVStream *stream, int64_t start_pts); -bool gsr_video_encoder_remove_recording_destination(gsr_video_encoder *encoder, size_t id); - #endif /* GSR_ENCODER_VIDEO_H */ diff --git a/meson.build b/meson.build index e47359e..1d386da 100644 --- a/meson.build +++ b/meson.build @@ -14,6 +14,7 @@ src = [ 'src/capture/xcomposite.c', 'src/capture/ximage.c', 'src/capture/kms.c', + 'src/encoder/encoder.c', 'src/encoder/video/video.c', 'src/encoder/video/nvenc.c', 'src/encoder/video/vaapi.c', diff --git a/src/encoder/encoder.c b/src/encoder/encoder.c new file mode 100644 index 0000000..d35cbbe --- /dev/null +++ b/src/encoder/encoder.c @@ -0,0 +1,152 @@ +#include "../../include/encoder/encoder.h" +#include "../../include/utils.h" + +#include <string.h> +#include <stdio.h> + +#include <libavcodec/avcodec.h> +#include <libavformat/avformat.h> + +bool gsr_encoder_init(gsr_encoder *self, size_t replay_buffer_num_packets) { + memset(self, 0, sizeof(*self)); + self->num_recording_destinations = 0; + self->recording_destination_id_counter = 0; + + if(pthread_mutex_init(&self->file_write_mutex, NULL) != 0) { + fprintf(stderr, "gsr error: gsr_encoder_init: failed to create mutex\n"); + return false; + } + self->mutex_created = true; + + if(replay_buffer_num_packets > 0) { + if(!gsr_replay_buffer_init(&self->replay_buffer, replay_buffer_num_packets)) { + fprintf(stderr, "gsr error: gsr_encoder_init: failed to create replay buffer\n"); + gsr_encoder_deinit(self); + return false; + } + self->has_replay_buffer = true; + } + + return true; +} + +void gsr_encoder_deinit(gsr_encoder *self) { + if(self->mutex_created) { + self->mutex_created = false; + pthread_mutex_destroy(&self->file_write_mutex); + } + + gsr_replay_buffer_deinit(&self->replay_buffer); + self->has_replay_buffer = false; + self->num_recording_destinations = 0; + self->recording_destination_id_counter = 0; +} + +void gsr_encoder_receive_packets(gsr_encoder *self, AVCodecContext *codec_context, int64_t pts, int stream_index) { + for(;;) { + AVPacket *av_packet = av_packet_alloc(); + if(!av_packet) + break; + + av_packet->data = NULL; + av_packet->size = 0; + int res = avcodec_receive_packet(codec_context, av_packet); + if(res == 0) { // we have a packet, send the packet to the muxer + av_packet->stream_index = stream_index; + av_packet->pts = pts; + av_packet->dts = pts; + + if(self->has_replay_buffer) { + const double time_now = clock_get_monotonic_seconds(); + if(!gsr_replay_buffer_append(&self->replay_buffer, av_packet, time_now)) + fprintf(stderr, "gsr error: gsr_encoder_receive_packets: failed to add replay buffer data\n"); + } + + pthread_mutex_lock(&self->file_write_mutex); + const bool is_keyframe = av_packet->flags & AV_PKT_FLAG_KEY; + for(size_t i = 0; i < self->num_recording_destinations; ++i) { + gsr_encoder_recording_destination *recording_destination = &self->recording_destinations[i]; + if(recording_destination->codec_context != codec_context) + continue; + + if(is_keyframe) + recording_destination->has_received_keyframe = true; + else if(!recording_destination->has_received_keyframe) + continue; + + av_packet->pts = pts - recording_destination->start_pts; + av_packet->dts = pts - recording_destination->start_pts; + + av_packet_rescale_ts(av_packet, codec_context->time_base, recording_destination->stream->time_base); + // TODO: Is av_interleaved_write_frame needed?. Answer: might be needed for mkv but dont use it! it causes frames to be inconsistent, skipping frames and duplicating frames. + // TODO: av_interleaved_write_frame might be needed for cfr, or always for flv + const int ret = av_write_frame(recording_destination->format_context, av_packet); + if(ret < 0) { + char error_buffer[AV_ERROR_MAX_STRING_SIZE]; + if(av_strerror(ret, error_buffer, sizeof(error_buffer)) < 0) + snprintf(error_buffer, sizeof(error_buffer), "Unknown error"); + fprintf(stderr, "gsr error: gsr_encoder_receive_packets: failed to write frame index %d to muxer, reason: %s (%d)\n", av_packet->stream_index, error_buffer, ret); + } + } + pthread_mutex_unlock(&self->file_write_mutex); + + av_packet_free(&av_packet); + } else if (res == AVERROR(EAGAIN)) { // we have no packet + // fprintf(stderr, "No packet!\n"); + av_packet_free(&av_packet); + break; + } else if (res == AVERROR_EOF) { // this is the end of the stream + av_packet_free(&av_packet); + fprintf(stderr, "End of stream!\n"); + break; + } else { + av_packet_free(&av_packet); + fprintf(stderr, "Unexpected error: %d\n", res); + break; + } + } +} + +size_t gsr_encoder_add_recording_destination(gsr_encoder *self, AVCodecContext *codec_context, AVFormatContext *format_context, AVStream *stream, int64_t start_pts) { + if(self->num_recording_destinations >= GSR_MAX_RECORDING_DESTINATIONS) { + fprintf(stderr, "gsr error: gsr_encoder_add_recording_destination: failed to add destination, reached the max amount of recording destinations (%d)\n", GSR_MAX_RECORDING_DESTINATIONS); + return (size_t)-1; + } + + for(size_t i = 0; i < self->num_recording_destinations; ++i) { + if(self->recording_destinations[i].stream == stream) { + fprintf(stderr, "gsr error: gsr_encoder_add_recording_destination: failed to add destination, the stream %p already exists as an output\n", (void*)stream); + return (size_t)-1; + } + } + + pthread_mutex_lock(&self->file_write_mutex); + gsr_encoder_recording_destination *recording_destination = &self->recording_destinations[self->num_recording_destinations]; + recording_destination->id = self->recording_destination_id_counter; + recording_destination->codec_context = codec_context; + recording_destination->format_context = format_context; + recording_destination->stream = stream; + recording_destination->start_pts = start_pts; + recording_destination->has_received_keyframe = false; + + ++self->recording_destination_id_counter; + ++self->num_recording_destinations; + pthread_mutex_unlock(&self->file_write_mutex); + + return recording_destination->id; +} + +bool gsr_encoder_remove_recording_destination(gsr_encoder *self, size_t id) { + bool found = false; + pthread_mutex_lock(&self->file_write_mutex); + for(size_t i = 0; i < self->num_recording_destinations; ++i) { + if(self->recording_destinations[i].id == id) { + self->recording_destinations[i] = self->recording_destinations[self->num_recording_destinations - 1]; + --self->num_recording_destinations; + found = true; + break; + } + } + pthread_mutex_unlock(&self->file_write_mutex); + return found; +} diff --git a/src/encoder/video/video.c b/src/encoder/video/video.c index 82711ce..ce3b61b 100644 --- a/src/encoder/video/video.c +++ b/src/encoder/video/video.c @@ -1,54 +1,18 @@ #include "../../../include/encoder/video/video.h" -#include "../../../include/utils.h" -#include <string.h> -#include <stdio.h> #include <assert.h> -#include <libavcodec/avcodec.h> -#include <libavformat/avformat.h> - -bool gsr_video_encoder_start(gsr_video_encoder *encoder, AVCodecContext *video_codec_context, AVFrame *frame, size_t replay_buffer_num_packets) { +bool gsr_video_encoder_start(gsr_video_encoder *encoder, AVCodecContext *video_codec_context, AVFrame *frame) { assert(!encoder->started); - encoder->num_recording_destinations = 0; - encoder->recording_destination_id = 0; - - if(pthread_mutex_init(&encoder->file_write_mutex, NULL) != 0) { - fprintf(stderr, "gsr error: gsr_video_encoder_start: failed to create mutex\n"); - return false; - } - - memset(&encoder->replay_buffer, 0, sizeof(encoder->replay_buffer)); - if(replay_buffer_num_packets > 0) { - if(!gsr_replay_buffer_init(&encoder->replay_buffer, replay_buffer_num_packets)) { - fprintf(stderr, "gsr error: gsr_video_encoder_start: failed to create replay buffer\n"); - goto error; - } - encoder->has_replay_buffer = true; - } - bool res = encoder->start(encoder, video_codec_context, frame); - if(res) { + if(res) encoder->started = true; - return true; - } else { - goto error; - } - - error: - pthread_mutex_destroy(&encoder->file_write_mutex); - gsr_replay_buffer_deinit(&encoder->replay_buffer); - return false; + return res; } void gsr_video_encoder_destroy(gsr_video_encoder *encoder, AVCodecContext *video_codec_context) { assert(encoder->started); encoder->started = false; - pthread_mutex_destroy(&encoder->file_write_mutex); - gsr_replay_buffer_deinit(&encoder->replay_buffer); - encoder->has_replay_buffer = false; - encoder->num_recording_destinations = 0; - encoder->recording_destination_id = 0; encoder->destroy(encoder, video_codec_context); } @@ -62,112 +26,3 @@ void gsr_video_encoder_get_textures(gsr_video_encoder *encoder, unsigned int *te assert(encoder->started); encoder->get_textures(encoder, textures, num_textures, destination_color); } - -void gsr_video_encoder_receive_packets(gsr_video_encoder *encoder, AVCodecContext *codec_context, int64_t pts, int stream_index) { - for (;;) { - AVPacket *av_packet = av_packet_alloc(); - if(!av_packet) - break; - - av_packet->data = NULL; - av_packet->size = 0; - int res = avcodec_receive_packet(codec_context, av_packet); - if(res == 0) { // we have a packet, send the packet to the muxer - av_packet->stream_index = stream_index; - av_packet->pts = pts; - av_packet->dts = pts; - - if(encoder->has_replay_buffer) { - const double time_now = clock_get_monotonic_seconds(); - if(!gsr_replay_buffer_append(&encoder->replay_buffer, av_packet, time_now)) - fprintf(stderr, "gsr error: gsr_video_encoder_receive_packets: failed to add replay buffer data\n"); - } - - pthread_mutex_lock(&encoder->file_write_mutex); - const bool is_keyframe = av_packet->flags & AV_PKT_FLAG_KEY; - for(size_t i = 0; i < encoder->num_recording_destinations; ++i) { - gsr_video_encoder_recording_destination *recording_destination = &encoder->recording_destinations[i]; - if(recording_destination->codec_context != codec_context) - continue; - - if(is_keyframe) - recording_destination->has_received_keyframe = true; - else if(!recording_destination->has_received_keyframe) - continue; - - av_packet->pts = pts - recording_destination->start_pts; - av_packet->dts = pts - recording_destination->start_pts; - - av_packet_rescale_ts(av_packet, codec_context->time_base, recording_destination->stream->time_base); - // TODO: Is av_interleaved_write_frame needed?. Answer: might be needed for mkv but dont use it! it causes frames to be inconsistent, skipping frames and duplicating frames. - // TODO: av_interleaved_write_frame might be needed for cfr, or always for flv - const int ret = av_write_frame(recording_destination->format_context, av_packet); - if(ret < 0) { - char error_buffer[AV_ERROR_MAX_STRING_SIZE]; - if(av_strerror(ret, error_buffer, sizeof(error_buffer)) < 0) - snprintf(error_buffer, sizeof(error_buffer), "Unknown error"); - fprintf(stderr, "Error: Failed to write frame index %d to muxer, reason: %s (%d)\n", av_packet->stream_index, error_buffer, ret); - } - } - pthread_mutex_unlock(&encoder->file_write_mutex); - - av_packet_free(&av_packet); - } else if (res == AVERROR(EAGAIN)) { // we have no packet - // fprintf(stderr, "No packet!\n"); - av_packet_free(&av_packet); - break; - } else if (res == AVERROR_EOF) { // this is the end of the stream - av_packet_free(&av_packet); - fprintf(stderr, "End of stream!\n"); - break; - } else { - av_packet_free(&av_packet); - fprintf(stderr, "Unexpected error: %d\n", res); - break; - } - } -} - -size_t gsr_video_encoder_add_recording_destination(gsr_video_encoder *encoder, AVCodecContext *codec_context, AVFormatContext *format_context, AVStream *stream, int64_t start_pts) { - if(encoder->num_recording_destinations >= GSR_MAX_RECORDING_DESTINATIONS) { - fprintf(stderr, "gsr error: gsr_video_encoder_add_recording_destination: failed to add destination, reached the max amount of recording destinations (%d)\n", GSR_MAX_RECORDING_DESTINATIONS); - return (size_t)-1; - } - - for(size_t i = 0; i < encoder->num_recording_destinations; ++i) { - if(encoder->recording_destinations[i].stream == stream) { - fprintf(stderr, "gsr error: gsr_video_encoder_add_recording_destination: failed to add destination, the stream %p already exists as an output\n", (void*)stream); - return (size_t)-1; - } - } - - pthread_mutex_lock(&encoder->file_write_mutex); - gsr_video_encoder_recording_destination *recording_destination = &encoder->recording_destinations[encoder->num_recording_destinations]; - recording_destination->id = encoder->recording_destination_id; - recording_destination->codec_context = codec_context; - recording_destination->format_context = format_context; - recording_destination->stream = stream; - recording_destination->start_pts = start_pts; - recording_destination->has_received_keyframe = false; - - ++encoder->recording_destination_id; - ++encoder->num_recording_destinations; - pthread_mutex_unlock(&encoder->file_write_mutex); - - return recording_destination->id; -} - -bool gsr_video_encoder_remove_recording_destination(gsr_video_encoder *encoder, size_t id) { - bool found = false; - pthread_mutex_lock(&encoder->file_write_mutex); - for(size_t i = 0; i < encoder->num_recording_destinations; ++i) { - if(encoder->recording_destinations[i].id == id) { - encoder->recording_destinations[i] = encoder->recording_destinations[encoder->num_recording_destinations - 1]; - --encoder->num_recording_destinations; - found = true; - break; - } - } - pthread_mutex_unlock(&encoder->file_write_mutex); - return found; -} diff --git a/src/main.cpp b/src/main.cpp index eca8db1..477d8f5 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -10,6 +10,7 @@ extern "C" { #ifdef GSR_APP_AUDIO #include "../include/pipewire_audio.h" #endif +#include "../include/encoder/encoder.h" #include "../include/encoder/video/nvenc.h" #include "../include/encoder/video/vaapi.h" #include "../include/encoder/video/vulkan.h" @@ -3143,14 +3144,20 @@ int main(int argc, char **argv) { video_frame->width = capture_metadata.width; video_frame->height = capture_metadata.height; + const size_t estimated_replay_buffer_packets = calculate_estimated_replay_buffer_packets(arg_parser.replay_buffer_size_secs, arg_parser.fps, arg_parser.audio_codec, requested_audio_inputs); + gsr_encoder encoder; + if(!gsr_encoder_init(&encoder, estimated_replay_buffer_packets)) { + fprintf(stderr, "Error: failed to create encoder\n"); + _exit(1); + } + gsr_video_encoder *video_encoder = create_video_encoder(&egl, arg_parser); if(!video_encoder) { fprintf(stderr, "Error: failed to create video encoder\n"); _exit(1); } - const size_t estimated_replay_buffer_packets = calculate_estimated_replay_buffer_packets(arg_parser.replay_buffer_size_secs, arg_parser.fps, arg_parser.audio_codec, requested_audio_inputs); - if(!gsr_video_encoder_start(video_encoder, video_codec_context, video_frame, estimated_replay_buffer_packets)) { + if(!gsr_video_encoder_start(video_encoder, video_codec_context, video_frame)) { fprintf(stderr, "Error: failed to start video encoder\n"); _exit(1); } @@ -3181,7 +3188,7 @@ int main(int argc, char **argv) { if(video_stream) { avcodec_parameters_from_context(video_stream->codecpar, video_codec_context); - gsr_video_encoder_add_recording_destination(video_encoder, video_codec_context, av_format_context, video_stream, 0); + gsr_encoder_add_recording_destination(&encoder, video_codec_context, av_format_context, video_stream, 0); } int audio_max_frame_size = 1024; @@ -3193,7 +3200,7 @@ int main(int argc, char **argv) { AVStream *audio_stream = nullptr; if(!is_replaying) { audio_stream = create_stream(av_format_context, audio_codec_context); - if(gsr_video_encoder_add_recording_destination(video_encoder, audio_codec_context, av_format_context, audio_stream, 0) == (size_t)-1) + if(gsr_encoder_add_recording_destination(&encoder, audio_codec_context, av_format_context, audio_stream, 0) == (size_t)-1) fprintf(stderr, "gsr error: added too many audio sources\n"); } @@ -3396,7 +3403,7 @@ int main(int argc, char **argv) { ret = avcodec_send_frame(audio_track.codec_context, audio_device.frame); if(ret >= 0) { // TODO: Move to separate thread because this could write to network (for example when livestreaming) - gsr_video_encoder_receive_packets(video_encoder, audio_track.codec_context, audio_device.frame->pts, audio_track.stream_index); + gsr_encoder_receive_packets(&encoder, audio_track.codec_context, audio_device.frame->pts, audio_track.stream_index); } else { fprintf(stderr, "Failed to encode audio!\n"); } @@ -3430,7 +3437,7 @@ int main(int argc, char **argv) { ret = avcodec_send_frame(audio_track.codec_context, audio_device.frame); if(ret >= 0) { // TODO: Move to separate thread because this could write to network (for example when livestreaming) - gsr_video_encoder_receive_packets(video_encoder, audio_track.codec_context, audio_device.frame->pts, audio_track.stream_index); + gsr_encoder_receive_packets(&encoder, audio_track.codec_context, audio_device.frame->pts, audio_track.stream_index); } else { fprintf(stderr, "Failed to encode audio!\n"); } @@ -3465,7 +3472,7 @@ int main(int argc, char **argv) { err = avcodec_send_frame(audio_track.codec_context, aframe); if(err >= 0){ // TODO: Move to separate thread because this could write to network (for example when livestreaming) - gsr_video_encoder_receive_packets(video_encoder, audio_track.codec_context, aframe->pts, audio_track.stream_index); + gsr_encoder_receive_packets(&encoder, audio_track.codec_context, aframe->pts, audio_track.stream_index); } else { fprintf(stderr, "Failed to encode audio!\n"); } @@ -3616,7 +3623,7 @@ int main(int argc, char **argv) { int ret = avcodec_send_frame(video_codec_context, video_frame); if(ret == 0) { // TODO: Move to separate thread because this could write to network (for example when livestreaming) - gsr_video_encoder_receive_packets(video_encoder, video_codec_context, video_frame->pts, VIDEO_STREAM_INDEX); + gsr_encoder_receive_packets(&encoder, video_codec_context, video_frame->pts, VIDEO_STREAM_INDEX); } else { fprintf(stderr, "Error: avcodec_send_frame failed, error: %s\n", av_error_to_string(ret)); } @@ -3659,12 +3666,12 @@ int main(int argc, char **argv) { replay_recording_filepath = create_new_recording_filepath_from_timestamp(arg_parser.replay_recording_directory, "Recording", file_extension, arg_parser.date_folders); replay_recording_start_result = start_recording_create_streams(replay_recording_filepath.c_str(), arg_parser.container_format, video_codec_context, audio_tracks, hdr, capture); if(replay_recording_start_result.av_format_context) { - const size_t video_recording_destination_id = gsr_video_encoder_add_recording_destination(video_encoder, video_codec_context, replay_recording_start_result.av_format_context, replay_recording_start_result.video_stream, video_frame->pts); + const size_t video_recording_destination_id = gsr_encoder_add_recording_destination(&encoder, video_codec_context, replay_recording_start_result.av_format_context, replay_recording_start_result.video_stream, video_frame->pts); if(video_recording_destination_id != (size_t)-1) replay_recording_items.push_back(video_recording_destination_id); for(const auto &audio_input : replay_recording_start_result.audio_inputs) { - const size_t audio_recording_destination_id = gsr_video_encoder_add_recording_destination(video_encoder, audio_input.audio_track->codec_context, replay_recording_start_result.av_format_context, audio_input.stream, audio_input.audio_track->pts); + const size_t audio_recording_destination_id = gsr_encoder_add_recording_destination(&encoder, audio_input.audio_track->codec_context, replay_recording_start_result.av_format_context, audio_input.stream, audio_input.audio_track->pts); if(audio_recording_destination_id != (size_t)-1) replay_recording_items.push_back(audio_recording_destination_id); } @@ -3678,7 +3685,7 @@ int main(int argc, char **argv) { } } else if(replay_recording_start_result.av_format_context) { for(size_t id : replay_recording_items) { - gsr_video_encoder_remove_recording_destination(video_encoder, id); + gsr_encoder_remove_recording_destination(&encoder, id); } replay_recording_items.clear(); @@ -3718,10 +3725,10 @@ int main(int argc, char **argv) { save_replay_seconds = 0; save_replay_output_filepath.clear(); - save_replay_async(video_codec_context, VIDEO_STREAM_INDEX, audio_tracks, &video_encoder->replay_buffer, arg_parser.filename, arg_parser.container_format, file_extension, arg_parser.date_folders, hdr, capture, current_save_replay_seconds); + save_replay_async(video_codec_context, VIDEO_STREAM_INDEX, audio_tracks, &encoder.replay_buffer, arg_parser.filename, arg_parser.container_format, file_extension, arg_parser.date_folders, hdr, capture, current_save_replay_seconds); if(arg_parser.restart_replay_on_save && current_save_replay_seconds == save_replay_seconds_full) { - gsr_replay_buffer_clear(&video_encoder->replay_buffer); + gsr_replay_buffer_clear(&encoder.replay_buffer); replay_start_time = clock_get_monotonic_seconds() - paused_time_offset; } } @@ -3768,7 +3775,7 @@ int main(int argc, char **argv) { if(replay_recording_start_result.av_format_context) { for(size_t id : replay_recording_items) { - gsr_video_encoder_remove_recording_destination(video_encoder, id); + gsr_encoder_remove_recording_destination(&encoder, id); } replay_recording_items.clear(); @@ -3807,6 +3814,7 @@ int main(int argc, char **argv) { gsr_damage_deinit(&damage); gsr_color_conversion_deinit(&color_conversion); gsr_video_encoder_destroy(video_encoder, video_codec_context); + gsr_encoder_deinit(&encoder); gsr_capture_destroy(capture); #ifdef GSR_APP_AUDIO gsr_pipewire_audio_deinit(&pipewire_audio); |