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