diff --git a/src/iotro.rs b/src/iotro.rs index 4f98798..94eca89 100644 --- a/src/iotro.rs +++ b/src/iotro.rs @@ -13,16 +13,18 @@ use svgwriter::{ #[derive(Clone)] pub struct Language<'a> { - lang: &'a str, - format_date_long: fn(Date) -> String, + pub(crate) lang: &'a str, + pub(crate) format_date_long: fn(Date) -> String, // intro lecture_from: &'a str, - video_created_by_us: &'a str, + pub(crate) video_created_by_us: &'a str, // outro video_created_by: &'a str, our_website: &'a str, download_videos: &'a str, - questions_feedback: &'a str + questions_feedback: &'a str, + // metadata + pub(crate) from: &'a str } pub const GERMAN: Language<'static> = Language { @@ -54,7 +56,9 @@ pub const GERMAN: Language<'static> = Language { video_created_by: "Video erstellt von der", our_website: "Website der Fachschaft", download_videos: "Videos herunterladen", - questions_feedback: "Fragen, Vorschläge und Feedback" + questions_feedback: "Fragen, Vorschläge und Feedback", + + from: "vom" }; pub const BRITISH: Language<'static> = Language { @@ -88,10 +92,13 @@ pub const BRITISH: Language<'static> = Language { lecture_from: "Lecture from", video_created_by_us: "Video created by the Video AG, Fachschaft I/1", + video_created_by: "Video created by the", our_website: "The Fachschaft's website", download_videos: "Download videos", - questions_feedback: "Questions, Suggestions and Feedback" + questions_feedback: "Questions, Suggestions and Feedback", + + from: "from" }; impl Default for Language<'static> { diff --git a/src/main.rs b/src/main.rs index 048fa36..6c9a7ee 100644 --- a/src/main.rs +++ b/src/main.rs @@ -133,10 +133,10 @@ macro_rules! resolutions { resolutions! { nHD: 640 x 360 at 500_000 in AvcAac, HD: 1280 x 720 at 1_000_000 in AvcAac, - FullHD: 1920 x 1080 at 2_000_000 in Av1Opus, - WQHD: 2560 x 1440 at 3_000_000 in Av1Opus, + FullHD: 1920 x 1080 at 750_000 in Av1Opus, + WQHD: 2560 x 1440 at 1_000_000 in Av1Opus, // TODO qsx muss mal sagen wieviel bitrate für 4k - UHD: 3840 x 2160 at 4_000_000 in Av1Opus + UHD: 3840 x 2160 at 2_000_000 in Av1Opus } #[derive(Deserialize, Serialize)] @@ -369,7 +369,7 @@ fn main() { continue; } if !project.progress.transcoded.contains(&res) { - videos.push(renderer.rescale(res).unwrap()); + videos.push(renderer.rescale(&project.lecture, res).unwrap()); project.progress.transcoded.insert(res); fs::write(&project_path, toml::to_string(&project).unwrap().as_bytes()) diff --git a/src/render/ffmpeg.rs b/src/render/ffmpeg.rs index cb42b53..0213a26 100644 --- a/src/render/ffmpeg.rs +++ b/src/render/ffmpeg.rs @@ -74,6 +74,14 @@ pub(crate) struct FfmpegOutput { pub(crate) fps_mode_vfr: bool, pub(crate) faststart: bool, + // video container metadata + pub(crate) title: Option, + pub(crate) author: Option, + pub(crate) album: Option, + pub(crate) year: Option, + pub(crate) comment: Option, + pub(crate) language: Option, + pub(crate) path: PathBuf } @@ -83,11 +91,20 @@ impl FfmpegOutput { format, audio_bitrate: None, video_bitrate: None, + fps: None, duration: None, time_base: None, fps_mode_vfr: false, faststart: false, + + title: None, + author: None, + album: None, + year: None, + comment: None, + language: None, + path } } @@ -102,7 +119,7 @@ impl FfmpegOutput { fn append_to_cmd(self, cmd: &mut Command, venc: bool, _aenc: bool, vaapi: bool) { // select codec and bitrate - const QUALITY: &str = "22"; + const QUALITY: &str = "18"; if venc { let vcodec = match (self.format, vaapi) { (FfmpegOutputFormat::Av1Flac, false) @@ -114,13 +131,22 @@ impl FfmpegOutput { }; cmd.arg("-c:v").arg(vcodec); - if let Some(bv) = self.video_bitrate { - cmd.arg("-b:v").arg(bv.to_string()); - } else if vaapi { - cmd.arg("-rc_mode").arg("CQP"); - cmd.arg("-global_quality").arg(QUALITY); - } else { - cmd.arg("-crf").arg(QUALITY); + if vcodec == "libsvtav1" { + cmd.arg("-svtav1-params").arg("fast-decode=1"); + cmd.arg("-preset").arg("8"); + } + + match self.video_bitrate { + Some(bv) if vcodec != "libsvtav1" => { + cmd.arg("-b:v").arg(bv.to_string()); + }, + None if vaapi => { + cmd.arg("-rc_mode").arg("CQP"); + cmd.arg("-global_quality").arg(QUALITY); + }, + _ => { + cmd.arg("-crf").arg(QUALITY); + } } } else { cmd.arg("-c:v").arg("copy"); @@ -152,6 +178,17 @@ impl FfmpegOutput { if self.faststart { cmd.arg("-movflags").arg("+faststart"); } + + // metadata + macro_rules! add_meta { + ($this:ident, $cmd:ident: $($meta:ident),+) => { + $(if let Some(value) = $this.$meta.as_deref() { + $cmd.arg("-metadata").arg(format!("{}={}", stringify!($meta), value)); + })+ + } + } + add_meta!(self, cmd: title, author, album, year, comment, language); + cmd.arg(self.path); } } diff --git a/src/render/mod.rs b/src/render/mod.rs index cfb79d8..012ff2c 100644 --- a/src/render/mod.rs +++ b/src/render/mod.rs @@ -9,7 +9,7 @@ use crate::{ iotro::{intro, outro}, render::ffmpeg::{Ffmpeg, FfmpegInput}, time::{format_date, Time}, - Project, ProjectSourceMetadata, Resolution + Project, ProjectLecture, ProjectSourceMetadata, Resolution }; use anyhow::{bail, Context}; use camino::{Utf8Path as Path, Utf8PathBuf as PathBuf}; @@ -501,13 +501,30 @@ impl<'a> Renderer<'a> { Ok(output) } - pub fn rescale(&self, res: Resolution) -> anyhow::Result { + pub fn rescale( + &self, + lecture: &ProjectLecture, + res: Resolution + ) -> anyhow::Result { let input = self.video_file_output(); let output = self.video_file_res(res); println!("\x1B[1m ==> Rescaling to {}p\x1B[0m", res.height()); let mut ffmpeg = Ffmpeg::new(FfmpegOutput { video_bitrate: Some(res.bitrate()), + + title: Some(format!( + "{} {} {}", + lecture.label, + lecture.lang.from, + (lecture.lang.format_date_long)(lecture.date) + )), + author: Some(lecture.docent.clone()), + album: Some(lecture.course.clone()), + year: Some(lecture.date.year.to_string()), + comment: Some(lecture.lang.video_created_by_us.into()), + language: Some(lecture.lang.lang.into()), + ..FfmpegOutput::new(res.format(), output.clone()).enable_faststart() }); ffmpeg.add_input(FfmpegInput::new(input));