remove some unstable unwarps, clode cleanup

This commit is contained in:
jb-alvarado 2022-05-13 15:59:09 +02:00
parent 52ce6197f0
commit 2902647200
9 changed files with 157 additions and 145 deletions

View File

@ -5,7 +5,7 @@ use crate::utils::GlobalConfig;
/// Add loudness normalization.
pub fn filter_node(config: &GlobalConfig) -> String {
format!(
",loudnorm=I={}:TP={}:LRA={}",
"loudnorm=I={}:TP={}:LRA={}",
config.processing.loud_i, config.processing.loud_tp, config.processing.loud_lra
)
}

View File

@ -8,6 +8,7 @@ fn audio_filter(config: &GlobalConfig) -> String {
let mut audio_chain = ";[0:a]afade=in:st=0:d=0.5".to_string();
if config.processing.loudnorm_ingest {
audio_chain.push(',');
audio_chain.push_str(&a_loudnorm::filter_node(config));
}

View File

@ -13,8 +13,8 @@ use crate::utils::{get_delta, is_close, GlobalConfig, Media};
struct Filters {
audio_chain: Option<String>,
video_chain: Option<String>,
audio_map: Option<String>,
video_map: Option<String>,
audio_map: String,
video_map: String,
}
impl Filters {
@ -22,8 +22,8 @@ impl Filters {
Filters {
audio_chain: None,
video_chain: None,
audio_map: Some("0:a".to_string()),
video_map: Some("0:v".to_string()),
audio_map: "1:a".to_string(),
video_map: "0:v".to_string(),
}
}
@ -41,10 +41,9 @@ impl Filters {
if filter.contains("aevalsrc") || filter.contains("anoisesrc") {
self.audio_chain = Some(filter.to_string());
} else {
self.audio_chain =
Some(format!("[{}]{filter}", self.audio_map.clone().unwrap()));
self.audio_chain = Some(format!("[{}]{filter}", self.audio_map.clone()));
}
self.audio_map = Some("[aout1]".to_string());
self.audio_map = "[aout1]".to_string();
}
},
"video" => match &self.video_chain {
@ -57,7 +56,7 @@ impl Filters {
}
None => {
self.video_chain = Some(format!("[0:v]{filter}"));
self.video_map = Some("[vout1]".to_string());
self.video_map = "[vout1]".to_string();
}
},
_ => (),
@ -101,8 +100,10 @@ fn fps(fps: f64, chain: &mut Filters, config: &GlobalConfig) {
}
}
fn scale(width: i64, height: i64, aspect: f64, chain: &mut Filters, config: &GlobalConfig) {
if width != config.processing.width || height != config.processing.height {
fn scale(v_stream: &ffprobe::Stream, aspect: f64, chain: &mut Filters, config: &GlobalConfig) {
// width: i64, height: i64
if let (Some(w), Some(h)) = (v_stream.width, v_stream.height) {
if w != config.processing.width || h != config.processing.height {
chain.add_filter(
&format!(
"scale={}:{}",
@ -115,6 +116,16 @@ fn scale(width: i64, height: i64, aspect: f64, chain: &mut Filters, config: &Glo
if !is_close(aspect, config.processing.aspect, 0.03) {
chain.add_filter(&format!("setdar=dar={}", config.processing.aspect), "video")
}
} else {
chain.add_filter(
&format!(
"scale={}:{}",
config.processing.width, config.processing.height
),
"video",
);
chain.add_filter(&format!("setdar=dar={}", config.processing.aspect), "video")
}
}
fn fade(node: &mut Media, chain: &mut Filters, codec_type: &str) {
@ -161,9 +172,12 @@ fn overlay(node: &mut Media, chain: &mut Filters, config: &GlobalConfig) {
}
fn extend_video(node: &mut Media, chain: &mut Filters) {
let video_streams = node.probe.clone().unwrap().video_streams.unwrap();
if !video_streams.is_empty() {
if let Some(duration) = &video_streams[0].duration {
if let Some(duration) = node
.probe
.as_ref()
.and_then(|p| p.video_streams.as_ref())
.and_then(|v| v[0].duration.as_ref())
{
let duration_float = duration.clone().parse::<f64>().unwrap();
if node.out - node.seek > duration_float - node.seek + 0.1 {
@ -176,7 +190,6 @@ fn extend_video(node: &mut Media, chain: &mut Filters) {
)
}
}
}
}
/// add drawtext filter for lower thirds messages
@ -198,8 +211,13 @@ fn add_text(node: &mut Media, chain: &mut Filters, config: &GlobalConfig) {
}
fn add_audio(node: &mut Media, chain: &mut Filters) {
let audio_streams = node.probe.clone().unwrap().audio_streams.unwrap();
if audio_streams.is_empty() {
if node
.probe
.as_ref()
.and_then(|p| p.audio_streams.as_ref())
.unwrap_or(&vec![])
.is_empty()
{
warn!("Clip: '{}' has no audio!", node.source);
let audio = format!(
"aevalsrc=0:channel_layout=stereo:duration={}:sample_rate=48000",
@ -210,29 +228,29 @@ fn add_audio(node: &mut Media, chain: &mut Filters) {
}
fn extend_audio(node: &mut Media, chain: &mut Filters) {
let audio_streams = node.probe.clone().unwrap().audio_streams.unwrap();
if !audio_streams.is_empty() {
if let Some(duration) = &audio_streams[0].duration {
if let Some(duration) = node
.probe
.as_ref()
.and_then(|p| p.audio_streams.as_ref())
.and_then(|a| a[0].duration.as_ref())
{
let duration_float = duration.clone().parse::<f64>().unwrap();
if node.out - node.seek > duration_float - node.seek + 0.1 {
chain.add_filter(&format!("apad=whole_dur={}", node.out - node.seek), "audio")
}
}
}
}
/// Add single pass loudnorm filter to audio line.
fn add_loudnorm(node: &mut Media, chain: &mut Filters, config: &GlobalConfig) {
if node.probe.is_some()
if config.processing.add_loudnorm
&& !node
.probe
.clone()
.unwrap()
.audio_streams
.unwrap()
.as_ref()
.and_then(|p| p.audio_streams.as_ref())
.unwrap_or(&vec![])
.is_empty()
&& config.processing.add_loudnorm
{
let loud_filter = a_loudnorm::filter_node(config);
chain.add_filter(&loud_filter, "audio");
@ -259,7 +277,7 @@ fn aspect_calc(aspect_string: &Option<String>, config: &GlobalConfig) -> f64 {
}
fn fps_calc(r_frame_rate: &str) -> f64 {
let frame_rate_vec: Vec<&str> = r_frame_rate.split('/').collect();
let frame_rate_vec = r_frame_rate.split('/').collect::<Vec<&str>>();
let rate: f64 = frame_rate_vec[0].parse().unwrap();
let factor: f64 = frame_rate_vec[1].parse().unwrap();
let fps: f64 = rate / factor;
@ -294,29 +312,24 @@ fn realtime_filter(node: &mut Media, chain: &mut Filters, config: &GlobalConfig,
pub fn filter_chains(config: &GlobalConfig, node: &mut Media) -> Vec<String> {
let mut filters = Filters::new();
let mut audio_map = "1:a".to_string();
filters.audio_map = Some(audio_map);
if let Some(probe) = node.probe.clone() {
if let Some(probe) = node.probe.as_ref() {
if probe.audio_streams.is_some() {
audio_map = "0:a".to_string();
filters.audio_map = Some(audio_map);
filters.audio_map = "0:a".to_string();
}
let v_stream = &probe.video_streams.unwrap()[0];
if let Some(v_streams) = &probe.video_streams.as_ref() {
let v_stream = &v_streams[0];
let aspect = aspect_calc(&v_stream.display_aspect_ratio, config);
let frame_per_sec = fps_calc(&v_stream.r_frame_rate);
deinterlace(&v_stream.field_order, &mut filters);
pad(aspect, &mut filters, config);
fps(frame_per_sec, &mut filters, config);
scale(
v_stream.width.unwrap(),
v_stream.height.unwrap(),
aspect,
&mut filters,
config,
);
scale(v_stream, aspect, &mut filters, config);
}
extend_video(node, &mut filters);
add_audio(node, &mut filters);
@ -339,8 +352,8 @@ pub fn filter_chains(config: &GlobalConfig, node: &mut Media) -> Vec<String> {
if let Some(v_filters) = filters.video_chain {
filter_str.push_str(v_filters.as_str());
filter_str.push_str(filters.video_map.clone().unwrap().as_str());
filter_map.append(&mut vec!["-map".to_string(), filters.video_map.unwrap()]);
filter_str.push_str(filters.video_map.clone().as_str());
filter_map.append(&mut vec!["-map".to_string(), filters.video_map]);
} else {
filter_map.append(&mut vec!["-map".to_string(), "0:v".to_string()]);
}
@ -350,10 +363,10 @@ pub fn filter_chains(config: &GlobalConfig, node: &mut Media) -> Vec<String> {
filter_str.push(';')
}
filter_str.push_str(a_filters.as_str());
filter_str.push_str(filters.audio_map.clone().unwrap().as_str());
filter_map.append(&mut vec!["-map".to_string(), filters.audio_map.unwrap()]);
filter_str.push_str(filters.audio_map.clone().as_str());
filter_map.append(&mut vec!["-map".to_string(), filters.audio_map]);
} else {
filter_map.append(&mut vec!["-map".to_string(), filters.audio_map.unwrap()]);
filter_map.append(&mut vec!["-map".to_string(), filters.audio_map]);
}
if filter_str.len() > 10 {

View File

@ -51,17 +51,15 @@ impl FolderSource {
for entry in WalkDir::new(config.storage.path.clone())
.into_iter()
.filter_map(|e| e.ok())
.flat_map(|e| e.ok())
.filter(|f| f.path().is_file())
{
if entry.path().is_file() {
let ext = file_extension(entry.path());
if ext.is_some()
&& config
if let Some(ext) = file_extension(entry.path()) {
if config
.storage
.extensions
.clone()
.contains(&ext.unwrap().to_lowercase())
.contains(&ext.to_lowercase())
{
let media = Media::new(0, entry.path().display().to_string(), false);
media_list.push(media);

View File

@ -80,11 +80,8 @@ impl CurrentProgram {
} else if Path::new(&self.json_path.clone().unwrap()).is_file() {
let mod_time = modified_time(&self.json_path.clone().unwrap());
if !mod_time
.unwrap()
.to_string()
.eq(&self.json_mod.clone().unwrap())
{
if let Some(m) = mod_time {
if !m.to_string().eq(&self.json_mod.clone().unwrap()) {
// when playlist has changed, reload it
info!(
"Reload playlist <b><magenta>{}</></b>",
@ -105,6 +102,7 @@ impl CurrentProgram {
self.get_current_clip();
self.index.fetch_add(1, Ordering::SeqCst);
}
}
} else {
error!(
"Playlist <b><magenta>{}</></b> not exists!",

View File

@ -230,7 +230,6 @@ pub fn json_rpc_server(
&& request.headers()["authorization"] == auth
{
if request.uri() == "/status" {
println!("{:?}", request.headers().contains_key("authorization"));
Response::ok("Server running OK.").into()
} else {
request.into()

View File

@ -240,6 +240,7 @@ impl GlobalConfig {
if let Some(folder) = args.folder {
config.storage.path = folder;
config.processing.mode = "folder".into();
}
if let Some(start) = args.start {

View File

@ -26,15 +26,15 @@ use crate::utils::GlobalConfig;
/// send log messages to mail recipient
fn send_mail(cfg: &GlobalConfig, msg: String) {
let email = Message::builder()
if let Ok(email) = Message::builder()
.from(cfg.mail.sender_addr.parse().unwrap())
.to(cfg.mail.recipient.parse().unwrap())
.subject(cfg.mail.subject.clone())
.header(header::ContentType::TEXT_PLAIN)
.body(clean_string(&msg))
.unwrap();
let credentials = Credentials::new(cfg.mail.sender_addr.clone(), cfg.mail.sender_pass.clone());
{
let credentials =
Credentials::new(cfg.mail.sender_addr.clone(), cfg.mail.sender_pass.clone());
let mut transporter = SmtpTransport::relay(cfg.mail.smtp_server.clone().as_str());
@ -45,9 +45,11 @@ fn send_mail(cfg: &GlobalConfig, msg: String) {
let mailer = transporter.unwrap().credentials(credentials).build();
// Send the email
match mailer.send(&email) {
Ok(_) => (),
Err(e) => info!("Could not send email: {:?}", e),
if let Err(e) = mailer.send(&email) {
error!("Could not send email: {:?}", e)
}
} else {
error!("Mail Message failed!")
}
}

View File

@ -69,16 +69,19 @@ pub struct Media {
impl Media {
pub fn new(index: usize, src: String, do_probe: bool) -> Self {
let mut duration: f64 = 0.0;
let mut duration = 0.0;
let mut probe = None;
if do_probe && Path::new(&src).is_file() {
probe = Some(MediaProbe::new(src.clone()));
duration = match probe.clone().unwrap().format.unwrap().duration {
Some(dur) => dur.parse().unwrap(),
None => 0.0,
};
if let Some(dur) = probe
.as_ref()
.and_then(|p| p.format.as_ref())
.and_then(|f| f.duration.as_ref())
{
duration = dur.parse().unwrap()
}
}
Self {
@ -103,14 +106,17 @@ impl Media {
let probe = MediaProbe::new(self.source.clone());
self.probe = Some(probe.clone());
if self.duration == 0.0 {
let duration = match probe.format.unwrap().duration {
Some(dur) => dur.parse().unwrap(),
None => 0.0,
};
if let Some(dur) = probe
.format
.and_then(|f| f.duration)
.map(|d| d.parse().unwrap())
.filter(|d| !is_close(*d, self.duration, 0.5))
{
self.duration = dur;
self.out = duration;
self.duration = duration;
if self.out == 0.0 {
self.out = dur;
}
}
}
}
@ -132,25 +138,22 @@ pub struct MediaProbe {
impl MediaProbe {
fn new(input: String) -> Self {
let probe = ffprobe(&input);
let mut a_stream: Vec<Stream> = vec![];
let mut v_stream: Vec<Stream> = vec![];
let mut a_stream = vec![];
let mut v_stream = vec![];
match probe {
Ok(obj) => {
for stream in obj.streams {
let cp_stream = stream.clone();
match cp_stream.codec_type {
Some(codec_type) => {
if codec_type == "audio" {
a_stream.push(stream)
} else if codec_type == "video" {
v_stream.push(stream)
}
}
_ => {
error!("No codec type found for stream: {stream:?}")
if let Some(c_type) = cp_stream.codec_type {
match c_type.as_str() {
"audio" => a_stream.push(stream),
"video" => v_stream.push(stream),
_ => {}
}
} else {
error!("No codec type found for stream: {stream:?}")
}
}
@ -187,15 +190,13 @@ impl MediaProbe {
///
/// The status file is init in main function and mostly modified in RPC server.
pub fn write_status(config: &GlobalConfig, date: &str, shift: f64) {
let stat_file = config.general.stat_file.clone();
let data = json!({
"time_shift": shift,
"date": date,
});
let status_data: String = serde_json::to_string(&data).expect("Serialize status data failed");
if let Err(e) = fs::write(stat_file, &status_data) {
if let Err(e) = fs::write(&config.general.stat_file, &status_data) {
error!("Unable to write file: {e:?}")
};
}
@ -234,9 +235,7 @@ pub fn get_date(seek: bool, start: f64, next_start: f64) -> String {
/// Get file modification time.
pub fn modified_time(path: &str) -> Option<DateTime<Local>> {
let metadata = metadata(path).unwrap();
if let Ok(time) = metadata.modified() {
if let Ok(time) = metadata(path).and_then(|metadata| metadata.modified()) {
let date_time: DateTime<Local> = time.into();
return Some(date_time);
}
@ -519,11 +518,12 @@ pub mod mock_time {
}
pub fn set_mock_time(date_time: &str) {
let date_obj = NaiveDateTime::parse_from_str(date_time, "%Y-%m-%dT%H:%M:%S");
let time = Local.from_local_datetime(&date_obj.unwrap()).unwrap();
if let Ok(d) = NaiveDateTime::parse_from_str(date_time, "%Y-%m-%dT%H:%M:%S") {
let time = Local.from_local_datetime(&d).unwrap();
DATE_TIME_DIFF.with(|cell| *cell.borrow_mut() = Some(Local::now() - time));
}
}
}
#[cfg(test)]