From a3ce15a9e538c2c2e84bd4de91a18ab6efb46faf Mon Sep 17 00:00:00 2001 From: Carl <5f365698229751c0461f57bb03a4e93134e6e936bd7039ebe7b737282a43c754@buzz.block.builderlab.xyz> Date: Tue, 18 Aug 2026 16:18:31 -0700 Subject: [PATCH] fix(media): accept portrait video resolutions Signed-off-by: Carl <5f365698229751c0461f57bb03a4e93134e6e936bd7039ebe7b737282a43c754@buzz.block.builderlab.xyz> --- crates/buzz-media/src/error.rs | 6 ++-- crates/buzz-media/src/validation.rs | 47 +++++++++++++++++++++++++++-- 2 files changed, 48 insertions(+), 5 deletions(-) diff --git a/crates/buzz-media/src/error.rs b/crates/buzz-media/src/error.rs index 14ce4afe1e8..5abbea6f580 100644 --- a/crates/buzz-media/src/error.rs +++ b/crates/buzz-media/src/error.rs @@ -72,8 +72,10 @@ pub enum MediaError { /// Video duration exceeds the 600-second limit. #[error("video too long: duration exceeds 600 seconds")] DurationTooLong, - /// Video resolution exceeds 3840×2160. - #[error("video resolution too high: maximum is 3840x2160")] + /// Video resolution exceeds the 2160 short-edge / 3840 long-edge envelope. + #[error( + "video resolution too high: maximum is 2160 on the short edge and 3840 on the long edge" + )] ResolutionTooHigh, /// MP4 moov atom appears after mdat — not fast-start. #[error("moov atom not at front of file (not fast-start)")] diff --git a/crates/buzz-media/src/validation.rs b/crates/buzz-media/src/validation.rs index dfc61c42751..706c354d043 100644 --- a/crates/buzz-media/src/validation.rs +++ b/crates/buzz-media/src/validation.rs @@ -294,7 +294,7 @@ pub fn validate_content(bytes: &[u8], config: &MediaConfig) -> Result Result 3840 || height > 2160 { + let short_edge = width.min(height); + let long_edge = width.max(height); + if short_edge > 2160 || long_edge > 3840 { return Err(MediaError::ResolutionTooHigh); } @@ -2547,6 +2551,43 @@ mod tests { ); } + #[test] + fn test_validate_video_accepts_portrait_resolution() { + let mp4_bytes = build_mp4_bytes(true, b"avc1", 1_000, 2160, 3840, false); + let tmp = tempfile::NamedTempFile::new().unwrap(); + std::fs::write(tmp.path(), &mp4_bytes).unwrap(); + + let meta = validate_video_file(tmp.path(), &test_config()) + .expect("portrait video within the 2160x3840 envelope should be accepted"); + assert_eq!((meta.width, meta.height), (2160, 3840)); + } + + #[test] + fn test_validate_video_rejects_resolution_above_short_edge_limit() { + let mp4_bytes = build_mp4_bytes(true, b"avc1", 1_000, 2161, 3840, false); + let tmp = tempfile::NamedTempFile::new().unwrap(); + std::fs::write(tmp.path(), &mp4_bytes).unwrap(); + + let result = validate_video_file(tmp.path(), &test_config()); + assert!( + matches!(result, Err(MediaError::ResolutionTooHigh)), + "expected ResolutionTooHigh, got {result:?}" + ); + } + + #[test] + fn test_validate_video_rejects_resolution_above_long_edge_limit() { + let mp4_bytes = build_mp4_bytes(true, b"avc1", 1_000, 2160, 3841, false); + let tmp = tempfile::NamedTempFile::new().unwrap(); + std::fs::write(tmp.path(), &mp4_bytes).unwrap(); + + let result = validate_video_file(tmp.path(), &test_config()); + assert!( + matches!(result, Err(MediaError::ResolutionTooHigh)), + "expected ResolutionTooHigh, got {result:?}" + ); + } + #[test] fn test_validate_video_resolution_too_high() { let config = test_config();