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.h23
-rw-r--r--include/capture/kms.h6
-rw-r--r--include/capture/nvfbc.h6
-rw-r--r--include/capture/portal.h2
-rw-r--r--include/capture/xcomposite.h2
-rw-r--r--include/capture/ximage.h18
-rw-r--r--include/color_conversion.h52
-rw-r--r--include/dbus.h26
-rw-r--r--include/defs.h92
-rw-r--r--include/egl.h43
-rw-r--r--include/encoder/encoder.h43
-rw-r--r--include/encoder/video/image.h15
-rw-r--r--include/encoder/video/video.h7
-rw-r--r--include/image_writer.h35
-rw-r--r--include/pipewire_audio.h58
-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.h6
-rw-r--r--include/sound.hpp3
-rw-r--r--include/utils.h21
-rw-r--r--include/window/wayland.h (renamed from include/window/window_wayland.h)0
-rw-r--r--include/window/x11.h (renamed from include/window/window_x11.h)0
25 files changed, 588 insertions, 103 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 dc5b7ac..c2128c5 100644
--- a/include/capture/capture.h
+++ b/include/capture/capture.h
@@ -13,31 +13,40 @@ typedef struct AVMasteringDisplayMetadata AVMasteringDisplayMetadata;
typedef struct AVContentLightMetadata AVContentLightMetadata;
typedef struct gsr_capture gsr_capture;
+typedef struct {
+ int width;
+ int height;
+ int fps;
+ AVCodecContext *video_codec_context; /* can be NULL */
+ AVFrame *frame; /* can be NULL, but will never be NULL if |video_codec_context| is set */
+} gsr_capture_metadata;
+
struct gsr_capture {
- /* These methods should not be called manually. Call gsr_capture_* instead */
- int (*start)(gsr_capture *cap, AVCodecContext *video_codec_context, AVFrame *frame);
+ /* 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, AVFrame *frame, 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 */
bool (*is_damaged)(gsr_capture *cap); /* can be NULL */
void (*clear_damage)(gsr_capture *cap); /* can be NULL */
- void (*destroy)(gsr_capture *cap, AVCodecContext *video_codec_context);
+ void (*destroy)(gsr_capture *cap);
void *priv; /* can be NULL */
bool started;
};
-int gsr_capture_start(gsr_capture *cap, AVCodecContext *video_codec_context, AVFrame *frame);
+int gsr_capture_start(gsr_capture *cap, gsr_capture_metadata *capture_metadata);
void gsr_capture_on_event(gsr_capture *cap, gsr_egl *egl);
void gsr_capture_tick(gsr_capture *cap);
bool gsr_capture_should_stop(gsr_capture *cap, bool *err);
-int gsr_capture_capture(gsr_capture *cap, AVFrame *frame, gsr_color_conversion *color_conversion);
+int gsr_capture_capture(gsr_capture *cap, gsr_capture_metadata *capture_metadata, gsr_color_conversion *color_conversion);
bool gsr_capture_uses_external_image(gsr_capture *cap);
bool gsr_capture_set_hdr_metadata(gsr_capture *cap, AVMasteringDisplayMetadata *mastering_display_metadata, AVContentLightMetadata *light_metadata);
-void gsr_capture_destroy(gsr_capture *cap, AVCodecContext *video_codec_context);
+void gsr_capture_destroy(gsr_capture *cap);
#endif /* GSR_CAPTURE_CAPTURE_H */
diff --git a/include/capture/kms.h b/include/capture/kms.h
index bf1ba62..ce09817 100644
--- a/include/capture/kms.h
+++ b/include/capture/kms.h
@@ -5,13 +5,13 @@
typedef struct {
gsr_egl *egl;
- const char *display_to_capture; /* if this is "screen", then the first monitor is captured. A copy is made of this */
- gsr_color_depth color_depth;
- gsr_color_range color_range;
+ const char *display_to_capture; /* A copy is made of this */
bool hdr;
bool record_cursor;
int fps;
vec2i output_resolution;
+ vec2i region_size;
+ vec2i region_position;
} gsr_capture_kms_params;
gsr_capture* gsr_capture_kms_create(const gsr_capture_kms_params *params);
diff --git a/include/capture/nvfbc.h b/include/capture/nvfbc.h
index 90da7fa..7e30d01 100644
--- a/include/capture/nvfbc.h
+++ b/include/capture/nvfbc.h
@@ -8,13 +8,11 @@ typedef struct {
gsr_egl *egl;
const char *display_to_capture; /* if this is "screen", then the entire x11 screen is captured (all displays). A copy is made of this */
int fps;
- vec2i pos;
- vec2i size;
bool direct_capture;
- gsr_color_depth color_depth;
- gsr_color_range color_range;
bool record_cursor;
vec2i output_resolution;
+ vec2i region_size;
+ vec2i region_position;
} gsr_capture_nvfbc_params;
gsr_capture* gsr_capture_nvfbc_create(const gsr_capture_nvfbc_params *params);
diff --git a/include/capture/portal.h b/include/capture/portal.h
index 3989b98..74cdba9 100644
--- a/include/capture/portal.h
+++ b/include/capture/portal.h
@@ -5,8 +5,6 @@
typedef struct {
gsr_egl *egl;
- gsr_color_depth color_depth;
- gsr_color_range color_range;
bool record_cursor;
bool restore_portal_session;
/* If this is set to NULL then this defaults to $XDG_CONFIG_HOME/gpu-screen-recorder/restore_token ($XDG_CONFIG_HOME defaults to $HOME/.config) */
diff --git a/include/capture/xcomposite.h b/include/capture/xcomposite.h
index 45eb481..bf6532e 100644
--- a/include/capture/xcomposite.h
+++ b/include/capture/xcomposite.h
@@ -8,9 +8,7 @@ typedef struct {
gsr_egl *egl;
unsigned long window;
bool follow_focused; /* If this is set then |window| is ignored */
- gsr_color_range color_range;
bool record_cursor;
- gsr_color_depth color_depth;
vec2i output_resolution;
} gsr_capture_xcomposite_params;
diff --git a/include/capture/ximage.h b/include/capture/ximage.h
new file mode 100644
index 0000000..e6c3607
--- /dev/null
+++ b/include/capture/ximage.h
@@ -0,0 +1,18 @@
+#ifndef GSR_CAPTURE_XIMAGE_H
+#define GSR_CAPTURE_XIMAGE_H
+
+#include "capture.h"
+#include "../vec2.h"
+
+typedef struct {
+ gsr_egl *egl;
+ const char *display_to_capture; /* A copy is made of this */
+ bool record_cursor;
+ vec2i output_resolution;
+ vec2i region_size;
+ vec2i region_position;
+} gsr_capture_ximage_params;
+
+gsr_capture* gsr_capture_ximage_create(const gsr_capture_ximage_params *params);
+
+#endif /* GSR_CAPTURE_XIMAGE_H */
diff --git a/include/color_conversion.h b/include/color_conversion.h
index b80be21..cb074a1 100644
--- a/include/color_conversion.h
+++ b/include/color_conversion.h
@@ -2,18 +2,13 @@
#define GSR_COLOR_CONVERSION_H
#include "shader.h"
+#include "defs.h"
#include "vec2.h"
#include <stdbool.h>
-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;
+#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_SOURCE_COLOR_RGB,
@@ -26,10 +21,24 @@ typedef enum {
GSR_DESTINATION_COLOR_RGB8
} gsr_destination_color;
+typedef enum {
+ GSR_ROT_0,
+ GSR_ROT_90,
+ GSR_ROT_180,
+ GSR_ROT_270
+} gsr_rotation;
+
typedef struct {
+ int rotation_matrix;
int offset;
- int rotation;
-} gsr_color_uniforms;
+} gsr_color_graphics_uniforms;
+
+typedef struct {
+ int rotation_matrix;
+ int source_position;
+ int target_position;
+ int scale;
+} gsr_color_compute_uniforms;
typedef struct {
gsr_egl *egl;
@@ -41,23 +50,36 @@ 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[4];
- gsr_shader shaders[4];
+ 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[2];
+ unsigned int framebuffers[GSR_COLOR_CONVERSION_MAX_FRAMEBUFFERS];
unsigned int vertex_array_object_id;
unsigned int vertex_buffer_object_id;
+
+ int max_local_size_dim;
} gsr_color_conversion;
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 source_pos, vec2i source_size, vec2i texture_pos, vec2i texture_size, float 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);
#endif /* GSR_COLOR_CONVERSION_H */
diff --git a/include/dbus.h b/include/dbus.h
index 6978634..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);
@@ -37,7 +37,11 @@ void gsr_dbus_deinit(gsr_dbus *self);
/* The follow functions should be called in order to setup ScreenCast properly */
/* These functions that return an int return the response status code */
int gsr_dbus_screencast_create_session(gsr_dbus *self, char **session_handle);
-int gsr_dbus_screencast_select_sources(gsr_dbus *self, const char *session_handle, gsr_portal_capture_type capture_type, gsr_portal_cursor_mode cursor_mode);
+/*
+ |capture_type| is a bitmask of gsr_portal_capture_type values. gsr_portal_capture_type values that are not supported by the desktop portal will be ignored.
+ |gsr_portal_cursor_mode| is a bitmask of gsr_portal_cursor_mode values. gsr_portal_cursor_mode values that are not supported will be ignored.
+*/
+int gsr_dbus_screencast_select_sources(gsr_dbus *self, const char *session_handle, uint32_t capture_type, uint32_t cursor_mode);
int gsr_dbus_screencast_start(gsr_dbus *self, const char *session_handle, uint32_t *pipewire_node);
bool gsr_dbus_screencast_open_pipewire_remote(gsr_dbus *self, const char *session_handle, int *pipewire_fd);
const char* gsr_dbus_screencast_get_restore_token(gsr_dbus *self);
diff --git a/include/defs.h b/include/defs.h
index 76e798e..d780005 100644
--- a/include/defs.h
+++ b/include/defs.h
@@ -3,34 +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_NVIDIA,
+ 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 8a2b6c2..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
@@ -98,7 +100,7 @@ typedef void(*__GLXextFuncPtr)(void);
#define GL_TEXTURE_EXTERNAL_OES 0x8D65
#define GL_RED 0x1903
#define GL_GREEN 0x1904
-#define GL_BLUE 0x1905
+#define GL_BLUE 0x1905
#define GL_ALPHA 0x1906
#define GL_TEXTURE_SWIZZLE_RGBA 0x8E46
#define GL_RG 0x8227
@@ -111,6 +113,7 @@ typedef void(*__GLXextFuncPtr)(void);
#define GL_R16 0x822A
#define GL_RG16 0x822C
#define GL_RGB16 0x8054
+#define GL_RGBA32F 0x8814
#define GL_UNSIGNED_BYTE 0x1401
#define GL_COLOR_BUFFER_BIT 0x00004000
#define GL_TEXTURE_WRAP_S 0x2802
@@ -132,6 +135,16 @@ typedef void(*__GLXextFuncPtr)(void);
#define GL_ONE_MINUS_SRC_ALPHA 0x0303
#define GL_DEBUG_OUTPUT 0x92E0
#define GL_SCISSOR_TEST 0x0C11
+#define GL_PACK_ALIGNMENT 0x0D05
+#define GL_UNPACK_ALIGNMENT 0x0CF5
+#define GL_READ_ONLY 0x88B8
+#define GL_WRITE_ONLY 0x88B9
+#define GL_READ_WRITE 0x88BA
+#define GL_MAX_COMPUTE_FIXED_GROUP_INVOCATIONS 0x90EB
+#define GL_TEXTURE0 0x84C0
+#define GL_TEXTURE1 0x84C1
+#define GL_SHADER_IMAGE_ACCESS_BARRIER_BIT 0x00000020
+#define GL_ALL_BARRIER_BITS 0xFFFFFFFF
#define GL_VENDOR 0x1F00
#define GL_RENDERER 0x1F01
@@ -141,6 +154,7 @@ typedef void(*__GLXextFuncPtr)(void);
#define GL_INFO_LOG_LENGTH 0x8B84
#define GL_FRAGMENT_SHADER 0x8B30
#define GL_VERTEX_SHADER 0x8B31
+#define GL_COMPUTE_SHADER 0x91B9
#define GL_COMPILE_STATUS 0x8B81
#define GL_LINK_STATUS 0x8B82
@@ -155,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,
@@ -205,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);
@@ -228,15 +256,22 @@ struct gsr_egl {
void (*glClearColor)(float red, float green, float blue, float alpha);
void (*glGenTextures)(int n, unsigned int *textures);
void (*glDeleteTextures)(int n, const unsigned int *texture);
+ void (*glActiveTexture)(unsigned int texture);
void (*glBindTexture)(unsigned int target, unsigned int texture);
+ void (*glBindImageTexture)(unsigned int unit, unsigned int texture, int level, unsigned char layered, int layer, unsigned int access, unsigned int format);
void (*glTexParameteri)(unsigned int target, unsigned int pname, int param);
void (*glTexParameteriv)(unsigned int target, unsigned int pname, const int *params);
+ void (*glTexParameterfv)(unsigned int target, unsigned int pname, const float *params);
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);
void (*glDeleteFramebuffers)(int n, const unsigned int *framebuffers);
+ void (*glDispatchCompute)(unsigned int num_groups_x, unsigned int num_groups_y, unsigned int num_groups_z);
+ void (*glMemoryBarrier)(unsigned int barriers);
void (*glViewport)(int x, int y, int width, int height);
void (*glFramebufferTexture2D)(unsigned int target, unsigned int attachment, unsigned int textarget, unsigned int texture, int level);
void (*glDrawBuffers)(int n, const unsigned int *bufs);
@@ -269,14 +304,20 @@ struct gsr_egl {
void (*glEnable)(unsigned int cap);
void (*glDisable)(unsigned int cap);
void (*glBlendFunc)(unsigned int sfactor, unsigned int dfactor);
+ void (*glPixelStorei)(unsigned int pname, int param);
int (*glGetUniformLocation)(unsigned int program, const char *name);
void (*glUniform1f)(int location, float v0);
void (*glUniform2f)(int location, float v0, float v1);
+ void (*glUniform1i)(int location, int v0);
+ void (*glUniform2i)(int location, int v0, int v1);
+ 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);
+ void (*glGetIntegerv)(unsigned int pname, int *params);
};
bool gsr_egl_load(gsr_egl *self, gsr_window *window, bool is_monitor_capture, bool enable_debug);
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/image.h b/include/encoder/video/image.h
deleted file mode 100644
index 76c7bd4..0000000
--- a/include/encoder/video/image.h
+++ /dev/null
@@ -1,15 +0,0 @@
-#ifndef GSR_ENCODER_VIDEO_IMAGE_H
-#define GSR_ENCODER_VIDEO_IMAGE_H
-
-#include "video.h"
-
-typedef struct gsr_egl gsr_egl;
-
-typedef struct {
- gsr_egl *egl;
- gsr_color_depth color_depth;
-} gsr_video_encoder_image_params;
-
-gsr_video_encoder* gsr_video_encoder_image_create(const gsr_video_encoder_image_params *params);
-
-#endif /* GSR_ENCODER_VIDEO_IMAGE_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/image_writer.h b/include/image_writer.h
new file mode 100644
index 0000000..65e7497
--- /dev/null
+++ b/include/image_writer.h
@@ -0,0 +1,35 @@
+#ifndef GSR_IMAGE_WRITER_H
+#define GSR_IMAGE_WRITER_H
+
+#include <stdbool.h>
+
+typedef struct gsr_egl gsr_egl;
+
+typedef enum {
+ GSR_IMAGE_FORMAT_JPEG,
+ GSR_IMAGE_FORMAT_PNG
+} gsr_image_format;
+
+typedef enum {
+ GSR_IMAGE_WRITER_SOURCE_OPENGL,
+ GSR_IMAGE_WRITER_SOURCE_MEMORY
+} gsr_image_writer_source;
+
+typedef struct {
+ gsr_image_writer_source source;
+ gsr_egl *egl;
+ int width;
+ int height;
+ unsigned int texture;
+ const void *memory; /* Reference */
+} gsr_image_writer;
+
+bool gsr_image_writer_init_opengl(gsr_image_writer *self, gsr_egl *egl, int width, int height);
+/* |memory| is taken as a reference. The data is expected to be in rgba8 format (8 bit rgba) */
+bool gsr_image_writer_init_memory(gsr_image_writer *self, const void *memory, int width, int height);
+void gsr_image_writer_deinit(gsr_image_writer *self);
+
+/* Quality is between 1 and 100 where 100 is the max quality. Quality doesn't apply to lossless formats */
+bool gsr_image_writer_write_to_file(gsr_image_writer *self, const char *filepath, gsr_image_format image_format, int quality);
+
+#endif /* GSR_IMAGE_WRITER_H */
diff --git a/include/pipewire_audio.h b/include/pipewire_audio.h
index e2ffd49..68e5356 100644
--- a/include/pipewire_audio.h
+++ b/include/pipewire_audio.h
@@ -8,11 +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_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 */
@@ -37,14 +32,31 @@ typedef struct {
char *name;
} gsr_pipewire_audio_port;
+typedef struct {
+ uint32_t id;
+ uint32_t output_node_id;
+ uint32_t input_node_id;
+} gsr_pipewire_audio_link;
+
typedef enum {
GSR_PIPEWIRE_AUDIO_LINK_INPUT_TYPE_STREAM, /* Application */
GSR_PIPEWIRE_AUDIO_LINK_INPUT_TYPE_SINK /* Combined (virtual) sink */
} gsr_pipewire_audio_link_input_type;
+typedef enum {
+ GSR_PIPEWIRE_AUDIO_REQUESTED_TYPE_STANDARD,
+ GSR_PIPEWIRE_AUDIO_REQUESTED_TYPE_DEFAULT_OUTPUT,
+ GSR_PIPEWIRE_AUDIO_REQUESTED_TYPE_DEFAULT_INPUT
+} gsr_pipewire_audio_requested_type;
+
typedef struct {
- char **output_names;
- int num_output_names;
+ char *name;
+ gsr_pipewire_audio_requested_type type;
+} gsr_pipewire_audio_requested_output;
+
+typedef struct {
+ gsr_pipewire_audio_requested_output *outputs;
+ int num_outputs;
char *input_name;
bool inverted;
gsr_pipewire_audio_node_type output_type;
@@ -60,17 +72,31 @@ typedef struct {
struct spa_hook registry_listener;
int server_version_sync;
- gsr_pipewire_audio_node stream_nodes[GSR_PIPEWIRE_AUDIO_MAX_STREAM_NODES];
- int num_stream_nodes;
+ struct pw_proxy *metadata_proxy;
+ struct spa_hook metadata_listener;
+ struct spa_hook metadata_proxy_listener;
+ char default_output_device_name[128];
+ char default_input_device_name[128];
+
+ gsr_pipewire_audio_node *stream_nodes;
+ size_t num_stream_nodes;
+ size_t stream_nodes_capacity_items;
+
+ gsr_pipewire_audio_port *ports;
+ size_t num_ports;
+ size_t ports_capacity_items;
- gsr_pipewire_audio_port ports[GSR_PIPEWIRE_AUDIO_MAX_PORTS];
- int num_ports;
+ 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);
@@ -118,6 +144,8 @@ bool gsr_pipewire_audio_add_link_from_apps_to_sink_inverted(gsr_pipewire_audio *
If a device or a new device starts outputting audio after this function is called and the device name matches
then it will automatically link the audio sources.
|source_names| and |sink_name_input| are case-insensitive matches.
+ |source_names| can include "default_output" or "default_input" to use the default output/input
+ and it will automatically switch when the default output/input is changed in system audio settings.
*/
bool gsr_pipewire_audio_add_link_from_sources_to_sink(gsr_pipewire_audio *self, const char **source_names, int num_source_names, const char *sink_name_input);
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 57d1096..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 {
@@ -9,11 +11,13 @@ typedef struct {
} gsr_shader;
/* |vertex_shader| or |fragment_shader| may be NULL */
-int gsr_shader_init(gsr_shader *self, gsr_egl *egl, const char *vertex_shader, const char *fragment_shader);
+int gsr_shader_init(gsr_shader *self, gsr_egl *egl, const char *vertex_shader, const char *fragment_shader, const char *compute_shader);
void gsr_shader_deinit(gsr_shader *self);
int gsr_shader_bind_attribute_location(gsr_shader *self, const char *attribute, int location);
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/sound.hpp b/include/sound.hpp
index 215e167..87e2e2d 100644
--- a/include/sound.hpp
+++ b/include/sound.hpp
@@ -61,6 +61,9 @@ typedef enum {
/*
Get a sound device by name, returning the device into the |device| parameter.
+ |device_name| can be a device name or "default_output" or "default_input".
+ If the device name is "default_output" or "default_input" then it will automatically switch which
+ device is records from when the default output/input is changed in the system audio settings.
Returns 0 on success, or a negative value on failure.
*/
int sound_device_get_by_name(SoundDevice *device, const char *device_name, const char *description, unsigned int num_channels, unsigned int period_frame_size, AudioFormat audio_format);
diff --git a/include/utils.h b/include/utils.h
index f9b41b9..74ccf18 100644
--- a/include/utils.h
+++ b/include/utils.h
@@ -7,15 +7,13 @@
#include <stdbool.h>
#include <stdint.h>
-#define CONNECTOR_TYPE_COUNTS 32
-
typedef struct AVCodecContext AVCodecContext;
typedef struct AVFrame AVFrame;
typedef struct {
const char *name;
int name_len;
- vec2i pos;
+ vec2i pos; /* This is 0, 0 on wayland. Use |drm_monitor_get_display_server_data| to get the position */
vec2i size;
uint32_t connector_id; /* Only on x11 and drm */
gsr_monitor_rotation rotation; /* Only on x11 and wayland */
@@ -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);
@@ -43,15 +35,13 @@ typedef void (*active_monitor_callback)(const gsr_monitor *monitor, void *userda
void for_each_active_monitor_output_x11_not_cached(Display *display, active_monitor_callback callback, void *userdata);
void for_each_active_monitor_output(const gsr_window *window, const char *card_path, gsr_connection_type connection_type, active_monitor_callback callback, void *userdata);
bool get_monitor_by_name(const gsr_egl *egl, gsr_connection_type connection_type, const char *name, gsr_monitor *monitor);
-gsr_monitor_rotation drm_monitor_get_display_server_rotation(const gsr_window *window, const gsr_monitor *monitor);
+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);
-bool version_greater_than(int major, int minor, int patch, int other_major, int other_minor, int other_patch);
-bool gl_driver_version_greater_than(const gsr_gpu_info *gpu_info, int major, int minor, int patch);
bool try_card_has_valid_plane(const char *card_path);
/* |output| should be at least 128 bytes in size */
@@ -63,10 +53,9 @@ 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);
-bool vaapi_copy_drm_planes_to_video_surface(AVCodecContext *video_codec_context, AVFrame *video_frame, vec2i source_pos, vec2i source_size, vec2i dest_pos, vec2i dest_size, uint32_t format, vec2i size, const int *fds, const uint32_t *offsets, const uint32_t *pitches, const uint64_t *modifiers, int num_planes);
-bool vaapi_copy_egl_image_to_video_surface(gsr_egl *egl, EGLImage image, vec2i source_pos, vec2i source_size, vec2i dest_pos, vec2i dest_size, AVCodecContext *video_codec_context, AVFrame *video_frame);
vec2i scale_keep_aspect_ratio(vec2i from, vec2i to);
+unsigned int gl_create_texture(gsr_egl *egl, int width, int height, int internal_format, unsigned int format, int filter);
+
#endif /* GSR_UTILS_H */
diff --git a/include/window/window_wayland.h b/include/window/wayland.h
index 3535b0f..3535b0f 100644
--- a/include/window/window_wayland.h
+++ b/include/window/wayland.h
diff --git a/include/window/window_x11.h b/include/window/x11.h
index e0c2948..e0c2948 100644
--- a/include/window/window_x11.h
+++ b/include/window/x11.h