integrate webvtt subtitles
This commit is contained in:
parent
1d4cdfaca6
commit
5061f21376
2
.vscode/settings.json
vendored
2
.vscode/settings.json
vendored
@ -51,11 +51,13 @@
|
||||
"canonicalize",
|
||||
"ffpengine",
|
||||
"flexi",
|
||||
"httpauth",
|
||||
"lettre",
|
||||
"libc",
|
||||
"neli",
|
||||
"nuxt",
|
||||
"paris",
|
||||
"Referer",
|
||||
"reqwest",
|
||||
"rsplit",
|
||||
"rustls",
|
||||
|
@ -72,6 +72,10 @@ pub fn ingest_server(
|
||||
dummy_media.add_filter(&config, &None);
|
||||
let is_terminated = channel_mgr.is_terminated.clone();
|
||||
let ingest_is_running = channel_mgr.ingest_is_running.clone();
|
||||
let vtt_dummy = config
|
||||
.channel
|
||||
.storage_path
|
||||
.join(&config.processing.vtt_dummy.clone().unwrap_or_default());
|
||||
|
||||
if let Some(ingest_input_cmd) = config.advanced.ingest.input_cmd {
|
||||
server_cmd.append(&mut ingest_input_cmd.clone());
|
||||
@ -79,11 +83,19 @@ pub fn ingest_server(
|
||||
|
||||
server_cmd.append(&mut stream_input.clone());
|
||||
|
||||
if config.processing.vtt_enable && vtt_dummy.is_file() {
|
||||
server_cmd.append(&mut vec_strings!["-i", vtt_dummy.to_string_lossy()]);
|
||||
}
|
||||
|
||||
if let Some(mut filter) = dummy_media.filter {
|
||||
server_cmd.append(&mut filter.cmd());
|
||||
server_cmd.append(&mut filter.map());
|
||||
}
|
||||
|
||||
if config.processing.vtt_enable && vtt_dummy.is_file() {
|
||||
server_cmd.append(&mut vec_strings!("-map", "1:s"));
|
||||
}
|
||||
|
||||
if let Some(mut cmd) = config.processing.cmd {
|
||||
server_cmd.append(&mut cmd);
|
||||
}
|
||||
|
@ -640,14 +640,14 @@ pub fn gen_source(
|
||||
.filter(|c| IMAGE_FORMAT.contains(&c.as_str()))
|
||||
.is_some()
|
||||
{
|
||||
node.cmd = Some(loop_image(&node));
|
||||
node.cmd = Some(loop_image(&config, &node));
|
||||
} else {
|
||||
if node.seek > 0.0 && node.out > node.duration {
|
||||
warn!(target: Target::file_mail(), channel = config.general.channel_id; "Clip loops and has seek value: duplicate clip to separate loop and seek.");
|
||||
duplicate_for_seek_and_loop(&mut node, &manager.current_list);
|
||||
}
|
||||
|
||||
node.cmd = Some(seek_and_length(&mut node));
|
||||
node.cmd = Some(seek_and_length(&config, &mut node));
|
||||
}
|
||||
} else {
|
||||
trace!("clip index: {node_index} | last index: {last_index}");
|
||||
@ -694,7 +694,7 @@ pub fn gen_source(
|
||||
node.seek = 0.0;
|
||||
node.out = filler_media.out;
|
||||
node.duration = filler_media.duration;
|
||||
node.cmd = Some(loop_filler(&node));
|
||||
node.cmd = Some(loop_filler(&config, &node));
|
||||
node.probe = filler_media.probe;
|
||||
} else {
|
||||
match MediaProbe::new(&config.storage.filler_path.to_string_lossy()) {
|
||||
@ -715,7 +715,7 @@ pub fn gen_source(
|
||||
.clone()
|
||||
.to_string_lossy()
|
||||
.to_string();
|
||||
node.cmd = Some(loop_image(&node));
|
||||
node.cmd = Some(loop_image(&config, &node));
|
||||
node.probe = Some(probe);
|
||||
} else if let Some(filler_duration) = probe
|
||||
.clone()
|
||||
@ -739,7 +739,7 @@ pub fn gen_source(
|
||||
node.seek = 0.0;
|
||||
node.out = filler_out;
|
||||
node.duration = filler_duration;
|
||||
node.cmd = Some(loop_filler(&node));
|
||||
node.cmd = Some(loop_filler(&config, &node));
|
||||
node.probe = Some(probe);
|
||||
} else {
|
||||
// Create colored placeholder.
|
||||
|
@ -62,6 +62,17 @@ fn ingest_to_hls_server(manager: ChannelManager) -> Result<(), ProcessError> {
|
||||
|
||||
server_prefix.append(&mut stream_input.clone());
|
||||
|
||||
if config.processing.vtt_enable {
|
||||
let vtt_dummy = config
|
||||
.channel
|
||||
.storage_path
|
||||
.join(&config.processing.vtt_dummy.clone().unwrap_or_default());
|
||||
|
||||
if vtt_dummy.is_file() {
|
||||
server_prefix.append(&mut vec_strings!["-i", vtt_dummy.to_string_lossy()]);
|
||||
}
|
||||
}
|
||||
|
||||
let mut is_running;
|
||||
|
||||
if let Some(url) = stream_input.iter().find(|s| s.contains("://")) {
|
||||
|
@ -150,6 +150,14 @@ pub fn player(manager: ChannelManager) -> Result<(), ProcessError> {
|
||||
dec_cmd.append(&mut filter.map());
|
||||
}
|
||||
|
||||
if config.processing.vtt_enable && dec_cmd.iter().any(|s| s.ends_with(".vtt")) {
|
||||
let mut i = dec_cmd.iter().filter(|&n| &*n == "-i").count();
|
||||
if i > 0 {
|
||||
i -= 1
|
||||
}
|
||||
dec_cmd.append(&mut vec_strings!("-map", format!("{i}:s"), "-c:s", "copy"));
|
||||
}
|
||||
|
||||
if let Some(mut cmd) = config.processing.cmd.clone() {
|
||||
dec_cmd.append(&mut cmd);
|
||||
}
|
||||
|
@ -65,9 +65,9 @@ fn check_media(
|
||||
.filter(|c| IMAGE_FORMAT.contains(&c.as_str()))
|
||||
.is_some()
|
||||
{
|
||||
node.cmd = Some(loop_image(&node));
|
||||
node.cmd = Some(loop_image(&config, &node));
|
||||
} else {
|
||||
node.cmd = Some(seek_and_length(&mut node));
|
||||
node.cmd = Some(seek_and_length(&config, &mut node));
|
||||
}
|
||||
|
||||
node.add_filter(&config, &None);
|
||||
|
@ -67,6 +67,10 @@ pub fn prepare_output_cmd(
|
||||
let mut new_params = vec![];
|
||||
let mut count = 0;
|
||||
let re_v = Regex::new(r"\[?0:v(:0)?\]?").unwrap();
|
||||
let vtt_dummy = config
|
||||
.channel
|
||||
.storage_path
|
||||
.join(&config.processing.vtt_dummy.clone().unwrap_or_default());
|
||||
|
||||
if let Some(mut filter) = filters.clone() {
|
||||
for (i, param) in output_params.iter().enumerate() {
|
||||
@ -119,6 +123,15 @@ pub fn prepare_output_cmd(
|
||||
}
|
||||
}
|
||||
|
||||
if config.processing.vtt_enable && vtt_dummy.is_file() {
|
||||
let mut i = cmd.iter().filter(|&n| &*n == "-i").count();
|
||||
if i > 0 {
|
||||
i -= 1
|
||||
}
|
||||
|
||||
cmd.append(&mut vec_strings!("-map", format!("{i}:s?")));
|
||||
}
|
||||
|
||||
cmd.append(&mut output_params);
|
||||
|
||||
cmd
|
||||
@ -589,7 +602,7 @@ pub fn get_delta(config: &PlayoutConfig, begin: &f64) -> (f64, f64) {
|
||||
}
|
||||
|
||||
/// Loop image until target duration is reached.
|
||||
pub fn loop_image(node: &Media) -> Vec<String> {
|
||||
pub fn loop_image(config: &PlayoutConfig, node: &Media) -> Vec<String> {
|
||||
let duration = node.out - node.seek;
|
||||
let mut source_cmd: Vec<String> = vec_strings!["-loop", "1", "-i", node.source.clone()];
|
||||
|
||||
@ -608,11 +621,30 @@ pub fn loop_image(node: &Media) -> Vec<String> {
|
||||
|
||||
source_cmd.append(&mut vec_strings!["-t", duration]);
|
||||
|
||||
if config.processing.vtt_enable {
|
||||
let vtt_file = Path::new(&node.source).with_extension("vtt");
|
||||
let vtt_dummy = config
|
||||
.channel
|
||||
.storage_path
|
||||
.join(&config.processing.vtt_dummy.clone().unwrap_or_default());
|
||||
|
||||
if vtt_file.is_file() {
|
||||
source_cmd.append(&mut vec_strings![
|
||||
"-i",
|
||||
vtt_file.to_string_lossy(),
|
||||
"-t",
|
||||
node.out
|
||||
]);
|
||||
} else if vtt_dummy.is_file() {
|
||||
source_cmd.append(&mut vec_strings!["-i", vtt_dummy.to_string_lossy()]);
|
||||
}
|
||||
}
|
||||
|
||||
source_cmd
|
||||
}
|
||||
|
||||
/// Loop filler until target duration is reached.
|
||||
pub fn loop_filler(node: &Media) -> Vec<String> {
|
||||
pub fn loop_filler(config: &PlayoutConfig, node: &Media) -> Vec<String> {
|
||||
let loop_count = (node.out / node.duration).ceil() as i32;
|
||||
let mut source_cmd = vec![];
|
||||
|
||||
@ -624,11 +656,34 @@ pub fn loop_filler(node: &Media) -> Vec<String> {
|
||||
|
||||
source_cmd.append(&mut vec_strings!["-i", node.source, "-t", node.out]);
|
||||
|
||||
if config.processing.vtt_enable {
|
||||
let vtt_file = Path::new(&node.source).with_extension("vtt");
|
||||
let vtt_dummy = config
|
||||
.channel
|
||||
.storage_path
|
||||
.join(&config.processing.vtt_dummy.clone().unwrap_or_default());
|
||||
|
||||
if vtt_file.is_file() {
|
||||
if loop_count > 1 {
|
||||
source_cmd.append(&mut vec_strings!["-stream_loop", loop_count]);
|
||||
}
|
||||
|
||||
source_cmd.append(&mut vec_strings![
|
||||
"-i",
|
||||
vtt_file.to_string_lossy(),
|
||||
"-t",
|
||||
node.out
|
||||
]);
|
||||
} else if vtt_dummy.is_file() {
|
||||
source_cmd.append(&mut vec_strings!["-i", vtt_dummy.to_string_lossy()]);
|
||||
}
|
||||
}
|
||||
|
||||
source_cmd
|
||||
}
|
||||
|
||||
/// Set clip seek in and length value.
|
||||
pub fn seek_and_length(node: &mut Media) -> Vec<String> {
|
||||
pub fn seek_and_length(config: &PlayoutConfig, node: &mut Media) -> Vec<String> {
|
||||
let loop_count = (node.out / node.duration).ceil() as i32;
|
||||
let mut source_cmd = vec![];
|
||||
let mut cut_audio = false;
|
||||
@ -673,6 +728,28 @@ pub fn seek_and_length(node: &mut Media) -> Vec<String> {
|
||||
}
|
||||
}
|
||||
|
||||
if config.processing.vtt_enable {
|
||||
let vtt_file = Path::new(&node.source).with_extension("vtt");
|
||||
let vtt_dummy = config
|
||||
.channel
|
||||
.storage_path
|
||||
.join(&config.processing.vtt_dummy.clone().unwrap_or_default());
|
||||
|
||||
if vtt_file.is_file() {
|
||||
if loop_count > 1 {
|
||||
source_cmd.append(&mut vec_strings!["-stream_loop", loop_count]);
|
||||
}
|
||||
|
||||
source_cmd.append(&mut vec_strings!["-i", vtt_file.to_string_lossy()]);
|
||||
|
||||
if node.duration > node.out || remote_source || loop_count > 1 {
|
||||
source_cmd.append(&mut vec_strings!["-t", node.out - node.seek]);
|
||||
}
|
||||
} else if vtt_dummy.is_file() {
|
||||
source_cmd.append(&mut vec_strings!["-i", vtt_dummy.to_string_lossy()]);
|
||||
}
|
||||
}
|
||||
|
||||
source_cmd
|
||||
}
|
||||
|
||||
@ -683,7 +760,7 @@ pub fn gen_dummy(config: &PlayoutConfig, duration: f64) -> (String, Vec<String>)
|
||||
"color=c={color}:s={}x{}:d={duration}",
|
||||
config.processing.width, config.processing.height
|
||||
);
|
||||
let cmd: Vec<String> = vec_strings![
|
||||
let mut source_cmd: Vec<String> = vec_strings![
|
||||
"-f",
|
||||
"lavfi",
|
||||
"-i",
|
||||
@ -697,7 +774,18 @@ pub fn gen_dummy(config: &PlayoutConfig, duration: f64) -> (String, Vec<String>)
|
||||
format!("anoisesrc=d={duration}:c=pink:r=48000:a=0.3")
|
||||
];
|
||||
|
||||
(source, cmd)
|
||||
if config.processing.vtt_enable {
|
||||
let vtt_dummy = config
|
||||
.channel
|
||||
.storage_path
|
||||
.join(&config.processing.vtt_dummy.clone().unwrap_or_default());
|
||||
|
||||
if vtt_dummy.is_file() {
|
||||
source_cmd.append(&mut vec_strings!["-i", vtt_dummy.to_string_lossy()]);
|
||||
}
|
||||
}
|
||||
|
||||
(source, source_cmd)
|
||||
}
|
||||
|
||||
// fn get_output_count(cmd: &[String]) -> i32 {
|
||||
|
Loading…
Reference in New Issue
Block a user