Prepare for pipewire audio routing

This commit is contained in:
dec05eba
2024-11-08 18:23:50 +01:00
parent ab662f1ed5
commit 0686b924de
9 changed files with 140 additions and 110 deletions

4
include/pipewire_audio.h Normal file
View File

@@ -0,0 +1,4 @@
#ifndef GSR_PIPEWIRE_AUDIO_H
#define GSR_PIPEWIRE_AUDIO_H
#endif /* GSR_PIPEWIRE_AUDIO_H */

View File

@@ -1,5 +1,5 @@
#ifndef GSR_PIPEWIRE_H #ifndef GSR_PIPEWIRE_VIDEO_H
#define GSR_PIPEWIRE_H #define GSR_PIPEWIRE_VIDEO_H
#include <stdbool.h> #include <stdbool.h>
#include <stdint.h> #include <stdint.h>
@@ -8,9 +8,9 @@
#include <spa/utils/hook.h> #include <spa/utils/hook.h>
#include <spa/param/video/format.h> #include <spa/param/video/format.h>
#define GSR_PIPEWIRE_MAX_MODIFIERS 1024 #define GSR_PIPEWIRE_VIDEO_MAX_MODIFIERS 1024
#define GSR_PIPEWIRE_NUM_VIDEO_FORMATS 6 #define GSR_PIPEWIRE_VIDEO_NUM_VIDEO_FORMATS 6
#define GSR_PIPEWIRE_DMABUF_MAX_PLANES 4 #define GSR_PIPEWIRE_VIDEO_DMABUF_MAX_PLANES 4
typedef struct gsr_egl gsr_egl; typedef struct gsr_egl gsr_egl;
@@ -18,23 +18,23 @@ typedef struct {
int major; int major;
int minor; int minor;
int micro; int micro;
} gsr_pipewire_data_version; } gsr_pipewire_video_data_version;
typedef struct { typedef struct {
uint32_t fps_num; uint32_t fps_num;
uint32_t fps_den; uint32_t fps_den;
} gsr_pipewire_video_info; } gsr_pipewire_video_video_info;
typedef struct { typedef struct {
int fd; int fd;
uint32_t offset; uint32_t offset;
int32_t stride; int32_t stride;
} gsr_pipewire_dmabuf_data; } gsr_pipewire_video_dmabuf_data;
typedef struct { typedef struct {
int x, y; int x, y;
int width, height; int width, height;
} gsr_pipewire_region; } gsr_pipewire_video_region;
typedef struct { typedef struct {
enum spa_video_format format; enum spa_video_format format;
@@ -82,31 +82,31 @@ typedef struct {
uint32_t width, height; uint32_t width, height;
} crop; } crop;
gsr_video_format supported_video_formats[GSR_PIPEWIRE_NUM_VIDEO_FORMATS]; gsr_video_format supported_video_formats[GSR_PIPEWIRE_VIDEO_NUM_VIDEO_FORMATS];
gsr_pipewire_data_version server_version; gsr_pipewire_video_data_version server_version;
gsr_pipewire_video_info video_info; gsr_pipewire_video_video_info video_info;
gsr_pipewire_dmabuf_data dmabuf_data[GSR_PIPEWIRE_DMABUF_MAX_PLANES]; gsr_pipewire_video_dmabuf_data dmabuf_data[GSR_PIPEWIRE_VIDEO_DMABUF_MAX_PLANES];
size_t dmabuf_num_planes; size_t dmabuf_num_planes;
bool no_modifiers_fallback; bool no_modifiers_fallback;
bool external_texture_fallback; bool external_texture_fallback;
uint64_t modifiers[GSR_PIPEWIRE_MAX_MODIFIERS]; uint64_t modifiers[GSR_PIPEWIRE_VIDEO_MAX_MODIFIERS];
size_t num_modifiers; size_t num_modifiers;
} gsr_pipewire; } gsr_pipewire_video;
/* /*
|capture_cursor| only applies to when capturing a window or region. |capture_cursor| only applies to when capturing a window or region.
In other cases |pipewire_node|'s setup will determine if the cursor is included. In other cases |pipewire_node|'s setup will determine if the cursor is included.
Note that the cursor is not guaranteed to be shown even if set to true, it depends on the wayland compositor. Note that the cursor is not guaranteed to be shown even if set to true, it depends on the wayland compositor.
*/ */
bool gsr_pipewire_init(gsr_pipewire *self, int pipewire_fd, uint32_t pipewire_node, int fps, bool capture_cursor, gsr_egl *egl); bool gsr_pipewire_video_init(gsr_pipewire_video *self, int pipewire_fd, uint32_t pipewire_node, int fps, bool capture_cursor, gsr_egl *egl);
void gsr_pipewire_deinit(gsr_pipewire *self); void gsr_pipewire_video_deinit(gsr_pipewire_video *self);
/* |dmabuf_data| should be at least GSR_PIPEWIRE_DMABUF_MAX_PLANES in size */ /* |dmabuf_data| should be at least GSR_PIPEWIRE_VIDEO_DMABUF_MAX_PLANES in size */
bool gsr_pipewire_map_texture(gsr_pipewire *self, gsr_texture_map texture_map, gsr_pipewire_region *region, gsr_pipewire_region *cursor_region, gsr_pipewire_dmabuf_data *dmabuf_data, int *num_dmabuf_data, uint32_t *fourcc, uint64_t *modifiers, bool *using_external_image); 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_is_damaged(gsr_pipewire *self); bool gsr_pipewire_video_is_damaged(gsr_pipewire_video *self);
void gsr_pipewire_clear_damage(gsr_pipewire *self); void gsr_pipewire_video_clear_damage(gsr_pipewire_video *self);
#endif /* GSR_PIPEWIRE_H */ #endif /* GSR_PIPEWIRE_VIDEO_H */

View File

@@ -57,20 +57,32 @@ dep = [
dependency('wayland-client'), dependency('wayland-client'),
] ]
uses_pipewire = false
if get_option('portal') == true if get_option('portal') == true
src += [ src += [
'src/capture/portal.c', 'src/capture/portal.c',
'src/dbus.c', 'src/dbus.c',
'src/pipewire.c', 'src/pipewire_video.c',
] ]
dep += dependency('dbus-1')
add_project_arguments('-DGSR_PORTAL', language : ['c', 'cpp'])
uses_pipewire = true
endif
if get_option('app_audio') == true
src += [
'src/pipewire_audio.c',
]
add_project_arguments('-DGSR_APP_AUDIO', language : ['c', 'cpp'])
uses_pipewire = true
endif
if uses_pipewire == true
dep += [ dep += [
dependency('dbus-1'),
dependency('libpipewire-0.3'), dependency('libpipewire-0.3'),
dependency('libspa-0.2'), dependency('libspa-0.2'),
] ]
add_project_arguments('-DGSR_PORTAL', language : ['c', 'cpp'])
endif endif
add_project_arguments('-DGSR_VERSION="' + meson.project_version() + '"', language: ['c', 'cpp']) add_project_arguments('-DGSR_VERSION="' + meson.project_version() + '"', language: ['c', 'cpp'])

View File

@@ -1,4 +1,5 @@
option('systemd', type : 'boolean', value : true, description : 'Install systemd service file') option('systemd', type : 'boolean', value : true, description : 'Install systemd service file')
option('capabilities', type : 'boolean', value : true, description : 'Set binary admin capability to remove password prompt when recording monitor (without desktop portal option) on amd/intel or nvidia wayland') option('capabilities', type : 'boolean', value : true, description : 'Set binary admin capability to remove password prompt when recording monitor (without desktop portal option) on amd/intel or nvidia wayland')
option('nvidia_suspend_fix', type : 'boolean', value : true, description : 'Install nvidia modprobe config file to tell nvidia driver to preserve video memory on suspend. This is a workaround for an nvidia driver bug that breaks cuda (and gpu screen recorder) on suspend') option('nvidia_suspend_fix', type : 'boolean', value : true, description : 'Install nvidia modprobe config file to tell nvidia driver to preserve video memory on suspend. This is a workaround for an nvidia driver bug that breaks cuda (and gpu screen recorder) on suspend')
option('portal', type : 'boolean', value : true, description : 'If GPU Screen Recorder should be built with support for xdg desktop portal ScreenCast capture (wayland only)') option('portal', type : 'boolean', value : true, description : 'Build with support for xdg desktop portal ScreenCast capture (wayland only) (-w portal option)')
option('app_audio', type : 'boolean', value : true, description : 'Build with support for recording a single audio source (-aa option). Requires pipewire')

View File

@@ -10,6 +10,7 @@ ignore_dirs = ["kms/server", "build", "debug-build"]
[define] [define]
GSR_PORTAL = "1" GSR_PORTAL = "1"
GSR_APP_AUDIO = "1"
[dependencies] [dependencies]
libavcodec = ">=58" libavcodec = ">=58"

View File

@@ -3,7 +3,7 @@
#include "../../include/egl.h" #include "../../include/egl.h"
#include "../../include/utils.h" #include "../../include/utils.h"
#include "../../include/dbus.h" #include "../../include/dbus.h"
#include "../../include/pipewire.h" #include "../../include/pipewire_video.h"
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h> #include <stdio.h>
@@ -20,9 +20,9 @@ typedef struct {
gsr_dbus dbus; gsr_dbus dbus;
char *session_handle; char *session_handle;
gsr_pipewire pipewire; gsr_pipewire_video pipewire;
vec2i capture_size; vec2i capture_size;
gsr_pipewire_dmabuf_data dmabuf_data[GSR_PIPEWIRE_DMABUF_MAX_PLANES]; gsr_pipewire_video_dmabuf_data dmabuf_data[GSR_PIPEWIRE_VIDEO_DMABUF_MAX_PLANES];
int num_dmabuf_data; int num_dmabuf_data;
AVCodecContext *video_codec_context; AVCodecContext *video_codec_context;
@@ -57,7 +57,7 @@ static void gsr_capture_portal_stop(gsr_capture_portal *self) {
gsr_capture_portal_cleanup_plane_fds(self); gsr_capture_portal_cleanup_plane_fds(self);
gsr_pipewire_deinit(&self->pipewire); gsr_pipewire_video_deinit(&self->pipewire);
if(self->session_handle) { if(self->session_handle) {
free(self->session_handle); free(self->session_handle);
@@ -233,8 +233,8 @@ static int gsr_capture_portal_setup_dbus(gsr_capture_portal *self, int *pipewire
} }
static bool gsr_capture_portal_get_frame_dimensions(gsr_capture_portal *self) { static bool gsr_capture_portal_get_frame_dimensions(gsr_capture_portal *self) {
gsr_pipewire_region region = {0, 0, 0, 0}; gsr_pipewire_video_region region = {0, 0, 0, 0};
gsr_pipewire_region cursor_region = {0, 0, 0, 0}; gsr_pipewire_video_region cursor_region = {0, 0, 0, 0};
fprintf(stderr, "gsr info: gsr_capture_portal_start: waiting for pipewire negotiation\n"); fprintf(stderr, "gsr info: gsr_capture_portal_start: waiting for pipewire negotiation\n");
const double start_time = clock_get_monotonic_seconds(); const double start_time = clock_get_monotonic_seconds();
@@ -242,7 +242,7 @@ static bool gsr_capture_portal_get_frame_dimensions(gsr_capture_portal *self) {
bool uses_external_image = false; bool uses_external_image = false;
uint32_t fourcc = 0; uint32_t fourcc = 0;
uint64_t modifiers = 0; uint64_t modifiers = 0;
if(gsr_pipewire_map_texture(&self->pipewire, self->texture_map, &region, &cursor_region, self->dmabuf_data, &self->num_dmabuf_data, &fourcc, &modifiers, &uses_external_image)) { if(gsr_pipewire_video_map_texture(&self->pipewire, self->texture_map, &region, &cursor_region, self->dmabuf_data, &self->num_dmabuf_data, &fourcc, &modifiers, &uses_external_image)) {
gsr_capture_portal_cleanup_plane_fds(self); gsr_capture_portal_cleanup_plane_fds(self);
self->capture_size.x = region.width; self->capture_size.x = region.width;
self->capture_size.y = region.height; self->capture_size.y = region.height;
@@ -285,7 +285,7 @@ static int gsr_capture_portal_start(gsr_capture *cap, AVCodecContext *video_code
fprintf(stderr, "gsr info: gsr_capture_portal_start: setting up pipewire\n"); fprintf(stderr, "gsr info: gsr_capture_portal_start: setting up pipewire\n");
/* TODO: support hdr when pipewire supports it */ /* TODO: support hdr when pipewire supports it */
/* gsr_pipewire closes the pipewire fd, even on failure */ /* gsr_pipewire closes the pipewire fd, even on failure */
if(!gsr_pipewire_init(&self->pipewire, pipewire_fd, pipewire_node, video_codec_context->framerate.num, self->params.record_cursor, self->params.egl)) { if(!gsr_pipewire_video_init(&self->pipewire, pipewire_fd, pipewire_node, video_codec_context->framerate.num, self->params.record_cursor, self->params.egl)) {
fprintf(stderr, "gsr error: gsr_capture_portal_start: failed to setup pipewire with fd: %d, node: %" PRIu32 "\n", pipewire_fd, pipewire_node); fprintf(stderr, "gsr error: gsr_capture_portal_start: failed to setup pipewire with fd: %d, node: %" PRIu32 "\n", pipewire_fd, pipewire_node);
gsr_capture_portal_stop(self); gsr_capture_portal_stop(self);
return -1; return -1;
@@ -327,12 +327,12 @@ static int gsr_capture_portal_capture(gsr_capture *cap, AVFrame *frame, gsr_colo
gsr_capture_portal *self = cap->priv; gsr_capture_portal *self = cap->priv;
/* TODO: Handle formats other than RGB(a) */ /* TODO: Handle formats other than RGB(a) */
gsr_pipewire_region region = {0, 0, 0, 0}; gsr_pipewire_video_region region = {0, 0, 0, 0};
gsr_pipewire_region cursor_region = {0, 0, 0, 0}; gsr_pipewire_video_region cursor_region = {0, 0, 0, 0};
uint32_t pipewire_fourcc = 0; uint32_t pipewire_fourcc = 0;
uint64_t pipewire_modifiers = 0; uint64_t pipewire_modifiers = 0;
bool using_external_image = false; bool using_external_image = false;
if(gsr_pipewire_map_texture(&self->pipewire, self->texture_map, &region, &cursor_region, self->dmabuf_data, &self->num_dmabuf_data, &pipewire_fourcc, &pipewire_modifiers, &using_external_image)) { if(gsr_pipewire_video_map_texture(&self->pipewire, self->texture_map, &region, &cursor_region, self->dmabuf_data, &self->num_dmabuf_data, &pipewire_fourcc, &pipewire_modifiers, &using_external_image)) {
if(region.width != self->capture_size.x || region.height != self->capture_size.y) { if(region.width != self->capture_size.x || region.height != self->capture_size.y) {
self->capture_size.x = region.width; self->capture_size.x = region.width;
self->capture_size.y = region.height; self->capture_size.y = region.height;
@@ -420,12 +420,12 @@ static bool gsr_capture_portal_uses_external_image(gsr_capture *cap) {
static bool gsr_capture_portal_is_damaged(gsr_capture *cap) { static bool gsr_capture_portal_is_damaged(gsr_capture *cap) {
gsr_capture_portal *self = cap->priv; gsr_capture_portal *self = cap->priv;
return gsr_pipewire_is_damaged(&self->pipewire); return gsr_pipewire_video_is_damaged(&self->pipewire);
} }
static void gsr_capture_portal_clear_damage(gsr_capture *cap) { static void gsr_capture_portal_clear_damage(gsr_capture *cap) {
gsr_capture_portal *self = cap->priv; gsr_capture_portal *self = cap->priv;
gsr_pipewire_clear_damage(&self->pipewire); gsr_pipewire_video_clear_damage(&self->pipewire);
} }
static void gsr_capture_portal_destroy(gsr_capture *cap, AVCodecContext *video_codec_context) { static void gsr_capture_portal_destroy(gsr_capture *cap, AVCodecContext *video_codec_context) {

View File

@@ -990,6 +990,8 @@ static void open_video_hardware(AVCodecContext *codec_context, VideoQuality vide
// TODO: Enable multipass // TODO: Enable multipass
// TODO: Set "usage" option to "record"/"stream" and "content" option to "rendered" for vulkan encoding
if(vendor == GSR_GPU_VENDOR_NVIDIA) { if(vendor == GSR_GPU_VENDOR_NVIDIA) {
// TODO: These dont seem to be necessary // TODO: These dont seem to be necessary
// av_dict_set_int(&options, "zerolatency", 1, 0); // av_dict_set_int(&options, "zerolatency", 1, 0);
@@ -1062,7 +1064,7 @@ static void open_video_hardware(AVCodecContext *codec_context, VideoQuality vide
static void usage_header() { static void usage_header() {
const bool inside_flatpak = getenv("FLATPAK_ID") != NULL; const bool inside_flatpak = getenv("FLATPAK_ID") != NULL;
const char *program_name = inside_flatpak ? "flatpak run --command=gpu-screen-recorder com.dec05eba.gpu_screen_recorder" : "gpu-screen-recorder"; const char *program_name = inside_flatpak ? "flatpak run --command=gpu-screen-recorder com.dec05eba.gpu_screen_recorder" : "gpu-screen-recorder";
fprintf(stderr, "usage: %s -w <window_id|monitor|focused|portal> [-c <container_format>] [-s WxH] -f <fps> [-a <audio_input>] [-q <quality>] [-r <replay_buffer_size_sec>] [-k h264|hevc|av1|vp8|vp9|hevc_hdr|av1_hdr|hevc_10bit|av1_10bit] [-ac aac|opus|flac] [-ab <bitrate>] [-oc yes|no] [-fm cfr|vfr|content] [-bm auto|qp|vbr|cbr] [-cr limited|full] [-df yes|no] [-sc <script_path>] [-cursor yes|no] [-keyint <value>] [-restore-portal-session yes|no] [-portal-session-token-filepath filepath] [-encoder gpu|cpu] [-o <output_file>] [-v yes|no] [--version] [-h|--help]\n", program_name); fprintf(stderr, "usage: %s -w <window_id|monitor|focused|portal> [-c <container_format>] [-s WxH] -f <fps> [-a <audio_input>] [-aa <application_name>] [-q <quality>] [-r <replay_buffer_size_sec>] [-k h264|hevc|av1|vp8|vp9|hevc_hdr|av1_hdr|hevc_10bit|av1_10bit] [-ac aac|opus|flac] [-ab <bitrate>] [-oc yes|no] [-fm cfr|vfr|content] [-bm auto|qp|vbr|cbr] [-cr limited|full] [-df yes|no] [-sc <script_path>] [-cursor yes|no] [-keyint <value>] [-restore-portal-session yes|no] [-portal-session-token-filepath filepath] [-encoder gpu|cpu] [-o <output_file>] [-v yes|no] [--version] [-h|--help]\n", program_name);
} }
// TODO: Update with portal info // TODO: Update with portal info
@@ -1100,6 +1102,15 @@ static void usage_full() {
fprintf(stderr, " If the audio device is an empty string then the audio device is ignored.\n"); fprintf(stderr, " If the audio device is an empty string then the audio device is ignored.\n");
fprintf(stderr, " Optional, no audio track is added by default.\n"); fprintf(stderr, " Optional, no audio track is added by default.\n");
fprintf(stderr, "\n"); fprintf(stderr, "\n");
#ifdef GSR_APP_AUDIO
fprintf(stderr, " -aa Audio device to record from (pulse audio device). Can be specified multiple times. Each time this is specified a new audio track is added for the specified audio device.\n");
fprintf(stderr, " A name can be given to the audio input device by prefixing the audio input with <name>/, for example \"dummy/alsa_output.pci-0000_00_1b.0.analog-stereo.monitor\".\n");
fprintf(stderr, " Multiple audio devices can be merged into one audio track by using \"|\" as a separator into one -a argument, for example: -a \"alsa_output1|alsa_output2\".\n");
fprintf(stderr, " The audio device can also be \"default_output\" in which case the default output device is used, or \"default_input\" in which case the default input device is used.\n");
fprintf(stderr, " If the audio device is an empty string then the audio device is ignored.\n");
fprintf(stderr, " Optional, no audio track is added by default.\n");
fprintf(stderr, "\n");
#endif
fprintf(stderr, " -q Video quality. Should be either 'medium', 'high', 'very_high' or 'ultra' when using '-bm qp' or '-bm vbr' options, and '-bm qp' is the default option used.\n"); fprintf(stderr, " -q Video quality. Should be either 'medium', 'high', 'very_high' or 'ultra' when using '-bm qp' or '-bm vbr' options, and '-bm qp' is the default option used.\n");
fprintf(stderr, " 'high' is the recommended option when live streaming or when you have a slower harddrive.\n"); fprintf(stderr, " 'high' is the recommended option when live streaming or when you have a slower harddrive.\n");
fprintf(stderr, " When using '-bm cbr' option then this is option is instead used to specify the video bitrate in kbps.\n"); fprintf(stderr, " When using '-bm cbr' option then this is option is instead used to specify the video bitrate in kbps.\n");
@@ -2120,7 +2131,7 @@ static gsr_capture* create_capture_impl(std::string &window_str, vec2i output_re
if(!capture) if(!capture)
_exit(1); _exit(1);
#else #else
fprintf(stderr, "Error: option '-w portal' used but GPU Screen Recorder was compiled without desktop portal support\n"); fprintf(stderr, "Error: option '-w portal' used but GPU Screen Recorder was compiled without desktop portal support. Please recompile GPU Screen recorder with the -Dportal=true option\n");
_exit(2); _exit(2);
#endif #endif
} else if(contains_non_hex_number(window_str.c_str())) { } else if(contains_non_hex_number(window_str.c_str())) {
@@ -2307,8 +2318,8 @@ static std::vector<MergedAudioInputs> parse_audio_inputs(const AudioDevices &aud
fprintf(stderr, " default_output (Default output)\n"); fprintf(stderr, " default_output (Default output)\n");
if(!audio_devices.default_input.empty()) if(!audio_devices.default_input.empty())
fprintf(stderr, " default_input (Default input)\n"); fprintf(stderr, " default_input (Default input)\n");
for(const auto &audio_input : audio_devices.audio_inputs) { for(const auto &audio_device_input : audio_devices.audio_inputs) {
fprintf(stderr, " %s (%s)\n", audio_input.name.c_str(), audio_input.description.c_str()); fprintf(stderr, " %s (%s)\n", audio_device_input.name.c_str(), audio_device_input.description.c_str());
} }
_exit(2); _exit(2);
} }

1
src/pipewire_audio.c Normal file
View File

@@ -0,0 +1 @@
#include "../include/pipewire_audio.h"

View File

@@ -1,4 +1,4 @@
#include "../include/pipewire.h" #include "../include/pipewire_video.h"
#include "../include/egl.h" #include "../include/egl.h"
#include "../include/utils.h" #include "../include/utils.h"
@@ -13,7 +13,7 @@
/* This code is partially based on xr-video-player pipewire implementation which is based on obs-studio's pipewire implementation */ /* This code is partially based on xr-video-player pipewire implementation which is based on obs-studio's pipewire implementation */
/* TODO: Make gsr_pipewire_init asynchronous */ /* TODO: Make gsr_pipewire_video_init asynchronous */
/* TODO: Support 10-bit capture (hdr) when pipewire supports it */ /* TODO: Support 10-bit capture (hdr) when pipewire supports it */
/* TODO: Test all of the image formats */ /* TODO: Test all of the image formats */
@@ -25,12 +25,12 @@
(sizeof(struct spa_meta_cursor) + sizeof(struct spa_meta_bitmap) + \ (sizeof(struct spa_meta_cursor) + sizeof(struct spa_meta_bitmap) + \
width * height * 4) width * height * 4)
static bool parse_pw_version(gsr_pipewire_data_version *dst, const char *version) { static bool parse_pw_version(gsr_pipewire_video_data_version *dst, const char *version) {
const int n_matches = sscanf(version, "%d.%d.%d", &dst->major, &dst->minor, &dst->micro); const int n_matches = sscanf(version, "%d.%d.%d", &dst->major, &dst->minor, &dst->micro);
return n_matches == 3; return n_matches == 3;
} }
static bool check_pw_version(const gsr_pipewire_data_version *pw_version, int major, int minor, int micro) { static bool check_pw_version(const gsr_pipewire_video_data_version *pw_version, int major, int minor, int micro) {
if (pw_version->major != major) if (pw_version->major != major)
return pw_version->major > major; return pw_version->major > major;
if (pw_version->minor != minor) if (pw_version->minor != minor)
@@ -38,7 +38,7 @@ static bool check_pw_version(const gsr_pipewire_data_version *pw_version, int ma
return pw_version->micro >= micro; return pw_version->micro >= micro;
} }
static void update_pw_versions(gsr_pipewire *self, const char *version) { static void update_pw_versions(gsr_pipewire_video *self, const char *version) {
fprintf(stderr, "gsr info: pipewire: server version: %s\n", version); fprintf(stderr, "gsr info: pipewire: server version: %s\n", version);
fprintf(stderr, "gsr info: pipewire: library version: %s\n", pw_get_library_version()); fprintf(stderr, "gsr info: pipewire: library version: %s\n", pw_get_library_version());
fprintf(stderr, "gsr info: pipewire: header version: %s\n", pw_get_headers_version()); fprintf(stderr, "gsr info: pipewire: header version: %s\n", pw_get_headers_version());
@@ -47,18 +47,18 @@ static void update_pw_versions(gsr_pipewire *self, const char *version) {
} }
static void on_core_info_cb(void *user_data, const struct pw_core_info *info) { static void on_core_info_cb(void *user_data, const struct pw_core_info *info) {
gsr_pipewire *self = user_data; gsr_pipewire_video *self = user_data;
update_pw_versions(self, info->version); update_pw_versions(self, info->version);
} }
static void on_core_error_cb(void *user_data, uint32_t id, int seq, int res, const char *message) { static void on_core_error_cb(void *user_data, uint32_t id, int seq, int res, const char *message) {
gsr_pipewire *self = user_data; gsr_pipewire_video *self = user_data;
fprintf(stderr, "gsr error: pipewire: error id:%u seq:%d res:%d: %s\n", id, seq, res, message); fprintf(stderr, "gsr error: pipewire: error id:%u seq:%d res:%d: %s\n", id, seq, res, message);
pw_thread_loop_signal(self->thread_loop, false); pw_thread_loop_signal(self->thread_loop, false);
} }
static void on_core_done_cb(void *user_data, uint32_t id, int seq) { static void on_core_done_cb(void *user_data, uint32_t id, int seq) {
gsr_pipewire *self = user_data; gsr_pipewire_video *self = user_data;
if (id == PW_ID_CORE && self->server_version_sync == seq) if (id == PW_ID_CORE && self->server_version_sync == seq)
pw_thread_loop_signal(self->thread_loop, false); pw_thread_loop_signal(self->thread_loop, false);
} }
@@ -86,7 +86,7 @@ static const struct pw_core_events core_events = {
}; };
static void on_process_cb(void *user_data) { static void on_process_cb(void *user_data) {
gsr_pipewire *self = user_data; gsr_pipewire_video *self = user_data;
struct spa_meta_cursor *cursor = NULL; struct spa_meta_cursor *cursor = NULL;
//struct spa_meta *video_damage = NULL; //struct spa_meta *video_damage = NULL;
@@ -122,8 +122,8 @@ static void on_process_cb(void *user_data) {
} }
self->dmabuf_num_planes = buffer->n_datas; self->dmabuf_num_planes = buffer->n_datas;
if(self->dmabuf_num_planes > GSR_PIPEWIRE_DMABUF_MAX_PLANES) if(self->dmabuf_num_planes > GSR_PIPEWIRE_VIDEO_DMABUF_MAX_PLANES)
self->dmabuf_num_planes = GSR_PIPEWIRE_DMABUF_MAX_PLANES; self->dmabuf_num_planes = GSR_PIPEWIRE_VIDEO_DMABUF_MAX_PLANES;
for(size_t i = 0; i < self->dmabuf_num_planes; ++i) { for(size_t i = 0; i < self->dmabuf_num_planes; ++i) {
self->dmabuf_data[i].fd = dup(buffer->datas[i].fd); self->dmabuf_data[i].fd = dup(buffer->datas[i].fd);
@@ -206,7 +206,7 @@ read_metadata:
} }
static void on_param_changed_cb(void *user_data, uint32_t id, const struct spa_pod *param) { static void on_param_changed_cb(void *user_data, uint32_t id, const struct spa_pod *param) {
gsr_pipewire *self = user_data; gsr_pipewire_video *self = user_data;
if (!param || id != SPA_PARAM_Format) if (!param || id != SPA_PARAM_Format)
return; return;
@@ -276,7 +276,7 @@ static void on_param_changed_cb(void *user_data, uint32_t id, const struct spa_p
static void on_state_changed_cb(void *user_data, enum pw_stream_state old, enum pw_stream_state state, const char *error) { static void on_state_changed_cb(void *user_data, enum pw_stream_state old, enum pw_stream_state state, const char *error) {
(void)old; (void)old;
gsr_pipewire *self = user_data; gsr_pipewire_video *self = user_data;
fprintf(stderr, "gsr info: pipewire: stream %p state: \"%s\" (error: %s)\n", fprintf(stderr, "gsr info: pipewire: stream %p state: \"%s\" (error: %s)\n",
(void*)self->stream, pw_stream_state_as_string(state), (void*)self->stream, pw_stream_state_as_string(state),
@@ -291,7 +291,7 @@ static const struct pw_stream_events stream_events = {
}; };
static inline struct spa_pod *build_format(struct spa_pod_builder *b, static inline struct spa_pod *build_format(struct spa_pod_builder *b,
const gsr_pipewire_video_info *ovi, const gsr_pipewire_video_video_info *ovi,
uint32_t format, const uint64_t *modifiers, uint32_t format, const uint64_t *modifiers,
size_t modifier_count) size_t modifier_count)
{ {
@@ -358,13 +358,13 @@ static const enum spa_video_format video_formats[] = {
SPA_VIDEO_FORMAT_RGB, SPA_VIDEO_FORMAT_RGB,
}; };
static bool gsr_pipewire_build_format_params(gsr_pipewire *self, struct spa_pod_builder *pod_builder, struct spa_pod **params, uint32_t *num_params) { static bool gsr_pipewire_video_build_format_params(gsr_pipewire_video *self, struct spa_pod_builder *pod_builder, struct spa_pod **params, uint32_t *num_params) {
*num_params = 0; *num_params = 0;
if(!check_pw_version(&self->server_version, 0, 3, 33)) if(!check_pw_version(&self->server_version, 0, 3, 33))
return false; return false;
for(size_t i = 0; i < GSR_PIPEWIRE_NUM_VIDEO_FORMATS; i++) { for(size_t i = 0; i < GSR_PIPEWIRE_VIDEO_NUM_VIDEO_FORMATS; i++) {
if(self->supported_video_formats[i].modifiers_size == 0) if(self->supported_video_formats[i].modifiers_size == 0)
continue; continue;
params[i] = build_format(pod_builder, &self->video_info, self->supported_video_formats[i].format, self->modifiers + self->supported_video_formats[i].modifiers_index, self->supported_video_formats[i].modifiers_size); params[i] = build_format(pod_builder, &self->video_info, self->supported_video_formats[i].format, self->modifiers + self->supported_video_formats[i].modifiers_index, self->supported_video_formats[i].modifiers_size);
@@ -376,15 +376,15 @@ static bool gsr_pipewire_build_format_params(gsr_pipewire *self, struct spa_pod_
static void renegotiate_format(void *data, uint64_t expirations) { static void renegotiate_format(void *data, uint64_t expirations) {
(void)expirations; (void)expirations;
gsr_pipewire *self = (gsr_pipewire*)data; gsr_pipewire_video *self = (gsr_pipewire_video*)data;
pw_thread_loop_lock(self->thread_loop); pw_thread_loop_lock(self->thread_loop);
struct spa_pod *params[GSR_PIPEWIRE_NUM_VIDEO_FORMATS]; struct spa_pod *params[GSR_PIPEWIRE_VIDEO_NUM_VIDEO_FORMATS];
uint32_t num_video_formats = 0; uint32_t num_video_formats = 0;
uint8_t params_buffer[2048]; uint8_t params_buffer[2048];
struct spa_pod_builder pod_builder = SPA_POD_BUILDER_INIT(params_buffer, sizeof(params_buffer)); struct spa_pod_builder pod_builder = SPA_POD_BUILDER_INIT(params_buffer, sizeof(params_buffer));
if (!gsr_pipewire_build_format_params(self, &pod_builder, params, &num_video_formats)) { if (!gsr_pipewire_video_build_format_params(self, &pod_builder, params, &num_video_formats)) {
pw_thread_loop_unlock(self->thread_loop); pw_thread_loop_unlock(self->thread_loop);
return; return;
} }
@@ -393,7 +393,7 @@ static void renegotiate_format(void *data, uint64_t expirations) {
pw_thread_loop_unlock(self->thread_loop); pw_thread_loop_unlock(self->thread_loop);
} }
static bool spa_video_format_get_modifiers(gsr_pipewire *self, const enum spa_video_format format, uint64_t *modifiers, int32_t max_modifiers, int32_t *num_modifiers) { static bool spa_video_format_get_modifiers(gsr_pipewire_video *self, const enum spa_video_format format, uint64_t *modifiers, int32_t max_modifiers, int32_t *num_modifiers) {
*num_modifiers = 0; *num_modifiers = 0;
if(max_modifiers == 0) { if(max_modifiers == 0) {
@@ -430,36 +430,36 @@ static bool spa_video_format_get_modifiers(gsr_pipewire *self, const enum spa_vi
return true; return true;
} }
static void gsr_pipewire_init_modifiers(gsr_pipewire *self) { static void gsr_pipewire_video_init_modifiers(gsr_pipewire_video *self) {
for(size_t i = 0; i < GSR_PIPEWIRE_NUM_VIDEO_FORMATS; i++) { for(size_t i = 0; i < GSR_PIPEWIRE_VIDEO_NUM_VIDEO_FORMATS; i++) {
self->supported_video_formats[i].format = video_formats[i]; self->supported_video_formats[i].format = video_formats[i];
int32_t num_modifiers = 0; int32_t num_modifiers = 0;
spa_video_format_get_modifiers(self, self->supported_video_formats[i].format, self->modifiers + self->num_modifiers, GSR_PIPEWIRE_MAX_MODIFIERS - self->num_modifiers, &num_modifiers); spa_video_format_get_modifiers(self, self->supported_video_formats[i].format, self->modifiers + self->num_modifiers, GSR_PIPEWIRE_VIDEO_MAX_MODIFIERS - self->num_modifiers, &num_modifiers);
self->supported_video_formats[i].modifiers_index = self->num_modifiers; self->supported_video_formats[i].modifiers_index = self->num_modifiers;
self->supported_video_formats[i].modifiers_size = num_modifiers; self->supported_video_formats[i].modifiers_size = num_modifiers;
} }
} }
static bool gsr_pipewire_setup_stream(gsr_pipewire *self) { static bool gsr_pipewire_video_setup_stream(gsr_pipewire_video *self) {
struct spa_pod *params[GSR_PIPEWIRE_NUM_VIDEO_FORMATS]; struct spa_pod *params[GSR_PIPEWIRE_VIDEO_NUM_VIDEO_FORMATS];
uint32_t num_video_formats = 0; uint32_t num_video_formats = 0;
uint8_t params_buffer[2048]; uint8_t params_buffer[2048];
struct spa_pod_builder pod_builder = SPA_POD_BUILDER_INIT(params_buffer, sizeof(params_buffer)); struct spa_pod_builder pod_builder = SPA_POD_BUILDER_INIT(params_buffer, sizeof(params_buffer));
self->thread_loop = pw_thread_loop_new("PipeWire thread loop", NULL); self->thread_loop = pw_thread_loop_new("PipeWire thread loop", NULL);
if(!self->thread_loop) { if(!self->thread_loop) {
fprintf(stderr, "gsr error: gsr_pipewire_setup_stream: failed to create pipewire thread\n"); fprintf(stderr, "gsr error: gsr_pipewire_video_setup_stream: failed to create pipewire thread\n");
goto error; goto error;
} }
self->context = pw_context_new(pw_thread_loop_get_loop(self->thread_loop), NULL, 0); self->context = pw_context_new(pw_thread_loop_get_loop(self->thread_loop), NULL, 0);
if(!self->context) { if(!self->context) {
fprintf(stderr, "gsr error: gsr_pipewire_setup_stream: failed to create pipewire context\n"); fprintf(stderr, "gsr error: gsr_pipewire_video_setup_stream: failed to create pipewire context\n");
goto error; goto error;
} }
if(pw_thread_loop_start(self->thread_loop) < 0) { if(pw_thread_loop_start(self->thread_loop) < 0) {
fprintf(stderr, "gsr error: gsr_pipewire_setup_stream: failed to start thread\n"); fprintf(stderr, "gsr error: gsr_pipewire_video_setup_stream: failed to start thread\n");
goto error; goto error;
} }
@@ -469,20 +469,20 @@ static bool gsr_pipewire_setup_stream(gsr_pipewire *self) {
self->core = pw_context_connect_fd(self->context, fcntl(self->fd, F_DUPFD_CLOEXEC, 5), NULL, 0); self->core = pw_context_connect_fd(self->context, fcntl(self->fd, F_DUPFD_CLOEXEC, 5), NULL, 0);
if(!self->core) { if(!self->core) {
pw_thread_loop_unlock(self->thread_loop); pw_thread_loop_unlock(self->thread_loop);
fprintf(stderr, "gsr error: gsr_pipewire_setup_stream: failed to connect to fd %d\n", self->fd); fprintf(stderr, "gsr error: gsr_pipewire_video_setup_stream: failed to connect to fd %d\n", self->fd);
goto error; goto error;
} }
// TODO: Error check // TODO: Error check
pw_core_add_listener(self->core, &self->core_listener, &core_events, self); pw_core_add_listener(self->core, &self->core_listener, &core_events, self);
gsr_pipewire_init_modifiers(self); gsr_pipewire_video_init_modifiers(self);
// TODO: Cleanup? // TODO: Cleanup?
self->reneg = pw_loop_add_event(pw_thread_loop_get_loop(self->thread_loop), renegotiate_format, self); self->reneg = pw_loop_add_event(pw_thread_loop_get_loop(self->thread_loop), renegotiate_format, self);
if(!self->reneg) { if(!self->reneg) {
pw_thread_loop_unlock(self->thread_loop); pw_thread_loop_unlock(self->thread_loop);
fprintf(stderr, "gsr error: gsr_pipewire_setup_stream: pw_loop_add_event failed\n"); fprintf(stderr, "gsr error: gsr_pipewire_video_setup_stream: pw_loop_add_event failed\n");
goto error; goto error;
} }
@@ -495,14 +495,14 @@ static bool gsr_pipewire_setup_stream(gsr_pipewire *self) {
PW_KEY_MEDIA_ROLE, "Screen", NULL)); PW_KEY_MEDIA_ROLE, "Screen", NULL));
if(!self->stream) { if(!self->stream) {
pw_thread_loop_unlock(self->thread_loop); pw_thread_loop_unlock(self->thread_loop);
fprintf(stderr, "gsr error: gsr_pipewire_setup_stream: failed to create stream\n"); fprintf(stderr, "gsr error: gsr_pipewire_video_setup_stream: failed to create stream\n");
goto error; goto error;
} }
pw_stream_add_listener(self->stream, &self->stream_listener, &stream_events, self); pw_stream_add_listener(self->stream, &self->stream_listener, &stream_events, self);
if(!gsr_pipewire_build_format_params(self, &pod_builder, params, &num_video_formats)) { if(!gsr_pipewire_video_build_format_params(self, &pod_builder, params, &num_video_formats)) {
pw_thread_loop_unlock(self->thread_loop); pw_thread_loop_unlock(self->thread_loop);
fprintf(stderr, "gsr error: gsr_pipewire_setup_stream: failed to build format params\n"); fprintf(stderr, "gsr error: gsr_pipewire_video_setup_stream: failed to build format params\n");
goto error; goto error;
} }
@@ -512,7 +512,7 @@ static bool gsr_pipewire_setup_stream(gsr_pipewire *self) {
num_video_formats) < 0) num_video_formats) < 0)
{ {
pw_thread_loop_unlock(self->thread_loop); pw_thread_loop_unlock(self->thread_loop);
fprintf(stderr, "gsr error: gsr_pipewire_setup_stream: failed to connect stream\n"); fprintf(stderr, "gsr error: gsr_pipewire_video_setup_stream: failed to connect stream\n");
goto error; goto error;
} }
@@ -549,7 +549,7 @@ static bool gsr_pipewire_setup_stream(gsr_pipewire *self) {
} }
static int pw_init_counter = 0; static int pw_init_counter = 0;
bool gsr_pipewire_init(gsr_pipewire *self, int pipewire_fd, uint32_t pipewire_node, int fps, bool capture_cursor, gsr_egl *egl) { bool gsr_pipewire_video_init(gsr_pipewire_video *self, int pipewire_fd, uint32_t pipewire_node, int fps, bool capture_cursor, gsr_egl *egl) {
if(pw_init_counter == 0) if(pw_init_counter == 0)
pw_init(NULL, NULL); pw_init(NULL, NULL);
++pw_init_counter; ++pw_init_counter;
@@ -559,8 +559,8 @@ bool gsr_pipewire_init(gsr_pipewire *self, int pipewire_fd, uint32_t pipewire_no
self->fd = pipewire_fd; self->fd = pipewire_fd;
self->node = pipewire_node; self->node = pipewire_node;
if(pthread_mutex_init(&self->mutex, NULL) != 0) { if(pthread_mutex_init(&self->mutex, NULL) != 0) {
fprintf(stderr, "gsr error: gsr_pipewire_init: failed to initialize mutex\n"); fprintf(stderr, "gsr error: gsr_pipewire_video_init: failed to initialize mutex\n");
gsr_pipewire_deinit(self); gsr_pipewire_video_deinit(self);
return false; return false;
} }
self->mutex_initialized = true; self->mutex_initialized = true;
@@ -568,15 +568,15 @@ bool gsr_pipewire_init(gsr_pipewire *self, int pipewire_fd, uint32_t pipewire_no
self->video_info.fps_den = 1; self->video_info.fps_den = 1;
self->cursor.visible = capture_cursor; self->cursor.visible = capture_cursor;
if(!gsr_pipewire_setup_stream(self)) { if(!gsr_pipewire_video_setup_stream(self)) {
gsr_pipewire_deinit(self); gsr_pipewire_video_deinit(self);
return false; return false;
} }
return true; return true;
} }
void gsr_pipewire_deinit(gsr_pipewire *self) { void gsr_pipewire_video_deinit(gsr_pipewire_video *self) {
if(self->thread_loop) { if(self->thread_loop) {
//pw_thread_loop_wait(self->thread_loop); //pw_thread_loop_wait(self->thread_loop);
pw_thread_loop_stop(self->thread_loop); pw_thread_loop_stop(self->thread_loop);
@@ -636,7 +636,7 @@ void gsr_pipewire_deinit(gsr_pipewire *self) {
} }
} }
static EGLImage gsr_pipewire_create_egl_image(gsr_pipewire *self, const int *fds, const uint32_t *offsets, const uint32_t *pitches, const uint64_t *modifiers, bool use_modifiers) { static EGLImage gsr_pipewire_video_create_egl_image(gsr_pipewire_video *self, const int *fds, const uint32_t *offsets, const uint32_t *pitches, const uint64_t *modifiers, bool use_modifiers) {
intptr_t img_attr[44]; intptr_t img_attr[44];
setup_dma_buf_attrs(img_attr, spa_video_format_to_drm_format(self->format.info.raw.format), self->format.info.raw.size.width, self->format.info.raw.size.height, setup_dma_buf_attrs(img_attr, spa_video_format_to_drm_format(self->format.info.raw.format), self->format.info.raw.size.width, self->format.info.raw.size.height,
fds, offsets, pitches, modifiers, self->dmabuf_num_planes, use_modifiers); fds, offsets, pitches, modifiers, self->dmabuf_num_planes, use_modifiers);
@@ -650,11 +650,11 @@ static EGLImage gsr_pipewire_create_egl_image(gsr_pipewire *self, const int *fds
return image; return image;
} }
static EGLImage gsr_pipewire_create_egl_image_with_fallback(gsr_pipewire *self) { static EGLImage gsr_pipewire_video_create_egl_image_with_fallback(gsr_pipewire_video *self) {
int fds[GSR_PIPEWIRE_DMABUF_MAX_PLANES]; int fds[GSR_PIPEWIRE_VIDEO_DMABUF_MAX_PLANES];
uint32_t offsets[GSR_PIPEWIRE_DMABUF_MAX_PLANES]; uint32_t offsets[GSR_PIPEWIRE_VIDEO_DMABUF_MAX_PLANES];
uint32_t pitches[GSR_PIPEWIRE_DMABUF_MAX_PLANES]; uint32_t pitches[GSR_PIPEWIRE_VIDEO_DMABUF_MAX_PLANES];
uint64_t modifiers[GSR_PIPEWIRE_DMABUF_MAX_PLANES]; uint64_t modifiers[GSR_PIPEWIRE_VIDEO_DMABUF_MAX_PLANES];
for(size_t i = 0; i < self->dmabuf_num_planes; ++i) { for(size_t i = 0; i < self->dmabuf_num_planes; ++i) {
fds[i] = self->dmabuf_data[i].fd; fds[i] = self->dmabuf_data[i].fd;
offsets[i] = self->dmabuf_data[i].offset; offsets[i] = self->dmabuf_data[i].offset;
@@ -664,19 +664,19 @@ static EGLImage gsr_pipewire_create_egl_image_with_fallback(gsr_pipewire *self)
EGLImage image = NULL; EGLImage image = NULL;
if(self->no_modifiers_fallback) { if(self->no_modifiers_fallback) {
image = gsr_pipewire_create_egl_image(self, fds, offsets, pitches, modifiers, false); image = gsr_pipewire_video_create_egl_image(self, fds, offsets, pitches, modifiers, false);
} else { } else {
image = gsr_pipewire_create_egl_image(self, fds, offsets, pitches, modifiers, true); image = gsr_pipewire_video_create_egl_image(self, fds, offsets, pitches, modifiers, true);
if(!image) { if(!image) {
fprintf(stderr, "gsr error: gsr_pipewire_create_egl_image_with_fallback: failed to create egl image with modifiers, trying without modifiers\n"); fprintf(stderr, "gsr error: gsr_pipewire_video_create_egl_image_with_fallback: failed to create egl image with modifiers, trying without modifiers\n");
self->no_modifiers_fallback = true; self->no_modifiers_fallback = true;
image = gsr_pipewire_create_egl_image(self, fds, offsets, pitches, modifiers, false); image = gsr_pipewire_video_create_egl_image(self, fds, offsets, pitches, modifiers, false);
} }
} }
return image; return image;
} }
static bool gsr_pipewire_bind_image_to_texture(gsr_pipewire *self, EGLImage image, unsigned int texture_id, bool external_texture) { static bool gsr_pipewire_video_bind_image_to_texture(gsr_pipewire_video *self, EGLImage image, unsigned int texture_id, bool external_texture) {
const int texture_target = external_texture ? GL_TEXTURE_EXTERNAL_OES : GL_TEXTURE_2D; const int texture_target = external_texture ? GL_TEXTURE_EXTERNAL_OES : GL_TEXTURE_2D;
while(self->egl->glGetError() != 0){} while(self->egl->glGetError() != 0){}
self->egl->glBindTexture(texture_target, texture_id); self->egl->glBindTexture(texture_target, texture_id);
@@ -686,19 +686,19 @@ static bool gsr_pipewire_bind_image_to_texture(gsr_pipewire *self, EGLImage imag
return success; return success;
} }
static void gsr_pipewire_bind_image_to_texture_with_fallback(gsr_pipewire *self, gsr_texture_map texture_map, EGLImage image) { static void gsr_pipewire_video_bind_image_to_texture_with_fallback(gsr_pipewire_video *self, gsr_texture_map texture_map, EGLImage image) {
if(self->external_texture_fallback) { if(self->external_texture_fallback) {
gsr_pipewire_bind_image_to_texture(self, image, texture_map.external_texture_id, true); gsr_pipewire_video_bind_image_to_texture(self, image, texture_map.external_texture_id, true);
} else { } else {
if(!gsr_pipewire_bind_image_to_texture(self, image, texture_map.texture_id, false)) { if(!gsr_pipewire_video_bind_image_to_texture(self, image, texture_map.texture_id, false)) {
fprintf(stderr, "gsr error: gsr_pipewire_map_texture: failed to bind image to texture, trying with external texture\n"); fprintf(stderr, "gsr error: gsr_pipewire_video_map_texture: failed to bind image to texture, trying with external texture\n");
self->external_texture_fallback = true; self->external_texture_fallback = true;
gsr_pipewire_bind_image_to_texture(self, image, texture_map.external_texture_id, true); gsr_pipewire_video_bind_image_to_texture(self, image, texture_map.external_texture_id, true);
} }
} }
} }
static void gsr_pipewire_update_cursor_texture(gsr_pipewire *self, gsr_texture_map texture_map) { static void gsr_pipewire_video_update_cursor_texture(gsr_pipewire_video *self, gsr_texture_map texture_map) {
if(!self->cursor.data) if(!self->cursor.data)
return; return;
@@ -715,9 +715,9 @@ static void gsr_pipewire_update_cursor_texture(gsr_pipewire *self, gsr_texture_m
self->cursor.data = NULL; self->cursor.data = NULL;
} }
bool gsr_pipewire_map_texture(gsr_pipewire *self, gsr_texture_map texture_map, gsr_pipewire_region *region, gsr_pipewire_region *cursor_region, gsr_pipewire_dmabuf_data *dmabuf_data, int *num_dmabuf_data, uint32_t *fourcc, uint64_t *modifiers, bool *using_external_image) { 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) {
for(int i = 0; i < GSR_PIPEWIRE_DMABUF_MAX_PLANES; ++i) { for(int i = 0; i < GSR_PIPEWIRE_VIDEO_DMABUF_MAX_PLANES; ++i) {
memset(&dmabuf_data[i], 0, sizeof(gsr_pipewire_dmabuf_data)); memset(&dmabuf_data[i], 0, sizeof(gsr_pipewire_video_dmabuf_data));
} }
*num_dmabuf_data = 0; *num_dmabuf_data = 0;
*using_external_image = self->external_texture_fallback; *using_external_image = self->external_texture_fallback;
@@ -730,14 +730,14 @@ bool gsr_pipewire_map_texture(gsr_pipewire *self, gsr_texture_map texture_map, g
return false; return false;
} }
EGLImage image = gsr_pipewire_create_egl_image_with_fallback(self); EGLImage image = gsr_pipewire_video_create_egl_image_with_fallback(self);
if(image) { if(image) {
gsr_pipewire_bind_image_to_texture_with_fallback(self, texture_map, image); gsr_pipewire_video_bind_image_to_texture_with_fallback(self, texture_map, image);
*using_external_image = self->external_texture_fallback; *using_external_image = self->external_texture_fallback;
self->egl->eglDestroyImage(self->egl->egl_display, image); self->egl->eglDestroyImage(self->egl->egl_display, image);
} }
gsr_pipewire_update_cursor_texture(self, texture_map); gsr_pipewire_video_update_cursor_texture(self, texture_map);
region->x = 0; region->x = 0;
region->y = 0; region->y = 0;
@@ -773,7 +773,7 @@ bool gsr_pipewire_map_texture(gsr_pipewire *self, gsr_texture_map texture_map, g
return true; return true;
} }
bool gsr_pipewire_is_damaged(gsr_pipewire *self) { bool gsr_pipewire_video_is_damaged(gsr_pipewire_video *self) {
bool damaged = false; bool damaged = false;
pthread_mutex_lock(&self->mutex); pthread_mutex_lock(&self->mutex);
damaged = self->damaged; damaged = self->damaged;
@@ -781,7 +781,7 @@ bool gsr_pipewire_is_damaged(gsr_pipewire *self) {
return damaged; return damaged;
} }
void gsr_pipewire_clear_damage(gsr_pipewire *self) { void gsr_pipewire_video_clear_damage(gsr_pipewire_video *self) {
pthread_mutex_lock(&self->mutex); pthread_mutex_lock(&self->mutex);
self->damaged = false; self->damaged = false;
pthread_mutex_unlock(&self->mutex); pthread_mutex_unlock(&self->mutex);