use g2g_core::RawVideoFormat;
pub fn format_to_py(fmt: RawVideoFormat) -> &'static str {
match fmt {
RawVideoFormat::Rgba8 => "RGBA",
RawVideoFormat::Bgra8 => "BGRA",
RawVideoFormat::Rgb8 => "RGB",
RawVideoFormat::Nv12 => "NV12",
RawVideoFormat::I420 => "I420",
RawVideoFormat::Yuyv => "YUY2",
RawVideoFormat::I420p10 => "I420_10LE",
RawVideoFormat::I420p12 => "I420_12LE",
RawVideoFormat::I422 => "Y42B",
RawVideoFormat::I422p10 => "I422_10LE",
RawVideoFormat::I422p12 => "I422_12LE",
RawVideoFormat::I444 => "Y444",
RawVideoFormat::I444p10 => "Y444_10LE",
RawVideoFormat::I444p12 => "Y444_12LE",
RawVideoFormat::P010 => "P010_10LE",
_ => "UNKNOWN",
}
}
pub fn format_from_py(s: &str) -> Option<RawVideoFormat> {
Some(match s {
"RGBA" => RawVideoFormat::Rgba8,
"BGRA" => RawVideoFormat::Bgra8,
"RGB" => RawVideoFormat::Rgb8,
"NV12" => RawVideoFormat::Nv12,
"I420" => RawVideoFormat::I420,
"YUY2" | "YUYV" => RawVideoFormat::Yuyv,
"I420_10LE" => RawVideoFormat::I420p10,
"I420_12LE" => RawVideoFormat::I420p12,
"Y42B" => RawVideoFormat::I422,
"I422_10LE" => RawVideoFormat::I422p10,
"I422_12LE" => RawVideoFormat::I422p12,
"Y444" => RawVideoFormat::I444,
"Y444_10LE" => RawVideoFormat::I444p10,
"Y444_12LE" => RawVideoFormat::I444p12,
"P010_10LE" => RawVideoFormat::P010,
_ => return None,
})
}
pub fn frame_bytes(fmt: RawVideoFormat, width: u32, height: u32) -> usize {
if let Some((hs, vs)) = fmt.chroma_shift() {
let (w, h) = (width as usize, height as usize);
let (cw, ch) = (w.div_ceil(1 << hs), h.div_ceil(1 << vs));
return (w * h + 2 * cw * ch) * fmt.bytes_per_sample();
}
let (w, h) = (width as usize, height as usize);
match fmt {
RawVideoFormat::Rgba8 | RawVideoFormat::Bgra8 => w * h * 4,
RawVideoFormat::Rgb8 => w * h * 3,
RawVideoFormat::Yuyv => w * h * 2,
RawVideoFormat::Nv12 => w * h * 3 / 2,
RawVideoFormat::P010 => w * h * 3,
RawVideoFormat::I420
| RawVideoFormat::I420p10
| RawVideoFormat::I420p12
| RawVideoFormat::I422
| RawVideoFormat::I422p10
| RawVideoFormat::I422p12
| RawVideoFormat::I444
| RawVideoFormat::I444p10
| RawVideoFormat::I444p12 => unreachable!("planar YUV handled by chroma_shift"),
_ => unreachable!("unmodeled packed RawVideoFormat: {fmt:?}"),
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn round_trips_every_modeled_format() {
for fmt in [
RawVideoFormat::Rgba8,
RawVideoFormat::Bgra8,
RawVideoFormat::Nv12,
RawVideoFormat::I420,
RawVideoFormat::Yuyv,
RawVideoFormat::I420p10,
RawVideoFormat::I420p12,
RawVideoFormat::I422,
RawVideoFormat::I422p10,
RawVideoFormat::I422p12,
RawVideoFormat::I444,
RawVideoFormat::I444p10,
RawVideoFormat::I444p12,
] {
assert_eq!(format_from_py(format_to_py(fmt)), Some(fmt));
}
}
#[test]
fn frame_bytes_match_planar_geometry() {
assert_eq!(frame_bytes(RawVideoFormat::I420, 4, 4), 24);
assert_eq!(frame_bytes(RawVideoFormat::I420p10, 4, 4), 48);
assert_eq!(frame_bytes(RawVideoFormat::I422, 4, 4), 32);
assert_eq!(frame_bytes(RawVideoFormat::I422p12, 4, 4), 64);
assert_eq!(frame_bytes(RawVideoFormat::I444, 4, 4), 48);
assert_eq!(frame_bytes(RawVideoFormat::I444p10, 4, 4), 96);
}
#[test]
fn yuyv_is_an_alias_for_yuy2() {
assert_eq!(format_from_py("YUYV"), Some(RawVideoFormat::Yuyv));
assert_eq!(format_from_py("YUY2"), Some(RawVideoFormat::Yuyv));
}
#[test]
fn unmodeled_format_is_none() {
assert_eq!(format_from_py("GRAY8"), None);
}
#[test]
fn frame_bytes_per_format() {
assert_eq!(frame_bytes(RawVideoFormat::Rgba8, 4, 2), 32);
assert_eq!(frame_bytes(RawVideoFormat::Yuyv, 4, 2), 16);
assert_eq!(frame_bytes(RawVideoFormat::Nv12, 4, 2), 12);
}
}