rskit_media/stream/
spatial.rs1use serde::{Deserialize, Serialize};
4
5#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
7pub struct Resolution {
8 pub width: u32,
10 pub height: u32,
12}
13
14impl Resolution {
15 pub fn new(w: u32, h: u32) -> Self {
17 Self {
18 width: w,
19 height: h,
20 }
21 }
22
23 pub fn p360() -> Self {
25 Self::new(640, 360)
26 }
27 pub fn p480() -> Self {
29 Self::new(854, 480)
30 }
31 pub fn p720() -> Self {
33 Self::new(1280, 720)
34 }
35 pub fn p1080() -> Self {
37 Self::new(1920, 1080)
38 }
39 pub fn p1440() -> Self {
41 Self::new(2560, 1440)
42 }
43 pub fn p4k() -> Self {
45 Self::new(3840, 2160)
46 }
47
48 pub fn aspect_ratio(&self) -> (u32, u32) {
50 let g = gcd(self.width, self.height);
51 match (self.width.checked_div(g), self.height.checked_div(g)) {
52 (Some(w), Some(h)) => (w, h),
53 _ => (0, 0),
54 }
55 }
56
57 pub fn aspect_ratio_f64(&self) -> f64 {
59 if self.height == 0 {
60 0.0
61 } else {
62 self.width as f64 / self.height as f64
63 }
64 }
65
66 pub fn is_portrait(&self) -> bool {
68 self.height > self.width
69 }
70
71 pub fn is_landscape(&self) -> bool {
73 self.width > self.height
74 }
75
76 pub fn is_square(&self) -> bool {
78 self.width == self.height
79 }
80
81 pub fn pixel_count(&self) -> u64 {
83 self.width as u64 * self.height as u64
84 }
85
86 pub fn scale_to_fit(&self, max_width: u32, max_height: u32) -> Self {
88 let w_ratio = max_width as f64 / self.width as f64;
89 let h_ratio = max_height as f64 / self.height as f64;
90 let ratio = w_ratio.min(h_ratio);
91 Self::new(
92 (self.width as f64 * ratio).round() as u32,
93 (self.height as f64 * ratio).round() as u32,
94 )
95 }
96
97 pub fn scale_to_fill(&self, width: u32, height: u32) -> Self {
99 let w_ratio = width as f64 / self.width as f64;
100 let h_ratio = height as f64 / self.height as f64;
101 let ratio = w_ratio.max(h_ratio);
102 Self::new(
103 (self.width as f64 * ratio).round() as u32,
104 (self.height as f64 * ratio).round() as u32,
105 )
106 }
107
108 pub fn scale_by(&self, factor: f64) -> Self {
110 Self::new(
111 (self.width as f64 * factor).round() as u32,
112 (self.height as f64 * factor).round() as u32,
113 )
114 }
115}
116
117fn gcd(a: u32, b: u32) -> u32 {
118 if b == 0 { a } else { gcd(b, a % b) }
119}
120
121#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
123pub struct FrameRate {
124 pub num: u32,
126 pub den: u32,
128}
129
130impl FrameRate {
131 pub fn new(num: u32, den: u32) -> Self {
133 Self { num, den }
134 }
135
136 pub fn fps(n: u32) -> Self {
138 Self::new(n, 1)
139 }
140
141 pub fn fps_24() -> Self {
143 Self::new(24, 1)
144 }
145 pub fn fps_25() -> Self {
147 Self::new(25, 1)
148 }
149 pub fn fps_30() -> Self {
151 Self::new(30, 1)
152 }
153 pub fn fps_50() -> Self {
155 Self::new(50, 1)
156 }
157 pub fn fps_60() -> Self {
159 Self::new(60, 1)
160 }
161 pub fn ntsc_30() -> Self {
163 Self::new(30000, 1001)
164 }
165 pub fn ntsc_24() -> Self {
167 Self::new(24000, 1001)
168 }
169 pub fn ntsc_60() -> Self {
171 Self::new(60000, 1001)
172 }
173
174 pub fn as_f64(&self) -> f64 {
176 if self.den == 0 {
177 0.0
178 } else {
179 self.num as f64 / self.den as f64
180 }
181 }
182}