support rescaling

This commit is contained in:
Dominic 2023-11-03 10:02:30 +01:00
parent 268c4b3af7
commit feb8596bfc
Signed by: msrd0
GPG key ID: DCC8C247452E98F9
2 changed files with 125 additions and 46 deletions

View file

@ -37,41 +37,56 @@ struct Args {
mem_limit: String mem_limit: String
} }
#[allow(non_camel_case_types, clippy::upper_case_acronyms)] macro_rules! resolutions {
#[derive(Clone, Copy, Deserialize, Eq, Ord, PartialEq, PartialOrd, Serialize)] ($($res:ident: $width:literal x $height:literal at $bitrate:literal),+) => {
enum Resolution { #[allow(non_camel_case_types, clippy::upper_case_acronyms)]
/// 640x360 #[derive(Clone, Copy, Deserialize, Eq, Ord, PartialEq, PartialOrd, Serialize)]
nHD, enum Resolution {
/// 1280x720 $(
HD, #[doc = concat!(stringify!($width), "x", stringify!($height))]
/// 1920x1080 $res
FullHD, ),+
/// 2560x1440 }
WQHD,
/// 3840x2160 const NUM_RESOLUTIONS: usize = {
UHD let mut num = 0;
} $(num += 1; stringify!($res);)+
num
};
impl Resolution {
fn values() -> [Self; NUM_RESOLUTIONS] {
[$(Self::$res),+]
}
impl Resolution {
fn width(self) -> usize { fn width(self) -> usize {
match self { match self {
Self::nHD => 640, $(Self::$res => $width),+
Self::HD => 1280,
Self::FullHD => 1920,
Self::WQHD => 2560,
Self::UHD => 3840
} }
} }
fn height(self) -> usize { fn height(self) -> usize {
match self { match self {
Self::nHD => 360, $(Self::$res => $height),+
Self::HD => 720,
Self::FullHD => 1080,
Self::WQHD => 1440,
Self::UHD => 2160
} }
} }
fn bitrate(self) -> &'static str {
match self {
$(Self::$res => $bitrate),+
}
}
}
}
}
resolutions! {
nHD: 640 x 360 at "500k",
HD: 1280 x 720 at "1M",
FullHD: 1920 x 1080 at "2M",
WQHD: 2560 x 1440 at "3M",
// TODO qsx muss mal sagen wieviel bitrate für 4k
UHD: 3840 x 2160 at "4M"
} }
#[derive(Deserialize, Serialize)] #[derive(Deserialize, Serialize)]
@ -245,6 +260,38 @@ fn main() {
fs::write(&project_path, toml::to_string(&project).unwrap().as_bytes()).unwrap(); fs::write(&project_path, toml::to_string(&project).unwrap().as_bytes()).unwrap();
} }
// render the video
let mut videos = Vec::new();
videos.push(if !project.progress.rendered {
let video = renderer.render(&mut project).unwrap(); let video = renderer.render(&mut project).unwrap();
println!("\x1B[1m ==> DONE :)\x1B[0m Video: {video}"); project.progress.rendered = true;
println!("{}", toml::to_string(&project).unwrap());
fs::write(&project_path, toml::to_string(&project).unwrap().as_bytes()).unwrap();
video
} else {
renderer.video_mp4(&project)
});
// rescale the video
for res in Resolution::values() {
if res >= project.source.metadata.as_ref().unwrap().source_res {
continue;
}
if !project.progress.transcoded.contains(&res) {
videos.push(renderer.rescale(res, &project).unwrap());
project.progress.transcoded.insert(res);
println!("{}", toml::to_string(&project).unwrap());
fs::write(&project_path, toml::to_string(&project).unwrap().as_bytes())
.unwrap();
}
}
println!("\x1B[1m ==> DONE :)\x1B[0m");
println!(" Videos:");
for v in &videos {
println!(" -> {v}");
}
} }

View file

@ -261,18 +261,17 @@ impl<'a> Renderer<'a> {
Ok(()) Ok(())
} }
fn video_mp4_res(&self, res: Resolution) -> PathBuf {
self.target
.join(format!("{}-{}p.mp4", self.slug, res.height()))
}
pub(crate) fn video_mp4(&self, project: &Project) -> PathBuf {
self.video_mp4_res(project.source.metadata.as_ref().unwrap().source_res)
}
pub(crate) fn render(&self, project: &mut Project) -> anyhow::Result<PathBuf> { pub(crate) fn render(&self, project: &mut Project) -> anyhow::Result<PathBuf> {
let mut output = self.target.join(format!( let output = self.video_mp4(project);
"{}-{}p.mp4",
self.slug,
project
.source
.metadata
.as_ref()
.unwrap()
.source_res
.height()
));
let mut ffmpeg = Ffmpeg::new(output.clone()); let mut ffmpeg = Ffmpeg::new(output.clone());
// add all of our inputs // add all of our inputs
@ -435,4 +434,37 @@ impl<'a> Renderer<'a> {
Ok(output) Ok(output)
} }
pub fn rescale(&self, res: Resolution, project: &Project) -> anyhow::Result<PathBuf> {
let input = self.video_mp4(project);
let output = self.video_mp4_res(res);
println!("\x1B[1m ==> Rescaling to {}p\x1B[0m", res.height());
let mut ffmpeg = cmd();
ffmpeg.arg("ffmpeg").arg("-hide_banner");
// TODO do we just always want hwaccel?
ffmpeg
.arg("-hwaccel")
.arg("vaapi")
.arg("-hwaccel_device")
.arg("/dev/dri/renderD128")
.arg("-hwaccel_output_format")
.arg("vaapi");
ffmpeg.arg("-i").arg(input);
ffmpeg.arg("-vf").arg(format!(
"scale_vaapi=w={}:h={}",
res.width(),
res.height()
));
ffmpeg.arg("-c:a").arg("copy").arg("-c:v").arg("h264_vaapi");
ffmpeg.arg("-b:v").arg(res.bitrate());
ffmpeg.arg(&output);
let status = ffmpeg.status()?;
if status.success() {
Ok(output)
} else {
bail!("ffmpeg failed with exit code {:?}", status.code())
}
}
} }