Add support for camera (yuyv, mjpeg) and multiple capture sources

This commit is contained in:
dec05eba
2025-12-23 18:05:48 +01:00
parent 390f2708f4
commit 62e180903e
30 changed files with 2228 additions and 632 deletions

View File

@@ -10,6 +10,15 @@ typedef struct gsr_egl gsr_egl;
#define NUM_ARGS 32
typedef enum {
GSR_CAPTURE_SOURCE_TYPE_WINDOW,
GSR_CAPTURE_SOURCE_TYPE_FOCUSED_WINDOW,
GSR_CAPTURE_SOURCE_TYPE_MONITOR,
GSR_CAPTURE_SOURCE_TYPE_REGION,
GSR_CAPTURE_SOURCE_TYPE_PORTAL,
GSR_CAPTURE_SOURCE_TYPE_V4L2
} CaptureSourceType;
typedef enum {
ARG_TYPE_STRING,
ARG_TYPE_BOOLEAN,
@@ -52,6 +61,7 @@ typedef struct {
void (*info)(void *userdata);
void (*list_audio_devices)(void *userdata);
void (*list_application_audio)(void *userdata);
void (*list_v4l2_devices)(void *userdata);
void (*list_capture_options)(const char *card_path, void *userdata);
} args_handlers;
@@ -68,7 +78,8 @@ typedef struct {
gsr_bitrate_mode bitrate_mode;
gsr_video_quality video_quality;
gsr_replay_storage replay_storage;
char window[64];
const char *capture_source;
const char *container_format;
const char *filename;
const char *replay_recording_directory;

View File

@@ -12,24 +12,34 @@ typedef struct AVFrame AVFrame;
typedef struct AVMasteringDisplayMetadata AVMasteringDisplayMetadata;
typedef struct AVContentLightMetadata AVContentLightMetadata;
typedef struct gsr_capture gsr_capture;
typedef struct gsr_capture_metadata gsr_capture_metadata;
typedef struct {
// Width and height of the video
int video_width;
int video_height;
// Width and height of the frame at the start of capture, the target size
int recording_width;
int recording_height;
typedef enum {
GSR_CAPTURE_ALIGN_START,
GSR_CAPTURE_ALIGN_CENTER,
GSR_CAPTURE_ALIGN_END
} gsr_capture_alignment;
struct gsr_capture_metadata {
// Size of the video
vec2i video_size;
// The captured output gets scaled to this size. By default this will be the same size as the captured target
vec2i recording_size;
vec2i position;
int fps;
} gsr_capture_metadata;
gsr_capture_alignment halign;
gsr_capture_alignment valign;
gsr_flip flip;
};
struct gsr_capture {
/* These methods should not be called manually. Call gsr_capture_* instead. |capture_metadata->video_width| and |capture_metadata->video_height| should be set by this function */
/* These methods should not be called manually. Call gsr_capture_* instead. |capture_metadata->video_size| 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 */
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) */
void (*pre_capture)(gsr_capture *cap, gsr_capture_metadata *capture_metadata, gsr_color_conversion *color_conversion); /* can be NULL */
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 */

View File

@@ -2,9 +2,13 @@
#define GSR_CAPTURE_KMS_H
#include "capture.h"
#include "../cursor.h"
#include "../../kms/kms_shared.h"
typedef struct {
gsr_egl *egl;
gsr_cursor *x11_cursor;
gsr_kms_response *kms_response;
const char *display_to_capture; /* A copy is made of this */
bool hdr;
bool record_cursor;

30
include/capture/v4l2.h Normal file
View File

@@ -0,0 +1,30 @@
#ifndef GSR_CAPTURE_V4L2_H
#define GSR_CAPTURE_V4L2_H
#include "capture.h"
typedef enum {
GSR_CAPTURE_V4L2_PIXFMT_AUTO,
GSR_CAPTURE_V4L2_PIXFMT_YUYV,
GSR_CAPTURE_V4L2_PIXFMT_MJPEG
} gsr_capture_v4l2_pixfmt;
typedef struct {
bool yuyv;
bool mjpeg;
} gsr_capture_v4l2_supported_pixfmts;
typedef struct {
gsr_egl *egl;
vec2i output_resolution;
const char *device_path;
gsr_capture_v4l2_pixfmt pixfmt;
int fps;
} gsr_capture_v4l2_params;
gsr_capture* gsr_capture_v4l2_create(const gsr_capture_v4l2_params *params);
typedef void (*v4l2_devices_query_callback)(const char *path, gsr_capture_v4l2_supported_pixfmts supported_pixfmts, vec2i size, void *userdata);
void gsr_capture_v4l2_list_devices(v4l2_devices_query_callback callback, void *userdata);
#endif /* GSR_CAPTURE_V4L2_H */

View File

@@ -3,9 +3,11 @@
#include "capture.h"
#include "../vec2.h"
#include "../cursor.h"
typedef struct {
gsr_egl *egl;
gsr_cursor *cursor;
unsigned long window;
bool follow_focused; /* If this is set then |window| is ignored */
bool record_cursor;

View File

@@ -3,9 +3,11 @@
#include "capture.h"
#include "../vec2.h"
#include "../cursor.h"
typedef struct {
gsr_egl *egl;
gsr_cursor *cursor;
const char *display_to_capture; /* A copy is made of this */
bool record_cursor;
vec2i output_resolution;

View File

@@ -27,6 +27,12 @@ typedef enum {
GSR_ROT_270
} gsr_rotation;
typedef enum {
GSR_FLIP_NONE = 0,
GSR_FLIP_HORIZONTAL = (1 << 0),
GSR_FLIP_VERTICAL = (1 << 1)
} gsr_flip;
typedef struct {
int rotation_matrix;
int offset;
@@ -55,12 +61,14 @@ typedef struct {
unsigned int vertex_array_object_id;
unsigned int vertex_buffer_object_id;
bool schedule_clear;
} 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 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);
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_flip flip, gsr_source_color source_color, bool external_texture);
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);

View File

@@ -9,40 +9,62 @@
typedef struct _XDisplay Display;
typedef union _XEvent XEvent;
typedef enum {
GSR_DAMAGE_TRACK_NONE,
GSR_DAMAGE_TRACK_WINDOW,
GSR_DAMAGE_TRACK_MONITOR
} gsr_damage_track_type;
#define GSR_DAMAGE_MAX_MONITORS 32
#define GSR_DAMAGE_MAX_TRACKED_TARGETS 12
typedef struct {
int64_t window_id;
vec2i window_pos;
vec2i window_size;
uint64_t damage;
int refcount;
} gsr_damage_window;
typedef struct {
char *monitor_name;
gsr_monitor *monitor;
int refcount;
} gsr_damage_monitor;
typedef struct {
gsr_egl *egl;
Display *display;
bool track_cursor;
gsr_damage_track_type track_type;
int damage_event;
int damage_error;
uint64_t damage;
bool damaged;
uint64_t monitor_damage;
int randr_event;
int randr_error;
uint64_t window;
//vec2i window_pos;
vec2i window_size;
gsr_cursor *cursor;
gsr_monitor monitors[GSR_DAMAGE_MAX_MONITORS];
int num_monitors;
gsr_cursor cursor; /* Relative to |window| */
gsr_monitor monitor;
char monitor_name[32];
gsr_damage_window windows_tracked[GSR_DAMAGE_MAX_TRACKED_TARGETS];
int num_windows_tracked;
gsr_damage_monitor monitors_tracked[GSR_DAMAGE_MAX_TRACKED_TARGETS];
int num_monitors_tracked;
int all_monitors_tracked_refcount;
vec2i cursor_pos;
} gsr_damage;
bool gsr_damage_init(gsr_damage *self, gsr_egl *egl, bool track_cursor);
bool gsr_damage_init(gsr_damage *self, gsr_egl *egl, gsr_cursor *cursor, bool track_cursor);
void gsr_damage_deinit(gsr_damage *self);
bool gsr_damage_set_target_window(gsr_damage *self, uint64_t window);
bool gsr_damage_set_target_monitor(gsr_damage *self, const char *monitor_name);
/* This is reference counted */
bool gsr_damage_start_tracking_window(gsr_damage *self, int64_t window);
void gsr_damage_stop_tracking_window(gsr_damage *self, int64_t window);
/* This is reference counted. If |monitor_name| is NULL then all monitors are tracked */
bool gsr_damage_start_tracking_monitor(gsr_damage *self, const char *monitor_name);
void gsr_damage_stop_tracking_monitor(gsr_damage *self, const char *monitor_name);
void gsr_damage_on_event(gsr_damage *self, XEvent *xev);
void gsr_damage_tick(gsr_damage *self);
/* Also returns true if damage tracking is not available */

View File

@@ -140,6 +140,7 @@ typedef void(*__GLXextFuncPtr)(void);
#define GL_TEXTURE1 0x84C1
#define GL_SHADER_IMAGE_ACCESS_BARRIER_BIT 0x00000020
#define GL_ALL_BARRIER_BITS 0xFFFFFFFF
#define GL_PIXEL_UNPACK_BUFFER 0x88EC
#define GL_VENDOR 0x1F00
#define GL_RENDERER 0x1F01

View File

@@ -9,6 +9,7 @@
typedef struct AVCodecContext AVCodecContext;
typedef struct AVFrame AVFrame;
typedef struct gsr_capture_metadata gsr_capture_metadata;
typedef struct {
const char *name;
@@ -55,6 +56,7 @@ int create_directory_recursive(char *path);
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);
vec2i scale_keep_aspect_ratio(vec2i from, vec2i to);
vec2i gsr_capture_get_target_position(vec2i output_size, gsr_capture_metadata *capture_metadata);
unsigned int gl_create_texture(gsr_egl *egl, int width, int height, int internal_format, unsigned int format, int filter);