aboutsummaryrefslogtreecommitdiff
path: root/include
diff options
context:
space:
mode:
Diffstat (limited to 'include')
-rw-r--r--include/args_parser.h106
-rw-r--r--include/capture/capture.h5
-rw-r--r--include/color_conversion.h35
-rw-r--r--include/dbus.h20
-rw-r--r--include/defs.h91
-rw-r--r--include/egl.h20
-rw-r--r--include/encoder/encoder.h43
-rw-r--r--include/encoder/video/video.h7
-rw-r--r--include/pipewire_audio.h31
-rw-r--r--include/pipewire_video.h7
-rw-r--r--include/replay_buffer/replay_buffer.h54
-rw-r--r--include/replay_buffer/replay_buffer_disk.h44
-rw-r--r--include/replay_buffer/replay_buffer_ram.h22
-rw-r--r--include/shader.h4
-rw-r--r--include/utils.h11
15 files changed, 434 insertions, 66 deletions
diff --git a/include/args_parser.h b/include/args_parser.h
new file mode 100644
index 0000000..e2fa46e
--- /dev/null
+++ b/include/args_parser.h
@@ -0,0 +1,106 @@
+#ifndef GSR_ARGS_PARSER_H
+#define GSR_ARGS_PARSER_H
+
+#include <stdbool.h>
+#include <stdint.h>
+#include "defs.h"
+#include "vec2.h"
+
+typedef struct gsr_egl gsr_egl;
+
+#define NUM_ARGS 30
+
+typedef enum {
+ ARG_TYPE_STRING,
+ ARG_TYPE_BOOLEAN,
+ ARG_TYPE_ENUM,
+ ARG_TYPE_I64,
+ ARG_TYPE_DOUBLE,
+} ArgType;
+
+typedef struct {
+ const char *name;
+ int value;
+} ArgEnum;
+
+typedef struct {
+ ArgType type;
+ const char **values;
+ int capacity_num_values;
+ int num_values;
+
+ const char *key;
+ bool optional;
+ bool list;
+
+ const ArgEnum *enum_values;
+ int num_enum_values;
+
+ int64_t integer_value_min;
+ int64_t integer_value_max;
+
+ union {
+ bool boolean;
+ int enum_value;
+ int64_t i64_value;
+ double d_value;
+ } typed_value;
+} Arg;
+
+typedef struct {
+ void (*version)(void *userdata);
+ void (*info)(void *userdata);
+ void (*list_audio_devices)(void *userdata);
+ void (*list_application_audio)(void *userdata);
+ void (*list_capture_options)(const char *card_path, void *userdata);
+} args_handlers;
+
+typedef struct {
+ Arg args[NUM_ARGS];
+
+ gsr_video_encoder_hardware video_encoder;
+ gsr_pixel_format pixel_format;
+ gsr_framerate_mode framerate_mode;
+ gsr_color_range color_range;
+ gsr_tune tune;
+ gsr_video_codec video_codec;
+ gsr_audio_codec audio_codec;
+ gsr_bitrate_mode bitrate_mode;
+ gsr_video_quality video_quality;
+ gsr_replay_storage replay_storage;
+ char window[64];
+ 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;
+ bool gl_debug;
+ bool record_cursor;
+ bool date_folders;
+ bool restore_portal_session;
+ bool restart_replay_on_save;
+ bool overclock;
+ bool is_livestream;
+ bool is_output_piped;
+ bool low_latency_recording;
+ bool very_old_gpu;
+ int64_t video_bitrate;
+ int64_t audio_bitrate;
+ int64_t fps;
+ int64_t replay_buffer_size_secs;
+ double keyint;
+ vec2i output_resolution;
+ vec2i region_size;
+ vec2i region_position;
+} args_parser;
+
+/* |argv| is stored as a reference */
+bool args_parser_parse(args_parser *self, int argc, char **argv, const args_handlers *args_handlers, void *userdata);
+void args_parser_deinit(args_parser *self);
+
+bool args_parser_validate_with_gl_info(args_parser *self, gsr_egl *egl);
+void args_parser_print_usage(void);
+Arg* args_parser_get_arg(args_parser *self, const char *arg_name);
+
+#endif /* GSR_ARGS_PARSER_H */
diff --git a/include/capture/capture.h b/include/capture/capture.h
index 634eee0..c2128c5 100644
--- a/include/capture/capture.h
+++ b/include/capture/capture.h
@@ -22,12 +22,13 @@ typedef struct {
} gsr_capture_metadata;
struct gsr_capture {
- /* These methods should not be called manually. Call gsr_capture_* instead */
+ /* These methods should not be called manually. Call gsr_capture_* instead. |capture_metdata->width| and |capture_metadata->height| should be set by this function */
int (*start)(gsr_capture *cap, gsr_capture_metadata *capture_metadata);
void (*on_event)(gsr_capture *cap, gsr_egl *egl); /* can be NULL */
void (*tick)(gsr_capture *cap); /* can be NULL. If there is an event then |on_event| is called before this */
bool (*should_stop)(gsr_capture *cap, bool *err); /* can be NULL. If NULL, return false */
- int (*capture)(gsr_capture *cap, gsr_capture_metadata *capture_metadata, gsr_color_conversion *color_conversion);
+ bool (*capture_has_synchronous_task)(gsr_capture *cap); /* can be NULL. If this returns true then the time spent in |capture| is ignored for video/audio (capture is paused while the synchronous task happens) */
+ int (*capture)(gsr_capture *cap, gsr_capture_metadata *capture_metadata, gsr_color_conversion *color_conversion); /* Return 0 if the frame was captured */
bool (*uses_external_image)(gsr_capture *cap); /* can be NULL. If NULL, return false */
bool (*set_hdr_metadata)(gsr_capture *cap, AVMasteringDisplayMetadata *mastering_display_metadata, AVContentLightMetadata *light_metadata); /* can be NULL. If NULL, return false */
uint64_t (*get_window_id)(gsr_capture *cap); /* can be NULL. Returns 0 if unknown */
diff --git a/include/color_conversion.h b/include/color_conversion.h
index 1c067e2..cb074a1 100644
--- a/include/color_conversion.h
+++ b/include/color_conversion.h
@@ -6,20 +6,11 @@
#include "vec2.h"
#include <stdbool.h>
-#define GSR_COLOR_CONVERSION_MAX_SHADERS 6
+#define GSR_COLOR_CONVERSION_MAX_COMPUTE_SHADERS 12
+#define GSR_COLOR_CONVERSION_MAX_GRAPHICS_SHADERS 6
#define GSR_COLOR_CONVERSION_MAX_FRAMEBUFFERS 2
typedef enum {
- GSR_COLOR_RANGE_LIMITED,
- GSR_COLOR_RANGE_FULL
-} gsr_color_range;
-
-typedef enum {
- GSR_COLOR_DEPTH_8_BITS,
- GSR_COLOR_DEPTH_10_BITS
-} gsr_color_depth;
-
-typedef enum {
GSR_SOURCE_COLOR_RGB,
GSR_SOURCE_COLOR_BGR
} gsr_source_color;
@@ -39,10 +30,15 @@ typedef enum {
typedef struct {
int rotation_matrix;
+ int offset;
+} gsr_color_graphics_uniforms;
+
+typedef struct {
+ int rotation_matrix;
int source_position;
int target_position;
int scale;
-} gsr_color_uniforms;
+} gsr_color_compute_uniforms;
typedef struct {
gsr_egl *egl;
@@ -54,12 +50,20 @@ typedef struct {
gsr_color_range color_range;
bool load_external_image_shader;
+ bool force_graphics_shader;
} gsr_color_conversion_params;
typedef struct {
gsr_color_conversion_params params;
- gsr_color_uniforms uniforms[GSR_COLOR_CONVERSION_MAX_SHADERS];
- gsr_shader shaders[GSR_COLOR_CONVERSION_MAX_SHADERS];
+ gsr_color_compute_uniforms compute_uniforms[GSR_COLOR_CONVERSION_MAX_COMPUTE_SHADERS];
+ gsr_shader compute_shaders[GSR_COLOR_CONVERSION_MAX_COMPUTE_SHADERS];
+
+ /* These are only loader if compute shaders (of the same type) fail to load */
+ gsr_color_graphics_uniforms graphics_uniforms[GSR_COLOR_CONVERSION_MAX_GRAPHICS_SHADERS];
+ gsr_shader graphics_shaders[GSR_COLOR_CONVERSION_MAX_GRAPHICS_SHADERS];
+
+ bool compute_shaders_failed_to_load;
+ bool external_compute_shaders_failed_to_load;
unsigned int framebuffers[GSR_COLOR_CONVERSION_MAX_FRAMEBUFFERS];
@@ -72,8 +76,9 @@ typedef struct {
int gsr_color_conversion_init(gsr_color_conversion *self, const gsr_color_conversion_params *params);
void gsr_color_conversion_deinit(gsr_color_conversion *self);
-void gsr_color_conversion_draw(gsr_color_conversion *self, unsigned int texture_id, vec2i destination_pos, vec2i destination_size, vec2i source_pos, vec2i source_size, vec2i texture_size, gsr_rotation rotation, bool external_texture, gsr_source_color source_color);
+void gsr_color_conversion_draw(gsr_color_conversion *self, unsigned int texture_id, vec2i destination_pos, vec2i destination_size, vec2i source_pos, vec2i source_size, vec2i texture_size, gsr_rotation rotation, gsr_source_color source_color, bool external_texture, bool alpha_blending);
void gsr_color_conversion_clear(gsr_color_conversion *self);
+void gsr_color_conversion_read_destination_texture(gsr_color_conversion *self, int destination_texture_index, int x, int y, int width, int height, unsigned int color_format, unsigned int data_format, void *pixels);
gsr_rotation gsr_monitor_rotation_to_rotation(gsr_monitor_rotation monitor_rotation);
diff --git a/include/dbus.h b/include/dbus.h
index 58edf3c..229f7ea 100644
--- a/include/dbus.h
+++ b/include/dbus.h
@@ -7,16 +7,6 @@
#define DBUS_RANDOM_STR_SIZE 16
-typedef struct {
- DBusConnection *con;
- DBusError err;
- char random_str[DBUS_RANDOM_STR_SIZE + 1];
- unsigned int handle_counter;
- bool desktop_portal_rule_added;
- uint32_t screencast_version;
- char *screencast_restore_token;
-} gsr_dbus;
-
typedef enum {
GSR_PORTAL_CAPTURE_TYPE_MONITOR = 1 << 0,
GSR_PORTAL_CAPTURE_TYPE_WINDOW = 1 << 1,
@@ -30,6 +20,16 @@ typedef enum {
GSR_PORTAL_CURSOR_MODE_METADATA = 1 << 2
} gsr_portal_cursor_mode;
+typedef struct {
+ DBusConnection *con;
+ DBusError err;
+ char random_str[DBUS_RANDOM_STR_SIZE + 1];
+ unsigned int handle_counter;
+ bool desktop_portal_rule_added;
+ uint32_t screencast_version;
+ char *screencast_restore_token;
+} gsr_dbus;
+
/* Blocking. TODO: Make non-blocking */
bool gsr_dbus_init(gsr_dbus *self, const char *screencast_restore_token);
void gsr_dbus_deinit(gsr_dbus *self);
diff --git a/include/defs.h b/include/defs.h
index 365a6e2..d780005 100644
--- a/include/defs.h
+++ b/include/defs.h
@@ -3,35 +3,110 @@
#include <stdbool.h>
+#define GSR_VIDEO_CODEC_AUTO -1
+#define GSR_BITRATE_MODE_AUTO -1
+
typedef enum {
GSR_GPU_VENDOR_AMD,
GSR_GPU_VENDOR_INTEL,
GSR_GPU_VENDOR_NVIDIA,
- GSR_GPU_VENDOR_BROADCOM
+ GSR_GPU_VENDOR_BROADCOM,
} gsr_gpu_vendor;
typedef struct {
gsr_gpu_vendor vendor;
int gpu_version; /* 0 if unknown */
bool is_steam_deck;
-
- /* Only currently set for Mesa. 0 if unknown format */
- int driver_major;
- int driver_minor;
- int driver_patch;
} gsr_gpu_info;
typedef enum {
GSR_MONITOR_ROT_0,
GSR_MONITOR_ROT_90,
GSR_MONITOR_ROT_180,
- GSR_MONITOR_ROT_270
+ GSR_MONITOR_ROT_270,
} gsr_monitor_rotation;
typedef enum {
GSR_CONNECTION_X11,
GSR_CONNECTION_WAYLAND,
- GSR_CONNECTION_DRM
+ GSR_CONNECTION_DRM,
} gsr_connection_type;
+typedef enum {
+ GSR_VIDEO_QUALITY_MEDIUM,
+ GSR_VIDEO_QUALITY_HIGH,
+ GSR_VIDEO_QUALITY_VERY_HIGH,
+ GSR_VIDEO_QUALITY_ULTRA,
+} gsr_video_quality;
+
+typedef enum {
+ GSR_VIDEO_CODEC_H264,
+ GSR_VIDEO_CODEC_HEVC,
+ GSR_VIDEO_CODEC_HEVC_HDR,
+ GSR_VIDEO_CODEC_HEVC_10BIT,
+ GSR_VIDEO_CODEC_AV1,
+ GSR_VIDEO_CODEC_AV1_HDR,
+ GSR_VIDEO_CODEC_AV1_10BIT,
+ GSR_VIDEO_CODEC_VP8,
+ GSR_VIDEO_CODEC_VP9,
+ GSR_VIDEO_CODEC_H264_VULKAN,
+ GSR_VIDEO_CODEC_HEVC_VULKAN,
+} gsr_video_codec;
+
+typedef enum {
+ GSR_AUDIO_CODEC_AAC,
+ GSR_AUDIO_CODEC_OPUS,
+ GSR_AUDIO_CODEC_FLAC,
+} gsr_audio_codec;
+
+typedef enum {
+ GSR_PIXEL_FORMAT_YUV420,
+ GSR_PIXEL_FORMAT_YUV444,
+} gsr_pixel_format;
+
+typedef enum {
+ GSR_FRAMERATE_MODE_CONSTANT,
+ GSR_FRAMERATE_MODE_VARIABLE,
+ GSR_FRAMERATE_MODE_CONTENT,
+} gsr_framerate_mode;
+
+typedef enum {
+ GSR_BITRATE_MODE_QP,
+ GSR_BITRATE_MODE_VBR,
+ GSR_BITRATE_MODE_CBR,
+} gsr_bitrate_mode;
+
+typedef enum {
+ GSR_TUNE_PERFORMANCE,
+ GSR_TUNE_QUALITY,
+} gsr_tune;
+
+typedef enum {
+ GSR_VIDEO_ENCODER_HW_GPU,
+ GSR_VIDEO_ENCODER_HW_CPU,
+} gsr_video_encoder_hardware;
+
+typedef enum {
+ GSR_COLOR_RANGE_LIMITED,
+ GSR_COLOR_RANGE_FULL,
+} gsr_color_range;
+
+typedef enum {
+ GSR_COLOR_DEPTH_8_BITS,
+ GSR_COLOR_DEPTH_10_BITS,
+} gsr_color_depth;
+
+typedef enum {
+ GSR_REPLAY_STORAGE_RAM,
+ GSR_REPLAY_STORAGE_DISK,
+} gsr_replay_storage;
+
+bool video_codec_is_hdr(gsr_video_codec video_codec);
+gsr_video_codec hdr_video_codec_to_sdr_video_codec(gsr_video_codec video_codec);
+gsr_color_depth video_codec_to_bit_depth(gsr_video_codec video_codec);
+const char* video_codec_to_string(gsr_video_codec video_codec);
+bool video_codec_is_av1(gsr_video_codec video_codec);
+bool video_codec_is_vulkan(gsr_video_codec video_codec);
+const char* audio_codec_get_name(gsr_audio_codec audio_codec);
+
#endif /* GSR_DEFS_H */
diff --git a/include/egl.h b/include/egl.h
index 730502f..e11557e 100644
--- a/include/egl.h
+++ b/include/egl.h
@@ -48,6 +48,8 @@ typedef void(*__GLXextFuncPtr)(void);
#define EGL_OPENGL_ES_API 0x30A0
#define EGL_OPENGL_BIT 0x0008
#define EGL_OPENGL_ES_BIT 0x0001
+#define EGL_OPENGL_ES2_BIT 0x0004
+#define EGL_OPENGL_ES3_BIT 0x00000040
#define EGL_NONE 0x3038
#define EGL_CONTEXT_CLIENT_VERSION 0x3098
#define EGL_BACK_BUFFER 0x3084
@@ -141,8 +143,6 @@ typedef void(*__GLXextFuncPtr)(void);
#define GL_MAX_COMPUTE_FIXED_GROUP_INVOCATIONS 0x90EB
#define GL_TEXTURE0 0x84C0
#define GL_TEXTURE1 0x84C1
-#define GL_CLAMP_TO_BORDER 0x812D
-#define GL_TEXTURE_BORDER_COLOR 0x1004
#define GL_SHADER_IMAGE_ACCESS_BARRIER_BIT 0x00000020
#define GL_ALL_BARRIER_BITS 0xFFFFFFFF
@@ -169,6 +169,13 @@ typedef void (*GLDEBUGPROC)(unsigned int source, unsigned int type, unsigned int
typedef int (*FUNC_eglQueryDisplayAttribEXT)(EGLDisplay dpy, int32_t attribute, intptr_t *value);
typedef const char* (*FUNC_eglQueryDeviceStringEXT)(void *device, int32_t name);
typedef int (*FUNC_eglQueryDmaBufModifiersEXT)(EGLDisplay dpy, int32_t format, int32_t max_modifiers, uint64_t *modifiers, int *external_only, int32_t *num_modifiers);
+typedef void (*FUNC_glCreateMemoryObjectsEXT)(int n, unsigned int *memoryObjects);
+typedef void (*FUNC_glImportMemoryFdEXT)(unsigned int memory, uint64_t size, unsigned int handleType, int fd);
+typedef unsigned char (*FUNC_glIsMemoryObjectEXT)(unsigned int memoryObject);
+typedef void (*FUNC_glTexStorageMem2DEXT)(unsigned int target, int levels, unsigned int internalFormat, int width, int height, unsigned int memory, uint64_t offset);
+typedef void (*FUNC_glBufferStorageMemEXT)(unsigned int target, ssize_t size, unsigned int memory, uint64_t offset);
+typedef void (*FUNC_glNamedBufferStorageMemEXT)(unsigned int buffer, ssize_t size, unsigned int memory, uint64_t offset);
+typedef void (*FUNC_glMemoryObjectParameterivEXT)(unsigned int memoryObject, unsigned int pname, const int *params);
typedef enum {
GSR_GL_CONTEXT_TYPE_EGL,
@@ -219,6 +226,13 @@ struct gsr_egl {
FUNC_eglQueryDisplayAttribEXT eglQueryDisplayAttribEXT;
FUNC_eglQueryDeviceStringEXT eglQueryDeviceStringEXT;
FUNC_eglQueryDmaBufModifiersEXT eglQueryDmaBufModifiersEXT;
+ FUNC_glCreateMemoryObjectsEXT glCreateMemoryObjectsEXT;
+ FUNC_glImportMemoryFdEXT glImportMemoryFdEXT;
+ FUNC_glIsMemoryObjectEXT glIsMemoryObjectEXT;
+ FUNC_glTexStorageMem2DEXT glTexStorageMem2DEXT;
+ FUNC_glBufferStorageMemEXT glBufferStorageMemEXT;
+ FUNC_glNamedBufferStorageMemEXT glNamedBufferStorageMemEXT;
+ FUNC_glMemoryObjectParameterivEXT glMemoryObjectParameterivEXT;
__GLXextFuncPtr (*glXGetProcAddress)(const unsigned char *procName);
GLXFBConfig* (*glXChooseFBConfig)(Display *dpy, int screen, const int *attribList, int *nitems);
@@ -251,6 +265,7 @@ struct gsr_egl {
void (*glGetTexLevelParameteriv)(unsigned int target, int level, unsigned int pname, int *params);
void (*glTexImage2D)(unsigned int target, int level, int internalFormat, int width, int height, int border, unsigned int format, unsigned int type, const void *pixels);
void (*glTexSubImage2D)(unsigned int target, int level, int xoffset, int yoffset, int width, int height, unsigned format, unsigned type, const void *pixels);
+ void (*glTexStorage2D)(unsigned int target, int levels, unsigned int internalformat, int width, int height);
void (*glGetTexImage)(unsigned int target, int level, unsigned int format, unsigned int type, void *pixels);
void (*glGenFramebuffers)(int n, unsigned int *framebuffers);
void (*glBindFramebuffer)(unsigned int target, unsigned int framebuffer);
@@ -298,6 +313,7 @@ struct gsr_egl {
void (*glUniformMatrix2fv)(int location, int count, unsigned char transpose, const float *value);
void (*glDebugMessageCallback)(GLDEBUGPROC callback, const void *userParam);
void (*glScissor)(int x, int y, int width, int height);
+ void (*glCreateBuffers)(int n, unsigned int *buffers);
void (*glReadPixels)(int x, int y, int width, int height, unsigned int format, unsigned int type, void *pixels);
void* (*glMapBuffer)(unsigned int target, unsigned int access);
unsigned char (*glUnmapBuffer)(unsigned int target);
diff --git a/include/encoder/encoder.h b/include/encoder/encoder.h
new file mode 100644
index 0000000..7e550f6
--- /dev/null
+++ b/include/encoder/encoder.h
@@ -0,0 +1,43 @@
+#ifndef GSR_ENCODER_H
+#define GSR_ENCODER_H
+
+#include "../replay_buffer/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;
+ 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, gsr_replay_storage replay_storage, size_t replay_buffer_num_packets, double replay_buffer_time, const char *replay_directory);
+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 49f48bd..7a706b5 100644
--- a/include/encoder/video/video.h
+++ b/include/encoder/video/video.h
@@ -4,24 +4,27 @@
#include "../../color_conversion.h"
#include <stdbool.h>
+#define GSR_MAX_RECORDING_DESTINATIONS 128
+
typedef struct gsr_video_encoder gsr_video_encoder;
typedef struct AVCodecContext AVCodecContext;
typedef struct AVFrame AVFrame;
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;
};
+/* 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);
+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);
#endif /* GSR_ENCODER_VIDEO_H */
diff --git a/include/pipewire_audio.h b/include/pipewire_audio.h
index 10d8c9b..68e5356 100644
--- a/include/pipewire_audio.h
+++ b/include/pipewire_audio.h
@@ -8,12 +8,6 @@
#include <stdbool.h>
-#define GSR_PIPEWIRE_AUDIO_MAX_STREAM_NODES 128
-#define GSR_PIPEWIRE_AUDIO_MAX_PORTS 256
-#define GSR_PIPEWIRE_AUDIO_MAX_LINKS 256
-#define GSR_PIPEWIRE_AUDIO_MAX_REQUESTED_LINKS 32
-#define GSR_PIPEWIRE_AUDIO_MAX_VIRTUAL_SINKS 32
-
typedef enum {
GSR_PIPEWIRE_AUDIO_NODE_TYPE_STREAM_OUTPUT, /* Application audio */
GSR_PIPEWIRE_AUDIO_NODE_TYPE_STREAM_INPUT, /* Audio recording input */
@@ -84,20 +78,25 @@ typedef struct {
char default_output_device_name[128];
char default_input_device_name[128];
- gsr_pipewire_audio_node stream_nodes[GSR_PIPEWIRE_AUDIO_MAX_STREAM_NODES];
- int num_stream_nodes;
+ gsr_pipewire_audio_node *stream_nodes;
+ size_t num_stream_nodes;
+ size_t stream_nodes_capacity_items;
- gsr_pipewire_audio_port ports[GSR_PIPEWIRE_AUDIO_MAX_PORTS];
- int num_ports;
+ gsr_pipewire_audio_port *ports;
+ size_t num_ports;
+ size_t ports_capacity_items;
- gsr_pipewire_audio_link links[GSR_PIPEWIRE_AUDIO_MAX_LINKS];
- int num_links;
+ gsr_pipewire_audio_link *links;
+ size_t num_links;
+ size_t links_capacity_items;
- gsr_pipewire_audio_requested_link requested_links[GSR_PIPEWIRE_AUDIO_MAX_REQUESTED_LINKS];
- int num_requested_links;
+ gsr_pipewire_audio_requested_link *requested_links;
+ size_t num_requested_links;
+ size_t requested_links_capacity_items;
- struct pw_proxy *virtual_sink_proxies[GSR_PIPEWIRE_AUDIO_MAX_VIRTUAL_SINKS];
- int num_virtual_sink_proxies;
+ struct pw_proxy **virtual_sink_proxies;
+ size_t num_virtual_sink_proxies;
+ size_t virtual_sink_proxies_capacity_items;
} gsr_pipewire_audio;
bool gsr_pipewire_audio_init(gsr_pipewire_audio *self);
diff --git a/include/pipewire_video.h b/include/pipewire_video.h
index 92622b8..d98e43d 100644
--- a/include/pipewire_video.h
+++ b/include/pipewire_video.h
@@ -9,7 +9,7 @@
#include <spa/param/video/format.h>
#define GSR_PIPEWIRE_VIDEO_MAX_MODIFIERS 1024
-#define GSR_PIPEWIRE_VIDEO_MAX_VIDEO_FORMATS 12
+#define GSR_PIPEWIRE_VIDEO_MAX_VIDEO_FORMATS 6
#define GSR_PIPEWIRE_VIDEO_DMABUF_MAX_PLANES 4
typedef struct gsr_egl gsr_egl;
@@ -65,6 +65,7 @@ typedef struct {
struct spa_video_info format;
int server_version_sync;
bool negotiated;
+ bool renegotiated;
bool damaged;
struct {
@@ -94,6 +95,9 @@ typedef struct {
uint64_t modifiers[GSR_PIPEWIRE_VIDEO_MAX_MODIFIERS];
size_t num_modifiers;
+
+ bool paused;
+ double paused_start_secs;
} gsr_pipewire_video;
/*
@@ -108,5 +112,6 @@ void gsr_pipewire_video_deinit(gsr_pipewire_video *self);
bool gsr_pipewire_video_map_texture(gsr_pipewire_video *self, gsr_texture_map texture_map, gsr_pipewire_video_region *region, gsr_pipewire_video_region *cursor_region, gsr_pipewire_video_dmabuf_data *dmabuf_data, int *num_dmabuf_data, uint32_t *fourcc, uint64_t *modifiers, bool *using_external_image);
bool gsr_pipewire_video_is_damaged(gsr_pipewire_video *self);
void gsr_pipewire_video_clear_damage(gsr_pipewire_video *self);
+bool gsr_pipewire_video_should_restart(gsr_pipewire_video *self);
#endif /* GSR_PIPEWIRE_VIDEO_H */
diff --git a/include/replay_buffer/replay_buffer.h b/include/replay_buffer/replay_buffer.h
new file mode 100644
index 0000000..a04a3be
--- /dev/null
+++ b/include/replay_buffer/replay_buffer.h
@@ -0,0 +1,54 @@
+#ifndef GSR_REPLAY_BUFFER_H
+#define GSR_REPLAY_BUFFER_H
+
+#include "../defs.h"
+#include <pthread.h>
+#include <stdbool.h>
+#include <libavcodec/packet.h>
+
+typedef struct gsr_replay_buffer gsr_replay_buffer;
+
+typedef struct {
+ size_t packet_index;
+ size_t file_index;
+} gsr_replay_buffer_iterator;
+
+struct gsr_replay_buffer {
+ void (*destroy)(gsr_replay_buffer *self);
+ bool (*append)(gsr_replay_buffer *self, const AVPacket *av_packet, double timestamp);
+ void (*clear)(gsr_replay_buffer *self);
+ AVPacket* (*iterator_get_packet)(gsr_replay_buffer *self, gsr_replay_buffer_iterator iterator);
+ /* The returned data should be free'd with free */
+ uint8_t* (*iterator_get_packet_data)(gsr_replay_buffer *self, gsr_replay_buffer_iterator iterator);
+ /* The clone has to be destroyed before the replay buffer it clones is destroyed */
+ gsr_replay_buffer* (*clone)(gsr_replay_buffer *self);
+ /* Returns {0, 0} if replay buffer is empty */
+ gsr_replay_buffer_iterator (*find_packet_index_by_time_passed)(gsr_replay_buffer *self, int seconds);
+ /* Returns {-1, 0} if not found */
+ gsr_replay_buffer_iterator (*find_keyframe)(gsr_replay_buffer *self, gsr_replay_buffer_iterator start_iterator, int stream_index, bool invert_stream_index);
+ bool (*iterator_next)(gsr_replay_buffer *self, gsr_replay_buffer_iterator *iterator);
+
+ pthread_mutex_t mutex;
+ bool mutex_initialized;
+ gsr_replay_buffer *original_replay_buffer;
+};
+
+gsr_replay_buffer* gsr_replay_buffer_create(gsr_replay_storage replay_storage, const char *replay_directory, double replay_buffer_time, size_t replay_buffer_num_packets);
+void gsr_replay_buffer_destroy(gsr_replay_buffer *self);
+
+void gsr_replay_buffer_lock(gsr_replay_buffer *self);
+void gsr_replay_buffer_unlock(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);
+AVPacket* gsr_replay_buffer_iterator_get_packet(gsr_replay_buffer *self, gsr_replay_buffer_iterator iterator);
+/* The returned data should be free'd with free */
+uint8_t* gsr_replay_buffer_iterator_get_packet_data(gsr_replay_buffer *self, gsr_replay_buffer_iterator iterator);
+/* The clone has to be destroyed before the replay buffer it clones is destroyed */
+gsr_replay_buffer* gsr_replay_buffer_clone(gsr_replay_buffer *self);
+/* Returns {0, 0} if replay buffer is empty */
+gsr_replay_buffer_iterator gsr_replay_buffer_find_packet_index_by_time_passed(gsr_replay_buffer *self, int seconds);
+/* Returns {-1, 0} if not found */
+gsr_replay_buffer_iterator gsr_replay_buffer_find_keyframe(gsr_replay_buffer *self, gsr_replay_buffer_iterator start_iterator, int stream_index, bool invert_stream_index);
+bool gsr_replay_buffer_iterator_next(gsr_replay_buffer *self, gsr_replay_buffer_iterator *iterator);
+
+#endif /* GSR_REPLAY_BUFFER_H */ \ No newline at end of file
diff --git a/include/replay_buffer/replay_buffer_disk.h b/include/replay_buffer/replay_buffer_disk.h
new file mode 100644
index 0000000..6873bb0
--- /dev/null
+++ b/include/replay_buffer/replay_buffer_disk.h
@@ -0,0 +1,44 @@
+#ifndef GSR_REPLAY_BUFFER_DISK_H
+#define GSR_REPLAY_BUFFER_DISK_H
+
+#include "replay_buffer.h"
+#include <limits.h>
+
+#define GSR_REPLAY_BUFFER_CAPACITY_NUM_FILES 1024
+
+typedef struct {
+ AVPacket packet;
+ size_t data_index;
+ double timestamp;
+} gsr_av_packet_disk;
+
+typedef struct {
+ size_t id;
+ double start_timestamp;
+ double end_timestamp;
+ int ref_counter;
+ int fd;
+
+ gsr_av_packet_disk *packets;
+ size_t capacity_num_packets;
+ size_t num_packets;
+} gsr_replay_buffer_file;
+
+typedef struct {
+ gsr_replay_buffer replay_buffer;
+ double replay_buffer_time;
+
+ size_t storage_counter;
+ size_t storage_num_bytes_written;
+ int storage_fd;
+ gsr_replay_buffer_file *files[GSR_REPLAY_BUFFER_CAPACITY_NUM_FILES]; // GSR_REPLAY_BUFFER_CAPACITY_NUM_FILES * REPLAY_BUFFER_FILE_SIZE_BYTES = 256gb, should be enough for everybody
+ size_t num_files;
+
+ char replay_directory[PATH_MAX];
+
+ bool owns_directory;
+} gsr_replay_buffer_disk;
+
+gsr_replay_buffer* gsr_replay_buffer_disk_create(const char *replay_directory, double replay_buffer_time);
+
+#endif /* GSR_REPLAY_BUFFER_DISK_H */ \ No newline at end of file
diff --git a/include/replay_buffer/replay_buffer_ram.h b/include/replay_buffer/replay_buffer_ram.h
new file mode 100644
index 0000000..a43d1b9
--- /dev/null
+++ b/include/replay_buffer/replay_buffer_ram.h
@@ -0,0 +1,22 @@
+#ifndef GSR_REPLAY_BUFFER_RAM_H
+#define GSR_REPLAY_BUFFER_RAM_H
+
+#include "replay_buffer.h"
+
+typedef struct {
+ AVPacket packet;
+ int ref_counter;
+ double timestamp;
+} gsr_av_packet_ram;
+
+typedef struct {
+ gsr_replay_buffer replay_buffer;
+ gsr_av_packet_ram **packets;
+ size_t capacity_num_packets;
+ size_t num_packets;
+ size_t index;
+} gsr_replay_buffer_ram;
+
+gsr_replay_buffer* gsr_replay_buffer_ram_create(size_t replay_buffer_num_packets);
+
+#endif /* GSR_REPLAY_BUFFER_RAM_H */ \ No newline at end of file
diff --git a/include/shader.h b/include/shader.h
index 8bc1104..285758d 100644
--- a/include/shader.h
+++ b/include/shader.h
@@ -1,6 +1,8 @@
#ifndef GSR_SHADER_H
#define GSR_SHADER_H
+#include <stdbool.h>
+
typedef struct gsr_egl gsr_egl;
typedef struct {
@@ -16,4 +18,6 @@ int gsr_shader_bind_attribute_location(gsr_shader *self, const char *attribute,
void gsr_shader_use(gsr_shader *self);
void gsr_shader_use_none(gsr_shader *self);
+void gsr_shader_enable_debug_output(bool enable);
+
#endif /* GSR_SHADER_H */
diff --git a/include/utils.h b/include/utils.h
index b6f51c1..74ccf18 100644
--- a/include/utils.h
+++ b/include/utils.h
@@ -7,8 +7,6 @@
#include <stdbool.h>
#include <stdint.h>
-#define CONNECTOR_TYPE_COUNTS 32
-
typedef struct AVCodecContext AVCodecContext;
typedef struct AVFrame AVFrame;
@@ -29,12 +27,6 @@ typedef struct {
bool found_monitor;
} get_monitor_by_name_userdata;
-typedef struct {
- int type;
- int count;
- int count_active;
-} drm_connector_type_count;
-
double clock_get_monotonic_seconds(void);
bool generate_random_characters(char *buffer, int buffer_size, const char *alphabet, size_t alphabet_size);
bool generate_random_characters_standard_alphabet(char *buffer, int buffer_size);
@@ -46,7 +38,7 @@ bool get_monitor_by_name(const gsr_egl *egl, gsr_connection_type connection_type
bool drm_monitor_get_display_server_data(const gsr_window *window, const gsr_monitor *monitor, gsr_monitor_rotation *monitor_rotation, vec2i *monitor_position);
int get_connector_type_by_name(const char *name);
-drm_connector_type_count* drm_connector_types_get_index(drm_connector_type_count *type_counts, int *num_type_counts, int connector_type);
+int get_connector_type_id_by_name(const char *name);
uint32_t monitor_identifier_from_type_and_count(int monitor_type_index, int monitor_type_count);
bool gl_get_gpu_info(gsr_egl *egl, gsr_gpu_info *info);
@@ -61,7 +53,6 @@ int create_directory_recursive(char *path);
/* |img_attr| needs to be at least 44 in size */
void setup_dma_buf_attrs(intptr_t *img_attr, uint32_t format, uint32_t width, uint32_t height, const int *fds, const uint32_t *offsets, const uint32_t *pitches, const uint64_t *modifiers, int num_planes, bool use_modifier);
-bool video_codec_context_is_vaapi(AVCodecContext *video_codec_context);
vec2i scale_keep_aspect_ratio(vec2i from, vec2i to);