diff --git a/src/main.rs b/src/main.rs index b9783194e63551a11e4e85e6c1b37b7edfdfd0d9..dcf9acd48786fc637e441412fe2bfbd3cb737c33 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,5 +1,5 @@ #![allow(clippy::manual_range_contains)] -#![warn(rust_2018_idioms)] +#![warn(clippy::unreadable_literal, rust_2018_idioms)] #![forbid(elided_lifetimes_in_paths, unsafe_code)] mod iotro; @@ -281,7 +281,9 @@ fn main() { // render the video let mut videos = Vec::new(); - videos.push(if !project.progress.rendered { + videos.push(if project.progress.rendered { + renderer.video_mp4(&project) + } else { let video = renderer.render(&mut project).unwrap(); project.progress.rendered = true; @@ -289,8 +291,6 @@ fn main() { fs::write(&project_path, toml::to_string(&project).unwrap().as_bytes()).unwrap(); video - } else { - renderer.video_mp4(&project) }); // rescale the video diff --git a/src/render/ffmpeg.rs b/src/render/ffmpeg.rs index f1e4a2ad3f88c71e0c11c17d76449f6696895a6a..2e2d174597b7c17e19b2d6e1de3acceb2d42c361 100644 --- a/src/render/ffmpeg.rs +++ b/src/render/ffmpeg.rs @@ -227,12 +227,13 @@ impl Ffmpeg { FfmpegFilter::Filters { filters, output } => { let mut complex = String::new(); for filter in filters { - filter.append_to_complex_filter(&mut complex, &mut self.filter_idx); + filter + .append_to_complex_filter(&mut complex, &mut self.filter_idx)?; } if vaapi { - write!(complex, "{}format=nv12,hwupload[v]", channel('v', &output)); + write!(complex, "{}format=nv12,hwupload[v]", channel('v', &output))?; } else { - write!(complex, "{}null[v]", channel('v', &output)); + write!(complex, "{}null[v]", channel('v', &output))?; } cmd.arg("-filter_complex").arg(complex); cmd.arg("-map").arg("[v]"); diff --git a/src/render/filter.rs b/src/render/filter.rs index 4f0f84d22b24b9b3b223023003458bcbb2a78af8..dd82ecbaace735594b19614e6b01e9c0bb0a6ab2 100644 --- a/src/render/filter.rs +++ b/src/render/filter.rs @@ -1,15 +1,11 @@ -use crate::time::{format_time, Time}; -use std::{borrow::Cow, collections::VecDeque, fmt::Write as _}; +use crate::time::Time; +use std::{ + borrow::Cow, + collections::VecDeque, + fmt::{self, Write as _} +}; pub(crate) enum Filter { - /// Trim audio and video alike - Trim { - input: Cow<'static, str>, - start: Option<Time>, - duration: Option<Time>, - output: Cow<'static, str> - }, - /// Apply an alpha channel on the video. No audio. Alpha { input: Cow<'static, str>, @@ -57,63 +53,12 @@ pub(crate) enum Filter { } impl Filter { - pub(crate) fn is_video_filter(&self) -> bool { - matches!( - self, - Self::Trim { .. } - | Self::Alpha { .. } - | Self::Concat { .. } - | Self::Fade { .. } - | Self::Overlay { .. } - ) - } - - pub(crate) fn is_audio_filter(&self) -> bool { - matches!( - self, - Self::Trim { .. } - | Self::Concat { .. } - | Self::Fade { .. } - | Self::GenerateSilence { .. } - ) - } - pub(crate) fn append_to_complex_filter( &self, complex: &mut String, filter_idx: &mut usize - ) { + ) -> fmt::Result { match self { - Self::Trim { - input, - start, - duration, - output - } => { - let mut args = String::new(); - if let Some(start) = start { - write!(args, "start={start}"); - } - if let Some(duration) = duration { - if !args.is_empty() { - args += ":"; - } - write!(args, "duration={duration}"); - } - writeln!( - complex, - "{}trim={args},setpts=PTS-STARTPTS{};", - channel('v', input), - channel('v', output) - ); - writeln!( - complex, - "{}atrim={args},asetpts=PTS-STARTPTS{};", - channel('a', input), - channel('a', output) - ); - }, - Self::Alpha { input, alpha, @@ -124,7 +69,7 @@ impl Filter { "{}format=yuva444p,colorchannelmixer=aa={alpha}{};", channel('v', input), channel('v', output) - ); + )?; }, Self::Overlay { @@ -140,18 +85,18 @@ impl Filter { channel('v', video_input), channel('v', overlay_input), channel('v', output) - ); + )?; writeln!( complex, "{}anull{};", channel('a', video_input), channel('a', output) - ); + )?; }, Self::Concat { inputs, output } => { for i in inputs { - write!(complex, "{}{}", channel('v', i), channel('a', i)); + write!(complex, "{}{}", channel('v', i), channel('a', i))?; } writeln!( complex, @@ -159,7 +104,7 @@ impl Filter { inputs.len(), channel('v', output), channel('a', output) - ); + )?; }, Self::Fade { @@ -175,13 +120,13 @@ impl Filter { "{}fade={args}{};", channel('v', input), channel('v', output) - ); + )?; writeln!( complex, "{}afade=t={args}{};", channel('a', input), channel('a', output) - ); + )?; }, Self::GenerateSilence { video, output } => { @@ -190,12 +135,12 @@ impl Filter { "{}null{};", channel('v', video), channel('v', output) - ); + )?; writeln!( complex, "aevalsrc=0:s=48000,pan=stereo|c0=c0|c1=c0{};", channel('a', output) - ); + )?; }, Self::FastForward { @@ -209,29 +154,29 @@ impl Filter { complex, "{}setpts=PTS/{multiplier}{vff};", channel('v', input) - ); + )?; writeln!( complex, "{}atempo={multiplier}{};", channel('a', input), channel('a', output) - ); + )?; writeln!( complex, "{vff}{}overlay=x=main_w/2-overlay_w/2:y=main_h/2-overlay_h/2{};", channel('v', ffinput), channel('v', output) - ); + )?; } } // add a newline after every filter to ease debugging - writeln!(complex); + writeln!(complex) } } pub(super) fn channel(channel: char, id: &str) -> String { - if id.chars().any(|ch| !ch.is_digit(10)) { + if id.chars().any(|ch| !ch.is_ascii_digit()) { format!("[{channel}_{id}]") } else { format!("[{id}:{channel}]") @@ -242,11 +187,3 @@ fn next_tmp(filter_idx: &mut usize) -> String { *filter_idx += 1; format!("[tmp{filter_idx}]") } - -fn next_tmp_3(filter_idx: &mut usize) -> [String; 3] { - [ - next_tmp(filter_idx), - next_tmp(filter_idx), - next_tmp(filter_idx) - ] -} diff --git a/src/render/mod.rs b/src/render/mod.rs index 2aa7398e0e2a289be9b789df93c5ef63378f4509..8d755edb8e6dc58b45c04574d3953736d8f84449 100644 --- a/src/render/mod.rs +++ b/src/render/mod.rs @@ -1,5 +1,3 @@ -#![allow(warnings)] - pub mod ffmpeg; mod filter; @@ -12,7 +10,6 @@ use crate::{ }; use anyhow::{bail, Context}; use camino::{Utf8Path as Path, Utf8PathBuf as PathBuf}; -use rational::Rational; use std::{ borrow::Cow, collections::VecDeque, @@ -189,7 +186,7 @@ impl<'a> Renderer<'a> { let recording_txt = self.target.join("recording.txt"); let mut file = File::create(&recording_txt)?; for filename in &project.source.files { - writeln!(file, "file '{}'", self.directory.join(filename).to_string()); + writeln!(file, "file '{}'", self.directory.join(filename))?; } drop(file); diff --git a/src/time.rs b/src/time.rs index 888451683e7ff8a54572eeaa83bde85452b8e400..d4d9a3dc8e1c6e1e65fbf8ff22d3cb3b072d94fb 100644 --- a/src/time.rs +++ b/src/time.rs @@ -147,7 +147,7 @@ pub fn parse_time(s: &str) -> anyhow::Result<Time> { } // the 4th split is subseconds, converting to micros if i == 3 { - micros = digits.parse::<u32>()? * 1000000 / 60; + micros = digits.parse::<u32>()? * 1_000_000 / 60; continue; } // add to seconds and potentially micros @@ -230,7 +230,7 @@ mod tests { fn test_time_subsecs() { test_time_parse_only("1:02:03:30", Time { seconds: 3723, - micros: 500000 + micros: 500_000 }); } @@ -238,7 +238,7 @@ mod tests { fn test_time_micros() { test_time("1:02:03.5", Time { seconds: 3723, - micros: 500000 + micros: 500_000 }); } }