Compare commits

...

1 commit

Author SHA1 Message Date
4a10d10d47
attempt to feed complex filtergraph into graph2dot 2023-11-01 08:56:20 +01:00
2 changed files with 50 additions and 14 deletions

View file

@ -1,12 +1,17 @@
use super::{cmd, filter::Filter};
use super::{filter::Filter, new_cmd};
use crate::{
render::filter::channel,
time::{format_time, Time}
};
use anyhow::bail;
use camino::Utf8PathBuf as PathBuf;
use camino::{Utf8Path as Path, Utf8PathBuf as PathBuf};
use rational::Rational;
use std::{borrow::Cow, fmt::Write as _, process::Command};
use std::{
borrow::Cow,
fmt::Write as _,
io::Write as _,
process::{Command, Stdio}
};
pub(crate) struct FfmpegInput {
pub(crate) concat: bool,
@ -29,7 +34,7 @@ impl FfmpegInput {
}
}
fn append_to_cmd(self, cmd: &mut Command) {
fn append_to_cmd(&self, cmd: &mut Command) {
if self.concat {
cmd.arg("-f").arg("concat").arg("-safe").arg("0");
}
@ -45,7 +50,7 @@ impl FfmpegInput {
if let Some(duration) = self.duration {
cmd.arg("-t").arg(format_time(duration));
}
cmd.arg("-i").arg(self.path);
cmd.arg("-i").arg(&self.path);
}
}
@ -104,8 +109,8 @@ impl Ffmpeg {
self
}
pub fn run(mut self) -> anyhow::Result<()> {
let mut cmd = cmd();
pub fn run(mut self, filter_graph: Option<&Path>) -> anyhow::Result<()> {
let mut cmd = new_cmd();
cmd.arg("ffmpeg").arg("-hide_banner").arg("-y");
// determine whether the video need to be re-encoded
@ -120,7 +125,7 @@ impl Ffmpeg {
}
// append all the inputs
for i in self.inputs {
for i in &self.inputs {
i.append_to_cmd(&mut cmd);
}
@ -149,6 +154,37 @@ impl Ffmpeg {
} else {
write!(complex, "{}null[v]", channel('v', &self.filters_output));
}
if let Some(filter_graph) = filter_graph {
let mut graph2dot = new_cmd();
graph2dot.stdin(Stdio::piped());
graph2dot.stdout(Stdio::piped());
graph2dot.arg("graph2dot");
let mut graph2dot = graph2dot.spawn()?;
let mut dot = new_cmd();
dot.stdin(Stdio::from(graph2dot.stdout.take().unwrap()));
dot.arg("dot").arg("-Tpng").arg("-o").arg(filter_graph);
let mut dot = dot.spawn()?;
let mut stdin = graph2dot.stdin.take().unwrap();
for (i, _) in self.inputs.iter().enumerate() {
writeln!(stdin, "nullsrc[{i}];[{i}]nullsink;");
}
writeln!(stdin, "{complex};")?;
writeln!(stdin, "[v]nullsink");
drop(stdin);
let status = graph2dot.wait()?;
if !status.success() {
bail!("graph2dot failed with status code {:?}", status.code());
}
let status = dot.wait()?;
if !status.success() {
bail!("graphviz dot failed with status code {:?}", status.code());
}
}
cmd.arg("-filter_complex").arg(complex);
cmd.arg("-map").arg("[v]");
cmd.arg("-map").arg(channel('a', &self.filters_output));

View file

@ -38,7 +38,7 @@ const FF_MULTIPLIER: usize = 8;
const FF_LOGO_SIZE: usize = 128;
const LOGO_SIZE: usize = 96;
fn cmd() -> Command {
fn new_cmd() -> Command {
let mut cmd = Command::new("busybox");
cmd.arg("ash")
.arg("-exuo")
@ -49,7 +49,7 @@ fn cmd() -> Command {
}
fn ffprobe() -> Command {
let mut cmd = cmd();
let mut cmd = new_cmd();
cmd.arg("ffprobe")
.arg("-v")
.arg("error")
@ -119,11 +119,11 @@ fn svg2mp4(svg: PathBuf, mp4: PathBuf, duration: Time) -> anyhow::Result<()> {
});
ffmpeg.set_filter_output("out");
ffmpeg.set_duration(duration);
ffmpeg.run()
ffmpeg.run(None)
}
fn svg2png(svg: &Path, png: &Path, size: usize) -> anyhow::Result<()> {
let mut cmd = cmd();
let mut cmd = new_cmd();
let size = size.to_string();
cmd.arg("inkscape")
.arg("-w")
@ -181,7 +181,7 @@ impl<'a> Renderer<'a> {
..FfmpegInput::new(recording_txt)
});
ffmpeg.enable_loudnorm();
ffmpeg.run()?;
ffmpeg.run(None)?;
let width = ffprobe_video("stream=width", &recording_mp4)?.parse()?;
let height = ffprobe_video("stream=height", &recording_mp4)?.parse()?;
@ -425,7 +425,7 @@ impl<'a> Renderer<'a> {
// we're done :)
ffmpeg.set_filter_output(overlay);
ffmpeg.run()?;
ffmpeg.run(Some(&self.target.join("filter_graph.png")))?;
Ok(output)
}