diff options
author | dec05eba <dec05eba@protonmail.com> | 2025-04-21 23:02:29 +0200 |
---|---|---|
committer | dec05eba <dec05eba@protonmail.com> | 2025-04-21 23:02:29 +0200 |
commit | 81f155bf6306a2aa378b03920ed2b6f44e013016 (patch) | |
tree | 4da99d1db6d44cfa87c3970d14525ad13b7a85f4 /include | |
parent | ce7b47a877a3e47632f27c44c333a96221885202 (diff) |
Refactor video encoding packet receiving, replay buffer and finish SIGRTMIN for recording while replay/replaying. Add -ro option to specify the directory
Diffstat (limited to 'include')
-rw-r--r-- | include/args_parser.h | 3 | ||||
-rw-r--r-- | include/encoder/video/video.h | 35 | ||||
-rw-r--r-- | include/replay_buffer.h | 41 |
3 files changed, 75 insertions, 4 deletions
diff --git a/include/args_parser.h b/include/args_parser.h index becc551..d1b9713 100644 --- a/include/args_parser.h +++ b/include/args_parser.h @@ -8,7 +8,7 @@ typedef struct gsr_egl gsr_egl; -#define NUM_ARGS 28 +#define NUM_ARGS 29 #define WINDOW_STR_MAX_SIZE 128 typedef enum { @@ -71,6 +71,7 @@ typedef struct { char window[WINDOW_STR_MAX_SIZE]; const char *container_format; const char *filename; + const char *replay_recording_directory; const char *portal_session_token_filepath; const char *recording_saved_script; bool verbose; diff --git a/include/encoder/video/video.h b/include/encoder/video/video.h index 49f48bd..97f63e8 100644 --- a/include/encoder/video/video.h +++ b/include/encoder/video/video.h @@ -2,26 +2,55 @@ #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); + void (*destroy)(gsr_video_encoder *encoder, AVCodecContext *video_codec_context); void (*copy_textures_to_frame)(gsr_video_encoder *encoder, AVFrame *frame, gsr_color_conversion *color_conversion); /* Can be NULL */ /* |textures| should be able to fit 2 elements */ void (*get_textures)(gsr_video_encoder *encoder, unsigned int *textures, int *num_textures, gsr_destination_color *destination_color); - void (*destroy)(gsr_video_encoder *encoder, AVCodecContext *video_codec_context); 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; }; -bool gsr_video_encoder_start(gsr_video_encoder *encoder, AVCodecContext *video_codec_context, AVFrame *frame); +/* 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); +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_destroy(gsr_video_encoder *encoder, AVCodecContext *video_codec_context); + +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/include/replay_buffer.h b/include/replay_buffer.h new file mode 100644 index 0000000..e99b844 --- /dev/null +++ b/include/replay_buffer.h @@ -0,0 +1,41 @@ +#ifndef GSR_REPLAY_BUFFER_H +#define GSR_REPLAY_BUFFER_H + +#include <pthread.h> +#include <stdbool.h> +#include <libavcodec/packet.h> + +typedef struct { + AVPacket packet; + int ref_counter; + double timestamp; +} gsr_av_packet; + +gsr_av_packet* gsr_av_packet_create(const AVPacket *av_packet, double timestamp); +gsr_av_packet* gsr_av_packet_ref(gsr_av_packet *self); +void gsr_av_packet_unref(gsr_av_packet *self); + +typedef struct { + gsr_av_packet **packets; + size_t capacity_num_packets; + size_t num_packets; + size_t index; + pthread_mutex_t mutex; + bool mutex_initialized; + bool owns_mutex; +} gsr_replay_buffer; + +bool gsr_replay_buffer_init(gsr_replay_buffer *self, size_t replay_buffer_num_packets); +void gsr_replay_buffer_deinit(gsr_replay_buffer *self); + +bool gsr_replay_buffer_append(gsr_replay_buffer *self, const AVPacket *av_packet, double timestamp); +void gsr_replay_buffer_clear(gsr_replay_buffer *self); +gsr_av_packet* gsr_replay_buffer_get_packet_at_index(gsr_replay_buffer *self, size_t index); +/* The clone has to be deinitialized before the replay buffer it clones */ +bool gsr_replay_buffer_clone(const gsr_replay_buffer *self, gsr_replay_buffer *destination); +/* Returns 0 if replay buffer is empty */ +size_t gsr_replay_buffer_find_packet_index_by_time_passed(gsr_replay_buffer *self, int seconds); +/* Returns -1 if not found */ +size_t gsr_replay_buffer_find_keyframe(gsr_replay_buffer *self, size_t start_index, int stream_index, bool invert_stream_index); + +#endif /* GSR_REPLAY_BUFFER_H */
\ No newline at end of file |