build output filters from scratch, fix #210
This commit is contained in:
parent
04906a7e96
commit
09dace92f4
@ -90,7 +90,8 @@ pub fn ingest_server(
|
|||||||
server_cmd.append(&mut stream_input.clone());
|
server_cmd.append(&mut stream_input.clone());
|
||||||
|
|
||||||
if let Some(mut filter) = dummy_media.filter {
|
if let Some(mut filter) = dummy_media.filter {
|
||||||
server_cmd.append(&mut filter.cmd);
|
server_cmd.append(&mut filter.cmd());
|
||||||
|
server_cmd.append(&mut filter.map());
|
||||||
}
|
}
|
||||||
|
|
||||||
server_cmd.append(&mut config.processing.settings.unwrap());
|
server_cmd.append(&mut config.processing.settings.unwrap());
|
||||||
|
@ -65,7 +65,7 @@ fn ingest_to_hls_server(
|
|||||||
|
|
||||||
loop {
|
loop {
|
||||||
dummy_media.add_filter(&config, &playout_stat.chain);
|
dummy_media.add_filter(&config, &playout_stat.chain);
|
||||||
let server_cmd = prepare_output_cmd(server_prefix.clone(), &dummy_media.filter, &config);
|
let server_cmd = prepare_output_cmd(&config, server_prefix.clone(), &dummy_media.filter);
|
||||||
|
|
||||||
debug!(
|
debug!(
|
||||||
"Server CMD: <bright-blue>\"ffmpeg {}\"</>",
|
"Server CMD: <bright-blue>\"ffmpeg {}\"</>",
|
||||||
@ -180,7 +180,7 @@ pub fn write_hls(
|
|||||||
|
|
||||||
let mut enc_prefix = vec_strings!["-hide_banner", "-nostats", "-v", &ff_log_format];
|
let mut enc_prefix = vec_strings!["-hide_banner", "-nostats", "-v", &ff_log_format];
|
||||||
enc_prefix.append(&mut cmd);
|
enc_prefix.append(&mut cmd);
|
||||||
let enc_cmd = prepare_output_cmd(enc_prefix, &node.filter, config);
|
let enc_cmd = prepare_output_cmd(config, enc_prefix, &node.filter);
|
||||||
|
|
||||||
debug!(
|
debug!(
|
||||||
"HLS writer CMD: <bright-blue>\"ffmpeg {}\"</>",
|
"HLS writer CMD: <bright-blue>\"ffmpeg {}\"</>",
|
||||||
|
@ -103,7 +103,8 @@ pub fn player(
|
|||||||
dec_cmd.append(&mut cmd);
|
dec_cmd.append(&mut cmd);
|
||||||
|
|
||||||
if let Some(mut filter) = node.filter {
|
if let Some(mut filter) = node.filter {
|
||||||
dec_cmd.append(&mut filter.cmd);
|
dec_cmd.append(&mut filter.cmd());
|
||||||
|
dec_cmd.append(&mut filter.map());
|
||||||
}
|
}
|
||||||
|
|
||||||
dec_cmd.append(&mut config.processing.clone().settings.unwrap());
|
dec_cmd.append(&mut config.processing.clone().settings.unwrap());
|
||||||
|
@ -26,7 +26,7 @@ pub fn output(config: &PlayoutConfig, log_format: &str) -> process::Child {
|
|||||||
"pipe:0"
|
"pipe:0"
|
||||||
];
|
];
|
||||||
|
|
||||||
let enc_cmd = prepare_output_cmd(enc_prefix, &media.filter, config);
|
let enc_cmd = prepare_output_cmd(config, enc_prefix, &media.filter);
|
||||||
|
|
||||||
debug!(
|
debug!(
|
||||||
"Encoder CMD: <bright-blue>\"ffmpeg {}\"</>",
|
"Encoder CMD: <bright-blue>\"ffmpeg {}\"</>",
|
||||||
|
@ -26,7 +26,7 @@ pub fn output(config: &PlayoutConfig, log_format: &str) -> process::Child {
|
|||||||
"pipe:0"
|
"pipe:0"
|
||||||
];
|
];
|
||||||
|
|
||||||
let enc_cmd = prepare_output_cmd(enc_prefix, &media.filter, config);
|
let enc_cmd = prepare_output_cmd(config, enc_prefix, &media.filter);
|
||||||
|
|
||||||
debug!(
|
debug!(
|
||||||
"Encoder CMD: <bright-blue>\"ffmpeg {}\"</>",
|
"Encoder CMD: <bright-blue>\"ffmpeg {}\"</>",
|
||||||
|
@ -9,8 +9,8 @@ pub mod arg_parse;
|
|||||||
|
|
||||||
pub use arg_parse::Args;
|
pub use arg_parse::Args;
|
||||||
use ffplayout_lib::{
|
use ffplayout_lib::{
|
||||||
filter::Filters,
|
filter::{FilterType::*, Filters},
|
||||||
utils::{time_to_sec, OutputMode::*, PlayoutConfig, ProcessMode::*},
|
utils::{time_to_sec, PlayoutConfig, ProcessMode::*},
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Read command line arguments, and override the config with them.
|
/// Read command line arguments, and override the config with them.
|
||||||
@ -87,19 +87,69 @@ pub fn get_config(args: Args) -> PlayoutConfig {
|
|||||||
config
|
config
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Process filter from output_param
|
||||||
|
///
|
||||||
|
/// Split filter string and add them to the existing filtergraph.
|
||||||
|
fn process_filters(filters: &mut Filters, output_filter: &str) {
|
||||||
|
let re_v = Regex::new(r"(\[0:v(:[0-9]+)?\]|\[v[\w_-]+\])").unwrap();
|
||||||
|
let re_a = Regex::new(r"(\[0:a(:[0-9]+)?\]|\[a[\w_-]+\])").unwrap();
|
||||||
|
let nr = Regex::new(r"\[[\w:-_]+([0-9])\]").unwrap();
|
||||||
|
|
||||||
|
for f in output_filter.split(';') {
|
||||||
|
if re_v.is_match(f) {
|
||||||
|
let filter_str = re_v.replace_all(f, "").to_string();
|
||||||
|
filters.add_filter(&filter_str, 0, Video);
|
||||||
|
} else if re_a.is_match(f) {
|
||||||
|
let filter_str = re_a.replace_all(f, "").to_string();
|
||||||
|
let track_nr = nr.replace(f, "$1").parse::<i32>().unwrap_or_default();
|
||||||
|
filters.add_filter(&filter_str, track_nr, Audio);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Process filter with multiple in- or output
|
||||||
|
///
|
||||||
|
/// Concat filter to the existing filters and adjust filter connections.
|
||||||
|
/// Output mapping is up to the user.
|
||||||
|
fn process_multi_in_out(filters: &mut Filters, output_filter: &str) -> Vec<String> {
|
||||||
|
let v_map = filters.video_map[filters.video_map.len() - 1].clone();
|
||||||
|
let mut new_filter = format!("{}{v_map}", filters.video_chain);
|
||||||
|
let re_v = Regex::new(r"\[0:v(:[0-9]+)?\]").unwrap();
|
||||||
|
let re_a = Regex::new(r"\[0:a(:(?P<num>[0-9]+))?\]").unwrap();
|
||||||
|
let mut o_filter = re_v.replace(output_filter, v_map).to_string();
|
||||||
|
|
||||||
|
if !filters.audio_map.is_empty() {
|
||||||
|
let a_map = filters.audio_map[filters.audio_map.len() - 1].clone();
|
||||||
|
let a_filter = format!("{}{a_map}", filters.audio_chain);
|
||||||
|
|
||||||
|
new_filter.push(';');
|
||||||
|
new_filter.push_str(&a_filter);
|
||||||
|
|
||||||
|
o_filter = re_a
|
||||||
|
.replace_all(&o_filter, "[aout$num]")
|
||||||
|
.to_string()
|
||||||
|
.replace("[aout]", "[aout0]"); // when no number matched, set default 0
|
||||||
|
}
|
||||||
|
|
||||||
|
new_filter.push(';');
|
||||||
|
new_filter.push_str(&o_filter);
|
||||||
|
|
||||||
|
vec!["-filter_complex".to_string(), new_filter]
|
||||||
|
}
|
||||||
|
|
||||||
/// Prepare output parameters
|
/// Prepare output parameters
|
||||||
///
|
///
|
||||||
/// seek for multiple outputs and add mapping for it
|
/// Seek for multiple outputs and add mapping for it.
|
||||||
pub fn prepare_output_cmd(
|
pub fn prepare_output_cmd(
|
||||||
|
config: &PlayoutConfig,
|
||||||
mut cmd: Vec<String>,
|
mut cmd: Vec<String>,
|
||||||
filters: &Option<Filters>,
|
filters: &Option<Filters>,
|
||||||
config: &PlayoutConfig,
|
|
||||||
) -> Vec<String> {
|
) -> Vec<String> {
|
||||||
let mut output_params = config.out.clone().output_cmd.unwrap();
|
let mut output_params = config.out.clone().output_cmd.unwrap();
|
||||||
let params_len = output_params.len();
|
|
||||||
let mut new_params = vec![];
|
let mut new_params = vec![];
|
||||||
let mut output_filter = String::new();
|
let mut output_filter = String::new();
|
||||||
let re_map = Regex::new(r"(\[?[0-9]:[av](:[0-9]+)?\]?|-map|\[[a-z_0-9]+\])").unwrap();
|
let re_map = Regex::new(r"(\[?[0-9]:[av](:[0-9]+)?\]?|-map$|\[[a-z_0-9]+\])").unwrap();
|
||||||
|
let re_multi = Regex::new(r"\[[\w:_-]+\]\[[\w:_-]+\]").unwrap();
|
||||||
|
|
||||||
if let Some(mut filter) = filters.clone() {
|
if let Some(mut filter) = filters.clone() {
|
||||||
// Loop over output parameters
|
// Loop over output parameters
|
||||||
@ -110,49 +160,40 @@ pub fn prepare_output_cmd(
|
|||||||
if param != "-filter_complex" {
|
if param != "-filter_complex" {
|
||||||
if i > 0 && output_params[i - 1] == "-filter_complex" {
|
if i > 0 && output_params[i - 1] == "-filter_complex" {
|
||||||
output_filter = param.clone();
|
output_filter = param.clone();
|
||||||
} else if !output_filter.contains("split") {
|
} else if !re_multi.is_match(&output_filter) {
|
||||||
if !re_map.is_match(param) {
|
if !re_map.is_match(param)
|
||||||
// Skip mapping parameters, when no split filter is set
|
|| (i < output_params.len() - 2
|
||||||
|
&& (output_params[i + 1].contains("0:s") || param.contains("0:s")))
|
||||||
|
{
|
||||||
|
// Skip mapping parameters, when no multi in/out filter is set.
|
||||||
|
// Only add subtitle mapping.
|
||||||
new_params.push(param.clone());
|
new_params.push(param.clone());
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
new_params.push(param.clone());
|
new_params.push(param.clone());
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Check if parameter is a output
|
// Check if parameter is a output
|
||||||
if i > 0
|
if i > 0
|
||||||
&& !param.starts_with('-')
|
&& !param.starts_with('-')
|
||||||
&& !output_params[i - 1].starts_with('-')
|
&& !output_params[i - 1].starts_with('-')
|
||||||
&& i < params_len - 1
|
&& i < output_params.len() - 1
|
||||||
{
|
{
|
||||||
// add mapping to following outputs
|
// add mapping to following outputs
|
||||||
new_params.append(&mut filter.output_map.clone());
|
new_params.append(&mut filter.map().clone());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if filter.cmd.contains(&"-filter_complex".to_string()) {
|
}
|
||||||
|
|
||||||
output_params = new_params;
|
output_params = new_params;
|
||||||
|
|
||||||
// Process A/V mapping
|
if re_multi.is_match(&output_filter) {
|
||||||
//
|
let mut split_filter = process_multi_in_out(&mut filter, &output_filter);
|
||||||
// when filter in output_param are found and we are in HLS mode, fix the mapping
|
cmd.append(&mut split_filter);
|
||||||
if !output_filter.is_empty() && config.out.mode == HLS {
|
|
||||||
let re = Regex::new(r"0:a:(?P<num>[0-9]+)").unwrap();
|
|
||||||
output_filter = re
|
|
||||||
.replace_all(&output_filter, "aout${num}")
|
|
||||||
.to_string()
|
|
||||||
.replace("[0:a]", &filter.audio_map[0])
|
|
||||||
.replace("[0:v]", &filter.video_map[0])
|
|
||||||
.replace("[0:v:0]", &filter.video_map[0]);
|
|
||||||
|
|
||||||
filter.cmd[1].push_str(&format!(";{output_filter}"));
|
|
||||||
filter.cmd.drain(2..);
|
|
||||||
cmd.append(&mut filter.cmd);
|
|
||||||
} else {
|
} else {
|
||||||
cmd.append(&mut filter.cmd);
|
process_filters(&mut filter, &output_filter);
|
||||||
}
|
cmd.append(&mut filter.cmd());
|
||||||
} else {
|
cmd.append(&mut filter.map());
|
||||||
cmd.append(&mut filter.cmd);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -36,9 +36,8 @@ use FilterType::*;
|
|||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct Filters {
|
pub struct Filters {
|
||||||
audio_chain: String,
|
pub audio_chain: String,
|
||||||
video_chain: String,
|
pub video_chain: String,
|
||||||
pub final_chain: String,
|
|
||||||
pub audio_map: Vec<String>,
|
pub audio_map: Vec<String>,
|
||||||
pub video_map: Vec<String>,
|
pub video_map: Vec<String>,
|
||||||
pub output_map: Vec<String>,
|
pub output_map: Vec<String>,
|
||||||
@ -47,7 +46,6 @@ pub struct Filters {
|
|||||||
video_position: i32,
|
video_position: i32,
|
||||||
audio_last: i32,
|
audio_last: i32,
|
||||||
video_last: i32,
|
video_last: i32,
|
||||||
pub cmd: Vec<String>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Filters {
|
impl Filters {
|
||||||
@ -55,7 +53,6 @@ impl Filters {
|
|||||||
Self {
|
Self {
|
||||||
audio_chain: String::new(),
|
audio_chain: String::new(),
|
||||||
video_chain: String::new(),
|
video_chain: String::new(),
|
||||||
final_chain: String::new(),
|
|
||||||
audio_map: vec![],
|
audio_map: vec![],
|
||||||
video_map: vec![],
|
video_map: vec![],
|
||||||
output_map: vec![],
|
output_map: vec![],
|
||||||
@ -64,7 +61,6 @@ impl Filters {
|
|||||||
video_position: 0,
|
video_position: 0,
|
||||||
audio_last: -1,
|
audio_last: -1,
|
||||||
video_last: -1,
|
video_last: -1,
|
||||||
cmd: vec![],
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -115,43 +111,56 @@ impl Filters {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn close_chains(&mut self) {
|
pub fn cmd(&mut self) -> Vec<String> {
|
||||||
// add final output selector
|
let mut v_chain = self.video_chain.clone();
|
||||||
|
let mut a_chain = self.audio_chain.clone();
|
||||||
|
|
||||||
if self.video_last >= 0 {
|
if self.video_last >= 0 {
|
||||||
self.video_chain
|
v_chain.push_str(&format!("[vout{}]", self.video_last));
|
||||||
.push_str(&format!("[vout{}]", self.video_last));
|
|
||||||
} else {
|
|
||||||
self.output_map
|
|
||||||
.append(&mut vec!["-map".to_string(), "0:v".to_string()]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.audio_last >= 0 {
|
if self.audio_last >= 0 {
|
||||||
self.audio_chain
|
a_chain.push_str(&format!("[aout{}]", self.audio_last));
|
||||||
.push_str(&format!("[aout{}]", self.audio_last));
|
}
|
||||||
} else {
|
|
||||||
|
let mut f_chain = v_chain;
|
||||||
|
let mut cmd = vec![];
|
||||||
|
|
||||||
|
if !a_chain.is_empty() {
|
||||||
|
f_chain.push(';');
|
||||||
|
f_chain.push_str(&a_chain);
|
||||||
|
}
|
||||||
|
|
||||||
|
if !f_chain.is_empty() {
|
||||||
|
cmd.push("-filter_complex".to_string());
|
||||||
|
cmd.push(f_chain);
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn map(&mut self) -> Vec<String> {
|
||||||
|
let mut o_map = self.output_map.clone();
|
||||||
|
|
||||||
|
if self.video_last == -1 {
|
||||||
|
let v_map = "0:v".to_string();
|
||||||
|
|
||||||
|
if !o_map.contains(&v_map) {
|
||||||
|
o_map.append(&mut vec!["-map".to_string(), v_map]);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.audio_last == -1 {
|
||||||
for i in 0..self.audio_track_count {
|
for i in 0..self.audio_track_count {
|
||||||
self.output_map.append(&mut vec![
|
let a_map = format!("{}:a:{i}", self.audio_position);
|
||||||
"-map".to_string(),
|
|
||||||
format!("{}:a:{i}", self.audio_position),
|
if !o_map.contains(&a_map) {
|
||||||
]);
|
o_map.append(&mut vec!["-map".to_string(), a_map]);
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn build_final_chain(&mut self) {
|
o_map
|
||||||
self.final_chain.push_str(&self.video_chain);
|
|
||||||
|
|
||||||
if !self.audio_chain.is_empty() {
|
|
||||||
self.final_chain.push(';');
|
|
||||||
self.final_chain.push_str(&self.audio_chain);
|
|
||||||
}
|
|
||||||
|
|
||||||
if !self.final_chain.is_empty() {
|
|
||||||
self.cmd.push("-filter_complex".to_string());
|
|
||||||
self.cmd.push(self.final_chain.clone());
|
|
||||||
}
|
|
||||||
|
|
||||||
self.cmd.append(&mut self.output_map.clone());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -421,9 +430,6 @@ pub fn filter_chains(
|
|||||||
if node.unit == Encoder {
|
if node.unit == Encoder {
|
||||||
add_text(node, &mut filters, config, filter_chain);
|
add_text(node, &mut filters, config, filter_chain);
|
||||||
|
|
||||||
filters.close_chains();
|
|
||||||
filters.build_final_chain();
|
|
||||||
|
|
||||||
return filters;
|
return filters;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -493,8 +499,5 @@ pub fn filter_chains(
|
|||||||
custom(&list_af, &mut filters, i, Audio);
|
custom(&list_af, &mut filters, i, Audio);
|
||||||
}
|
}
|
||||||
|
|
||||||
filters.close_chains();
|
|
||||||
filters.build_final_chain();
|
|
||||||
|
|
||||||
filters
|
filters
|
||||||
}
|
}
|
||||||
|
@ -57,12 +57,13 @@ fn check_media(
|
|||||||
|
|
||||||
let mut filter = node.filter.unwrap_or_default();
|
let mut filter = node.filter.unwrap_or_default();
|
||||||
|
|
||||||
if filter.cmd.len() > 1 {
|
if filter.cmd().len() > 1 {
|
||||||
filter.cmd[1] = filter.cmd[1].replace("realtime=speed=1", "null")
|
filter.cmd()[1] = filter.cmd()[1].replace("realtime=speed=1", "null")
|
||||||
}
|
}
|
||||||
|
|
||||||
enc_cmd.append(&mut node.cmd.unwrap_or_default());
|
enc_cmd.append(&mut node.cmd.unwrap_or_default());
|
||||||
enc_cmd.append(&mut filter.cmd);
|
enc_cmd.append(&mut filter.cmd());
|
||||||
|
enc_cmd.append(&mut filter.map());
|
||||||
enc_cmd.append(&mut vec_strings!["-t", "0.1", "-f", "null", "-"]);
|
enc_cmd.append(&mut vec_strings!["-t", "0.1", "-f", "null", "-"]);
|
||||||
|
|
||||||
let mut enc_proc = match Command::new("ffmpeg")
|
let mut enc_proc = match Command::new("ffmpeg")
|
||||||
|
@ -20,18 +20,17 @@ fn video_audio_input() {
|
|||||||
let test_filter_cmd =
|
let test_filter_cmd =
|
||||||
vec_strings![
|
vec_strings![
|
||||||
"-filter_complex",
|
"-filter_complex",
|
||||||
format!("[0:v:0]scale=1024:576,null[v];movie={}:loop=0,setpts=N/(FRAME_RATE*TB),format=rgba,colorchannelmixer=aa=0.7[l];[v][l]overlay=W-w-12:12:shortest=1[vout0];[0:a:0]anull[aout0]", config.processing.logo),
|
format!("[0:v:0]scale=1024:576,null[v];movie={}:loop=0,setpts=N/(FRAME_RATE*TB),format=rgba,colorchannelmixer=aa=0.7[l];[v][l]overlay=W-w-12:12:shortest=1[vout0];[0:a:0]anull[aout0]", config.processing.logo)
|
||||||
"-map",
|
|
||||||
"[vout0]",
|
|
||||||
"-map",
|
|
||||||
"[aout0]"
|
|
||||||
];
|
];
|
||||||
|
|
||||||
|
let test_filter_map = vec_strings!["-map", "[vout0]", "-map", "[aout0]"];
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
media.cmd,
|
media.cmd,
|
||||||
Some(vec_strings!["-i", "./assets/with_audio.mp4"])
|
Some(vec_strings!["-i", "./assets/with_audio.mp4"])
|
||||||
);
|
);
|
||||||
assert_eq!(media.filter.unwrap().cmd, test_filter_cmd);
|
assert_eq!(media.filter.clone().unwrap().cmd(), test_filter_cmd);
|
||||||
|
assert_eq!(media.filter.unwrap().map(), test_filter_map);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -47,20 +46,17 @@ fn dual_audio_aevalsrc_input() {
|
|||||||
let test_filter_cmd =
|
let test_filter_cmd =
|
||||||
vec_strings![
|
vec_strings![
|
||||||
"-filter_complex",
|
"-filter_complex",
|
||||||
"[0:v:0]scale=1024:576[vout0];[0:a:0]anull[aout0];aevalsrc=0:channel_layout=stereo:duration=30:sample_rate=48000,anull[aout1]",
|
"[0:v:0]scale=1024:576[vout0];[0:a:0]anull[aout0];aevalsrc=0:channel_layout=stereo:duration=30:sample_rate=48000,anull[aout1]"
|
||||||
"-map",
|
|
||||||
"[vout0]",
|
|
||||||
"-map",
|
|
||||||
"[aout0]",
|
|
||||||
"-map",
|
|
||||||
"[aout1]"
|
|
||||||
];
|
];
|
||||||
|
|
||||||
|
let test_filter_map = vec_strings!["-map", "[vout0]", "-map", "[aout0]", "-map", "[aout1]"];
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
media.cmd,
|
media.cmd,
|
||||||
Some(vec_strings!["-i", "./assets/with_audio.mp4"])
|
Some(vec_strings!["-i", "./assets/with_audio.mp4"])
|
||||||
);
|
);
|
||||||
assert_eq!(media.filter.unwrap().cmd, test_filter_cmd);
|
assert_eq!(media.filter.clone().unwrap().cmd(), test_filter_cmd);
|
||||||
|
assert_eq!(media.filter.unwrap().map(), test_filter_map);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -75,20 +71,17 @@ fn dual_audio_input() {
|
|||||||
|
|
||||||
let test_filter_cmd = vec_strings![
|
let test_filter_cmd = vec_strings![
|
||||||
"-filter_complex",
|
"-filter_complex",
|
||||||
"[0:v:0]scale=1024:576[vout0];[0:a:0]anull[aout0];[0:a:1]anull[aout1]",
|
"[0:v:0]scale=1024:576[vout0];[0:a:0]anull[aout0];[0:a:1]anull[aout1]"
|
||||||
"-map",
|
|
||||||
"[vout0]",
|
|
||||||
"-map",
|
|
||||||
"[aout0]",
|
|
||||||
"-map",
|
|
||||||
"[aout1]"
|
|
||||||
];
|
];
|
||||||
|
|
||||||
|
let test_filter_map = vec_strings!["-map", "[vout0]", "-map", "[aout0]", "-map", "[aout1]"];
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
media.cmd,
|
media.cmd,
|
||||||
Some(vec_strings!["-i", "./assets/dual_audio.mp4"])
|
Some(vec_strings!["-i", "./assets/dual_audio.mp4"])
|
||||||
);
|
);
|
||||||
assert_eq!(media.filter.unwrap().cmd, test_filter_cmd);
|
assert_eq!(media.filter.clone().unwrap().cmd(), test_filter_cmd);
|
||||||
|
assert_eq!(media.filter.unwrap().map(), test_filter_map);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -104,13 +97,11 @@ fn video_separate_audio_input() {
|
|||||||
|
|
||||||
let test_filter_cmd = vec_strings![
|
let test_filter_cmd = vec_strings![
|
||||||
"-filter_complex",
|
"-filter_complex",
|
||||||
"[0:v:0]scale=1024:576[vout0];[1:a:0]anull[aout0]",
|
"[0:v:0]scale=1024:576[vout0];[1:a:0]anull[aout0]"
|
||||||
"-map",
|
|
||||||
"[vout0]",
|
|
||||||
"-map",
|
|
||||||
"[aout0]"
|
|
||||||
];
|
];
|
||||||
|
|
||||||
|
let test_filter_map = vec_strings!["-map", "[vout0]", "-map", "[aout0]"];
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
media.cmd,
|
media.cmd,
|
||||||
Some(vec_strings![
|
Some(vec_strings![
|
||||||
@ -122,7 +113,8 @@ fn video_separate_audio_input() {
|
|||||||
"30"
|
"30"
|
||||||
])
|
])
|
||||||
);
|
);
|
||||||
assert_eq!(media.filter.unwrap().cmd, test_filter_cmd);
|
assert_eq!(media.filter.clone().unwrap().cmd(), test_filter_cmd);
|
||||||
|
assert_eq!(media.filter.unwrap().map(), test_filter_map);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -146,8 +138,75 @@ fn video_audio_stream() {
|
|||||||
"rtmp://localhost/live/stream"
|
"rtmp://localhost/live/stream"
|
||||||
]);
|
]);
|
||||||
|
|
||||||
let mut enc_cmd = vec![];
|
let enc_prefix = vec_strings![
|
||||||
let mut output_cmd = config.out.output_cmd.as_ref().unwrap().clone();
|
"-hide_banner",
|
||||||
|
"-nostats",
|
||||||
|
"-v",
|
||||||
|
"level+error",
|
||||||
|
"-re",
|
||||||
|
"-i",
|
||||||
|
"pipe:0"
|
||||||
|
];
|
||||||
|
|
||||||
|
let enc_cmd = prepare_output_cmd(&config, enc_prefix, &None);
|
||||||
|
|
||||||
|
let test_cmd = vec_strings![
|
||||||
|
"-hide_banner",
|
||||||
|
"-nostats",
|
||||||
|
"-v",
|
||||||
|
"level+error",
|
||||||
|
"-re",
|
||||||
|
"-i",
|
||||||
|
"pipe:0",
|
||||||
|
"-c:v",
|
||||||
|
"libx264",
|
||||||
|
"-c:a",
|
||||||
|
"aac",
|
||||||
|
"-ar",
|
||||||
|
"44100",
|
||||||
|
"-b:a",
|
||||||
|
"128k",
|
||||||
|
"-flags",
|
||||||
|
"+global_header",
|
||||||
|
"-f",
|
||||||
|
"flv",
|
||||||
|
"rtmp://localhost/live/stream"
|
||||||
|
];
|
||||||
|
|
||||||
|
assert_eq!(enc_cmd, test_cmd);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn video_audio_filter_stream() {
|
||||||
|
let mut config = PlayoutConfig::new(Some("../assets/ffplayout.yml".to_string()));
|
||||||
|
config.out.mode = Stream;
|
||||||
|
config.processing.add_logo = false;
|
||||||
|
config.text.add_text = false;
|
||||||
|
config.out.output_cmd = Some(vec_strings![
|
||||||
|
"-filter_complex",
|
||||||
|
"[0:v]gblur=2[vout0];[0:a]volume=0.2[aout0]",
|
||||||
|
"-map",
|
||||||
|
"[vout0]",
|
||||||
|
"-map",
|
||||||
|
"[aout0]",
|
||||||
|
"-c:v",
|
||||||
|
"libx264",
|
||||||
|
"-c:a",
|
||||||
|
"aac",
|
||||||
|
"-ar",
|
||||||
|
"44100",
|
||||||
|
"-b:a",
|
||||||
|
"128k",
|
||||||
|
"-flags",
|
||||||
|
"+global_header",
|
||||||
|
"-f",
|
||||||
|
"flv",
|
||||||
|
"rtmp://localhost/live/stream"
|
||||||
|
]);
|
||||||
|
|
||||||
|
let mut media = Media::new(0, "", false);
|
||||||
|
media.unit = Encoder;
|
||||||
|
media.add_filter(&config, &None);
|
||||||
|
|
||||||
let enc_prefix = vec_strings![
|
let enc_prefix = vec_strings![
|
||||||
"-hide_banner",
|
"-hide_banner",
|
||||||
@ -159,9 +218,7 @@ fn video_audio_stream() {
|
|||||||
"pipe:0"
|
"pipe:0"
|
||||||
];
|
];
|
||||||
|
|
||||||
enc_cmd.append(&mut output_cmd);
|
let enc_cmd = prepare_output_cmd(&config, enc_prefix, &media.filter);
|
||||||
|
|
||||||
let enc_cmd = prepare_output_cmd(enc_prefix, &None, &config);
|
|
||||||
|
|
||||||
let test_cmd = vec_strings![
|
let test_cmd = vec_strings![
|
||||||
"-hide_banner",
|
"-hide_banner",
|
||||||
@ -171,6 +228,257 @@ fn video_audio_stream() {
|
|||||||
"-re",
|
"-re",
|
||||||
"-i",
|
"-i",
|
||||||
"pipe:0",
|
"pipe:0",
|
||||||
|
"-filter_complex",
|
||||||
|
"[0:v:0]gblur=2[vout0];[0:a:0]volume=0.2[aout0]",
|
||||||
|
"-map",
|
||||||
|
"[vout0]",
|
||||||
|
"-map",
|
||||||
|
"[aout0]",
|
||||||
|
"-c:v",
|
||||||
|
"libx264",
|
||||||
|
"-c:a",
|
||||||
|
"aac",
|
||||||
|
"-ar",
|
||||||
|
"44100",
|
||||||
|
"-b:a",
|
||||||
|
"128k",
|
||||||
|
"-flags",
|
||||||
|
"+global_header",
|
||||||
|
"-f",
|
||||||
|
"flv",
|
||||||
|
"rtmp://localhost/live/stream"
|
||||||
|
];
|
||||||
|
|
||||||
|
assert_eq!(enc_cmd, test_cmd);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn video_audio_filter2_stream() {
|
||||||
|
let mut config = PlayoutConfig::new(Some("../assets/ffplayout.yml".to_string()));
|
||||||
|
config.out.mode = Stream;
|
||||||
|
config.processing.add_logo = false;
|
||||||
|
config.text.add_text = true;
|
||||||
|
config.out.output_cmd = Some(vec_strings![
|
||||||
|
"-filter_complex",
|
||||||
|
"[0:v]gblur=2[vout0];[0:a]volume=0.2[aout0]",
|
||||||
|
"-map",
|
||||||
|
"[vout0]",
|
||||||
|
"-map",
|
||||||
|
"[aout0]",
|
||||||
|
"-c:v",
|
||||||
|
"libx264",
|
||||||
|
"-c:a",
|
||||||
|
"aac",
|
||||||
|
"-ar",
|
||||||
|
"44100",
|
||||||
|
"-b:a",
|
||||||
|
"128k",
|
||||||
|
"-flags",
|
||||||
|
"+global_header",
|
||||||
|
"-f",
|
||||||
|
"flv",
|
||||||
|
"rtmp://localhost/live/stream"
|
||||||
|
]);
|
||||||
|
|
||||||
|
let mut media = Media::new(0, "", false);
|
||||||
|
media.unit = Encoder;
|
||||||
|
media.add_filter(&config, &None);
|
||||||
|
|
||||||
|
let socket = config
|
||||||
|
.text
|
||||||
|
.zmq_stream_socket
|
||||||
|
.clone()
|
||||||
|
.unwrap()
|
||||||
|
.replace(':', "\\:");
|
||||||
|
|
||||||
|
let enc_prefix = vec_strings![
|
||||||
|
"-hide_banner",
|
||||||
|
"-nostats",
|
||||||
|
"-v",
|
||||||
|
"level+error",
|
||||||
|
"-re",
|
||||||
|
"-i",
|
||||||
|
"pipe:0"
|
||||||
|
];
|
||||||
|
|
||||||
|
let enc_cmd = prepare_output_cmd(&config, enc_prefix, &media.filter);
|
||||||
|
|
||||||
|
let test_cmd = vec_strings![
|
||||||
|
"-hide_banner",
|
||||||
|
"-nostats",
|
||||||
|
"-v",
|
||||||
|
"level+error",
|
||||||
|
"-re",
|
||||||
|
"-i",
|
||||||
|
"pipe:0",
|
||||||
|
"-filter_complex",
|
||||||
|
format!("[0:v:0]zmq=b=tcp\\\\://'{socket}',drawtext@dyntext=text='',gblur=2[vout0];[0:a:0]volume=0.2[aout0]"),
|
||||||
|
"-map",
|
||||||
|
"[vout0]",
|
||||||
|
"-map",
|
||||||
|
"[aout0]",
|
||||||
|
"-c:v",
|
||||||
|
"libx264",
|
||||||
|
"-c:a",
|
||||||
|
"aac",
|
||||||
|
"-ar",
|
||||||
|
"44100",
|
||||||
|
"-b:a",
|
||||||
|
"128k",
|
||||||
|
"-flags",
|
||||||
|
"+global_header",
|
||||||
|
"-f",
|
||||||
|
"flv",
|
||||||
|
"rtmp://localhost/live/stream"
|
||||||
|
];
|
||||||
|
|
||||||
|
assert_eq!(enc_cmd, test_cmd);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn video_audio_filter3_stream() {
|
||||||
|
let mut config = PlayoutConfig::new(Some("../assets/ffplayout.yml".to_string()));
|
||||||
|
config.out.mode = Stream;
|
||||||
|
config.processing.add_logo = false;
|
||||||
|
config.text.add_text = true;
|
||||||
|
config.out.output_cmd = Some(vec_strings![
|
||||||
|
"-filter_complex",
|
||||||
|
"[0:v]null[o];movie=/path/to/lower_third.png[l];[o][l]overlay=shortest=1[v_out0]",
|
||||||
|
"-map",
|
||||||
|
"[v_out0]",
|
||||||
|
"-c:v",
|
||||||
|
"libx264",
|
||||||
|
"-c:a",
|
||||||
|
"aac",
|
||||||
|
"-ar",
|
||||||
|
"44100",
|
||||||
|
"-b:a",
|
||||||
|
"128k",
|
||||||
|
"-flags",
|
||||||
|
"+global_header",
|
||||||
|
"-f",
|
||||||
|
"flv",
|
||||||
|
"rtmp://localhost/live/stream"
|
||||||
|
]);
|
||||||
|
|
||||||
|
let mut media = Media::new(0, "", false);
|
||||||
|
media.unit = Encoder;
|
||||||
|
media.add_filter(&config, &None);
|
||||||
|
|
||||||
|
let socket = config
|
||||||
|
.text
|
||||||
|
.zmq_stream_socket
|
||||||
|
.clone()
|
||||||
|
.unwrap()
|
||||||
|
.replace(':', "\\:");
|
||||||
|
|
||||||
|
let enc_prefix = vec_strings![
|
||||||
|
"-hide_banner",
|
||||||
|
"-nostats",
|
||||||
|
"-v",
|
||||||
|
"level+error",
|
||||||
|
"-re",
|
||||||
|
"-i",
|
||||||
|
"pipe:0"
|
||||||
|
];
|
||||||
|
|
||||||
|
let enc_cmd = prepare_output_cmd(&config, enc_prefix, &media.filter);
|
||||||
|
|
||||||
|
let test_cmd = vec_strings![
|
||||||
|
"-hide_banner",
|
||||||
|
"-nostats",
|
||||||
|
"-v",
|
||||||
|
"level+error",
|
||||||
|
"-re",
|
||||||
|
"-i",
|
||||||
|
"pipe:0",
|
||||||
|
"-filter_complex",
|
||||||
|
format!("[0:v:0]zmq=b=tcp\\\\://'{socket}',drawtext@dyntext=text=''[vout0];[vout0]null[o];movie=/path/to/lower_third.png[l];[o][l]overlay=shortest=1[v_out0]"),
|
||||||
|
"-map",
|
||||||
|
"[v_out0]",
|
||||||
|
"-c:v",
|
||||||
|
"libx264",
|
||||||
|
"-c:a",
|
||||||
|
"aac",
|
||||||
|
"-ar",
|
||||||
|
"44100",
|
||||||
|
"-b:a",
|
||||||
|
"128k",
|
||||||
|
"-flags",
|
||||||
|
"+global_header",
|
||||||
|
"-f",
|
||||||
|
"flv",
|
||||||
|
"rtmp://localhost/live/stream"
|
||||||
|
];
|
||||||
|
|
||||||
|
assert_eq!(enc_cmd, test_cmd);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn video_audio_filter4_stream() {
|
||||||
|
let mut config = PlayoutConfig::new(Some("../assets/ffplayout.yml".to_string()));
|
||||||
|
config.out.mode = Stream;
|
||||||
|
config.processing.add_logo = false;
|
||||||
|
config.text.add_text = true;
|
||||||
|
config.out.output_cmd = Some(vec_strings![
|
||||||
|
"-filter_complex",
|
||||||
|
"[0:v]null[o];movie=/path/to/lower_third.png[l];[o][l]overlay=shortest=1[v_out0];[0:a:0]volume=0.2[a_out0]",
|
||||||
|
"-map",
|
||||||
|
"[v_out0]",
|
||||||
|
"-map",
|
||||||
|
"[a_out0]",
|
||||||
|
"-c:v",
|
||||||
|
"libx264",
|
||||||
|
"-c:a",
|
||||||
|
"aac",
|
||||||
|
"-ar",
|
||||||
|
"44100",
|
||||||
|
"-b:a",
|
||||||
|
"128k",
|
||||||
|
"-flags",
|
||||||
|
"+global_header",
|
||||||
|
"-f",
|
||||||
|
"flv",
|
||||||
|
"rtmp://localhost/live/stream"
|
||||||
|
]);
|
||||||
|
|
||||||
|
let mut media = Media::new(0, "", false);
|
||||||
|
media.unit = Encoder;
|
||||||
|
media.add_filter(&config, &None);
|
||||||
|
|
||||||
|
let socket = config
|
||||||
|
.text
|
||||||
|
.zmq_stream_socket
|
||||||
|
.clone()
|
||||||
|
.unwrap()
|
||||||
|
.replace(':', "\\:");
|
||||||
|
|
||||||
|
let enc_prefix = vec_strings![
|
||||||
|
"-hide_banner",
|
||||||
|
"-nostats",
|
||||||
|
"-v",
|
||||||
|
"level+error",
|
||||||
|
"-re",
|
||||||
|
"-i",
|
||||||
|
"pipe:0"
|
||||||
|
];
|
||||||
|
|
||||||
|
let enc_cmd = prepare_output_cmd(&config, enc_prefix, &media.filter);
|
||||||
|
|
||||||
|
let test_cmd = vec_strings![
|
||||||
|
"-hide_banner",
|
||||||
|
"-nostats",
|
||||||
|
"-v",
|
||||||
|
"level+error",
|
||||||
|
"-re",
|
||||||
|
"-i",
|
||||||
|
"pipe:0",
|
||||||
|
"-filter_complex",
|
||||||
|
format!("[0:v:0]zmq=b=tcp\\\\://'{socket}',drawtext@dyntext=text=''[vout0];[vout0]null[o];movie=/path/to/lower_third.png[l];[o][l]overlay=shortest=1[v_out0];[0:a:0]volume=0.2[a_out0]"),
|
||||||
|
"-map",
|
||||||
|
"[v_out0]",
|
||||||
|
"-map",
|
||||||
|
"[a_out0]",
|
||||||
"-c:v",
|
"-c:v",
|
||||||
"libx264",
|
"libx264",
|
||||||
"-c:a",
|
"-c:a",
|
||||||
@ -216,10 +524,6 @@ fn video_dual_audio_stream() {
|
|||||||
media.unit = Encoder;
|
media.unit = Encoder;
|
||||||
media.add_filter(&config, &None);
|
media.add_filter(&config, &None);
|
||||||
|
|
||||||
let mut enc_cmd = vec![];
|
|
||||||
|
|
||||||
let mut output_cmd = config.out.output_cmd.as_ref().unwrap().clone();
|
|
||||||
|
|
||||||
let enc_prefix = vec_strings![
|
let enc_prefix = vec_strings![
|
||||||
"-hide_banner",
|
"-hide_banner",
|
||||||
"-nostats",
|
"-nostats",
|
||||||
@ -230,9 +534,7 @@ fn video_dual_audio_stream() {
|
|||||||
"pipe:0"
|
"pipe:0"
|
||||||
];
|
];
|
||||||
|
|
||||||
enc_cmd.append(&mut output_cmd);
|
let enc_cmd = prepare_output_cmd(&config, enc_prefix, &media.filter);
|
||||||
|
|
||||||
let enc_cmd = prepare_output_cmd(enc_prefix, &media.filter, &config);
|
|
||||||
|
|
||||||
let test_cmd = vec_strings![
|
let test_cmd = vec_strings![
|
||||||
"-hide_banner",
|
"-hide_banner",
|
||||||
@ -289,7 +591,6 @@ fn video_dual_audio_filter_stream() {
|
|||||||
"srt://127.0.0.1:40051"
|
"srt://127.0.0.1:40051"
|
||||||
]);
|
]);
|
||||||
|
|
||||||
let mut enc_cmd = vec![];
|
|
||||||
let enc_prefix = vec_strings![
|
let enc_prefix = vec_strings![
|
||||||
"-hide_banner",
|
"-hide_banner",
|
||||||
"-nostats",
|
"-nostats",
|
||||||
@ -311,11 +612,7 @@ fn video_dual_audio_filter_stream() {
|
|||||||
media.unit = Encoder;
|
media.unit = Encoder;
|
||||||
media.add_filter(&config, &None);
|
media.add_filter(&config, &None);
|
||||||
|
|
||||||
let mut output_cmd = config.out.output_cmd.as_ref().unwrap().clone();
|
let enc_cmd = prepare_output_cmd(&config, enc_prefix, &media.filter);
|
||||||
|
|
||||||
enc_cmd.append(&mut output_cmd);
|
|
||||||
|
|
||||||
let enc_cmd = prepare_output_cmd(enc_prefix, &media.filter, &config);
|
|
||||||
|
|
||||||
let test_cmd = vec_strings![
|
let test_cmd = vec_strings![
|
||||||
"-hide_banner",
|
"-hide_banner",
|
||||||
@ -387,9 +684,6 @@ fn video_audio_multi_stream() {
|
|||||||
"rtmp://localhost:1936/live/stream"
|
"rtmp://localhost:1936/live/stream"
|
||||||
]);
|
]);
|
||||||
|
|
||||||
let mut enc_cmd = vec![];
|
|
||||||
let mut output_cmd = config.out.output_cmd.as_ref().unwrap().clone();
|
|
||||||
|
|
||||||
let enc_prefix = vec_strings![
|
let enc_prefix = vec_strings![
|
||||||
"-hide_banner",
|
"-hide_banner",
|
||||||
"-nostats",
|
"-nostats",
|
||||||
@ -400,9 +694,7 @@ fn video_audio_multi_stream() {
|
|||||||
"pipe:0"
|
"pipe:0"
|
||||||
];
|
];
|
||||||
|
|
||||||
enc_cmd.append(&mut output_cmd);
|
let enc_cmd = prepare_output_cmd(&config, enc_prefix, &None);
|
||||||
|
|
||||||
let enc_cmd = prepare_output_cmd(enc_prefix, &None, &config);
|
|
||||||
|
|
||||||
let test_cmd = vec_strings![
|
let test_cmd = vec_strings![
|
||||||
"-hide_banner",
|
"-hide_banner",
|
||||||
@ -494,9 +786,6 @@ fn video_dual_audio_multi_stream() {
|
|||||||
"srt://127.0.0.1:40052"
|
"srt://127.0.0.1:40052"
|
||||||
]);
|
]);
|
||||||
|
|
||||||
let mut enc_cmd = vec![];
|
|
||||||
let mut output_cmd = config.out.output_cmd.as_ref().unwrap().clone();
|
|
||||||
|
|
||||||
let enc_prefix = vec_strings![
|
let enc_prefix = vec_strings![
|
||||||
"-hide_banner",
|
"-hide_banner",
|
||||||
"-nostats",
|
"-nostats",
|
||||||
@ -507,9 +796,7 @@ fn video_dual_audio_multi_stream() {
|
|||||||
"pipe:0"
|
"pipe:0"
|
||||||
];
|
];
|
||||||
|
|
||||||
enc_cmd.append(&mut output_cmd);
|
let enc_cmd = prepare_output_cmd(&config, enc_prefix, &None);
|
||||||
|
|
||||||
let enc_cmd = prepare_output_cmd(enc_prefix, &None, &config);
|
|
||||||
|
|
||||||
let test_cmd = vec_strings![
|
let test_cmd = vec_strings![
|
||||||
"-hide_banner",
|
"-hide_banner",
|
||||||
@ -614,7 +901,6 @@ fn video_dual_audio_multi_filter_stream() {
|
|||||||
"srt://127.0.0.1:40052"
|
"srt://127.0.0.1:40052"
|
||||||
]);
|
]);
|
||||||
|
|
||||||
let mut enc_cmd = vec![];
|
|
||||||
let enc_prefix = vec_strings![
|
let enc_prefix = vec_strings![
|
||||||
"-hide_banner",
|
"-hide_banner",
|
||||||
"-nostats",
|
"-nostats",
|
||||||
@ -636,11 +922,7 @@ fn video_dual_audio_multi_filter_stream() {
|
|||||||
media.unit = Encoder;
|
media.unit = Encoder;
|
||||||
media.add_filter(&config, &None);
|
media.add_filter(&config, &None);
|
||||||
|
|
||||||
let mut output_cmd = config.out.output_cmd.as_ref().unwrap().clone();
|
let enc_cmd = prepare_output_cmd(&config, enc_prefix, &media.filter);
|
||||||
|
|
||||||
enc_cmd.append(&mut output_cmd);
|
|
||||||
|
|
||||||
let enc_cmd = prepare_output_cmd(enc_prefix, &media.filter, &config);
|
|
||||||
|
|
||||||
let test_cmd = vec_strings![
|
let test_cmd = vec_strings![
|
||||||
"-hide_banner",
|
"-hide_banner",
|
||||||
@ -694,8 +976,6 @@ fn video_dual_audio_multi_filter_stream() {
|
|||||||
"srt://127.0.0.1:40052"
|
"srt://127.0.0.1:40052"
|
||||||
];
|
];
|
||||||
|
|
||||||
// println!("{enc_cmd:?}");
|
|
||||||
|
|
||||||
assert_eq!(enc_cmd, test_cmd);
|
assert_eq!(enc_cmd, test_cmd);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -742,7 +1022,7 @@ fn video_audio_hls() {
|
|||||||
"./assets/with_audio.mp4"
|
"./assets/with_audio.mp4"
|
||||||
];
|
];
|
||||||
|
|
||||||
let enc_cmd = prepare_output_cmd(enc_prefix, &media.filter, &config);
|
let enc_cmd = prepare_output_cmd(&config, enc_prefix, &media.filter);
|
||||||
|
|
||||||
let test_cmd = vec_strings![
|
let test_cmd = vec_strings![
|
||||||
"-hide_banner",
|
"-hide_banner",
|
||||||
@ -784,6 +1064,99 @@ fn video_audio_hls() {
|
|||||||
assert_eq!(enc_cmd, test_cmd);
|
assert_eq!(enc_cmd, test_cmd);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn video_audio_sub_meta_hls() {
|
||||||
|
let mut config = PlayoutConfig::new(Some("../assets/ffplayout.yml".to_string()));
|
||||||
|
config.out.mode = HLS;
|
||||||
|
config.processing.add_logo = false;
|
||||||
|
config.text.add_text = false;
|
||||||
|
config.out.output_cmd = Some(vec_strings![
|
||||||
|
"-map",
|
||||||
|
"0:s:0",
|
||||||
|
"-map_metadata",
|
||||||
|
"0",
|
||||||
|
"-c:v",
|
||||||
|
"libx264",
|
||||||
|
"-c:a",
|
||||||
|
"aac",
|
||||||
|
"-ar",
|
||||||
|
"44100",
|
||||||
|
"-b:a",
|
||||||
|
"128k",
|
||||||
|
"-flags",
|
||||||
|
"+cgop",
|
||||||
|
"-f",
|
||||||
|
"hls",
|
||||||
|
"-hls_time",
|
||||||
|
"6",
|
||||||
|
"-hls_list_size",
|
||||||
|
"600",
|
||||||
|
"-hls_flags",
|
||||||
|
"append_list+delete_segments+omit_endlist",
|
||||||
|
"-hls_segment_filename",
|
||||||
|
"/usr/share/ffplayout/public/live/stream-%d.ts",
|
||||||
|
"/usr/share/ffplayout/public/live/stream.m3u8"
|
||||||
|
]);
|
||||||
|
|
||||||
|
let media_obj = Media::new(0, "./assets/with_audio.mp4", true);
|
||||||
|
let media = gen_source(&config, media_obj, &None);
|
||||||
|
|
||||||
|
let enc_prefix = vec_strings![
|
||||||
|
"-hide_banner",
|
||||||
|
"-nostats",
|
||||||
|
"-v",
|
||||||
|
"level+error",
|
||||||
|
"-re",
|
||||||
|
"-i",
|
||||||
|
"./assets/with_audio.mp4"
|
||||||
|
];
|
||||||
|
|
||||||
|
let enc_cmd = prepare_output_cmd(&config, enc_prefix, &media.filter);
|
||||||
|
|
||||||
|
let test_cmd = vec_strings![
|
||||||
|
"-hide_banner",
|
||||||
|
"-nostats",
|
||||||
|
"-v",
|
||||||
|
"level+error",
|
||||||
|
"-re",
|
||||||
|
"-i",
|
||||||
|
"./assets/with_audio.mp4",
|
||||||
|
"-filter_complex",
|
||||||
|
"[0:v:0]scale=1024:576,realtime=speed=1[vout0];[0:a:0]anull[aout0]",
|
||||||
|
"-map",
|
||||||
|
"[vout0]",
|
||||||
|
"-map",
|
||||||
|
"[aout0]",
|
||||||
|
"-map",
|
||||||
|
"0:s:0",
|
||||||
|
"-map_metadata",
|
||||||
|
"0",
|
||||||
|
"-c:v",
|
||||||
|
"libx264",
|
||||||
|
"-c:a",
|
||||||
|
"aac",
|
||||||
|
"-ar",
|
||||||
|
"44100",
|
||||||
|
"-b:a",
|
||||||
|
"128k",
|
||||||
|
"-flags",
|
||||||
|
"+cgop",
|
||||||
|
"-f",
|
||||||
|
"hls",
|
||||||
|
"-hls_time",
|
||||||
|
"6",
|
||||||
|
"-hls_list_size",
|
||||||
|
"600",
|
||||||
|
"-hls_flags",
|
||||||
|
"append_list+delete_segments+omit_endlist",
|
||||||
|
"-hls_segment_filename",
|
||||||
|
"/usr/share/ffplayout/public/live/stream-%d.ts",
|
||||||
|
"/usr/share/ffplayout/public/live/stream.m3u8"
|
||||||
|
];
|
||||||
|
|
||||||
|
assert_eq!(enc_cmd, test_cmd);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn video_multi_audio_hls() {
|
fn video_multi_audio_hls() {
|
||||||
let mut config = PlayoutConfig::new(Some("../assets/ffplayout.yml".to_string()));
|
let mut config = PlayoutConfig::new(Some("../assets/ffplayout.yml".to_string()));
|
||||||
@ -828,7 +1201,7 @@ fn video_multi_audio_hls() {
|
|||||||
"./assets/dual_audio.mp4"
|
"./assets/dual_audio.mp4"
|
||||||
];
|
];
|
||||||
|
|
||||||
let enc_cmd = prepare_output_cmd(enc_prefix, &media.filter, &config);
|
let enc_cmd = prepare_output_cmd(&config, enc_prefix, &media.filter);
|
||||||
|
|
||||||
let test_cmd = vec_strings![
|
let test_cmd = vec_strings![
|
||||||
"-hide_banner",
|
"-hide_banner",
|
||||||
@ -931,7 +1304,7 @@ fn multi_video_audio_hls() {
|
|||||||
"./assets/with_audio.mp4"
|
"./assets/with_audio.mp4"
|
||||||
];
|
];
|
||||||
|
|
||||||
let enc_cmd = prepare_output_cmd(enc_prefix, &media.filter, &config);
|
let enc_cmd = prepare_output_cmd(&config, enc_prefix, &media.filter);
|
||||||
|
|
||||||
let test_cmd = vec_strings![
|
let test_cmd = vec_strings![
|
||||||
"-hide_banner",
|
"-hide_banner",
|
||||||
@ -1047,7 +1420,7 @@ fn multi_video_multi_audio_hls() {
|
|||||||
"./assets/dual_audio.mp4"
|
"./assets/dual_audio.mp4"
|
||||||
];
|
];
|
||||||
|
|
||||||
let enc_cmd = prepare_output_cmd(enc_prefix, &media.filter, &config);
|
let enc_cmd = prepare_output_cmd(&config, enc_prefix, &media.filter);
|
||||||
|
|
||||||
let test_cmd = vec_strings![
|
let test_cmd = vec_strings![
|
||||||
"-hide_banner",
|
"-hide_banner",
|
||||||
|
Loading…
x
Reference in New Issue
Block a user