diff --git a/src/iotro.rs b/src/iotro.rs index cdbd1b2..e37045e 100644 --- a/src/iotro.rs +++ b/src/iotro.rs @@ -191,8 +191,8 @@ impl Iotro { fn finish(self) -> Graphic { let mut svg = Graphic::new(); - svg.set_width(self.res.width); - svg.set_height(self.res.height); + svg.set_width(self.res.width()); + svg.set_height(self.res.height()); svg.set_view_box("0 0 1920 1080"); svg.push( Rect::new() diff --git a/src/project.rs b/src/project.rs index 3611317..93d7a45 100644 --- a/src/project.rs +++ b/src/project.rs @@ -16,32 +16,41 @@ use std::{ }; #[derive(Clone, Copy, Debug, Deserialize, Serialize)] -pub struct Resolution { - pub width: u32, - pub height: u32 -} +pub struct Resolution(u32, u32); impl Resolution { + pub fn new(width: u32, height: u32) -> Self { + Self(width, height) + } + + pub fn width(self) -> u32 { + self.0 + } + + pub fn height(self) -> u32 { + self.1 + } + pub(crate) fn bitrate(self) -> u64 { // 640 * 360: 500k - if self.width <= 640 { + if self.width() <= 640 { 500_000 } // 1280 * 720: 1M - else if self.width <= 1280 { + else if self.width() <= 1280 { 1_000_000 } // 1920 * 1080: 2M - else if self.width <= 1920 { + else if self.width() <= 1920 { 2_000_000 } // 2560 * 1440: 3M - else if self.width <= 2560 { + else if self.width() <= 2560 { 3_000_000 } // 3840 * 2160: 4M // TODO die bitrate von 4M ist absolut an den haaren herbeigezogen - else if self.width <= 3840 { + else if self.width() <= 3840 { 4_000_000 } // we'll cap everything else at 5M for no apparent reason @@ -51,7 +60,7 @@ impl Resolution { } pub(crate) fn default_codec(self) -> FfmpegOutputFormat { - if self.width > 1920 { + if self.width() > 1920 { FfmpegOutputFormat::Av1Opus } else { FfmpegOutputFormat::AvcAac @@ -59,32 +68,17 @@ impl Resolution { } pub const STANDARD_RESOLUTIONS: [Self; 5] = [ - Self { - width: 640, - height: 360 - }, - Self { - width: 1280, - height: 720 - }, - Self { - width: 1920, - height: 1080 - }, - Self { - width: 2560, - height: 1440 - }, - Self { - width: 3840, - height: 2160 - } + Self(640, 360), + Self(1280, 720), + Self(1920, 1080), + Self(2560, 1440), + Self(3840, 2160) ]; } impl Display for Resolution { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - write!(f, "{}p", self.height) + write!(f, "{}p", self.height()) } } @@ -93,34 +87,13 @@ impl FromStr for Resolution { fn from_str(s: &str) -> anyhow::Result { Ok(match s.to_lowercase().as_str() { - "360p" | "nhd" => Self { - width: 640, - height: 360 - }, - "540p" | "qhd" => Self { - width: 960, - height: 540 - }, - "720p" | "hd" => Self { - width: 1280, - height: 720 - }, - "900p" | "hd+" => Self { - width: 1600, - height: 900 - }, - "1080p" | "fhd" | "fullhd" => Self { - width: 1920, - height: 1080 - }, - "1440p" | "wqhd" => Self { - width: 2560, - height: 1440 - }, - "2160p" | "4k" | "uhd" => Self { - width: 3840, - height: 2160 - }, + "360p" | "nhd" => Self(640, 360), + "540p" | "qhd" => Self(960, 540), + "720p" | "hd" => Self(1280, 720), + "900p" | "hd+" => Self(1600, 900), + "1080p" | "fhd" | "fullhd" => Self(1920, 1080), + "1440p" | "wqhd" => Self(2560, 1440), + "2160p" | "4k" | "uhd" => Self(3840, 2160), _ => anyhow::bail!("Unknown Resolution: {s:?}") }) } @@ -128,7 +101,7 @@ impl FromStr for Resolution { impl Ord for Resolution { fn cmp(&self, other: &Self) -> cmp::Ordering { - (self.width * self.height).cmp(&(other.width * other.height)) + (self.0 * self.1).cmp(&(other.0 * other.1)) } } @@ -146,7 +119,7 @@ impl PartialEq for Resolution { } } -#[derive(Deserialize, Serialize)] +#[derive(Debug, Deserialize, Serialize)] pub struct Project { pub lecture: ProjectLecture, pub source: ProjectSource, @@ -154,7 +127,7 @@ pub struct Project { } #[serde_as] -#[derive(Deserialize, Serialize)] +#[derive(Debug, Deserialize, Serialize)] pub struct ProjectLecture { pub course: String, pub label: String, @@ -167,7 +140,7 @@ pub struct ProjectLecture { } #[serde_as] -#[derive(Deserialize, Serialize)] +#[derive(Debug, Deserialize, Serialize)] pub struct ProjectSource { pub files: Vec, pub stereo: bool, @@ -189,7 +162,7 @@ pub struct ProjectSource { } #[serde_as] -#[derive(Deserialize, Serialize)] +#[derive(Debug, Deserialize, Serialize)] pub struct ProjectSourceMetadata { /// The duration of the source video. #[serde_as(as = "DisplayFromStr")] @@ -207,7 +180,7 @@ pub struct ProjectSourceMetadata { } #[serde_as] -#[derive(Default, Deserialize, Serialize)] +#[derive(Debug, Default, Deserialize, Serialize)] pub struct ProjectProgress { #[serde(default)] pub preprocessed: bool, diff --git a/src/question.rs b/src/question.rs index 0f61a1c..6bf0da6 100644 --- a/src/question.rs +++ b/src/question.rs @@ -131,8 +131,8 @@ impl Question { pub(crate) fn finish(self) -> Graphic { let mut svg = Graphic::new(); - svg.set_width(self.res.width); - svg.set_height(self.res.height); + svg.set_width(self.res.width()); + svg.set_height(self.res.height()); svg.set_view_box("0 0 1920 1080"); svg.push(self.g); svg diff --git a/src/render/ffmpeg.rs b/src/render/ffmpeg.rs index af41095..07bca84 100644 --- a/src/render/ffmpeg.rs +++ b/src/render/ffmpeg.rs @@ -359,9 +359,9 @@ impl Ffmpeg { }, FfmpegFilter::Rescale(res) => { cmd.arg("-vf").arg(if vaapi { - format!("scale_vaapi=w={}:h={}", res.width, res.height) + format!("scale_vaapi=w={}:h={}", res.width(), res.height()) } else { - format!("scale=w={}:h={}", res.width, res.height) + format!("scale=w={}:h={}", res.width(), res.height()) }); } } diff --git a/src/render/mod.rs b/src/render/mod.rs index 1845862..332bea1 100644 --- a/src/render/mod.rs +++ b/src/render/mod.rs @@ -264,7 +264,7 @@ impl<'a> Renderer<'a> { let width = ffprobe_video("stream=width", &recording_mkv)?.parse()?; let height = ffprobe_video("stream=height", &recording_mkv)?.parse()?; - let source_res = Resolution { width, height }; + let source_res = Resolution::new(width, height); project.source.metadata = Some(ProjectSourceMetadata { source_duration: ffprobe_video("format=duration", &recording_mkv)?.parse()?, source_fps: ffprobe_video("stream=r_frame_rate", &recording_mkv)?.parse()?, @@ -316,7 +316,7 @@ impl<'a> Renderer<'a> { include_bytes!(concat!(env!("CARGO_MANIFEST_DIR"), "/assets/logo.svg")) )?; let logo_png = self.target.join("logo.png"); - let logo_size = LOGO_SIZE * metadata.source_res.width / 1920; + let logo_size = LOGO_SIZE * metadata.source_res.width() / 1920; svg2png(&logo_svg, &logo_png, logo_size, logo_size)?; // copy fastforward then render to png @@ -329,7 +329,7 @@ impl<'a> Renderer<'a> { )) )?; let fastforward_png = self.target.join("fastforward.png"); - let ff_logo_size = FF_LOGO_SIZE * metadata.source_res.width / 1920; + let ff_logo_size = FF_LOGO_SIZE * metadata.source_res.width() / 1920; svg2png( &fastforward_svg, &fastforward_png, @@ -349,8 +349,8 @@ impl<'a> Renderer<'a> { svg2png( &q_svg, &q_png, - metadata.source_res.width, - metadata.source_res.height + metadata.source_res.width(), + metadata.source_res.height() )?; } @@ -365,7 +365,7 @@ impl<'a> Renderer<'a> { FfmpegOutputFormat::AvcAac => "mp4" }; self.target - .join(format!("{}-{}p.{extension}", self.slug, res.height)) + .join(format!("{}-{}p.{extension}", self.slug, res.height())) } /// Get the video file directly outputed to further transcode. @@ -622,8 +622,8 @@ impl<'a> Renderer<'a> { output: logoalpha.into() }); let overlay = "overlay"; - let overlay_off_x = 130 * source_res.width / 3840; - let overlay_off_y = 65 * source_res.height / 2160; + let overlay_off_x = 130 * source_res.width() / 3840; + let overlay_off_y = 65 * source_res.height() / 2160; ffmpeg.add_filter(Filter::Overlay { video_input: concat.into(), overlay_input: logoalpha.into(), @@ -652,7 +652,7 @@ impl<'a> Renderer<'a> { println!( " {} {}", style("==>").bold().cyan(), - style(format!("Rescaling to {}p", res.height)).bold() + style(format!("Rescaling to {}p", res.height())).bold() ); let mut ffmpeg = Ffmpeg::new(FfmpegOutput {