fix toml serialiser being stupid
All checks were successful
Trigger quay.io Webhook / run (push) Successful in 5s
All checks were successful
Trigger quay.io Webhook / run (push) Successful in 5s
This commit is contained in:
parent
7662150b89
commit
330515d6b4
5 changed files with 53 additions and 80 deletions
|
@ -191,8 +191,8 @@ impl Iotro {
|
||||||
|
|
||||||
fn finish(self) -> Graphic {
|
fn finish(self) -> Graphic {
|
||||||
let mut svg = Graphic::new();
|
let mut svg = Graphic::new();
|
||||||
svg.set_width(self.res.width);
|
svg.set_width(self.res.width());
|
||||||
svg.set_height(self.res.height);
|
svg.set_height(self.res.height());
|
||||||
svg.set_view_box("0 0 1920 1080");
|
svg.set_view_box("0 0 1920 1080");
|
||||||
svg.push(
|
svg.push(
|
||||||
Rect::new()
|
Rect::new()
|
||||||
|
|
103
src/project.rs
103
src/project.rs
|
@ -16,32 +16,41 @@ use std::{
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, Deserialize, Serialize)]
|
#[derive(Clone, Copy, Debug, Deserialize, Serialize)]
|
||||||
pub struct Resolution {
|
pub struct Resolution(u32, u32);
|
||||||
pub width: u32,
|
|
||||||
pub height: u32
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Resolution {
|
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 {
|
pub(crate) fn bitrate(self) -> u64 {
|
||||||
// 640 * 360: 500k
|
// 640 * 360: 500k
|
||||||
if self.width <= 640 {
|
if self.width() <= 640 {
|
||||||
500_000
|
500_000
|
||||||
}
|
}
|
||||||
// 1280 * 720: 1M
|
// 1280 * 720: 1M
|
||||||
else if self.width <= 1280 {
|
else if self.width() <= 1280 {
|
||||||
1_000_000
|
1_000_000
|
||||||
}
|
}
|
||||||
// 1920 * 1080: 2M
|
// 1920 * 1080: 2M
|
||||||
else if self.width <= 1920 {
|
else if self.width() <= 1920 {
|
||||||
2_000_000
|
2_000_000
|
||||||
}
|
}
|
||||||
// 2560 * 1440: 3M
|
// 2560 * 1440: 3M
|
||||||
else if self.width <= 2560 {
|
else if self.width() <= 2560 {
|
||||||
3_000_000
|
3_000_000
|
||||||
}
|
}
|
||||||
// 3840 * 2160: 4M
|
// 3840 * 2160: 4M
|
||||||
// TODO die bitrate von 4M ist absolut an den haaren herbeigezogen
|
// TODO die bitrate von 4M ist absolut an den haaren herbeigezogen
|
||||||
else if self.width <= 3840 {
|
else if self.width() <= 3840 {
|
||||||
4_000_000
|
4_000_000
|
||||||
}
|
}
|
||||||
// we'll cap everything else at 5M for no apparent reason
|
// we'll cap everything else at 5M for no apparent reason
|
||||||
|
@ -51,7 +60,7 @@ impl Resolution {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn default_codec(self) -> FfmpegOutputFormat {
|
pub(crate) fn default_codec(self) -> FfmpegOutputFormat {
|
||||||
if self.width > 1920 {
|
if self.width() > 1920 {
|
||||||
FfmpegOutputFormat::Av1Opus
|
FfmpegOutputFormat::Av1Opus
|
||||||
} else {
|
} else {
|
||||||
FfmpegOutputFormat::AvcAac
|
FfmpegOutputFormat::AvcAac
|
||||||
|
@ -59,32 +68,17 @@ impl Resolution {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const STANDARD_RESOLUTIONS: [Self; 5] = [
|
pub const STANDARD_RESOLUTIONS: [Self; 5] = [
|
||||||
Self {
|
Self(640, 360),
|
||||||
width: 640,
|
Self(1280, 720),
|
||||||
height: 360
|
Self(1920, 1080),
|
||||||
},
|
Self(2560, 1440),
|
||||||
Self {
|
Self(3840, 2160)
|
||||||
width: 1280,
|
|
||||||
height: 720
|
|
||||||
},
|
|
||||||
Self {
|
|
||||||
width: 1920,
|
|
||||||
height: 1080
|
|
||||||
},
|
|
||||||
Self {
|
|
||||||
width: 2560,
|
|
||||||
height: 1440
|
|
||||||
},
|
|
||||||
Self {
|
|
||||||
width: 3840,
|
|
||||||
height: 2160
|
|
||||||
}
|
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Display for Resolution {
|
impl Display for Resolution {
|
||||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
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<Self> {
|
fn from_str(s: &str) -> anyhow::Result<Self> {
|
||||||
Ok(match s.to_lowercase().as_str() {
|
Ok(match s.to_lowercase().as_str() {
|
||||||
"360p" | "nhd" => Self {
|
"360p" | "nhd" => Self(640, 360),
|
||||||
width: 640,
|
"540p" | "qhd" => Self(960, 540),
|
||||||
height: 360
|
"720p" | "hd" => Self(1280, 720),
|
||||||
},
|
"900p" | "hd+" => Self(1600, 900),
|
||||||
"540p" | "qhd" => Self {
|
"1080p" | "fhd" | "fullhd" => Self(1920, 1080),
|
||||||
width: 960,
|
"1440p" | "wqhd" => Self(2560, 1440),
|
||||||
height: 540
|
"2160p" | "4k" | "uhd" => Self(3840, 2160),
|
||||||
},
|
|
||||||
"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
|
|
||||||
},
|
|
||||||
_ => anyhow::bail!("Unknown Resolution: {s:?}")
|
_ => anyhow::bail!("Unknown Resolution: {s:?}")
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -128,7 +101,7 @@ impl FromStr for Resolution {
|
||||||
|
|
||||||
impl Ord for Resolution {
|
impl Ord for Resolution {
|
||||||
fn cmp(&self, other: &Self) -> cmp::Ordering {
|
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 struct Project {
|
||||||
pub lecture: ProjectLecture,
|
pub lecture: ProjectLecture,
|
||||||
pub source: ProjectSource,
|
pub source: ProjectSource,
|
||||||
|
@ -154,7 +127,7 @@ pub struct Project {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[serde_as]
|
#[serde_as]
|
||||||
#[derive(Deserialize, Serialize)]
|
#[derive(Debug, Deserialize, Serialize)]
|
||||||
pub struct ProjectLecture {
|
pub struct ProjectLecture {
|
||||||
pub course: String,
|
pub course: String,
|
||||||
pub label: String,
|
pub label: String,
|
||||||
|
@ -167,7 +140,7 @@ pub struct ProjectLecture {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[serde_as]
|
#[serde_as]
|
||||||
#[derive(Deserialize, Serialize)]
|
#[derive(Debug, Deserialize, Serialize)]
|
||||||
pub struct ProjectSource {
|
pub struct ProjectSource {
|
||||||
pub files: Vec<String>,
|
pub files: Vec<String>,
|
||||||
pub stereo: bool,
|
pub stereo: bool,
|
||||||
|
@ -189,7 +162,7 @@ pub struct ProjectSource {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[serde_as]
|
#[serde_as]
|
||||||
#[derive(Deserialize, Serialize)]
|
#[derive(Debug, Deserialize, Serialize)]
|
||||||
pub struct ProjectSourceMetadata {
|
pub struct ProjectSourceMetadata {
|
||||||
/// The duration of the source video.
|
/// The duration of the source video.
|
||||||
#[serde_as(as = "DisplayFromStr")]
|
#[serde_as(as = "DisplayFromStr")]
|
||||||
|
@ -207,7 +180,7 @@ pub struct ProjectSourceMetadata {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[serde_as]
|
#[serde_as]
|
||||||
#[derive(Default, Deserialize, Serialize)]
|
#[derive(Debug, Default, Deserialize, Serialize)]
|
||||||
pub struct ProjectProgress {
|
pub struct ProjectProgress {
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub preprocessed: bool,
|
pub preprocessed: bool,
|
||||||
|
|
|
@ -131,8 +131,8 @@ impl Question {
|
||||||
|
|
||||||
pub(crate) fn finish(self) -> Graphic {
|
pub(crate) fn finish(self) -> Graphic {
|
||||||
let mut svg = Graphic::new();
|
let mut svg = Graphic::new();
|
||||||
svg.set_width(self.res.width);
|
svg.set_width(self.res.width());
|
||||||
svg.set_height(self.res.height);
|
svg.set_height(self.res.height());
|
||||||
svg.set_view_box("0 0 1920 1080");
|
svg.set_view_box("0 0 1920 1080");
|
||||||
svg.push(self.g);
|
svg.push(self.g);
|
||||||
svg
|
svg
|
||||||
|
|
|
@ -359,9 +359,9 @@ impl Ffmpeg {
|
||||||
},
|
},
|
||||||
FfmpegFilter::Rescale(res) => {
|
FfmpegFilter::Rescale(res) => {
|
||||||
cmd.arg("-vf").arg(if vaapi {
|
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 {
|
} else {
|
||||||
format!("scale=w={}:h={}", res.width, res.height)
|
format!("scale=w={}:h={}", res.width(), res.height())
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -264,7 +264,7 @@ impl<'a> Renderer<'a> {
|
||||||
|
|
||||||
let width = ffprobe_video("stream=width", &recording_mkv)?.parse()?;
|
let width = ffprobe_video("stream=width", &recording_mkv)?.parse()?;
|
||||||
let height = ffprobe_video("stream=height", &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 {
|
project.source.metadata = Some(ProjectSourceMetadata {
|
||||||
source_duration: ffprobe_video("format=duration", &recording_mkv)?.parse()?,
|
source_duration: ffprobe_video("format=duration", &recording_mkv)?.parse()?,
|
||||||
source_fps: ffprobe_video("stream=r_frame_rate", &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"))
|
include_bytes!(concat!(env!("CARGO_MANIFEST_DIR"), "/assets/logo.svg"))
|
||||||
)?;
|
)?;
|
||||||
let logo_png = self.target.join("logo.png");
|
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)?;
|
svg2png(&logo_svg, &logo_png, logo_size, logo_size)?;
|
||||||
|
|
||||||
// copy fastforward then render to png
|
// copy fastforward then render to png
|
||||||
|
@ -329,7 +329,7 @@ impl<'a> Renderer<'a> {
|
||||||
))
|
))
|
||||||
)?;
|
)?;
|
||||||
let fastforward_png = self.target.join("fastforward.png");
|
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(
|
svg2png(
|
||||||
&fastforward_svg,
|
&fastforward_svg,
|
||||||
&fastforward_png,
|
&fastforward_png,
|
||||||
|
@ -349,8 +349,8 @@ impl<'a> Renderer<'a> {
|
||||||
svg2png(
|
svg2png(
|
||||||
&q_svg,
|
&q_svg,
|
||||||
&q_png,
|
&q_png,
|
||||||
metadata.source_res.width,
|
metadata.source_res.width(),
|
||||||
metadata.source_res.height
|
metadata.source_res.height()
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -365,7 +365,7 @@ impl<'a> Renderer<'a> {
|
||||||
FfmpegOutputFormat::AvcAac => "mp4"
|
FfmpegOutputFormat::AvcAac => "mp4"
|
||||||
};
|
};
|
||||||
self.target
|
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.
|
/// Get the video file directly outputed to further transcode.
|
||||||
|
@ -622,8 +622,8 @@ impl<'a> Renderer<'a> {
|
||||||
output: logoalpha.into()
|
output: logoalpha.into()
|
||||||
});
|
});
|
||||||
let overlay = "overlay";
|
let overlay = "overlay";
|
||||||
let overlay_off_x = 130 * source_res.width / 3840;
|
let overlay_off_x = 130 * source_res.width() / 3840;
|
||||||
let overlay_off_y = 65 * source_res.height / 2160;
|
let overlay_off_y = 65 * source_res.height() / 2160;
|
||||||
ffmpeg.add_filter(Filter::Overlay {
|
ffmpeg.add_filter(Filter::Overlay {
|
||||||
video_input: concat.into(),
|
video_input: concat.into(),
|
||||||
overlay_input: logoalpha.into(),
|
overlay_input: logoalpha.into(),
|
||||||
|
@ -652,7 +652,7 @@ impl<'a> Renderer<'a> {
|
||||||
println!(
|
println!(
|
||||||
" {} {}",
|
" {} {}",
|
||||||
style("==>").bold().cyan(),
|
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 {
|
let mut ffmpeg = Ffmpeg::new(FfmpegOutput {
|
||||||
|
|
Loading…
Reference in a new issue