attempt to feed complex filtergraph into graph2dot

This commit is contained in:
Dominic 2023-11-01 08:56:20 +01:00
parent 164bb8faa3
commit 4a10d10d47
Signed by: msrd0
GPG key ID: DCC8C247452E98F9
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::{ use crate::{
render::filter::channel, render::filter::channel,
time::{format_time, Time} time::{format_time, Time}
}; };
use anyhow::bail; use anyhow::bail;
use camino::Utf8PathBuf as PathBuf; use camino::{Utf8Path as Path, Utf8PathBuf as PathBuf};
use rational::Rational; 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) struct FfmpegInput {
pub(crate) concat: bool, 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 { if self.concat {
cmd.arg("-f").arg("concat").arg("-safe").arg("0"); cmd.arg("-f").arg("concat").arg("-safe").arg("0");
} }
@ -45,7 +50,7 @@ impl FfmpegInput {
if let Some(duration) = self.duration { if let Some(duration) = self.duration {
cmd.arg("-t").arg(format_time(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 self
} }
pub fn run(mut self) -> anyhow::Result<()> { pub fn run(mut self, filter_graph: Option<&Path>) -> anyhow::Result<()> {
let mut cmd = cmd(); let mut cmd = new_cmd();
cmd.arg("ffmpeg").arg("-hide_banner").arg("-y"); cmd.arg("ffmpeg").arg("-hide_banner").arg("-y");
// determine whether the video need to be re-encoded // determine whether the video need to be re-encoded
@ -120,7 +125,7 @@ impl Ffmpeg {
} }
// append all the inputs // append all the inputs
for i in self.inputs { for i in &self.inputs {
i.append_to_cmd(&mut cmd); i.append_to_cmd(&mut cmd);
} }
@ -149,6 +154,37 @@ impl Ffmpeg {
} else { } else {
write!(complex, "{}null[v]", channel('v', &self.filters_output)); 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("-filter_complex").arg(complex);
cmd.arg("-map").arg("[v]"); cmd.arg("-map").arg("[v]");
cmd.arg("-map").arg(channel('a', &self.filters_output)); 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 FF_LOGO_SIZE: usize = 128;
const LOGO_SIZE: usize = 96; const LOGO_SIZE: usize = 96;
fn cmd() -> Command { fn new_cmd() -> Command {
let mut cmd = Command::new("busybox"); let mut cmd = Command::new("busybox");
cmd.arg("ash") cmd.arg("ash")
.arg("-exuo") .arg("-exuo")
@ -49,7 +49,7 @@ fn cmd() -> Command {
} }
fn ffprobe() -> Command { fn ffprobe() -> Command {
let mut cmd = cmd(); let mut cmd = new_cmd();
cmd.arg("ffprobe") cmd.arg("ffprobe")
.arg("-v") .arg("-v")
.arg("error") .arg("error")
@ -119,11 +119,11 @@ fn svg2mp4(svg: PathBuf, mp4: PathBuf, duration: Time) -> anyhow::Result<()> {
}); });
ffmpeg.set_filter_output("out"); ffmpeg.set_filter_output("out");
ffmpeg.set_duration(duration); ffmpeg.set_duration(duration);
ffmpeg.run() ffmpeg.run(None)
} }
fn svg2png(svg: &Path, png: &Path, size: usize) -> anyhow::Result<()> { fn svg2png(svg: &Path, png: &Path, size: usize) -> anyhow::Result<()> {
let mut cmd = cmd(); let mut cmd = new_cmd();
let size = size.to_string(); let size = size.to_string();
cmd.arg("inkscape") cmd.arg("inkscape")
.arg("-w") .arg("-w")
@ -181,7 +181,7 @@ impl<'a> Renderer<'a> {
..FfmpegInput::new(recording_txt) ..FfmpegInput::new(recording_txt)
}); });
ffmpeg.enable_loudnorm(); ffmpeg.enable_loudnorm();
ffmpeg.run()?; ffmpeg.run(None)?;
let width = ffprobe_video("stream=width", &recording_mp4)?.parse()?; let width = ffprobe_video("stream=width", &recording_mp4)?.parse()?;
let height = ffprobe_video("stream=height", &recording_mp4)?.parse()?; let height = ffprobe_video("stream=height", &recording_mp4)?.parse()?;
@ -425,7 +425,7 @@ impl<'a> Renderer<'a> {
// we're done :) // we're done :)
ffmpeg.set_filter_output(overlay); ffmpeg.set_filter_output(overlay);
ffmpeg.run()?; ffmpeg.run(Some(&self.target.join("filter_graph.png")))?;
Ok(output) Ok(output)
} }