From ab5988a2bb2d71df1cc1401ed1e67ca59cd99e48 Mon Sep 17 00:00:00 2001 From: dec05eba Date: Tue, 18 Nov 2025 02:52:11 +0100 Subject: [PATCH] Dont scale image frame to padding in video --- include/capture/capture.h | 10 ++++++--- src/capture/kms.c | 16 +++++++------- src/capture/nvfbc.c | 18 +++++++-------- src/capture/portal.c | 12 +++++----- src/capture/xcomposite.c | 12 +++++----- src/capture/ximage.c | 16 +++++++------- src/encoder/video/vaapi.c | 4 ++-- src/main.cpp | 46 ++++++++++++++++++++++++--------------- 8 files changed, 74 insertions(+), 60 deletions(-) diff --git a/include/capture/capture.h b/include/capture/capture.h index 201a271..db80d4f 100644 --- a/include/capture/capture.h +++ b/include/capture/capture.h @@ -14,13 +14,17 @@ typedef struct AVContentLightMetadata AVContentLightMetadata; typedef struct gsr_capture gsr_capture; typedef struct { - int width; - int height; + // Width and height of the video + int video_width; + int video_height; + // Width and height of the frame at the start of capture, the target size + int recording_width; + int recording_height; int fps; } gsr_capture_metadata; struct gsr_capture { - /* These methods should not be called manually. Call gsr_capture_* instead. |capture_metadata->width| and |capture_metadata->height| should be set by this function */ + /* These methods should not be called manually. Call gsr_capture_* instead. |capture_metadata->video_width| and |capture_metadata->video_height| should be set by this function */ int (*start)(gsr_capture *cap, gsr_capture_metadata *capture_metadata); void (*on_event)(gsr_capture *cap, gsr_egl *egl); /* can be NULL */ void (*tick)(gsr_capture *cap); /* can be NULL. If there is an event then |on_event| is called before this */ diff --git a/src/capture/kms.c b/src/capture/kms.c index b2d058a..23d7840 100644 --- a/src/capture/kms.c +++ b/src/capture/kms.c @@ -209,14 +209,14 @@ static int gsr_capture_kms_start(gsr_capture *cap, gsr_capture_metadata *capture if(self->params.output_resolution.x > 0 && self->params.output_resolution.y > 0) { self->params.output_resolution = scale_keep_aspect_ratio(self->capture_size, self->params.output_resolution); - capture_metadata->width = self->params.output_resolution.x; - capture_metadata->height = self->params.output_resolution.y; + capture_metadata->video_width = self->params.output_resolution.x; + capture_metadata->video_height = self->params.output_resolution.y; } else if(self->params.region_size.x > 0 && self->params.region_size.y > 0) { - capture_metadata->width = self->params.region_size.x; - capture_metadata->height = self->params.region_size.y; + capture_metadata->video_width = self->params.region_size.x; + capture_metadata->video_height = self->params.region_size.y; } else { - capture_metadata->width = self->capture_size.x; - capture_metadata->height = self->capture_size.y; + capture_metadata->video_width = self->capture_size.x; + capture_metadata->video_height = self->capture_size.y; } self->last_time_monitor_check = clock_get_monotonic_seconds(); @@ -625,8 +625,8 @@ static int gsr_capture_kms_capture(gsr_capture *cap, gsr_capture_metadata *captu if(self->params.region_size.x > 0 && self->params.region_size.y > 0) self->capture_size = self->params.region_size; - const vec2i output_size = scale_keep_aspect_ratio(self->capture_size, (vec2i){capture_metadata->width, capture_metadata->height}); - const vec2i target_pos = { max_int(0, capture_metadata->width / 2 - output_size.x / 2), max_int(0, capture_metadata->height / 2 - output_size.y / 2) }; + const vec2i output_size = scale_keep_aspect_ratio(self->capture_size, (vec2i){capture_metadata->recording_width, capture_metadata->recording_height}); + const vec2i target_pos = { max_int(0, capture_metadata->video_width / 2 - output_size.x / 2), max_int(0, capture_metadata->video_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; diff --git a/src/capture/nvfbc.c b/src/capture/nvfbc.c index 46c6c02..5d01f47 100644 --- a/src/capture/nvfbc.c +++ b/src/capture/nvfbc.c @@ -283,16 +283,16 @@ static int gsr_capture_nvfbc_start(gsr_capture *cap, gsr_capture_metadata *captu goto error_cleanup; } - capture_metadata->width = self->tracking_width; - capture_metadata->height = self->tracking_height; + capture_metadata->video_width = self->tracking_width; + capture_metadata->video_height = self->tracking_height; if(self->params.output_resolution.x > 0 && self->params.output_resolution.y > 0) { - self->params.output_resolution = scale_keep_aspect_ratio((vec2i){capture_metadata->width, capture_metadata->height}, self->params.output_resolution); - capture_metadata->width = self->params.output_resolution.x; - capture_metadata->height = self->params.output_resolution.y; + self->params.output_resolution = scale_keep_aspect_ratio((vec2i){capture_metadata->recording_width, capture_metadata->recording_height}, self->params.output_resolution); + capture_metadata->video_width = self->params.output_resolution.x; + capture_metadata->video_height = self->params.output_resolution.y; } else if(self->params.region_size.x > 0 && self->params.region_size.y > 0) { - capture_metadata->width = self->params.region_size.x; - capture_metadata->height = self->params.region_size.y; + capture_metadata->video_width = self->params.region_size.x; + capture_metadata->video_height = self->params.region_size.y; } return 0; @@ -333,8 +333,8 @@ static int gsr_capture_nvfbc_capture(gsr_capture *cap, gsr_capture_metadata *cap if(self->params.region_size.x > 0 && self->params.region_size.y > 0) frame_size = self->params.region_size; - const vec2i output_size = scale_keep_aspect_ratio(frame_size, (vec2i){capture_metadata->width, capture_metadata->height}); - const vec2i target_pos = { max_int(0, capture_metadata->width / 2 - output_size.x / 2), max_int(0, capture_metadata->height / 2 - output_size.y / 2) }; + const vec2i output_size = scale_keep_aspect_ratio(frame_size, (vec2i){capture_metadata->recording_width, capture_metadata->recording_height}); + const vec2i target_pos = { max_int(0, capture_metadata->video_width / 2 - output_size.x / 2), max_int(0, capture_metadata->video_height / 2 - output_size.y / 2) }; NVFBC_FRAME_GRAB_INFO frame_info; memset(&frame_info, 0, sizeof(frame_info)); diff --git a/src/capture/portal.c b/src/capture/portal.c index b158530..2d4eff1 100644 --- a/src/capture/portal.c +++ b/src/capture/portal.c @@ -293,12 +293,12 @@ static int gsr_capture_portal_start(gsr_capture *cap, gsr_capture_metadata *capt } if(self->params.output_resolution.x == 0 && self->params.output_resolution.y == 0) { - capture_metadata->width = self->capture_size.x; - capture_metadata->height = self->capture_size.y; + capture_metadata->video_width = self->capture_size.x; + capture_metadata->video_height = self->capture_size.y; } else { self->params.output_resolution = scale_keep_aspect_ratio(self->capture_size, self->params.output_resolution); - capture_metadata->width = self->params.output_resolution.x; - capture_metadata->height = self->params.output_resolution.y; + capture_metadata->video_width = self->params.output_resolution.x; + capture_metadata->video_height = self->params.output_resolution.y; } return 0; @@ -353,8 +353,8 @@ static int gsr_capture_portal_capture(gsr_capture *cap, gsr_capture_metadata *ca } } - const vec2i output_size = scale_keep_aspect_ratio(self->capture_size, (vec2i){capture_metadata->width, capture_metadata->height}); - const vec2i target_pos = { max_int(0, capture_metadata->width / 2 - output_size.x / 2), max_int(0, capture_metadata->height / 2 - output_size.y / 2) }; + const vec2i output_size = scale_keep_aspect_ratio(self->capture_size, (vec2i){capture_metadata->recording_width, capture_metadata->recording_height}); + const vec2i target_pos = { max_int(0, capture_metadata->video_width / 2 - output_size.x / 2), max_int(0, capture_metadata->video_height / 2 - output_size.y / 2) }; const vec2i actual_texture_size = {self->pipewire_data.texture_width, self->pipewire_data.texture_height}; diff --git a/src/capture/xcomposite.c b/src/capture/xcomposite.c index e148d28..6814fe8 100644 --- a/src/capture/xcomposite.c +++ b/src/capture/xcomposite.c @@ -104,11 +104,11 @@ static int gsr_capture_xcomposite_start(gsr_capture *cap, gsr_capture_metadata * self->texture_size.y = self->window_texture.window_height; if(self->params.output_resolution.x == 0 && self->params.output_resolution.y == 0) { - capture_metadata->width = self->texture_size.x; - capture_metadata->height = self->texture_size.y; + capture_metadata->video_width = self->texture_size.x; + capture_metadata->video_height = self->texture_size.y; } else { - capture_metadata->width = self->params.output_resolution.x; - capture_metadata->height = self->params.output_resolution.y; + capture_metadata->video_width = self->params.output_resolution.x; + capture_metadata->video_height = self->params.output_resolution.y; } self->window_resize_timer = clock_get_monotonic_seconds(); @@ -232,8 +232,8 @@ static int gsr_capture_xcomposite_capture(gsr_capture *cap, gsr_capture_metadata gsr_color_conversion_clear(color_conversion); } - const vec2i output_size = scale_keep_aspect_ratio(self->texture_size, (vec2i){capture_metadata->width, capture_metadata->height}); - const vec2i target_pos = { max_int(0, capture_metadata->width / 2 - output_size.x / 2), max_int(0, capture_metadata->height / 2 - output_size.y / 2) }; + const vec2i output_size = scale_keep_aspect_ratio(self->texture_size, (vec2i){capture_metadata->recording_width, capture_metadata->recording_height}); + const vec2i target_pos = { max_int(0, capture_metadata->video_width / 2 - output_size.x / 2), max_int(0, capture_metadata->video_height / 2 - output_size.y / 2) }; //self->params.egl->glFlush(); //self->params.egl->glFinish(); diff --git a/src/capture/ximage.c b/src/capture/ximage.c index 17e2a02..61aed9c 100644 --- a/src/capture/ximage.c +++ b/src/capture/ximage.c @@ -59,14 +59,14 @@ static int gsr_capture_ximage_start(gsr_capture *cap, gsr_capture_metadata *capt if(self->params.output_resolution.x > 0 && self->params.output_resolution.y > 0) { self->params.output_resolution = scale_keep_aspect_ratio(self->capture_size, self->params.output_resolution); - capture_metadata->width = self->params.output_resolution.x; - capture_metadata->height = self->params.output_resolution.y; + capture_metadata->video_width = self->params.output_resolution.x; + capture_metadata->video_height = self->params.output_resolution.y; } else if(self->params.region_size.x > 0 && self->params.region_size.y > 0) { - capture_metadata->width = self->params.region_size.x; - capture_metadata->height = self->params.region_size.y; + capture_metadata->video_width = self->params.region_size.x; + capture_metadata->video_height = self->params.region_size.y; } else { - capture_metadata->width = self->capture_size.x; - capture_metadata->height = self->capture_size.y; + capture_metadata->video_width = self->capture_size.x; + capture_metadata->video_height = self->capture_size.y; } self->texture_id = gl_create_texture(self->params.egl, self->capture_size.x, self->capture_size.y, GL_RGB8, GL_RGB, GL_LINEAR); @@ -150,8 +150,8 @@ static bool gsr_capture_ximage_upload_to_texture(gsr_capture_ximage *self, int x static int gsr_capture_ximage_capture(gsr_capture *cap, gsr_capture_metadata *capture_metadata, gsr_color_conversion *color_conversion) { gsr_capture_ximage *self = cap->priv; - const vec2i output_size = scale_keep_aspect_ratio(self->capture_size, (vec2i){capture_metadata->width, capture_metadata->height}); - const vec2i target_pos = { max_int(0, capture_metadata->width / 2 - output_size.x / 2), max_int(0, capture_metadata->height / 2 - output_size.y / 2) }; + const vec2i output_size = scale_keep_aspect_ratio(self->capture_size, (vec2i){capture_metadata->recording_width, capture_metadata->recording_height}); + const vec2i target_pos = { max_int(0, capture_metadata->video_width / 2 - output_size.x / 2), max_int(0, capture_metadata->video_height / 2 - output_size.y / 2) }; gsr_capture_ximage_upload_to_texture(self, self->capture_pos.x + self->params.region_position.x, self->capture_pos.y + self->params.region_position.y, self->capture_size.x, self->capture_size.y); gsr_color_conversion_draw(color_conversion, self->texture_id, diff --git a/src/encoder/video/vaapi.c b/src/encoder/video/vaapi.c index 81c03c8..b32d8d3 100644 --- a/src/encoder/video/vaapi.c +++ b/src/encoder/video/vaapi.c @@ -245,8 +245,8 @@ static bool gsr_video_encoder_vaapi_start(gsr_video_encoder *encoder, AVCodecCon video_codec_context->width = FFALIGN(video_codec_context->width, 2); video_codec_context->height = FFALIGN(video_codec_context->height, 2); } else { - video_codec_context->width = FFALIGN(video_codec_context->width, 64); - video_codec_context->height = FFALIGN(video_codec_context->height, 16); + video_codec_context->width = FFALIGN(video_codec_context->width, 256); + video_codec_context->height = FFALIGN(video_codec_context->height, 256); } } else if(self->params.egl->gpu_info.vendor == GSR_GPU_VENDOR_AMD && video_codec_context->codec_id == AV_CODEC_ID_AV1) { // TODO: Dont do this for VCN 5 and forward which should fix this hardware bug diff --git a/src/main.cpp b/src/main.cpp index 0f29b3a..0d1b891 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -2326,8 +2326,10 @@ static void capture_image_to_file(args_parser &arg_parser, gsr_egl *egl, gsr_ima gsr_capture *capture = create_capture_impl(arg_parser, egl, prefer_ximage); gsr_capture_metadata capture_metadata; - capture_metadata.width = 0; - capture_metadata.height = 0; + capture_metadata.video_width = 0; + capture_metadata.video_height = 0; + capture_metadata.recording_width = 0; + capture_metadata.recording_height = 0; capture_metadata.fps = fps; int capture_result = gsr_capture_start(capture, &capture_metadata); @@ -2336,8 +2338,11 @@ static void capture_image_to_file(args_parser &arg_parser, gsr_egl *egl, gsr_ima _exit(capture_result); } + capture_metadata.recording_width = capture_metadata.video_width; + capture_metadata.recording_height = capture_metadata.video_height; + gsr_image_writer image_writer; - if(!gsr_image_writer_init_opengl(&image_writer, egl, capture_metadata.width, capture_metadata.height)) { + if(!gsr_image_writer_init_opengl(&image_writer, egl, capture_metadata.video_width, capture_metadata.video_height)) { fprintf(stderr, "gsr error: capture_image_to_file_wayland: gsr_image_write_gl_init failed\n"); _exit(1); } @@ -2349,7 +2354,7 @@ static void capture_image_to_file(args_parser &arg_parser, gsr_egl *egl, gsr_ima color_conversion_params.load_external_image_shader = gsr_capture_uses_external_image(capture); color_conversion_params.destination_textures[0] = image_writer.texture; - color_conversion_params.destination_textures_size[0] = { capture_metadata.width, capture_metadata.height }; + color_conversion_params.destination_textures_size[0] = { capture_metadata.video_width, capture_metadata.video_height }; color_conversion_params.num_destination_textures = 1; color_conversion_params.destination_color = GSR_DESTINATION_COLOR_RGB8; @@ -2826,7 +2831,7 @@ static const AVCodec* pick_video_codec(gsr_egl *egl, args_parser *args_parser, b /* Returns -1 if none is available */ static gsr_video_codec select_appropriate_video_codec_automatically(gsr_capture_metadata capture_metadata, const gsr_supported_video_codecs *supported_video_codecs) { - const vec2i capture_size = {capture_metadata.width, capture_metadata.height}; + const vec2i capture_size = {capture_metadata.video_width, capture_metadata.video_height}; if(supported_video_codecs->h264.supported && codec_supports_resolution(supported_video_codecs->h264.max_resolution, capture_size)) { fprintf(stderr, "gsr info: using h264 encoder because a codec was not specified\n"); return GSR_VIDEO_CODEC_H264; @@ -2910,7 +2915,7 @@ static const AVCodec* select_video_codec_with_fallback(gsr_capture_metadata capt const AVCodec *codec = pick_video_codec(egl, args_parser, is_flv, low_power, &supported_video_codecs); const vec2i codec_max_resolution = codec_get_max_resolution(args_parser->video_codec, args_parser->video_encoder == GSR_VIDEO_ENCODER_HW_CPU, &supported_video_codecs); - const vec2i capture_size = {capture_metadata.width, capture_metadata.height}; + const vec2i capture_size = {capture_metadata.video_width, capture_metadata.video_height}; if(!codec_supports_resolution(codec_max_resolution, capture_size)) { const char *video_codec_name = video_codec_to_string(args_parser->video_codec); fprintf(stderr, "gsr error: The max resolution for video codec %s is %dx%d while you are trying to capture at resolution %dx%d. Change capture resolution or video codec and try again\n", @@ -3310,8 +3315,10 @@ int main(int argc, char **argv) { gsr_capture *capture = create_capture_impl(arg_parser, &egl, false); gsr_capture_metadata capture_metadata; - capture_metadata.width = 0; - capture_metadata.height = 0; + capture_metadata.video_width = 0; + capture_metadata.video_height = 0; + capture_metadata.recording_width = 0; + capture_metadata.recording_height = 0; capture_metadata.fps = arg_parser.fps; int capture_result = gsr_capture_start(capture, &capture_metadata); @@ -3336,7 +3343,7 @@ int main(int argc, char **argv) { const AVCodec *video_codec_f = select_video_codec_with_fallback(capture_metadata, &arg_parser, file_extension.c_str(), &egl, &low_power); const enum AVPixelFormat video_pix_fmt = get_pixel_format(arg_parser.video_codec, egl.gpu_info.vendor, arg_parser.video_encoder == GSR_VIDEO_ENCODER_HW_CPU); - AVCodecContext *video_codec_context = create_video_codec_context(video_pix_fmt, video_codec_f, egl, arg_parser, capture_metadata.width, capture_metadata.height); + AVCodecContext *video_codec_context = create_video_codec_context(video_pix_fmt, video_codec_f, egl, arg_parser, capture_metadata.video_width, capture_metadata.video_height); if(!is_replaying) video_stream = create_stream(av_format_context, video_codec_context); @@ -3346,8 +3353,8 @@ int main(int argc, char **argv) { _exit(1); } video_frame->format = video_codec_context->pix_fmt; - video_frame->width = capture_metadata.width; - video_frame->height = capture_metadata.height; + video_frame->width = capture_metadata.video_width; + video_frame->height = capture_metadata.video_height; video_frame->color_range = video_codec_context->color_range; video_frame->color_primaries = video_codec_context->color_primaries; video_frame->color_trc = video_codec_context->color_trc; @@ -3372,9 +3379,12 @@ int main(int argc, char **argv) { _exit(1); } + capture_metadata.recording_width = capture_metadata.video_width; + capture_metadata.recording_height = capture_metadata.video_height; + // TODO: What if this updated resolution is above max resolution? - capture_metadata.width = video_codec_context->width; - capture_metadata.height = video_codec_context->height; + capture_metadata.video_width = video_codec_context->width; + capture_metadata.video_height = video_codec_context->height; const Arg *plugin_arg = args_parser_get_arg(&arg_parser, "-p"); assert(plugin_arg); @@ -3387,8 +3397,8 @@ int main(int argc, char **argv) { assert(color_depth == GSR_COLOR_DEPTH_8_BITS || color_depth == GSR_COLOR_DEPTH_10_BITS); const gsr_plugin_init_params plugin_init_params = { - (unsigned int)capture_metadata.width, - (unsigned int)capture_metadata.height, + (unsigned int)capture_metadata.video_width, + (unsigned int)capture_metadata.video_height, (unsigned int)arg_parser.fps, color_depth == GSR_COLOR_DEPTH_8_BITS ? GSR_PLUGIN_COLOR_DEPTH_8_BITS : GSR_PLUGIN_COLOR_DEPTH_10_BITS, egl.context_type == GSR_GL_CONTEXT_TYPE_GLX ? GSR_PLUGIN_GRAPHICS_API_GLX : GSR_PLUGIN_GRAPHICS_API_EGL_ES, @@ -3828,9 +3838,9 @@ int main(int argc, char **argv) { if(plugins.num_plugins > 0) { gsr_plugins_draw(&plugins); gsr_color_conversion_draw(&color_conversion, plugins.texture, - {0, 0}, {capture_metadata.width, capture_metadata.height}, - {0, 0}, {capture_metadata.width, capture_metadata.height}, - {capture_metadata.width, capture_metadata.height}, GSR_ROT_0, GSR_SOURCE_COLOR_RGB, false); + {0, 0}, {capture_metadata.video_width, capture_metadata.video_height}, + {0, 0}, {capture_metadata.video_width, capture_metadata.video_height}, + {capture_metadata.video_width, capture_metadata.video_height}, GSR_ROT_0, GSR_SOURCE_COLOR_RGB, false); } if(capture_has_synchronous_task) {