play longer filler clips
This commit is contained in:
parent
98d1d5d606
commit
72b390aba9
@ -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, ¤t_time);
|
let (_, total_delta) = get_delta(&self.config, ¤t_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);
|
||||||
|
@ -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
|
||||||
|
@ -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();
|
||||||
|
@ -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,
|
||||||
|
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user