use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct RenditionSpec {
pub name: String,
pub width: u32,
pub height: u32,
pub video_bitrate_kbps: u32,
pub audio_bitrate_kbps: u32,
}
impl RenditionSpec {
pub fn new(
name: impl Into<String>,
width: u32,
height: u32,
video_bitrate_kbps: u32,
audio_bitrate_kbps: u32,
) -> Self {
Self {
name: name.into(),
width,
height,
video_bitrate_kbps,
audio_bitrate_kbps,
}
}
pub fn preset_720p() -> Self {
Self::new("720p", 1280, 720, 2_500, 128)
}
pub fn preset_480p() -> Self {
Self::new("480p", 854, 480, 1_200, 96)
}
pub fn preset_240p() -> Self {
Self::new("240p", 426, 240, 400, 64)
}
pub fn default_ladder() -> Vec<Self> {
vec![Self::preset_720p(), Self::preset_480p(), Self::preset_240p()]
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn presets_match_plan_defaults() {
let r = RenditionSpec::preset_720p();
assert_eq!(r.name, "720p");
assert_eq!((r.width, r.height), (1280, 720));
assert_eq!(r.video_bitrate_kbps, 2_500);
assert_eq!(r.audio_bitrate_kbps, 128);
let r = RenditionSpec::preset_480p();
assert_eq!((r.width, r.height), (854, 480));
let r = RenditionSpec::preset_240p();
assert_eq!((r.width, r.height), (426, 240));
}
#[test]
fn default_ladder_is_highest_to_lowest() {
let ladder = RenditionSpec::default_ladder();
assert_eq!(ladder.len(), 3);
for pair in ladder.windows(2) {
assert!(
pair[0].video_bitrate_kbps > pair[1].video_bitrate_kbps,
"ladder must be highest-to-lowest; got {} before {}",
pair[0].name,
pair[1].name,
);
}
}
#[test]
fn rendition_spec_round_trips_through_json() {
let r = RenditionSpec::new("custom", 1920, 1080, 5_000, 192);
let j = serde_json::to_string(&r).expect("serialize");
let parsed: RenditionSpec = serde_json::from_str(&j).expect("deserialize");
assert_eq!(parsed, r);
}
}