aboutsummaryrefslogtreecommitdiff
path: root/src/capture/portal.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/capture/portal.c')
-rw-r--r--src/capture/portal.c72
1 files changed, 41 insertions, 31 deletions
diff --git a/src/capture/portal.c b/src/capture/portal.c
index 9ab7e8b..d68e86f 100644
--- a/src/capture/portal.c
+++ b/src/capture/portal.c
@@ -3,7 +3,7 @@
#include "../../include/egl.h"
#include "../../include/utils.h"
#include "../../include/dbus.h"
-#include "../../include/pipewire.h"
+#include "../../include/pipewire_video.h"
#include <stdlib.h>
#include <stdio.h>
@@ -20,9 +20,9 @@ typedef struct {
gsr_dbus dbus;
char *session_handle;
- gsr_pipewire pipewire;
+ gsr_pipewire_video pipewire;
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;
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_pipewire_deinit(&self->pipewire);
+ gsr_pipewire_video_deinit(&self->pipewire);
if(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) {
- gsr_pipewire_region region = {0, 0, 0, 0};
- gsr_pipewire_region cursor_region = {0, 0, 0, 0};
+ gsr_pipewire_video_region 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");
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;
uint32_t fourcc = 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);
self->capture_size.x = region.width;
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");
/* TODO: support hdr when pipewire supports it */
/* 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);
gsr_capture_portal_stop(self);
return -1;
@@ -300,8 +300,15 @@ static int gsr_capture_portal_start(gsr_capture *cap, AVCodecContext *video_code
/* Disable vsync */
self->params.egl->eglSwapInterval(self->params.egl->egl_display, 0);
- video_codec_context->width = FFALIGN(self->capture_size.x, 2);
- video_codec_context->height = FFALIGN(self->capture_size.y, 2);
+ if(self->params.output_resolution.x == 0 && self->params.output_resolution.y == 0) {
+ self->params.output_resolution = self->capture_size;
+ video_codec_context->width = FFALIGN(self->capture_size.x, 2);
+ video_codec_context->height = FFALIGN(self->capture_size.y, 2);
+ } else {
+ self->params.output_resolution = scale_keep_aspect_ratio(self->capture_size, self->params.output_resolution);
+ video_codec_context->width = FFALIGN(self->params.output_resolution.x, 2);
+ video_codec_context->height = FFALIGN(self->params.output_resolution.y, 2);
+ }
frame->width = video_codec_context->width;
frame->height = video_codec_context->height;
@@ -320,12 +327,12 @@ static int gsr_capture_portal_capture(gsr_capture *cap, AVFrame *frame, gsr_colo
gsr_capture_portal *self = cap->priv;
/* TODO: Handle formats other than RGB(a) */
- gsr_pipewire_region region = {0, 0, 0, 0};
- gsr_pipewire_region cursor_region = {0, 0, 0, 0};
+ gsr_pipewire_video_region region = {0, 0, 0, 0};
+ gsr_pipewire_video_region cursor_region = {0, 0, 0, 0};
uint32_t pipewire_fourcc = 0;
uint64_t pipewire_modifiers = 0;
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) {
self->capture_size.x = region.width;
self->capture_size.y = region.height;
@@ -334,8 +341,12 @@ static int gsr_capture_portal_capture(gsr_capture *cap, AVFrame *frame, gsr_colo
} else {
return 0;
}
+
+ const bool is_scaled = self->params.output_resolution.x > 0 && self->params.output_resolution.y > 0;
+ vec2i output_size = is_scaled ? self->params.output_resolution : self->capture_size;
+ output_size = scale_keep_aspect_ratio(self->capture_size, output_size);
- const vec2i target_pos = { max_int(0, frame->width / 2 - self->capture_size.x / 2), max_int(0, frame->height / 2 - self->capture_size.y / 2) };
+ const vec2i target_pos = { max_int(0, frame->width / 2 - output_size.x / 2), max_int(0, frame->height / 2 - output_size.y / 2) };
self->params.egl->glFlush();
self->params.egl->glFinish();
@@ -354,7 +365,7 @@ static int gsr_capture_portal_capture(gsr_capture *cap, AVFrame *frame, gsr_colo
pitches[i] = self->dmabuf_data[i].stride;
modifiers[i] = pipewire_modifiers;
}
- if(!vaapi_copy_drm_planes_to_video_surface(self->video_codec_context, frame, (vec2i){region.x, region.y}, self->capture_size, target_pos, self->capture_size, pipewire_fourcc, self->capture_size, fds, offsets, pitches, modifiers, self->num_dmabuf_data)) {
+ if(!vaapi_copy_drm_planes_to_video_surface(self->video_codec_context, frame, (vec2i){region.x, region.y}, self->capture_size, target_pos, output_size, pipewire_fourcc, self->capture_size, fds, offsets, pitches, modifiers, self->num_dmabuf_data)) {
fprintf(stderr, "gsr error: gsr_capture_portal_capture: vaapi_copy_drm_planes_to_video_surface failed, falling back to opengl copy. Please report this as an issue at https://github.com/dec05eba/gpu-screen-recorder-issues\n");
self->fast_path_failed = true;
}
@@ -364,23 +375,28 @@ static int gsr_capture_portal_capture(gsr_capture *cap, AVFrame *frame, gsr_colo
if(self->fast_path_failed) {
gsr_color_conversion_draw(color_conversion, using_external_image ? self->texture_map.external_texture_id : self->texture_map.texture_id,
- target_pos, self->capture_size,
+ target_pos, output_size,
(vec2i){region.x, region.y}, self->capture_size,
- 0.0f, using_external_image);
+ 0.0f, using_external_image, GSR_SOURCE_COLOR_RGB);
}
- if(self->params.record_cursor) {
+ if(self->params.record_cursor && self->texture_map.cursor_texture_id > 0 && cursor_region.width > 0) {
+ const vec2d scale = {
+ self->capture_size.x == 0 ? 0 : (double)output_size.x / (double)self->capture_size.x,
+ self->capture_size.y == 0 ? 0 : (double)output_size.y / (double)self->capture_size.y
+ };
+
const vec2i cursor_pos = {
- target_pos.x + cursor_region.x,
- target_pos.y + cursor_region.y
+ target_pos.x + (cursor_region.x * scale.x),
+ target_pos.y + (cursor_region.y * scale.y)
};
self->params.egl->glEnable(GL_SCISSOR_TEST);
- self->params.egl->glScissor(target_pos.x, target_pos.y, self->capture_size.x, self->capture_size.y);
+ self->params.egl->glScissor(target_pos.x, target_pos.y, output_size.x, output_size.y);
gsr_color_conversion_draw(color_conversion, self->texture_map.cursor_texture_id,
- (vec2i){cursor_pos.x, cursor_pos.y}, (vec2i){cursor_region.width, cursor_region.height},
+ (vec2i){cursor_pos.x, cursor_pos.y}, (vec2i){cursor_region.width * scale.x, cursor_region.height * scale.y},
(vec2i){0, 0}, (vec2i){cursor_region.width, cursor_region.height},
- 0.0f, false);
+ 0.0f, false, GSR_SOURCE_COLOR_RGB);
self->params.egl->glDisable(GL_SCISSOR_TEST);
}
@@ -392,11 +408,6 @@ static int gsr_capture_portal_capture(gsr_capture *cap, AVFrame *frame, gsr_colo
return 0;
}
-static gsr_source_color gsr_capture_portal_get_source_color(gsr_capture *cap) {
- (void)cap;
- return GSR_SOURCE_COLOR_RGB;
-}
-
static bool gsr_capture_portal_uses_external_image(gsr_capture *cap) {
(void)cap;
return true;
@@ -404,12 +415,12 @@ static bool gsr_capture_portal_uses_external_image(gsr_capture *cap) {
static bool gsr_capture_portal_is_damaged(gsr_capture *cap) {
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) {
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) {
@@ -446,7 +457,6 @@ gsr_capture* gsr_capture_portal_create(const gsr_capture_portal_params *params)
.tick = NULL,
.should_stop = NULL,
.capture = gsr_capture_portal_capture,
- .get_source_color = gsr_capture_portal_get_source_color,
.uses_external_image = gsr_capture_portal_uses_external_image,
.is_damaged = gsr_capture_portal_is_damaged,
.clear_damage = gsr_capture_portal_clear_damage,