Lazily compile all regexes, move macros to util module (#345)
* Lazily compile all regexes, move macros to util module * Clarify/fix documentation
This commit is contained in:
parent
9240f27c20
commit
cef0df5e87
|
@ -1,4 +1,7 @@
|
|||
use crate::into_vec;
|
||||
use crate::list_index_of_regex;
|
||||
use crate::regex;
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use itertools::chain;
|
||||
|
@ -10,7 +13,11 @@ use std::path::PathBuf;
|
|||
|
||||
use regex::Regex;
|
||||
|
||||
use crate::list_index_of_regex;
|
||||
const NULL: &'static str = if cfg!(target_os = "windows") {
|
||||
"nul"
|
||||
} else {
|
||||
"/dev/null"
|
||||
};
|
||||
|
||||
#[allow(non_camel_case_types)]
|
||||
#[derive(Clone, Copy, Serialize, Deserialize, Debug, strum::EnumString, strum::IntoStaticStr)]
|
||||
|
@ -86,46 +93,19 @@ impl Encoder {
|
|||
Self::aom => chain!(
|
||||
into_vec!["aomenc", "--passes=2", "--pass=1"],
|
||||
params,
|
||||
into_vec![
|
||||
format!("--fpf={}.log", fpf),
|
||||
"-o",
|
||||
if cfg!(target_os = "windows") {
|
||||
"nul"
|
||||
} else {
|
||||
"/dev/null"
|
||||
},
|
||||
"-"
|
||||
],
|
||||
into_vec![format!("--fpf={}.log", fpf), "-o", NULL, "-"],
|
||||
)
|
||||
.collect(),
|
||||
Self::rav1e => chain!(
|
||||
into_vec!["rav1e", "-", "-y", "-q"],
|
||||
params,
|
||||
into_vec![
|
||||
"--first-pass",
|
||||
format!("{}.stat", fpf),
|
||||
"--output",
|
||||
if cfg!(target_os = "windows") {
|
||||
"nul"
|
||||
} else {
|
||||
"/dev/null"
|
||||
},
|
||||
]
|
||||
into_vec!["--first-pass", format!("{}.stat", fpf), "--output", NULL]
|
||||
)
|
||||
.collect(),
|
||||
Self::vpx => chain!(
|
||||
into_vec!["vpxenc", "--passes=2", "--pass=1"],
|
||||
params,
|
||||
into_vec![
|
||||
format!("--fpf={}.log", fpf),
|
||||
"-o",
|
||||
if cfg!(target_os = "windows") {
|
||||
"nul"
|
||||
} else {
|
||||
"/dev/null"
|
||||
},
|
||||
"-"
|
||||
],
|
||||
into_vec![format!("--fpf={}.log", fpf), "-o", NULL, "-"],
|
||||
)
|
||||
.collect(),
|
||||
Self::svt_av1 => chain!(
|
||||
|
@ -145,11 +125,7 @@ impl Encoder {
|
|||
"--stats",
|
||||
format!("{}.stat", fpf),
|
||||
"-b",
|
||||
if cfg!(target_os = "windows") {
|
||||
"nul"
|
||||
} else {
|
||||
"/dev/null"
|
||||
},
|
||||
NULL,
|
||||
],
|
||||
)
|
||||
.collect(),
|
||||
|
@ -165,17 +141,7 @@ impl Encoder {
|
|||
"y4m",
|
||||
],
|
||||
params,
|
||||
into_vec![
|
||||
"--stats",
|
||||
format!("{}.log", fpf),
|
||||
"-",
|
||||
"-o",
|
||||
if cfg!(target_os = "windows") {
|
||||
"nul"
|
||||
} else {
|
||||
"/dev/null"
|
||||
},
|
||||
]
|
||||
into_vec!["--stats", format!("{}.log", fpf), "-", "-o", NULL]
|
||||
)
|
||||
.collect(),
|
||||
Self::x265 => chain!(
|
||||
|
@ -190,17 +156,7 @@ impl Encoder {
|
|||
"y4m",
|
||||
],
|
||||
params,
|
||||
into_vec![
|
||||
"--stats",
|
||||
format!("{}.log", fpf),
|
||||
"-",
|
||||
"-o",
|
||||
if cfg!(target_os = "windows") {
|
||||
"nul"
|
||||
} else {
|
||||
"/dev/null"
|
||||
},
|
||||
]
|
||||
into_vec!["--stats", format!("{}.log", fpf), "-", "-o", NULL]
|
||||
)
|
||||
.collect(),
|
||||
}
|
||||
|
@ -370,13 +326,13 @@ impl Encoder {
|
|||
}
|
||||
}
|
||||
|
||||
/// Returns string used for regex matching q/crf arguments in command line
|
||||
const fn q_regex_str(&self) -> &str {
|
||||
/// Returns regex used for matching q/crf arguments in command line
|
||||
fn q_regex(&self) -> &'static Regex {
|
||||
match &self {
|
||||
Self::aom | Self::vpx => r"--cq-level=.+",
|
||||
Self::rav1e => r"--quantizer",
|
||||
Self::svt_av1 => r"(--qp|-q|--crf)",
|
||||
Self::x264 | Self::x265 => r"--crf",
|
||||
Self::aom | Self::vpx => regex!(r"--cq-level=.+"),
|
||||
Self::rav1e => regex!(r"--quantizer"),
|
||||
Self::svt_av1 => regex!(r"(--qp|-q|--crf)"),
|
||||
Self::x264 | Self::x265 => regex!(r"--crf"),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -389,7 +345,7 @@ impl Encoder {
|
|||
|
||||
/// Returns changed q/crf in command line arguments
|
||||
pub fn man_command(self, params: Vec<String>, q: usize) -> Vec<String> {
|
||||
let index = list_index_of_regex(¶ms, self.q_regex_str()).unwrap();
|
||||
let index = list_index_of_regex(¶ms, self.q_regex()).unwrap();
|
||||
|
||||
let mut new_params = params;
|
||||
let (replace_index, replace_q) = self.replace_q(index, q);
|
||||
|
@ -398,20 +354,20 @@ impl Encoder {
|
|||
new_params
|
||||
}
|
||||
|
||||
/// Retuns string for regex to matching encoder progress in cli
|
||||
const fn pipe_match(&self) -> &str {
|
||||
/// Retuns regex for matching encoder progress in cli
|
||||
fn pipe_match(&self) -> &'static Regex {
|
||||
match &self {
|
||||
Self::aom | Self::vpx => r".*Pass (?:1/1|2/2) .*frame.*?/([^ ]+?) ",
|
||||
Self::rav1e => r"encoded.*? ([^ ]+?) ",
|
||||
Self::svt_av1 => r"Encoding frame\s+(\d+)",
|
||||
Self::x264 => r"^[^\d]*(\d+)",
|
||||
Self::x265 => r"(\d+) frames",
|
||||
Self::aom | Self::vpx => regex!(r".*Pass (?:1/1|2/2) .*frame.*?/([^ ]+?) "),
|
||||
Self::rav1e => regex!(r"encoded.*? ([^ ]+?) "),
|
||||
Self::svt_av1 => regex!(r"Encoding frame\s+(\d+)"),
|
||||
Self::x264 => regex!(r"^[^\d]*(\d+)"),
|
||||
Self::x265 => regex!(r"(\d+) frames"),
|
||||
}
|
||||
}
|
||||
|
||||
/// Returs option of q/crf value from cli encoder output
|
||||
pub fn match_line(self, line: &str) -> Option<usize> {
|
||||
let encoder_regex = Regex::new(self.pipe_match()).unwrap();
|
||||
let encoder_regex = self.pipe_match();
|
||||
if !encoder_regex.is_match(line) {
|
||||
return Some(0);
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
use crate::regex;
|
||||
|
||||
use path_abs::{PathAbs, PathInfo};
|
||||
use regex::Regex;
|
||||
use std::ffi::OsStr;
|
||||
use std::path::Path;
|
||||
use std::process::{Command, Stdio};
|
||||
|
@ -29,10 +30,12 @@ pub fn get_frame_count(source: impl AsRef<Path>) -> usize {
|
|||
|
||||
assert!(out.status.success());
|
||||
|
||||
let re = Regex::new(r".*frame=\s*([0-9]+)\s").unwrap();
|
||||
let output = String::from_utf8(out.stderr).unwrap();
|
||||
|
||||
let cap = re.captures_iter(&output).last().unwrap();
|
||||
let cap = regex!(r".*frame=\s*([0-9]+)\s")
|
||||
.captures_iter(&output)
|
||||
.last()
|
||||
.unwrap();
|
||||
cap[1].parse::<usize>().unwrap()
|
||||
}
|
||||
|
||||
|
@ -60,10 +63,9 @@ pub fn get_keyframes<P: AsRef<Path>>(source: P) -> Vec<usize> {
|
|||
let out = cmd.output().unwrap();
|
||||
assert!(out.status.success());
|
||||
|
||||
let re = Regex::new(r".*n:([0-9]+)\.[0-9]+ pts:.+key:1").unwrap();
|
||||
let output = String::from_utf8(out.stderr).unwrap();
|
||||
let mut kfs: Vec<usize> = vec![];
|
||||
for found in re.captures_iter(&output) {
|
||||
for found in regex!(r".*n:([0-9]+)\.[0-9]+ pts:.+key:1").captures_iter(&output) {
|
||||
kfs.push(found.get(1).unwrap().as_str().parse::<usize>().unwrap());
|
||||
}
|
||||
|
||||
|
@ -81,15 +83,13 @@ pub fn has_audio(file: &Path) -> bool {
|
|||
cmd.stdout(Stdio::piped());
|
||||
cmd.stderr(Stdio::piped());
|
||||
|
||||
let re = Regex::new(r".*Stream.+(Audio)").unwrap();
|
||||
|
||||
cmd.args(&["-hide_banner", "-i", file.to_str().unwrap()]);
|
||||
|
||||
let out = cmd.output().unwrap();
|
||||
|
||||
let output = String::from_utf8(out.stderr).unwrap();
|
||||
|
||||
re.is_match(&output)
|
||||
regex!(r".*Stream.+(Audio)").is_match(&output)
|
||||
}
|
||||
|
||||
/// Encodes the audio using FFmpeg, blocking the current thread.
|
||||
|
|
|
@ -29,7 +29,7 @@ use std::sync::{atomic, mpsc};
|
|||
use sysinfo::SystemExt;
|
||||
|
||||
use anyhow::{anyhow, bail, ensure, Context};
|
||||
use once_cell::sync::{Lazy, OnceCell};
|
||||
use once_cell::sync::OnceCell;
|
||||
use tokio::io::{AsyncBufReadExt, BufReader};
|
||||
|
||||
use crate::progress_bar::finish_progress_bar;
|
||||
|
@ -50,7 +50,6 @@ use std::collections::VecDeque;
|
|||
use std::convert::TryInto;
|
||||
use std::fs::File;
|
||||
use std::hash::{Hash, Hasher};
|
||||
use std::io;
|
||||
use std::io::Write;
|
||||
use std::iter;
|
||||
use std::string::ToString;
|
||||
|
@ -71,20 +70,10 @@ pub mod progress_bar;
|
|||
pub mod scene_detect;
|
||||
pub mod split;
|
||||
pub mod target_quality;
|
||||
pub mod util;
|
||||
pub mod vapoursynth;
|
||||
pub mod vmaf;
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! into_vec {
|
||||
($($x:expr),* $(,)?) => {
|
||||
vec![
|
||||
$(
|
||||
$x.into(),
|
||||
)*
|
||||
]
|
||||
};
|
||||
}
|
||||
|
||||
pub fn compose_ffmpeg_pipe(params: Vec<String>) -> Vec<String> {
|
||||
let mut p: Vec<String> = into_vec![
|
||||
"ffmpeg",
|
||||
|
@ -101,9 +90,7 @@ pub fn compose_ffmpeg_pipe(params: Vec<String>) -> Vec<String> {
|
|||
p
|
||||
}
|
||||
|
||||
pub fn list_index_of_regex(params: &[String], regex_str: &str) -> Option<usize> {
|
||||
let re = Regex::new(regex_str).unwrap();
|
||||
|
||||
pub fn list_index_of_regex(params: &[String], re: &Regex) -> Option<usize> {
|
||||
assert!(
|
||||
!params.is_empty(),
|
||||
"List index of regex got empty list of params"
|
||||
|
@ -435,8 +422,6 @@ pub struct Project {
|
|||
pub vmaf_filter: Option<String>,
|
||||
}
|
||||
|
||||
static HELP_REGEX: Lazy<Regex> = Lazy::new(|| Regex::new(r"\s+(-\w+|(?:--\w+(?:-\w+)*))").unwrap());
|
||||
|
||||
// TODO refactor to make types generic
|
||||
fn invalid_params(params: &[String], valid_options: &HashSet<String>) -> Vec<String> {
|
||||
params
|
||||
|
@ -491,23 +476,6 @@ fn init_done(done: DoneJson) -> &'static DoneJson {
|
|||
DONE_JSON.get_or_init(|| done)
|
||||
}
|
||||
|
||||
/// Attempts to create the directory if it does not exist, logging and returning
|
||||
/// and error if creating the directory failed.
|
||||
macro_rules! create_dir {
|
||||
($loc:expr) => {
|
||||
match fs::create_dir(&$loc) {
|
||||
Ok(_) => Ok(()),
|
||||
Err(e) => match e.kind() {
|
||||
io::ErrorKind::AlreadyExists => Ok(()),
|
||||
_ => {
|
||||
error!("Error while creating directory {:?}: {}", &$loc, e);
|
||||
Err(e)
|
||||
}
|
||||
},
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
impl Project {
|
||||
/// Initialize logging routines and create temporary directories
|
||||
pub fn initialize(&mut self) -> anyhow::Result<()> {
|
||||
|
@ -706,7 +674,7 @@ impl Project {
|
|||
)
|
||||
.unwrap();
|
||||
|
||||
HELP_REGEX
|
||||
regex!(r"\s+(-\w+|(?:--\w+(?:-\w+)*))")
|
||||
.find_iter(&help_text)
|
||||
.filter_map(|m| {
|
||||
m.as_str()
|
||||
|
|
36
av1an-core/src/util.rs
Normal file
36
av1an-core/src/util.rs
Normal file
|
@ -0,0 +1,36 @@
|
|||
#[macro_export]
|
||||
macro_rules! regex {
|
||||
($re:literal $(,)?) => {{
|
||||
static RE: once_cell::sync::OnceCell<regex::Regex> = once_cell::sync::OnceCell::new();
|
||||
RE.get_or_init(|| regex::Regex::new($re).unwrap())
|
||||
}};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! into_vec {
|
||||
($($x:expr),* $(,)?) => {
|
||||
vec![
|
||||
$(
|
||||
$x.into(),
|
||||
)*
|
||||
]
|
||||
};
|
||||
}
|
||||
|
||||
/// Attempts to create the directory if it does not exist, logging and returning
|
||||
/// and error if creating the directory failed.
|
||||
#[macro_export]
|
||||
macro_rules! create_dir {
|
||||
($loc:expr) => {
|
||||
match std::fs::create_dir(&$loc) {
|
||||
Ok(_) => Ok(()),
|
||||
Err(e) => match e.kind() {
|
||||
std::io::ErrorKind::AlreadyExists => Ok(()),
|
||||
_ => {
|
||||
error!("Error while creating directory {:?}: {}", &$loc, e);
|
||||
Err(e)
|
||||
}
|
||||
},
|
||||
}
|
||||
};
|
||||
}
|
Loading…
Reference in a new issue