add assets; some cmd building
This commit is contained in:
parent
ffad525857
commit
c55906f70a
4 changed files with 307 additions and 3 deletions
|
@ -2,9 +2,10 @@ use super::cmd;
|
|||
use crate::time::{format_time, Time};
|
||||
use camino::{Utf8Path as Path, Utf8PathBuf as PathBuf};
|
||||
use rational::Rational;
|
||||
use std::process::Command;
|
||||
use std::{borrow::Cow, process::Command};
|
||||
|
||||
pub(crate) struct FfmpegInput {
|
||||
pub(crate) concat: bool,
|
||||
pub(crate) loop_input: bool,
|
||||
pub(crate) fps: Option<Rational>,
|
||||
pub(crate) start: Option<Time>,
|
||||
|
@ -15,6 +16,7 @@ pub(crate) struct FfmpegInput {
|
|||
impl FfmpegInput {
|
||||
pub(crate) fn new(path: PathBuf) -> Self {
|
||||
Self {
|
||||
concat: false,
|
||||
loop_input: false,
|
||||
fps: None,
|
||||
start: None,
|
||||
|
@ -24,6 +26,9 @@ impl FfmpegInput {
|
|||
}
|
||||
|
||||
fn append_to_cmd(self, cmd: &mut Command) {
|
||||
if self.concat {
|
||||
cmd.arg("-f").arg("concat").arg("-safe").arg("0");
|
||||
}
|
||||
if self.loop_input {
|
||||
cmd.arg("-loop").arg("1");
|
||||
}
|
||||
|
@ -40,8 +45,65 @@ impl FfmpegInput {
|
|||
}
|
||||
}
|
||||
|
||||
pub(crate) enum Filter {
|
||||
Concat {
|
||||
inputs: Vec<Cow<'static, str>>,
|
||||
n: usize,
|
||||
output: Cow<'static, str>
|
||||
},
|
||||
|
||||
FadeIn {
|
||||
input: Cow<'static, str>,
|
||||
start: Time,
|
||||
duration: Time,
|
||||
output: Cow<'static, str>
|
||||
},
|
||||
|
||||
FadeOut {
|
||||
input: Cow<'static, str>,
|
||||
start: Time,
|
||||
duration: Time,
|
||||
output: Cow<'static, str>
|
||||
},
|
||||
|
||||
Overlay {
|
||||
video_input: Cow<'static, str>,
|
||||
overlay_input: Cow<'static, str>,
|
||||
x: Cow<'static, str>,
|
||||
y: Cow<'static, str>,
|
||||
output: Cow<'static, str>
|
||||
},
|
||||
|
||||
GenerateSilence {
|
||||
output: Cow<'static, str>
|
||||
}
|
||||
}
|
||||
|
||||
impl Filter {
|
||||
fn is_video_filter(&self) -> bool {
|
||||
matches!(
|
||||
self,
|
||||
Self::Concat { .. }
|
||||
| Self::FadeIn { .. }
|
||||
| Self::FadeOut { .. }
|
||||
| Self::Overlay { .. }
|
||||
)
|
||||
}
|
||||
|
||||
fn is_audio_filter(&self) -> bool {
|
||||
matches!(
|
||||
self,
|
||||
Self::Concat { .. }
|
||||
| Self::FadeIn { .. }
|
||||
| Self::FadeOut { .. }
|
||||
| Self::GenerateSilence { .. }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct Ffmpeg {
|
||||
inputs: Vec<FfmpegInput>,
|
||||
filters: Vec<Filter>,
|
||||
output: PathBuf
|
||||
}
|
||||
|
||||
|
@ -49,6 +111,7 @@ impl Ffmpeg {
|
|||
pub fn new(output: PathBuf) -> Self {
|
||||
Self {
|
||||
inputs: Vec::new(),
|
||||
filters: Vec::new(),
|
||||
output
|
||||
}
|
||||
}
|
||||
|
@ -57,9 +120,13 @@ impl Ffmpeg {
|
|||
let mut cmd = cmd();
|
||||
cmd.arg("ffmpeg").arg("-hide_banner");
|
||||
|
||||
// determine whether the video need to be re-encoded
|
||||
let venc = self.filters.iter().any(|f| f.is_video_filter());
|
||||
let aenc = self.filters.iter().any(|f| f.is_audio_filter());
|
||||
|
||||
// initialise a vaapi device if one exists
|
||||
let vaapi_device: PathBuf = "/dev/dri/renderD128".into();
|
||||
let vaapi = vaapi_device.exists();
|
||||
let vaapi = venc && vaapi_device.exists();
|
||||
if vaapi {
|
||||
cmd.arg("-vaapi_device").arg(&vaapi_device);
|
||||
}
|
||||
|
@ -72,6 +139,20 @@ impl Ffmpeg {
|
|||
// always try to synchronise audio
|
||||
cmd.arg("-async").arg("1");
|
||||
|
||||
// TODO apply filters
|
||||
|
||||
// append encoding options
|
||||
if vaapi {
|
||||
cmd.arg("-c:v").arg("h264_vaapi");
|
||||
cmd.arg("-rc_mode").arg("CQP");
|
||||
cmd.arg("-global_quality").arg("22");
|
||||
} else if venc {
|
||||
cmd.arg("-c:v").arg("libx264");
|
||||
cmd.arg("-crf").arg("22");
|
||||
} else {
|
||||
cmd.arg("-c:v").arg("copy");
|
||||
}
|
||||
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@ pub mod ffmpeg;
|
|||
|
||||
use crate::{
|
||||
iotro::intro,
|
||||
render::ffmpeg::Ffmpeg,
|
||||
time::{format_date, Time},
|
||||
Project, ProjectSourceMetadata, Resolution
|
||||
};
|
||||
|
@ -133,6 +134,20 @@ impl<'a> Renderer<'a> {
|
|||
pub(crate) fn preprocess(&self, project: &mut Project) -> anyhow::Result<()> {
|
||||
assert!(!project.progress.preprocessed);
|
||||
|
||||
let logo = self.target.join("logo.svg");
|
||||
fs::write(
|
||||
&logo,
|
||||
include_bytes!(concat!(env!("CARGO_MANIFEST_DIR"), "/assets/logo.svg"))
|
||||
)?;
|
||||
let fastforward = self.target.join("fastforward.svg");
|
||||
fs::write(
|
||||
&fastforward,
|
||||
include_bytes!(concat!(
|
||||
env!("CARGO_MANIFEST_DIR"),
|
||||
"/assets/fastforward.svg"
|
||||
))
|
||||
)?;
|
||||
|
||||
let recording_txt = self.target.join("recording.txt");
|
||||
let mut file = File::create(recording_txt)?;
|
||||
for filename in &project.source.files {
|
||||
|
@ -141,7 +156,8 @@ impl<'a> Renderer<'a> {
|
|||
drop(file);
|
||||
|
||||
println!("\x1B[1m ==> Concatenating Video and Normalising Audio ...");
|
||||
let mut ffmpeg = Ffmpeg::new();
|
||||
let recording_mp4 = self.target.join("recording.mp4");
|
||||
let mut ffmpeg = Ffmpeg::new(recording_mp4);
|
||||
|
||||
// project.source.metadata = Some(ProjectSourceMetadata {
|
||||
// source_duration: ffprobe_video("format=duration", input)?.parse()?
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue