1use g2g_core::RawVideoFormat;
13
14pub fn format_to_py(fmt: RawVideoFormat) -> &'static str {
17 match fmt {
18 RawVideoFormat::Rgba8 => "RGBA",
19 RawVideoFormat::Bgra8 => "BGRA",
20 RawVideoFormat::Rgb8 => "RGB",
21 RawVideoFormat::Nv12 => "NV12",
22 RawVideoFormat::I420 => "I420",
23 RawVideoFormat::Yuyv => "YUY2",
24 RawVideoFormat::I420p10 => "I420_10LE",
25 RawVideoFormat::I420p12 => "I420_12LE",
26 RawVideoFormat::I422 => "Y42B",
27 RawVideoFormat::I422p10 => "I422_10LE",
28 RawVideoFormat::I422p12 => "I422_12LE",
29 RawVideoFormat::I444 => "Y444",
30 RawVideoFormat::I444p10 => "Y444_10LE",
31 RawVideoFormat::I444p12 => "Y444_12LE",
32 RawVideoFormat::P010 => "P010_10LE",
33 _ => "UNKNOWN",
36 }
37}
38
39pub fn format_from_py(s: &str) -> Option<RawVideoFormat> {
43 Some(match s {
44 "RGBA" => RawVideoFormat::Rgba8,
45 "BGRA" => RawVideoFormat::Bgra8,
46 "RGB" => RawVideoFormat::Rgb8,
47 "NV12" => RawVideoFormat::Nv12,
48 "I420" => RawVideoFormat::I420,
49 "YUY2" | "YUYV" => RawVideoFormat::Yuyv,
50 "I420_10LE" => RawVideoFormat::I420p10,
51 "I420_12LE" => RawVideoFormat::I420p12,
52 "Y42B" => RawVideoFormat::I422,
53 "I422_10LE" => RawVideoFormat::I422p10,
54 "I422_12LE" => RawVideoFormat::I422p12,
55 "Y444" => RawVideoFormat::I444,
56 "Y444_10LE" => RawVideoFormat::I444p10,
57 "Y444_12LE" => RawVideoFormat::I444p12,
58 "P010_10LE" => RawVideoFormat::P010,
59 _ => return None,
60 })
61}
62
63pub fn frame_bytes(fmt: RawVideoFormat, width: u32, height: u32) -> usize {
67 if let Some((hs, vs)) = fmt.chroma_shift() {
70 let (w, h) = (width as usize, height as usize);
71 let (cw, ch) = (w.div_ceil(1 << hs), h.div_ceil(1 << vs));
72 return (w * h + 2 * cw * ch) * fmt.bytes_per_sample();
73 }
74 let (w, h) = (width as usize, height as usize);
75 match fmt {
76 RawVideoFormat::Rgba8 | RawVideoFormat::Bgra8 => w * h * 4,
77 RawVideoFormat::Rgb8 => w * h * 3,
79 RawVideoFormat::Yuyv => w * h * 2,
80 RawVideoFormat::Nv12 => w * h * 3 / 2,
81 RawVideoFormat::P010 => w * h * 3,
83 RawVideoFormat::I420
85 | RawVideoFormat::I420p10
86 | RawVideoFormat::I420p12
87 | RawVideoFormat::I422
88 | RawVideoFormat::I422p10
89 | RawVideoFormat::I422p12
90 | RawVideoFormat::I444
91 | RawVideoFormat::I444p10
92 | RawVideoFormat::I444p12 => unreachable!("planar YUV handled by chroma_shift"),
93 _ => unreachable!("unmodeled packed RawVideoFormat: {fmt:?}"),
96 }
97}
98
99#[cfg(test)]
100mod tests {
101 use super::*;
102
103 #[test]
104 fn round_trips_every_modeled_format() {
105 for fmt in [
106 RawVideoFormat::Rgba8,
107 RawVideoFormat::Bgra8,
108 RawVideoFormat::Nv12,
109 RawVideoFormat::I420,
110 RawVideoFormat::Yuyv,
111 RawVideoFormat::I420p10,
112 RawVideoFormat::I420p12,
113 RawVideoFormat::I422,
114 RawVideoFormat::I422p10,
115 RawVideoFormat::I422p12,
116 RawVideoFormat::I444,
117 RawVideoFormat::I444p10,
118 RawVideoFormat::I444p12,
119 ] {
120 assert_eq!(format_from_py(format_to_py(fmt)), Some(fmt));
121 }
122 }
123
124 #[test]
125 fn frame_bytes_match_planar_geometry() {
126 assert_eq!(frame_bytes(RawVideoFormat::I420, 4, 4), 24);
128 assert_eq!(frame_bytes(RawVideoFormat::I420p10, 4, 4), 48);
129 assert_eq!(frame_bytes(RawVideoFormat::I422, 4, 4), 32);
131 assert_eq!(frame_bytes(RawVideoFormat::I422p12, 4, 4), 64);
132 assert_eq!(frame_bytes(RawVideoFormat::I444, 4, 4), 48);
134 assert_eq!(frame_bytes(RawVideoFormat::I444p10, 4, 4), 96);
135 }
136
137 #[test]
138 fn yuyv_is_an_alias_for_yuy2() {
139 assert_eq!(format_from_py("YUYV"), Some(RawVideoFormat::Yuyv));
140 assert_eq!(format_from_py("YUY2"), Some(RawVideoFormat::Yuyv));
141 }
142
143 #[test]
144 fn unmodeled_format_is_none() {
145 assert_eq!(format_from_py("GRAY8"), None);
146 }
147
148 #[test]
149 fn frame_bytes_per_format() {
150 assert_eq!(frame_bytes(RawVideoFormat::Rgba8, 4, 2), 32);
151 assert_eq!(frame_bytes(RawVideoFormat::Yuyv, 4, 2), 16);
152 assert_eq!(frame_bytes(RawVideoFormat::Nv12, 4, 2), 12);
153 }
154}