diff options
Diffstat (limited to 'src/capture')
-rw-r--r-- | src/capture/capture.c | 4 | ||||
-rw-r--r-- | src/capture/kms.c | 71 | ||||
-rw-r--r-- | src/capture/nvfbc.c | 32 | ||||
-rw-r--r-- | src/capture/portal.c | 72 | ||||
-rw-r--r-- | src/capture/xcomposite.c | 48 |
5 files changed, 136 insertions, 91 deletions
diff --git a/src/capture/capture.c b/src/capture/capture.c index ec10854..2a4a689 100644 --- a/src/capture/capture.c +++ b/src/capture/capture.c @@ -34,10 +34,6 @@ int gsr_capture_capture(gsr_capture *cap, AVFrame *frame, gsr_color_conversion * return cap->capture(cap, frame, color_conversion); } -gsr_source_color gsr_capture_get_source_color(gsr_capture *cap) { - return cap->get_source_color(cap); -} - bool gsr_capture_uses_external_image(gsr_capture *cap) { if(cap->uses_external_image) return cap->uses_external_image(cap); diff --git a/src/capture/kms.c b/src/capture/kms.c index 8b16ec9..c85811e 100644 --- a/src/capture/kms.c +++ b/src/capture/kms.c @@ -214,8 +214,15 @@ static int gsr_capture_kms_start(gsr_capture *cap, AVCodecContext *video_codec_c /* 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; @@ -429,7 +436,12 @@ static gsr_kms_response_item* find_cursor_drm_if_on_monitor(gsr_capture_kms *sel return cursor_drm_fd; } -static void render_drm_cursor(gsr_capture_kms *self, gsr_color_conversion *color_conversion, const gsr_kms_response_item *cursor_drm_fd, vec2i target_pos, float texture_rotation) { +static void render_drm_cursor(gsr_capture_kms *self, gsr_color_conversion *color_conversion, const gsr_kms_response_item *cursor_drm_fd, vec2i target_pos, float texture_rotation, vec2i output_size) { + 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 bool cursor_texture_id_is_external = self->params.egl->gpu_info.vendor == GSR_GPU_VENDOR_NVIDIA; const vec2i cursor_size = {cursor_drm_fd->width, cursor_drm_fd->height}; @@ -458,6 +470,9 @@ static void render_drm_cursor(gsr_capture_kms *self, gsr_color_conversion *color break; } + cursor_pos.x *= scale.x; + cursor_pos.y *= scale.y; + cursor_pos.x += target_pos.x; cursor_pos.y += target_pos.y; @@ -487,34 +502,39 @@ static void render_drm_cursor(gsr_capture_kms *self, gsr_color_conversion *color self->params.egl->eglDestroyImage(self->params.egl->egl_display, cursor_image); 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->cursor_texture_id, - cursor_pos, cursor_size, + cursor_pos, (vec2i){cursor_size.x * scale.x, cursor_size.y * scale.y}, (vec2i){0, 0}, cursor_size, - texture_rotation, cursor_texture_id_is_external); + texture_rotation, cursor_texture_id_is_external, GSR_SOURCE_COLOR_RGB); self->params.egl->glDisable(GL_SCISSOR_TEST); } -static void render_x11_cursor(gsr_capture_kms *self, gsr_color_conversion *color_conversion, vec2i capture_pos, vec2i target_pos) { +static void render_x11_cursor(gsr_capture_kms *self, gsr_color_conversion *color_conversion, vec2i capture_pos, vec2i target_pos, vec2i output_size) { if(!self->x11_cursor.visible) return; + 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 + }; + gsr_cursor_tick(&self->x11_cursor, DefaultRootWindow(self->params.egl->x11.dpy)); const vec2i cursor_pos = { - target_pos.x + self->x11_cursor.position.x - self->x11_cursor.hotspot.x - capture_pos.x, - target_pos.y + self->x11_cursor.position.y - self->x11_cursor.hotspot.y - capture_pos.y + target_pos.x + (self->x11_cursor.position.x - self->x11_cursor.hotspot.x - capture_pos.x) * scale.x, + target_pos.y + (self->x11_cursor.position.y - self->x11_cursor.hotspot.y - capture_pos.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->x11_cursor.texture_id, - cursor_pos, self->x11_cursor.size, + cursor_pos, (vec2i){self->x11_cursor.size.x * scale.x, self->x11_cursor.size.y * scale.y}, (vec2i){0, 0}, self->x11_cursor.size, - 0.0f, false); + 0.0f, false, GSR_SOURCE_COLOR_RGB); self->params.egl->glDisable(GL_SCISSOR_TEST); } @@ -562,9 +582,14 @@ static int gsr_capture_kms_capture(gsr_capture *cap, AVFrame *frame, gsr_color_c " If you are experience performance problems in the video then record a single window on X11 or use portal capture option instead\n"); } - const float texture_rotation = monitor_rotation_to_radians(self->monitor_rotation); - 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) }; self->capture_size = rotate_capture_size_if_rotated(self, (vec2i){ drm_fd->src_w, drm_fd->src_h }); + + 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 float texture_rotation = monitor_rotation_to_radians(self->monitor_rotation); + const vec2i target_pos = { max_int(0, frame->width / 2 - output_size.x / 2), max_int(0, frame->height / 2 - output_size.y / 2) }; gsr_capture_kms_update_capture_size_change(self, color_conversion, target_pos, drm_fd); vec2i capture_pos = self->capture_pos; @@ -586,7 +611,7 @@ static int gsr_capture_kms_capture(gsr_capture *cap, AVFrame *frame, gsr_color_c pitches[i] = drm_fd->dma_buf[i].pitch; modifiers[i] = drm_fd->modifier; } - if(!vaapi_copy_drm_planes_to_video_surface(self->video_codec_context, frame, (vec2i){capture_pos.x, capture_pos.y}, self->capture_size, target_pos, self->capture_size, drm_fd->pixel_format, (vec2i){drm_fd->width, drm_fd->height}, fds, offsets, pitches, modifiers, drm_fd->num_dma_bufs)) { + if(!vaapi_copy_drm_planes_to_video_surface(self->video_codec_context, frame, (vec2i){capture_pos.x, capture_pos.y}, self->capture_size, target_pos, output_size, drm_fd->pixel_format, (vec2i){drm_fd->width, drm_fd->height}, fds, offsets, pitches, modifiers, drm_fd->num_dma_bufs)) { fprintf(stderr, "gsr error: gsr_capture_kms_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; } @@ -602,20 +627,22 @@ static int gsr_capture_kms_capture(gsr_capture *cap, AVFrame *frame, gsr_color_c } gsr_color_conversion_draw(color_conversion, self->external_texture_fallback ? self->external_input_texture_id : self->input_texture_id, - target_pos, self->capture_size, + target_pos, output_size, capture_pos, self->capture_size, - texture_rotation, self->external_texture_fallback); + texture_rotation, self->external_texture_fallback, GSR_SOURCE_COLOR_RGB); } if(self->params.record_cursor) { gsr_kms_response_item *cursor_drm_fd = find_cursor_drm_if_on_monitor(self, drm_fd->connector_id, capture_is_combined_plane); // The cursor is handled by x11 on x11 instead of using the cursor drm plane because on prime systems with a dedicated nvidia gpu // the cursor plane is not available when the cursor is on the monitor controlled by the nvidia device. + // TODO: This doesn't work properly with software cursor on x11 since it will draw the x11 cursor on top of the cursor already in the framebuffer. + // Detect if software cursor is used on x11 somehow. if(self->is_x11) { const vec2i cursor_monitor_offset = self->capture_pos; - render_x11_cursor(self, color_conversion, cursor_monitor_offset, target_pos); + render_x11_cursor(self, color_conversion, cursor_monitor_offset, target_pos, output_size); } else if(cursor_drm_fd) { - render_drm_cursor(self, color_conversion, cursor_drm_fd, target_pos, texture_rotation); + render_drm_cursor(self, color_conversion, cursor_drm_fd, target_pos, texture_rotation, output_size); } } @@ -634,11 +661,6 @@ static bool gsr_capture_kms_should_stop(gsr_capture *cap, bool *err) { return false; } -static gsr_source_color gsr_capture_kms_get_source_color(gsr_capture *cap) { - (void)cap; - return GSR_SOURCE_COLOR_RGB; -} - static bool gsr_capture_kms_uses_external_image(gsr_capture *cap) { (void)cap; return true; @@ -725,7 +747,6 @@ gsr_capture* gsr_capture_kms_create(const gsr_capture_kms_params *params) { //.tick = gsr_capture_kms_tick, .should_stop = gsr_capture_kms_should_stop, .capture = gsr_capture_kms_capture, - .get_source_color = gsr_capture_kms_get_source_color, .uses_external_image = gsr_capture_kms_uses_external_image, .set_hdr_metadata = gsr_capture_kms_set_hdr_metadata, //.is_damaged = gsr_capture_kms_is_damaged, diff --git a/src/capture/nvfbc.c b/src/capture/nvfbc.c index ee77a20..d5a270e 100644 --- a/src/capture/nvfbc.c +++ b/src/capture/nvfbc.c @@ -240,6 +240,11 @@ static int gsr_capture_nvfbc_setup_handle(gsr_capture_nvfbc *self) { } } + if(!self->capture_region) { + self->width = self->tracking_width; + self->height = self->tracking_height; + } + return 0; error_cleanup: @@ -351,6 +356,14 @@ static int gsr_capture_nvfbc_start(gsr_capture *cap, AVCodecContext *video_codec video_codec_context->height = FFALIGN(self->tracking_height, 2); } + if(self->params.output_resolution.x == 0 && self->params.output_resolution.y == 0) { + self->params.output_resolution = (vec2i){video_codec_context->width, video_codec_context->height}; + } else { + self->params.output_resolution = scale_keep_aspect_ratio((vec2i){video_codec_context->width, video_codec_context->height}, 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; @@ -390,6 +403,13 @@ static int gsr_capture_nvfbc_capture(gsr_capture *cap, AVFrame *frame, gsr_color } } + const vec2i frame_size = (vec2i){self->width, self->height}; + 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 : frame_size; + output_size = scale_keep_aspect_ratio(frame_size, output_size); + + const vec2i target_pos = { max_int(0, frame->width / 2 - output_size.x / 2), max_int(0, frame->height / 2 - output_size.y / 2) }; + NVFBC_FRAME_GRAB_INFO frame_info; memset(&frame_info, 0, sizeof(frame_info)); @@ -412,9 +432,9 @@ static int gsr_capture_nvfbc_capture(gsr_capture *cap, AVFrame *frame, gsr_color self->params.egl->glFinish(); gsr_color_conversion_draw(color_conversion, self->setup_params.dwTextures[grab_params.dwTextureIndex], - (vec2i){0, 0}, (vec2i){frame->width, frame->height}, - (vec2i){0, 0}, (vec2i){frame->width, frame->height}, - 0.0f, false); + target_pos, (vec2i){output_size.x, output_size.y}, + (vec2i){0, 0}, frame_size, + 0.0f, false, GSR_SOURCE_COLOR_BGR); self->params.egl->glFlush(); self->params.egl->glFinish(); @@ -422,11 +442,6 @@ static int gsr_capture_nvfbc_capture(gsr_capture *cap, AVFrame *frame, gsr_color return 0; } -static gsr_source_color gsr_capture_nvfbc_get_source_color(gsr_capture *cap) { - (void)cap; - return GSR_SOURCE_COLOR_BGR; -} - static void gsr_capture_nvfbc_destroy(gsr_capture *cap, AVCodecContext *video_codec_context) { (void)video_codec_context; gsr_capture_nvfbc *self = cap->priv; @@ -472,7 +487,6 @@ gsr_capture* gsr_capture_nvfbc_create(const gsr_capture_nvfbc_params *params) { .tick = NULL, .should_stop = NULL, .capture = gsr_capture_nvfbc_capture, - .get_source_color = gsr_capture_nvfbc_get_source_color, .uses_external_image = NULL, .destroy = gsr_capture_nvfbc_destroy, .priv = cap_nvfbc 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, ®ion, &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, ®ion, &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, ®ion, &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, ®ion, &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, diff --git a/src/capture/xcomposite.c b/src/capture/xcomposite.c index 9e208d6..2867b45 100644 --- a/src/capture/xcomposite.c +++ b/src/capture/xcomposite.c @@ -113,13 +113,14 @@ static int gsr_capture_xcomposite_start(gsr_capture *cap, AVCodecContext *video_ self->params.egl->glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &self->texture_size.y); self->params.egl->glBindTexture(GL_TEXTURE_2D, 0); - vec2i video_size = self->texture_size; - - if(self->params.region_size.x > 0 && self->params.region_size.y > 0) - video_size = self->params.region_size; - - video_codec_context->width = FFALIGN(video_size.x, 2); - video_codec_context->height = FFALIGN(video_size.y, 2); + if(self->params.output_resolution.x == 0 && self->params.output_resolution.y == 0) { + self->params.output_resolution = self->texture_size; + video_codec_context->width = FFALIGN(self->texture_size.x, 2); + video_codec_context->height = FFALIGN(self->texture_size.y, 2); + } else { + 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; @@ -257,14 +258,18 @@ static int gsr_capture_xcomposite_capture(gsr_capture *cap, AVFrame *frame, gsr_ gsr_color_conversion_clear(color_conversion); } - const vec2i target_pos = { max_int(0, frame->width / 2 - self->texture_size.x / 2), max_int(0, frame->height / 2 - self->texture_size.y / 2) }; + 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->texture_size; + output_size = scale_keep_aspect_ratio(self->texture_size, output_size); + + 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(); /* Fast opengl free path */ if(!self->fast_path_failed && video_codec_context_is_vaapi(self->video_codec_context) && self->params.egl->gpu_info.vendor == GSR_GPU_VENDOR_AMD) { - if(!vaapi_copy_egl_image_to_video_surface(self->params.egl, self->window_texture.image, (vec2i){0, 0}, self->texture_size, target_pos, self->texture_size, self->video_codec_context, frame)) { + if(!vaapi_copy_egl_image_to_video_surface(self->params.egl, self->window_texture.image, (vec2i){0, 0}, self->texture_size, target_pos, output_size, self->video_codec_context, frame)) { fprintf(stderr, "gsr error: gsr_capture_xcomposite_capture: vaapi_copy_egl_image_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; } @@ -274,26 +279,31 @@ static int gsr_capture_xcomposite_capture(gsr_capture *cap, AVFrame *frame, gsr_ if(self->fast_path_failed) { gsr_color_conversion_draw(color_conversion, window_texture_get_opengl_texture_id(&self->window_texture), - target_pos, self->texture_size, + target_pos, output_size, (vec2i){0, 0}, self->texture_size, - 0.0f, false); + 0.0f, false, GSR_SOURCE_COLOR_RGB); } if(self->params.record_cursor && self->cursor.visible) { + const vec2d scale = { + self->texture_size.x == 0 ? 0 : (double)output_size.x / (double)self->texture_size.x, + self->texture_size.y == 0 ? 0 : (double)output_size.y / (double)self->texture_size.y + }; + gsr_cursor_tick(&self->cursor, self->window); const vec2i cursor_pos = { - target_pos.x + self->cursor.position.x - self->cursor.hotspot.x, - target_pos.y + self->cursor.position.y - self->cursor.hotspot.y + target_pos.x + (self->cursor.position.x - self->cursor.hotspot.x) * scale.x, + target_pos.y + (self->cursor.position.y - self->cursor.hotspot.y) * scale.y }; self->params.egl->glEnable(GL_SCISSOR_TEST); - self->params.egl->glScissor(target_pos.x, target_pos.y, self->texture_size.x, self->texture_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->cursor.texture_id, - cursor_pos, self->cursor.size, + cursor_pos, (vec2i){self->cursor.size.x * scale.x, self->cursor.size.y * scale.y}, (vec2i){0, 0}, self->cursor.size, - 0.0f, false); + 0.0f, false, GSR_SOURCE_COLOR_RGB); self->params.egl->glDisable(GL_SCISSOR_TEST); } @@ -304,11 +314,6 @@ static int gsr_capture_xcomposite_capture(gsr_capture *cap, AVFrame *frame, gsr_ return 0; } -static gsr_source_color gsr_capture_xcomposite_get_source_color(gsr_capture *cap) { - (void)cap; - return GSR_SOURCE_COLOR_RGB; -} - static uint64_t gsr_capture_xcomposite_get_window_id(gsr_capture *cap) { gsr_capture_xcomposite *self = cap->priv; return self->window; @@ -348,7 +353,6 @@ gsr_capture* gsr_capture_xcomposite_create(const gsr_capture_xcomposite_params * .tick = gsr_capture_xcomposite_tick, .should_stop = gsr_capture_xcomposite_should_stop, .capture = gsr_capture_xcomposite_capture, - .get_source_color = gsr_capture_xcomposite_get_source_color, .uses_external_image = NULL, .get_window_id = gsr_capture_xcomposite_get_window_id, .destroy = gsr_capture_xcomposite_destroy, |