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:
redzic 2021-08-28 23:11:25 -04:00 committed by GitHub
parent 9240f27c20
commit cef0df5e87
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 77 additions and 117 deletions

View file

@ -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(&params, self.q_regex_str()).unwrap();
let index = list_index_of_regex(&params, 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);
}

View file

@ -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.

View file

@ -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
View 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)
}
},
}
};
}