Skip to content

Commit f0415a3

Browse files
committed
clamp resolution better
1 parent fa9701b commit f0415a3

File tree

2 files changed

+227
-11
lines changed

2 files changed

+227
-11
lines changed

crates/recording/src/capture_pipeline.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ impl MakeCapturePipeline for screen_capture::Direct3DCapture {
8585
.build::<WindowsMuxer>(WindowsMuxerConfig {
8686
pixel_format: screen_capture::Direct3DCapture::PIXEL_FORMAT.as_dxgi(),
8787
d3d_device,
88-
bitrate_multiplier: 0.1f32,
88+
bitrate_multiplier: 0.15f32,
8989
frame_rate: 30u32,
9090
output_size: None,
9191
})
@@ -115,7 +115,7 @@ impl MakeCapturePipeline for screen_capture::Direct3DCapture {
115115
output_builder
116116
.build::<WindowsMuxer>(WindowsMuxerConfig {
117117
pixel_format: screen_capture::Direct3DCapture::PIXEL_FORMAT.as_dxgi(),
118-
bitrate_multiplier: 0.08f32,
118+
bitrate_multiplier: 0.15f32,
119119
frame_rate: 30u32,
120120
d3d_device,
121121
output_size: Some(windows::Graphics::SizeInt32 {

crates/recording/src/instant_recording.rs

Lines changed: 225 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -205,15 +205,18 @@ async fn create_pipeline(
205205
let screen_info = screen_source.info();
206206

207207
let output_resolution = max_output_size
208-
.map(|max_size| {
209-
// restrict width if more square-y and w > h, or excessively tall
210-
// we don't just uniformly restrict width or height as this massively squashes ultrawide/ultratall captures
208+
.map(|max_output_width| {
209+
(
210+
max_output_width,
211+
(max_output_width as f64 / 16.0 * 9.0) as u32,
212+
)
213+
})
214+
.map(|(max_width, max_height)| {
215+
// 16/9-ish
211216
if screen_info.width >= screen_info.height
212-
&& (screen_info.width as f64 / screen_info.height as f64) <= 16.9
213-
|| (screen_info.width < screen_info.height
214-
&& (screen_info.width as f64 / screen_info.height as f64) >= 16.9)
217+
&& (screen_info.width as f64 / screen_info.height as f64) <= 16.0 / 9.0
215218
{
216-
let mut width = max_size.min(screen_info.width);
219+
let mut width = max_width.min(screen_info.width);
217220
if width % 2 != 0 {
218221
width -= 1;
219222
}
@@ -225,8 +228,29 @@ async fn create_pipeline(
225228
}
226229

227230
(width, height)
228-
} else {
229-
let mut height = max_size.min(screen_info.height);
231+
}
232+
// 9/16-ish
233+
else if screen_info.width <= screen_info.height
234+
&& (screen_info.width as f64 / screen_info.height as f64) >= 9.0 / 16.0
235+
{
236+
let mut height = max_height.min(screen_info.height);
237+
if height % 2 != 0 {
238+
height -= 1;
239+
}
240+
241+
let width_ratio = screen_info.width as f64 / screen_info.height as f64;
242+
let mut width = (width_ratio * height as f64).round() as u32;
243+
if width % 2 != 0 {
244+
width -= 1;
245+
}
246+
247+
(width, height)
248+
}
249+
// ultrawide
250+
else if screen_info.width >= screen_info.height
251+
&& (screen_info.width as f64 / screen_info.height as f64) > 16.0 / 9.0
252+
{
253+
let mut height = max_height.min(screen_info.height);
230254
if height % 2 != 0 {
231255
height -= 1;
232256
}
@@ -239,6 +263,26 @@ async fn create_pipeline(
239263

240264
(width, height)
241265
}
266+
// ultratall
267+
else if screen_info.width < screen_info.height
268+
&& (screen_info.width as f64 / screen_info.height as f64) <= 9.0 / 16.0
269+
{
270+
// swapped since max_width/height assume horizontal
271+
let mut width = max_height.min(screen_info.width);
272+
if width % 2 != 0 {
273+
width -= 1;
274+
}
275+
276+
let height_ratio = screen_info.height as f64 / screen_info.width as f64;
277+
let mut height = (height_ratio * width as f64).round() as u32;
278+
if height % 2 != 0 {
279+
height -= 1;
280+
}
281+
282+
(width, height)
283+
} else {
284+
unreachable!()
285+
}
242286
})
243287
.unwrap_or((screen_info.width, screen_info.height));
244288

@@ -423,3 +467,175 @@ fn current_time_f64() -> f64 {
423467
.unwrap()
424468
.as_secs_f64()
425469
}
470+
471+
fn clamp_size(input: (u32, u32), max: (u32, u32)) -> (u32, u32) {
472+
// 16/9-ish
473+
if input.0 >= input.1 && (input.0 as f64 / input.1 as f64) <= 16.0 / 9.0 {
474+
let mut width = max.0.min(input.0);
475+
if width % 2 != 0 {
476+
width -= 1;
477+
}
478+
479+
let height_ratio = input.1 as f64 / input.0 as f64;
480+
let mut height = (height_ratio * width as f64).round() as u32;
481+
if height % 2 != 0 {
482+
height -= 1;
483+
}
484+
485+
(width, height)
486+
}
487+
// 9/16-ish
488+
else if input.0 <= input.1 && (input.0 as f64 / input.1 as f64) >= 9.0 / 16.0 {
489+
let mut height = max.0.min(input.1);
490+
if height % 2 != 0 {
491+
height -= 1;
492+
}
493+
494+
let width_ratio = input.0 as f64 / input.1 as f64;
495+
let mut width = (width_ratio * height as f64).round() as u32;
496+
if width % 2 != 0 {
497+
width -= 1;
498+
}
499+
500+
(width, height)
501+
}
502+
// ultrawide
503+
else if input.0 >= input.1 && (input.0 as f64 / input.1 as f64) > 16.0 / 9.0 {
504+
let mut height = max.1.min(input.1);
505+
if height % 2 != 0 {
506+
height -= 1;
507+
}
508+
509+
let width_ratio = input.0 as f64 / input.1 as f64;
510+
let mut width = (width_ratio * height as f64).round() as u32;
511+
if width % 2 != 0 {
512+
width -= 1;
513+
}
514+
515+
(width, height)
516+
}
517+
// ultratall
518+
else if input.0 < input.1 && (input.0 as f64 / input.1 as f64) <= 9.0 / 16.0 {
519+
// swapped since max_width/height assume horizontal
520+
let mut width = max.1.min(input.0);
521+
if width % 2 != 0 {
522+
width -= 1;
523+
}
524+
525+
let height_ratio = input.1 as f64 / input.0 as f64;
526+
let mut height = (height_ratio * width as f64).round() as u32;
527+
if height % 2 != 0 {
528+
height -= 1;
529+
}
530+
531+
(width, height)
532+
} else {
533+
unreachable!()
534+
}
535+
}
536+
537+
#[cfg(test)]
538+
mod tests {
539+
use super::*;
540+
541+
#[test]
542+
fn test_clamp_size_16_9_ish_landscape() {
543+
// Test 16:9 aspect ratio (boundary case)
544+
let result = clamp_size((1920, 1080), (1920, 1080));
545+
assert_eq!(result, (1920, 1080));
546+
547+
// Test aspect ratio less than 16:9 (wider than tall, but not ultrawide)
548+
let result = clamp_size((1600, 1200), (1920, 1080)); // 4:3 ratio
549+
assert_eq!(result, (1600, 1200));
550+
551+
// Test scaling down when input exceeds max width
552+
let result = clamp_size((2560, 1440), (1920, 1080)); // 16:9 ratio, needs scaling
553+
assert_eq!(result, (1920, 1080));
554+
}
555+
556+
#[test]
557+
fn test_clamp_size_9_16_ish_portrait() {
558+
// Test 9:16 aspect ratio (boundary case)
559+
let result = clamp_size((1080, 1920), (1920, 1080));
560+
assert_eq!(result, (1080, 1920));
561+
562+
// Test aspect ratio greater than 9:16 but still portrait
563+
let result = clamp_size((1200, 1600), (1920, 1080)); // 3:4 ratio
564+
assert_eq!(result, (1200, 1600));
565+
566+
// Test square format (1:1 ratio) - should use portrait path when width <= height
567+
let result = clamp_size((1080, 1080), (1920, 1080));
568+
assert_eq!(result, (1080, 1080));
569+
}
570+
571+
#[test]
572+
fn test_clamp_size_ultrawide() {
573+
// Test ultrawide aspect ratio (> 16:9)
574+
let result = clamp_size((2560, 1080), (1920, 1080)); // ~2.37:1 ratio
575+
assert_eq!(result, (2560, 1080));
576+
577+
// Test very ultrawide
578+
let result = clamp_size((3440, 1440), (1920, 1080)); // ~2.39:1 ratio
579+
assert_eq!(result, (2580, 1080));
580+
581+
// Test when height constraint is the limiting factor
582+
let result = clamp_size((3840, 1600), (1920, 1080)); // 2.4:1 ratio
583+
assert_eq!(result, (2592, 1080));
584+
585+
// Test even number enforcement for height
586+
let result = clamp_size((2561, 1080), (1920, 1081)); // Odd max height
587+
assert_eq!(result, (2560, 1080)); // Height should be made even
588+
589+
// Test even number enforcement for calculated width
590+
let result = clamp_size((2561, 1080), (1920, 1080)); // Results in odd width calculation
591+
assert_eq!(result, (2560, 1080)); // Width should be made even
592+
}
593+
594+
#[test]
595+
fn test_clamp_size_ultratall() {
596+
// Test ultratall aspect ratio (< 9:16)
597+
let result = clamp_size((1080, 2560), (1920, 1920)); // ~9:21.3 ratio
598+
assert_eq!(result, (1080, 2560));
599+
600+
// Test very ultratall that needs scaling
601+
let result = clamp_size((800, 3200), (1920, 2000)); // 1:4 ratio
602+
assert_eq!(result, (800, 3200));
603+
604+
// Test when width constraint is the limiting factor (using max.1 as width limit)
605+
let result = clamp_size((500, 3000), (1920, 1000)); // Very tall, width limited by max.1
606+
assert_eq!(result, (500, 3000));
607+
608+
// Test even number enforcement for width (using max.1)
609+
let result = clamp_size((500, 3000), (1920, 1001)); // Odd max.1 used as width
610+
assert_eq!(result, (500, 3000)); // Width should be made even
611+
612+
// Test even number enforcement for calculated height
613+
let result = clamp_size((500, 3000), (1920, 1000)); // Results in odd height calculation
614+
assert_eq!(result, (500, 3000)); // Height should be made even
615+
}
616+
617+
#[test]
618+
fn test_clamp_size_edge_cases() {
619+
// Test minimum sizes
620+
let result = clamp_size((2, 2), (1920, 1080));
621+
assert_eq!(result, (2, 2));
622+
623+
// Test when input is smaller than max in all dimensions
624+
let result = clamp_size((800, 600), (1920, 1080));
625+
assert_eq!(result, (800, 600));
626+
627+
// Test exact 16:9 boundary
628+
let sixteen_nine = 16.0 / 9.0;
629+
let width = 1920;
630+
let height = (width as f64 / sixteen_nine) as u32; // Should be exactly 1080
631+
let result = clamp_size((width, height), (1920, 1080));
632+
assert_eq!(result, (1920, 1080));
633+
634+
// Test exact 9:16 boundary
635+
let nine_sixteen = 9.0 / 16.0;
636+
let height = 1920;
637+
let width = (height as f64 * nine_sixteen) as u32; // Should be exactly 1080
638+
let result = clamp_size((width, height), (1920, 1080));
639+
assert_eq!(result, (1080, 1920));
640+
}
641+
}

0 commit comments

Comments
 (0)