play longer filler clips

This commit is contained in:
jb-alvarado 2023-07-24 16:57:07 +02:00
parent 98d1d5d606
commit 72b390aba9
8 changed files with 130 additions and 55 deletions

View File

@ -141,6 +141,7 @@ impl CurrentProgram {
duration = self.current_node.duration duration = self.current_node.duration
} }
// TODO: add unwrap_or_default()
let mut next_start = self.current_node.begin.unwrap() - start_sec + duration + delta; let mut next_start = self.current_node.begin.unwrap() - start_sec + duration + delta;
if self.player_control.current_index.load(Ordering::SeqCst) if self.player_control.current_index.load(Ordering::SeqCst)
@ -313,11 +314,30 @@ impl Iterator for CurrentProgram {
// fill missing length from playlist // fill missing length from playlist
let mut current_time = get_sec(); let mut current_time = get_sec();
let (_, total_delta) = get_delta(&self.config, &current_time); let (_, total_delta) = get_delta(&self.config, &current_time);
let mut duration = DUMMY_LEN; let mut out = total_delta.abs();
let mut duration = out + 0.001;
if DUMMY_LEN > total_delta {
duration = total_delta;
self.playout_stat.list_init.store(false, Ordering::SeqCst); self.playout_stat.list_init.store(false, Ordering::SeqCst);
trace!("Total delta on list init: {total_delta}");
let filler_index = self.player_control.filler_index.load(Ordering::SeqCst);
let mut filler =
self.player_control.filler_list.lock().unwrap()[filler_index].clone();
filler.add_probe();
if filler.duration > 0.0 {
if duration > filler.duration {
out = filler.duration;
}
duration = filler.duration;
} else if DUMMY_LEN > total_delta {
duration = total_delta;
out = total_delta;
} else {
duration = DUMMY_LEN;
out = DUMMY_LEN;
} }
if self.config.playlist.start_sec.unwrap() > current_time { if self.config.playlist.start_sec.unwrap() > current_time {
@ -330,7 +350,7 @@ impl Iterator for CurrentProgram {
let mut media = Media::new(index, "", false); let mut media = Media::new(index, "", false);
media.begin = Some(current_time); media.begin = Some(current_time);
media.duration = duration; media.duration = duration;
media.out = duration; media.out = out;
self.current_node = gen_source( self.current_node = gen_source(
&self.config, &self.config,
@ -392,18 +412,32 @@ impl Iterator for CurrentProgram {
&& last_playlist == self.json_path && last_playlist == self.json_path
&& total_delta.abs() > 1.0 && total_delta.abs() > 1.0
{ {
// Test if playlist is to early finish, trace!("Total delta on list end: {total_delta}");
// Playlist is to early finish,
// and if we have to fill it with a placeholder. // and if we have to fill it with a placeholder.
let index = self.player_control.current_index.load(Ordering::SeqCst); let index = self.player_control.current_index.load(Ordering::SeqCst);
self.current_node = Media::new(index, "", false); self.current_node = Media::new(index, "", false);
self.current_node.begin = Some(get_sec()); self.current_node.begin = Some(get_sec());
let mut duration = total_delta.abs(); let mut out = total_delta.abs();
let mut duration = out + 0.001;
if duration > DUMMY_LEN { let filler_index = self.player_control.filler_index.load(Ordering::SeqCst);
duration = DUMMY_LEN; let mut filler =
self.player_control.filler_list.lock().unwrap()[filler_index].clone();
filler.add_probe();
if filler.duration > 0.0 {
if duration > filler.duration {
out = filler.duration;
} }
duration = filler.duration;
}
self.current_node.duration = duration; self.current_node.duration = duration;
self.current_node.out = duration; self.current_node.out = out;
self.current_node = gen_source( self.current_node = gen_source(
&self.config, &self.config,
self.current_node.clone(), self.current_node.clone(),
@ -526,7 +560,9 @@ pub fn gen_source(
player_control: &PlayerControl, player_control: &PlayerControl,
last_index: usize, last_index: usize,
) -> Media { ) -> Media {
let duration = node.out - node.seek; let mut duration = node.out - node.seek;
trace!("Clip out: {duration}, duration: {}", node.duration);
if valid_source(&node.source) { if valid_source(&node.source) {
node.add_probe(); node.add_probe();
@ -553,9 +589,9 @@ pub fn gen_source(
error!("Source not found: <b><magenta>\"{}\"</></b>", node.source); error!("Source not found: <b><magenta>\"{}\"</></b>", node.source);
} }
if Path::new(&config.storage.filler).is_dir() let filler_source = Path::new(&config.storage.filler);
&& !player_control.filler_list.lock().unwrap().is_empty()
{ if filler_source.is_dir() && !player_control.filler_list.lock().unwrap().is_empty() {
let filler_index = player_control.filler_index.fetch_add(1, Ordering::SeqCst); let filler_index = player_control.filler_index.fetch_add(1, Ordering::SeqCst);
let mut filler_media = player_control.filler_list.lock().unwrap()[filler_index].clone(); let mut filler_media = player_control.filler_list.lock().unwrap()[filler_index].clone();
@ -563,22 +599,20 @@ pub fn gen_source(
player_control.filler_index.store(0, Ordering::SeqCst) player_control.filler_index.store(0, Ordering::SeqCst)
} }
if filler_media.probe.is_none() {
filler_media.add_probe(); filler_media.add_probe();
}
if filler_media.duration > duration { if node.duration > duration && filler_media.duration > duration {
filler_media.out = duration; filler_media.out = duration;
} }
warn!( node.source = filler_media.source;
"Generate filler with <yellow>{:.2}</> seconds length!", node.duration = filler_media.duration;
filler_media.out node.out = filler_media.out;
);
node = filler_media;
node.cmd = Some(loop_filler(&node)); node.cmd = Some(loop_filler(&node));
} else { node.probe = filler_media.probe;
warn!("Generate filler with <yellow>{duration:.2}</> seconds length!"); } else if filler_source.is_file() {
let probe = MediaProbe::new(&config.storage.filler); let probe = MediaProbe::new(&config.storage.filler);
if config if config
@ -592,7 +626,7 @@ pub fn gen_source(
node.source = config.storage.filler.clone(); node.source = config.storage.filler.clone();
node.cmd = Some(loop_image(&node)); node.cmd = Some(loop_image(&node));
node.probe = Some(probe); node.probe = Some(probe);
} else if let Some(length) = probe } else if let Some(filler_duration) = probe
.clone() .clone()
.format .format
.and_then(|f| f.duration) .and_then(|f| f.duration)
@ -600,8 +634,14 @@ pub fn gen_source(
{ {
// Create placeholder from config filler. // Create placeholder from config filler.
node.source = config.storage.filler.clone(); node.source = config.storage.filler.clone();
node.duration = length;
node.out = duration; node.out = if node.duration > duration && filler_duration > duration {
duration
} else {
filler_duration
};
node.duration = filler_duration;
node.cmd = Some(loop_filler(&node)); node.cmd = Some(loop_filler(&node));
node.probe = Some(probe); node.probe = Some(probe);
} else { } else {
@ -610,7 +650,21 @@ pub fn gen_source(
node.source = source; node.source = source;
node.cmd = Some(cmd); node.cmd = Some(cmd);
} }
} else {
if duration > DUMMY_LEN {
duration = DUMMY_LEN;
node.duration = duration;
node.out = duration;
} }
let (source, cmd) = gen_dummy(config, duration);
node.source = source;
node.cmd = Some(cmd);
}
warn!(
"Generate filler with <yellow>{:.2}</> seconds length!",
node.out
);
} }
node.add_filter(config, filter_chain); node.add_filter(config, filter_chain);

View File

@ -212,14 +212,8 @@ fn main() {
config.general.config_path config.general.config_path
); );
if Path::new(&config.storage.filler).is_dir() { // Fill filler list, can also be a single file.
debug!(
"Fill filler list from: <b><magenta>{}</></b>",
config.storage.filler
);
thread::spawn(move || fill_filler_list(config_clone2, play_ctl2)); thread::spawn(move || fill_filler_list(config_clone2, play_ctl2));
}
match config.out.mode { match config.out.mode {
// write files/playlist to HLS m3u8 playlist // write files/playlist to HLS m3u8 playlist

View File

@ -111,6 +111,8 @@ pub fn player(
} }
} }
trace!("Decoder CMD: {:?}", node.cmd);
let mut cmd = match node.cmd { let mut cmd = match node.cmd {
Some(cmd) => cmd, Some(cmd) => cmd,
None => break, None => break,
@ -223,6 +225,8 @@ pub fn player(
}; };
} }
trace!("Out of source loop");
sleep(Duration::from_secs(1)); sleep(Duration::from_secs(1));
proc_control.stop_all(); proc_control.stop_all();

View File

@ -66,6 +66,9 @@ pub struct Args {
)] )]
pub length: Option<String>, pub length: Option<String>,
#[clap(long, help = "Override logging level")]
pub level: Option<String>,
#[clap(short, long, help = "Loop playlist infinitely")] #[clap(short, long, help = "Loop playlist infinitely")]
pub infinit: bool, pub infinit: bool,

View File

@ -86,6 +86,11 @@ pub fn get_config(args: Args) -> PlayoutConfig {
} }
} }
// TODO: implement this
// if let Some(level) = args.level {
// config.logging.level = LevelFilter::from(level);
// }
if args.infinit { if args.infinit {
config.playlist.infinit = args.infinit; config.playlist.infinit = args.infinit;
} }

View File

@ -577,10 +577,13 @@ pub fn filter_chains(
{ {
extend_audio(node, &mut filters, i); extend_audio(node, &mut filters, i);
} else if node.unit == Decoder { } else if node.unit == Decoder {
if !node.source.contains("color=c=") {
warn!( warn!(
"Missing audio track (id {i}) from <b><magenta>{}</></b>", "Missing audio track (id {i}) from <b><magenta>{}</></b>",
node.source node.source
); );
}
add_audio(node, &mut filters, i); add_audio(node, &mut filters, i);
} }

View File

@ -163,6 +163,12 @@ impl Iterator for FolderSource {
pub fn fill_filler_list(config: PlayoutConfig, player_control: PlayerControl) { pub fn fill_filler_list(config: PlayoutConfig, player_control: PlayerControl) {
let mut filler_list = vec![]; let mut filler_list = vec![];
if Path::new(&config.storage.filler).is_dir() {
debug!(
"Fill filler list from: <b><magenta>{}</></b>",
config.storage.filler
);
for (index, entry) in WalkDir::new(&config.storage.filler) for (index, entry) in WalkDir::new(&config.storage.filler)
.into_iter() .into_iter()
.flat_map(|e| e.ok()) .flat_map(|e| e.ok())
@ -170,8 +176,7 @@ pub fn fill_filler_list(config: PlayoutConfig, player_control: PlayerControl) {
.filter(|f| include_file_extension(&config, f.path())) .filter(|f| include_file_extension(&config, f.path()))
.enumerate() .enumerate()
{ {
let media = Media::new(index, &entry.path().to_string_lossy(), false); filler_list.push(Media::new(index, &entry.path().to_string_lossy(), false));
filler_list.push(media);
} }
if config.storage.shuffle { if config.storage.shuffle {
@ -179,6 +184,9 @@ pub fn fill_filler_list(config: PlayoutConfig, player_control: PlayerControl) {
filler_list.shuffle(&mut rng); filler_list.shuffle(&mut rng);
} }
} else {
filler_list.push(Media::new(0, &config.storage.filler, false));
}
*player_control.filler_list.lock().unwrap() = filler_list; *player_control.filler_list.lock().unwrap() = filler_list;
} }

View File

@ -238,9 +238,13 @@ impl MediaProbe {
} }
} }
Err(e) => { Err(e) => {
if Path::new(input).is_file() {
error!( error!(
"Can't read source <b><magenta>{input}</></b> with ffprobe, source not exists or damaged! Error in: {e:?}" "Can't read source <b><magenta>{input}</></b> with ffprobe! Error: {e:?}"
); );
} else if !input.is_empty() {
error!("File not exists: <b><magenta>{input}</></b>");
}
MediaProbe { MediaProbe {
format: None, format: None,