From baf10cfddae202d13a610a8be6a7ad5919f74134 Mon Sep 17 00:00:00 2001 From: jb-alvarado Date: Fri, 29 Jul 2022 12:28:34 +0200 Subject: [PATCH] default when category is net set, use filler_clip from config instead of a dummy clip --- Cargo.lock | 4 +-- ffplayout-engine/Cargo.toml | 2 +- ffplayout-engine/src/input/playlist.rs | 7 ++++- ffplayout-engine/src/output/mod.rs | 2 +- lib/Cargo.toml | 2 +- lib/src/filter/mod.rs | 16 +++++------ lib/src/utils/mod.rs | 39 +++++++++++++++++++++++++- 7 files changed, 56 insertions(+), 16 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0c0d5170..b0b9a12e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1014,7 +1014,7 @@ dependencies = [ [[package]] name = "ffplayout" -version = "0.13.2" +version = "0.14.0" dependencies = [ "clap", "crossbeam-channel 0.5.6", @@ -1062,7 +1062,7 @@ dependencies = [ [[package]] name = "ffplayout-lib" -version = "0.13.1" +version = "0.14.0" dependencies = [ "chrono", "crossbeam-channel 0.5.6", diff --git a/ffplayout-engine/Cargo.toml b/ffplayout-engine/Cargo.toml index b405a0d4..2c5c24a5 100644 --- a/ffplayout-engine/Cargo.toml +++ b/ffplayout-engine/Cargo.toml @@ -4,7 +4,7 @@ description = "24/7 playout based on rust and ffmpeg" license = "GPL-3.0" authors = ["Jonathan Baecker jonbae77@gmail.com"] readme = "README.md" -version = "0.13.2" +version = "0.14.0" edition = "2021" [dependencies] diff --git a/ffplayout-engine/src/input/playlist.rs b/ffplayout-engine/src/input/playlist.rs index 06268c90..1db52101 100644 --- a/ffplayout-engine/src/input/playlist.rs +++ b/ffplayout-engine/src/input/playlist.rs @@ -479,8 +479,13 @@ fn gen_source( error!("Source not found: {}", node.source); } let (source, cmd) = gen_dummy(config, node.out - node.seek); - node.source = source; + node.source = source.clone(); node.cmd = Some(cmd); + + if source == config.storage.filler_clip { + node.add_probe(); + } + node.add_filter(config, filter_chain); } diff --git a/ffplayout-engine/src/output/mod.rs b/ffplayout-engine/src/output/mod.rs index e223413d..9184247b 100644 --- a/ffplayout-engine/src/output/mod.rs +++ b/ffplayout-engine/src/output/mod.rs @@ -119,11 +119,11 @@ pub fn player( .stderr(Stdio::piped()) .spawn() { + Ok(proc) => proc, Err(e) => { error!("couldn't spawn decoder process: {}", e); panic!("couldn't spawn decoder process: {}", e) } - Ok(proc) => proc, }; let mut dec_reader = BufReader::new(dec_proc.stdout.take().unwrap()); diff --git a/lib/Cargo.toml b/lib/Cargo.toml index 2f890872..4c5a3fb4 100644 --- a/lib/Cargo.toml +++ b/lib/Cargo.toml @@ -4,7 +4,7 @@ description = "Library for ffplayout" license = "GPL-3.0" authors = ["Jonathan Baecker jonbae77@gmail.com"] readme = "README.md" -version = "0.13.1" +version = "0.14.0" edition = "2021" [dependencies] diff --git a/lib/src/filter/mod.rs b/lib/src/filter/mod.rs index 9f9bc071..b9e2376a 100644 --- a/lib/src/filter/mod.rs +++ b/lib/src/filter/mod.rs @@ -167,19 +167,18 @@ fn overlay(node: &mut Media, chain: &mut Filters, config: &PlayoutConfig) { } fn extend_video(node: &mut Media, chain: &mut Filters) { - if let Some(duration) = node + if let Some(video_duration) = node .probe .as_ref() .and_then(|p| p.video_streams.as_ref()) .and_then(|v| v[0].duration.as_ref()) + .and_then(|v| v.parse::().ok()) { - let duration_float = duration.clone().parse::().unwrap(); - - if node.out - node.seek > duration_float - node.seek + 0.1 { + if node.out - node.seek > video_duration - node.seek + 0.1 && node.duration >= node.out { chain.add_filter( &format!( "tpad=stop_mode=add:stop_duration={}", - (node.out - node.seek) - (duration_float - node.seek) + (node.out - node.seek) - (video_duration - node.seek) ), "video", ) @@ -221,15 +220,14 @@ fn add_audio(node: &mut Media, chain: &mut Filters) { } fn extend_audio(node: &mut Media, chain: &mut Filters) { - if let Some(duration) = node + if let Some(audio_duration) = node .probe .as_ref() .and_then(|p| p.audio_streams.as_ref()) .and_then(|a| a[0].duration.as_ref()) + .and_then(|a| a.parse::().ok()) { - let duration_float = duration.clone().parse::().unwrap(); - - if node.out - node.seek > duration_float - node.seek + 0.1 { + if node.out - node.seek > audio_duration - node.seek + 0.1 && node.duration >= node.out { chain.add_filter(&format!("apad=whole_dur={}", node.out - node.seek), "audio") } } diff --git a/lib/src/utils/mod.rs b/lib/src/utils/mod.rs index fa1b478b..4e9c8322 100644 --- a/lib/src/utils/mod.rs +++ b/lib/src/utils/mod.rs @@ -49,7 +49,7 @@ pub struct Media { pub out: f64, pub duration: f64, - #[serde(deserialize_with = "null_string")] + #[serde(default, deserialize_with = "null_string")] pub category: String, #[serde(deserialize_with = "null_string")] pub source: String, @@ -394,8 +394,40 @@ pub fn check_sync(config: &PlayoutConfig, delta: f64) -> bool { true } +/// Loop source until target duration is reached. +fn loop_input(source: &str, source_duration: f64, target_duration: f64) -> Vec { + let loop_count = (target_duration / source_duration).ceil() as i32; + + info!("Loop {source} {loop_count} times, total duration: {target_duration:.2}"); + + vec_strings![ + "-stream_loop", + loop_count.to_string(), + "-i", + source, + "-t", + target_duration.to_string() + ] +} + /// Create a dummy clip as a placeholder for missing video files. pub fn gen_dummy(config: &PlayoutConfig, duration: f64) -> (String, Vec) { + // create placeholder from config filler. + if Path::new(&config.storage.filler_clip).is_file() { + let probe = MediaProbe::new(&config.storage.filler_clip); + + if let Some(length) = probe + .format + .and_then(|f| f.duration) + .and_then(|d| d.parse::().ok()) + { + let cmd = loop_input(&config.storage.filler_clip, length, duration); + + return (config.storage.filler_clip.clone(), cmd); + } + } + + // create colored placeholder. let color = "#121212"; let source = format!( "color=c={color}:s={}x{}:d={duration}", @@ -551,6 +583,11 @@ pub fn stderr_reader(buffer: BufReader, suffix: &str) -> Result<(), "[{suffix}] {}", format_log_line(line, "error") ) + } else if line.contains("[fatal]") { + error!( + "[{suffix}] {}", + format_log_line(line, "fatal") + ) } }