mirror of
https://repo.dec05eba.com/gpu-screen-recorder
synced 2026-03-31 09:07:13 +09:00
HACK: portal: copy external image to internal image before render. Dont stop screencast when paused as that stops recording when window is resized
This commit is contained in:
@@ -88,8 +88,6 @@ typedef struct {
|
|||||||
gsr_pipewire_dmabuf_data dmabuf_data[GSR_PIPEWIRE_DMABUF_MAX_PLANES];
|
gsr_pipewire_dmabuf_data dmabuf_data[GSR_PIPEWIRE_DMABUF_MAX_PLANES];
|
||||||
size_t dmabuf_num_planes;
|
size_t dmabuf_num_planes;
|
||||||
|
|
||||||
bool started;
|
|
||||||
bool stopped;
|
|
||||||
bool no_modifiers_fallback;
|
bool no_modifiers_fallback;
|
||||||
bool external_texture_fallback;
|
bool external_texture_fallback;
|
||||||
|
|
||||||
@@ -107,6 +105,5 @@ void gsr_pipewire_deinit(gsr_pipewire *self);
|
|||||||
|
|
||||||
/* |plane_fds| should be at least GSR_PIPEWIRE_DMABUF_MAX_PLANES in size */
|
/* |plane_fds| should be at least GSR_PIPEWIRE_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, int *plane_fds, int *num_plane_fds, bool *using_external_image);
|
bool gsr_pipewire_map_texture(gsr_pipewire *self, gsr_texture_map texture_map, gsr_pipewire_region *region, gsr_pipewire_region *cursor_region, int *plane_fds, int *num_plane_fds, bool *using_external_image);
|
||||||
bool gsr_pipewire_recording_stopped(gsr_pipewire *self);
|
|
||||||
|
|
||||||
#endif /* GSR_PIPEWIRE_H */
|
#endif /* GSR_PIPEWIRE_H */
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ typedef struct {
|
|||||||
gsr_capture_portal_params params;
|
gsr_capture_portal_params params;
|
||||||
|
|
||||||
gsr_texture_map texture_map;
|
gsr_texture_map texture_map;
|
||||||
|
unsigned int external_intermediate_texture;
|
||||||
|
|
||||||
gsr_dbus dbus;
|
gsr_dbus dbus;
|
||||||
char *session_handle;
|
char *session_handle;
|
||||||
@@ -47,6 +48,11 @@ static void gsr_capture_portal_stop(gsr_capture_portal *self) {
|
|||||||
self->texture_map.external_texture_id = 0;
|
self->texture_map.external_texture_id = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(self->external_intermediate_texture) {
|
||||||
|
self->params.egl->glDeleteTextures(1, &self->external_intermediate_texture);
|
||||||
|
self->external_intermediate_texture = 0;
|
||||||
|
}
|
||||||
|
|
||||||
if(self->texture_map.cursor_texture_id) {
|
if(self->texture_map.cursor_texture_id) {
|
||||||
self->params.egl->glDeleteTextures(1, &self->texture_map.cursor_texture_id);
|
self->params.egl->glDeleteTextures(1, &self->texture_map.cursor_texture_id);
|
||||||
self->texture_map.cursor_texture_id = 0;
|
self->texture_map.cursor_texture_id = 0;
|
||||||
@@ -318,21 +324,42 @@ static int gsr_capture_portal_capture(gsr_capture *cap, AVFrame *frame, gsr_colo
|
|||||||
gsr_pipewire_region region = {0, 0, 0, 0};
|
gsr_pipewire_region region = {0, 0, 0, 0};
|
||||||
gsr_pipewire_region cursor_region = {0, 0, 0, 0};
|
gsr_pipewire_region cursor_region = {0, 0, 0, 0};
|
||||||
bool using_external_image = false;
|
bool using_external_image = false;
|
||||||
|
bool resized = false;
|
||||||
if(gsr_pipewire_map_texture(&self->pipewire, self->texture_map, ®ion, &cursor_region, self->plane_fds, &self->num_plane_fds, &using_external_image)) {
|
if(gsr_pipewire_map_texture(&self->pipewire, self->texture_map, ®ion, &cursor_region, self->plane_fds, &self->num_plane_fds, &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) {
|
||||||
gsr_color_conversion_clear(color_conversion);
|
gsr_color_conversion_clear(color_conversion);
|
||||||
self->capture_size.x = region.width;
|
self->capture_size.x = region.width;
|
||||||
self->capture_size.y = region.height;
|
self->capture_size.y = region.height;
|
||||||
|
resized = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(using_external_image && (self->external_intermediate_texture == 0 || resized)) {
|
||||||
|
if(self->external_intermediate_texture == 0)
|
||||||
|
self->params.egl->glGenTextures(1, &self->external_intermediate_texture);
|
||||||
|
self->params.egl->glBindTexture(GL_TEXTURE_2D, self->external_intermediate_texture);
|
||||||
|
self->params.egl->glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, self->capture_size.x, self->capture_size.y, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
|
||||||
|
self->params.egl->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||||
|
self->params.egl->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||||
|
self->params.egl->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||||
|
self->params.egl->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||||
|
self->params.egl->glBindTexture(GL_TEXTURE_2D, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* The image glitches a lot unless this is done. TODO: Find a proper solution */
|
||||||
|
if(using_external_image) {
|
||||||
|
self->params.egl->glCopyImageSubData(self->texture_map.external_texture_id, GL_TEXTURE_EXTERNAL_OES, 0, 0, 0, 0,
|
||||||
|
self->external_intermediate_texture, GL_TEXTURE_2D, 0, 0, 0, 0,
|
||||||
|
self->capture_size.x, self->capture_size.y, 1);
|
||||||
|
}
|
||||||
|
|
||||||
const int target_x = max_int(0, frame->width / 2 - self->capture_size.x / 2);
|
const int target_x = max_int(0, frame->width / 2 - self->capture_size.x / 2);
|
||||||
const int target_y = max_int(0, frame->height / 2 - self->capture_size.y / 2);
|
const int target_y = max_int(0, frame->height / 2 - self->capture_size.y / 2);
|
||||||
|
|
||||||
gsr_color_conversion_draw(color_conversion, using_external_image ? self->texture_map.external_texture_id : self->texture_map.texture_id,
|
gsr_color_conversion_draw(color_conversion, using_external_image ? self->external_intermediate_texture : self->texture_map.texture_id,
|
||||||
(vec2i){target_x, target_y}, self->capture_size,
|
(vec2i){target_x, target_y}, self->capture_size,
|
||||||
(vec2i){region.x, region.y}, self->capture_size,
|
(vec2i){region.x, region.y}, self->capture_size,
|
||||||
0.0f, using_external_image);
|
0.0f, false);
|
||||||
|
|
||||||
if(self->params.record_cursor) {
|
if(self->params.record_cursor) {
|
||||||
const vec2i cursor_pos = {
|
const vec2i cursor_pos = {
|
||||||
@@ -355,13 +382,6 @@ static int gsr_capture_portal_capture(gsr_capture *cap, AVFrame *frame, gsr_colo
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool gsr_capture_portal_should_stop(gsr_capture *cap, bool *err) {
|
|
||||||
gsr_capture_portal *self = cap->priv;
|
|
||||||
if(err)
|
|
||||||
*err = false;
|
|
||||||
return gsr_pipewire_recording_stopped(&self->pipewire);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void gsr_capture_portal_capture_end(gsr_capture *cap, AVFrame *frame) {
|
static void gsr_capture_portal_capture_end(gsr_capture *cap, AVFrame *frame) {
|
||||||
(void)frame;
|
(void)frame;
|
||||||
gsr_capture_portal *self = cap->priv;
|
gsr_capture_portal *self = cap->priv;
|
||||||
@@ -410,7 +430,7 @@ gsr_capture* gsr_capture_portal_create(const gsr_capture_portal_params *params)
|
|||||||
*cap = (gsr_capture) {
|
*cap = (gsr_capture) {
|
||||||
.start = gsr_capture_portal_start,
|
.start = gsr_capture_portal_start,
|
||||||
.tick = NULL,
|
.tick = NULL,
|
||||||
.should_stop = gsr_capture_portal_should_stop,
|
.should_stop = NULL,
|
||||||
.capture = gsr_capture_portal_capture,
|
.capture = gsr_capture_portal_capture,
|
||||||
.capture_end = gsr_capture_portal_capture_end,
|
.capture_end = gsr_capture_portal_capture_end,
|
||||||
.get_source_color = gsr_capture_portal_get_source_color,
|
.get_source_color = gsr_capture_portal_get_source_color,
|
||||||
|
|||||||
@@ -254,13 +254,6 @@ 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 *self = user_data;
|
||||||
if(state == PW_STREAM_STATE_STREAMING)
|
|
||||||
self->started = true;
|
|
||||||
|
|
||||||
if(self->started && state == PW_STREAM_STATE_PAUSED) {
|
|
||||||
self->started = false;
|
|
||||||
self->stopped = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
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),
|
||||||
@@ -740,7 +733,3 @@ bool gsr_pipewire_map_texture(gsr_pipewire *self, gsr_texture_map texture_map, g
|
|||||||
pthread_mutex_unlock(&self->mutex);
|
pthread_mutex_unlock(&self->mutex);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool gsr_pipewire_recording_stopped(gsr_pipewire *self) {
|
|
||||||
return self->stopped;
|
|
||||||
}
|
|
||||||
|
|||||||
Reference in New Issue
Block a user