default when category is net set, use filler_clip from config instead of a dummy clip

This commit is contained in:
jb-alvarado 2022-07-29 12:28:34 +02:00
parent b57f078f8a
commit baf10cfdda
7 changed files with 56 additions and 16 deletions

4
Cargo.lock generated
View File

@ -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",

View File

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

View File

@ -479,8 +479,13 @@ fn gen_source(
error!("Source not found: <b><magenta>{}</></b>", 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);
}

View File

@ -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());

View File

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

View File

@ -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::<f64>().ok())
{
let duration_float = duration.clone().parse::<f64>().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::<f64>().ok())
{
let duration_float = duration.clone().parse::<f64>().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")
}
}

View File

@ -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<String> {
let loop_count = (target_duration / source_duration).ceil() as i32;
info!("Loop <b><magenta>{source}</></b> <yellow>{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<String>) {
// 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::<f64>().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<ChildStderr>, suffix: &str) -> Result<(),
"<bright black>[{suffix}]</> {}",
format_log_line(line, "error")
)
} else if line.contains("[fatal]") {
error!(
"<bright black>[{suffix}]</> {}",
format_log_line(line, "fatal")
)
}
}