From 98f415ade7d07a1193d86c7c72020d32d6d14cfa Mon Sep 17 00:00:00 2001 From: Dominic Date: Fri, 24 May 2024 12:17:40 +0200 Subject: [PATCH] add metadata to transcoded videos --- src/iotro.rs | 19 +++++++++++++------ src/main.rs | 2 +- src/render/ffmpeg.rs | 28 ++++++++++++++++++++++++++++ src/render/mod.rs | 21 +++++++++++++++++++-- 4 files changed, 61 insertions(+), 9 deletions(-) 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 862fb42..6c9a7ee 100644 --- a/src/main.rs +++ b/src/main.rs @@ -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 a0288ab..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 } } @@ -161,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));