try to fix it enough to render a lecture
This commit is contained in:
parent
228e1648f0
commit
85297910ae
3 changed files with 52 additions and 32 deletions
|
@ -10,13 +10,9 @@ edition = "2021"
|
||||||
anyhow = "1.0"
|
anyhow = "1.0"
|
||||||
camino = "1.1"
|
camino = "1.1"
|
||||||
clap = { version = "4.4", features = ["derive"] }
|
clap = { version = "4.4", features = ["derive"] }
|
||||||
#ffmpeg = { package = "ffmpeg-next", version = "6.0" }
|
|
||||||
indexmap = "1.9"
|
indexmap = "1.9"
|
||||||
rational = "1.4"
|
rational = "1.5"
|
||||||
serde = { version = "1.0.188", features = ["derive"] }
|
serde = { version = "1.0.188", features = ["derive"] }
|
||||||
serde_with = "3.4"
|
serde_with = "3.4"
|
||||||
svgwriter = "0.1"
|
svgwriter = "0.1"
|
||||||
toml = { package = "basic-toml", version = "0.1.4" }
|
toml = { package = "basic-toml", version = "0.1.4" }
|
||||||
|
|
||||||
[patch.crates-io]
|
|
||||||
rational = { git = "https://github.com/msrd0/rational", branch = "error" }
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use crate::time::{format_time, Time};
|
use crate::time::{format_time, Time};
|
||||||
use std::{borrow::Cow, fmt::Write as _};
|
use std::{borrow::Cow, collections::VecDeque, fmt::Write as _};
|
||||||
|
|
||||||
pub(crate) enum Filter {
|
pub(crate) enum Filter {
|
||||||
/// Trim audio and video alike
|
/// Trim audio and video alike
|
||||||
|
@ -28,8 +28,7 @@ pub(crate) enum Filter {
|
||||||
|
|
||||||
/// Concatenate audio and video.
|
/// Concatenate audio and video.
|
||||||
Concat {
|
Concat {
|
||||||
inputs: Vec<Cow<'static, str>>,
|
inputs: VecDeque<Cow<'static, str>>,
|
||||||
n: usize,
|
|
||||||
output: Cow<'static, str>
|
output: Cow<'static, str>
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -48,14 +47,14 @@ pub(crate) enum Filter {
|
||||||
output: Cow<'static, str>
|
output: Cow<'static, str>
|
||||||
},
|
},
|
||||||
|
|
||||||
/// Fast forward. Too complex to explain. Its magic.
|
/// Fast forward. Will output before, ff, and after parts separately.
|
||||||
FastForward {
|
FastForward {
|
||||||
input: Cow<'static, str>,
|
input: Cow<'static, str>,
|
||||||
ffinput: Cow<'static, str>,
|
ffinput: Cow<'static, str>,
|
||||||
start: Time,
|
start: Time,
|
||||||
duration: Time,
|
duration: Time,
|
||||||
multiplier: usize,
|
multiplier: usize,
|
||||||
output: Cow<'static, str>
|
output: [Cow<'static, str>; 3]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -152,13 +151,14 @@ impl Filter {
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
||||||
Self::Concat { inputs, n, output } => {
|
Self::Concat { inputs, output } => {
|
||||||
for i in inputs {
|
for i in inputs {
|
||||||
write!(complex, "{}{}", channel('v', i), channel('a', i));
|
write!(complex, "{}{}", channel('v', i), channel('a', i));
|
||||||
}
|
}
|
||||||
writeln!(
|
writeln!(
|
||||||
complex,
|
complex,
|
||||||
"concat=n={n}:v=1:a=1{}{};",
|
"concat=n={}:v=1:a=1{}{};",
|
||||||
|
inputs.len(),
|
||||||
channel('v', output),
|
channel('v', output),
|
||||||
channel('a', output)
|
channel('a', output)
|
||||||
);
|
);
|
||||||
|
@ -266,17 +266,23 @@ impl Filter {
|
||||||
channel('v', ffinput)
|
channel('v', ffinput)
|
||||||
);
|
);
|
||||||
|
|
||||||
// and finally we concatenate everything back together
|
// and finally we place everything into the output
|
||||||
writeln!(
|
for (i, o) in [
|
||||||
complex,
|
(&vcut[0], &output[0]),
|
||||||
"{}{}{voverlay}{aff}{}{}concat=n=3:v=1:a=1{}{};",
|
(&voverlay, &output[1]),
|
||||||
vcut[0],
|
(&vcut[2], &output[2])
|
||||||
acut[0],
|
] {
|
||||||
vcut[2],
|
write!(complex, "{i}null{};", channel('v', o));
|
||||||
acut[2],
|
}
|
||||||
channel('v', output),
|
writeln!(complex);
|
||||||
channel('a', output)
|
for (i, o) in [
|
||||||
);
|
(&acut[0], &output[0]),
|
||||||
|
(&aff, &output[1]),
|
||||||
|
(&acut[2], &output[2])
|
||||||
|
] {
|
||||||
|
write!(complex, "{i}anull{};", channel('a', o));
|
||||||
|
}
|
||||||
|
writeln!(complex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -15,6 +15,7 @@ use camino::{Utf8Path as Path, Utf8PathBuf as PathBuf};
|
||||||
use rational::Rational;
|
use rational::Rational;
|
||||||
use std::{
|
use std::{
|
||||||
borrow::Cow,
|
borrow::Cow,
|
||||||
|
collections::VecDeque,
|
||||||
fs::{self, File},
|
fs::{self, File},
|
||||||
io::Write as _,
|
io::Write as _,
|
||||||
process::{Command, Stdio}
|
process::{Command, Stdio}
|
||||||
|
@ -226,7 +227,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");
|
||||||
svg2png(&logo_svg, &logo_png, 150 * 1920 / source_res.width())?;
|
svg2png(&logo_svg, &logo_png, 150 * source_res.width() / 1920)?;
|
||||||
|
|
||||||
// copy fastforward then render to png
|
// copy fastforward then render to png
|
||||||
let fastforward_svg = self.target.join("fastforward.svg");
|
let fastforward_svg = self.target.join("fastforward.svg");
|
||||||
|
@ -241,7 +242,7 @@ impl<'a> Renderer<'a> {
|
||||||
svg2png(
|
svg2png(
|
||||||
&fastforward_svg,
|
&fastforward_svg,
|
||||||
&fastforward_png,
|
&fastforward_png,
|
||||||
128 * 1920 / source_res.width()
|
128 * source_res.width() / 1920
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -251,7 +252,13 @@ impl<'a> Renderer<'a> {
|
||||||
let mut output = self.target.join(format!(
|
let mut output = self.target.join(format!(
|
||||||
"{}-{}p.mp4",
|
"{}-{}p.mp4",
|
||||||
self.slug,
|
self.slug,
|
||||||
project.source.metadata.as_ref().unwrap().source_res.width()
|
project
|
||||||
|
.source
|
||||||
|
.metadata
|
||||||
|
.as_ref()
|
||||||
|
.unwrap()
|
||||||
|
.source_res
|
||||||
|
.height()
|
||||||
));
|
));
|
||||||
let mut ffmpeg = Ffmpeg::new(output.clone());
|
let mut ffmpeg = Ffmpeg::new(output.clone());
|
||||||
|
|
||||||
|
@ -328,26 +335,37 @@ impl<'a> Renderer<'a> {
|
||||||
});
|
});
|
||||||
part3 = outrofade.into();
|
part3 = outrofade.into();
|
||||||
|
|
||||||
|
// prepare list for concat
|
||||||
|
let mut parts = VecDeque::new();
|
||||||
|
parts.push_back(part2);
|
||||||
|
|
||||||
// fast-forward the requested parts in reverse order
|
// fast-forward the requested parts in reverse order
|
||||||
project.source.fast.sort();
|
project.source.fast.sort();
|
||||||
for (i, (ff_st, ff_end)) in project.source.fast.iter().rev().enumerate() {
|
for (i, (ff_st, ff_end)) in project.source.fast.iter().rev().enumerate() {
|
||||||
let recff = format!("recff{i}");
|
let recff = [
|
||||||
|
format!("recff{i}b").into(),
|
||||||
|
format!("recff{i}ff").into(),
|
||||||
|
format!("recff{i}a").into()
|
||||||
|
];
|
||||||
ffmpeg.add_filter(Filter::FastForward {
|
ffmpeg.add_filter(Filter::FastForward {
|
||||||
input: part2,
|
input: parts.pop_front().unwrap(),
|
||||||
ffinput: ff.clone().into(),
|
ffinput: ff.clone().into(),
|
||||||
start: *ff_st - start,
|
start: *ff_st - start,
|
||||||
duration: *ff_end - *ff_st,
|
duration: *ff_end - *ff_st,
|
||||||
multiplier: FF_MULTIPLIER,
|
multiplier: FF_MULTIPLIER,
|
||||||
output: recff.clone().into()
|
output: recff.clone()
|
||||||
});
|
});
|
||||||
part2 = recff.into();
|
parts.push_front(recff[2].clone());
|
||||||
|
parts.push_front(recff[1].clone());
|
||||||
|
parts.push_front(recff[0].clone());
|
||||||
}
|
}
|
||||||
|
|
||||||
// concatenate everything
|
// concatenate everything
|
||||||
|
parts.push_front(part1);
|
||||||
|
parts.push_back(part3);
|
||||||
let concat = "concat";
|
let concat = "concat";
|
||||||
ffmpeg.add_filter(Filter::Concat {
|
ffmpeg.add_filter(Filter::Concat {
|
||||||
inputs: vec![part1, part2, part3],
|
inputs: parts,
|
||||||
n: 3,
|
|
||||||
output: concat.into()
|
output: concat.into()
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue