move function prepare_output_cmd, add test video_audio_output
This commit is contained in:
parent
87c508be54
commit
b7a3e356d1
@ -28,10 +28,11 @@ use std::{
|
|||||||
use simplelog::*;
|
use simplelog::*;
|
||||||
|
|
||||||
use crate::input::{ingest::log_line, source_generator};
|
use crate::input::{ingest::log_line, source_generator};
|
||||||
|
use crate::utils::prepare_output_cmd;
|
||||||
use ffplayout_lib::filter::filter_chains;
|
use ffplayout_lib::filter::filter_chains;
|
||||||
use ffplayout_lib::utils::{
|
use ffplayout_lib::utils::{
|
||||||
prepare_output_cmd, sec_to_time, stderr_reader, test_tcp_port, Encoder, Ingest, Media,
|
sec_to_time, stderr_reader, test_tcp_port, Encoder, Ingest, Media, PlayerControl,
|
||||||
PlayerControl, PlayoutConfig, PlayoutStatus, ProcessControl,
|
PlayoutConfig, PlayoutStatus, ProcessControl,
|
||||||
};
|
};
|
||||||
use ffplayout_lib::vec_strings;
|
use ffplayout_lib::vec_strings;
|
||||||
|
|
||||||
|
@ -5,8 +5,9 @@ use std::{
|
|||||||
|
|
||||||
use simplelog::*;
|
use simplelog::*;
|
||||||
|
|
||||||
|
use crate::utils::prepare_output_cmd;
|
||||||
use ffplayout_lib::filter::v_drawtext;
|
use ffplayout_lib::filter::v_drawtext;
|
||||||
use ffplayout_lib::utils::{prepare_output_cmd, PlayoutConfig};
|
use ffplayout_lib::utils::PlayoutConfig;
|
||||||
use ffplayout_lib::vec_strings;
|
use ffplayout_lib::vec_strings;
|
||||||
|
|
||||||
/// Streaming Output
|
/// Streaming Output
|
||||||
|
@ -6,8 +6,12 @@ use std::{
|
|||||||
pub mod arg_parse;
|
pub mod arg_parse;
|
||||||
|
|
||||||
pub use arg_parse::Args;
|
pub use arg_parse::Args;
|
||||||
use ffplayout_lib::utils::{time_to_sec, PlayoutConfig};
|
use ffplayout_lib::{
|
||||||
|
utils::{time_to_sec, PlayoutConfig},
|
||||||
|
vec_strings,
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Read command line arguments, and override the config with them.
|
||||||
pub fn get_config(args: Args) -> PlayoutConfig {
|
pub fn get_config(args: Args) -> PlayoutConfig {
|
||||||
let cfg_path = match args.channel {
|
let cfg_path = match args.channel {
|
||||||
Some(c) => {
|
Some(c) => {
|
||||||
@ -80,4 +84,79 @@ pub fn get_config(args: Args) -> PlayoutConfig {
|
|||||||
|
|
||||||
config
|
config
|
||||||
}
|
}
|
||||||
// Read command line arguments, and override the config with them.
|
|
||||||
|
/// Prepare output parameters
|
||||||
|
///
|
||||||
|
/// seek for multiple outputs and add mapping for it
|
||||||
|
pub fn prepare_output_cmd(
|
||||||
|
prefix: Vec<String>,
|
||||||
|
mut filter: Vec<String>,
|
||||||
|
params: Vec<String>,
|
||||||
|
mode: &str,
|
||||||
|
) -> Vec<String> {
|
||||||
|
let params_len = params.len();
|
||||||
|
let mut output_params = params.clone();
|
||||||
|
let mut output_a_map = "[a_out1]".to_string();
|
||||||
|
let mut output_v_map = "[v_out1]".to_string();
|
||||||
|
let mut output_count = 1;
|
||||||
|
let mut cmd = prefix;
|
||||||
|
|
||||||
|
if !filter.is_empty() {
|
||||||
|
output_params.clear();
|
||||||
|
|
||||||
|
for (i, p) in params.iter().enumerate() {
|
||||||
|
let mut param = p.clone();
|
||||||
|
|
||||||
|
param = param.replace("[0:v]", "[vout0]");
|
||||||
|
param = param.replace("[0:a]", "[aout0]");
|
||||||
|
|
||||||
|
if param != "-filter_complex" {
|
||||||
|
output_params.push(param.clone());
|
||||||
|
}
|
||||||
|
|
||||||
|
if i > 0
|
||||||
|
&& !param.starts_with('-')
|
||||||
|
&& !params[i - 1].starts_with('-')
|
||||||
|
&& i < params_len - 1
|
||||||
|
{
|
||||||
|
output_count += 1;
|
||||||
|
let mut a_map = "0:a".to_string();
|
||||||
|
let v_map = format!("[v_out{output_count}]");
|
||||||
|
output_v_map.push_str(&v_map);
|
||||||
|
|
||||||
|
if mode == "hls" {
|
||||||
|
a_map = format!("[a_out{output_count}]");
|
||||||
|
}
|
||||||
|
|
||||||
|
output_a_map.push_str(&a_map);
|
||||||
|
|
||||||
|
let mut map = vec_strings!["-map", v_map, "-map", a_map];
|
||||||
|
|
||||||
|
output_params.append(&mut map);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if output_count > 1 && mode == "hls" {
|
||||||
|
filter[1].push_str(&format!(";[vout0]split={output_count}{output_v_map}"));
|
||||||
|
filter[1].push_str(&format!(";[aout0]asplit={output_count}{output_a_map}"));
|
||||||
|
filter.drain(2..);
|
||||||
|
cmd.append(&mut filter);
|
||||||
|
cmd.append(&mut vec_strings!["-map", "[v_out1]", "-map", "[a_out1]"]);
|
||||||
|
} else if output_count == 1 && mode == "hls" && output_params[0].contains("split") {
|
||||||
|
let out_filter = output_params.remove(0);
|
||||||
|
filter[1].push_str(&format!(";{out_filter}"));
|
||||||
|
filter.drain(2..);
|
||||||
|
cmd.append(&mut filter);
|
||||||
|
} else if output_count > 1 && mode == "stream" {
|
||||||
|
filter[1].push_str(&format!(",split={output_count}{output_v_map}"));
|
||||||
|
cmd.append(&mut filter);
|
||||||
|
cmd.append(&mut vec_strings!["-map", "[v_out1]", "-map", "0:a"]);
|
||||||
|
} else {
|
||||||
|
cmd.append(&mut filter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd.append(&mut output_params);
|
||||||
|
|
||||||
|
cmd
|
||||||
|
}
|
||||||
|
@ -570,82 +570,6 @@ pub fn gen_dummy(config: &PlayoutConfig, duration: f64) -> (String, Vec<String>)
|
|||||||
// count
|
// count
|
||||||
// }
|
// }
|
||||||
|
|
||||||
/// Prepare output parameters
|
|
||||||
///
|
|
||||||
/// seek for multiple outputs and add mapping for it
|
|
||||||
pub fn prepare_output_cmd(
|
|
||||||
prefix: Vec<String>,
|
|
||||||
mut filter: Vec<String>,
|
|
||||||
params: Vec<String>,
|
|
||||||
mode: &str,
|
|
||||||
) -> Vec<String> {
|
|
||||||
let params_len = params.len();
|
|
||||||
let mut output_params = params.clone();
|
|
||||||
let mut output_a_map = "[a_out1]".to_string();
|
|
||||||
let mut output_v_map = "[v_out1]".to_string();
|
|
||||||
let mut output_count = 1;
|
|
||||||
let mut cmd = prefix;
|
|
||||||
|
|
||||||
if !filter.is_empty() {
|
|
||||||
output_params.clear();
|
|
||||||
|
|
||||||
for (i, p) in params.iter().enumerate() {
|
|
||||||
let mut param = p.clone();
|
|
||||||
|
|
||||||
param = param.replace("[0:v]", "[vout0]");
|
|
||||||
param = param.replace("[0:a]", "[aout0]");
|
|
||||||
|
|
||||||
if param != "-filter_complex" {
|
|
||||||
output_params.push(param.clone());
|
|
||||||
}
|
|
||||||
|
|
||||||
if i > 0
|
|
||||||
&& !param.starts_with('-')
|
|
||||||
&& !params[i - 1].starts_with('-')
|
|
||||||
&& i < params_len - 1
|
|
||||||
{
|
|
||||||
output_count += 1;
|
|
||||||
let mut a_map = "0:a".to_string();
|
|
||||||
let v_map = format!("[v_out{output_count}]");
|
|
||||||
output_v_map.push_str(&v_map);
|
|
||||||
|
|
||||||
if mode == "hls" {
|
|
||||||
a_map = format!("[a_out{output_count}]");
|
|
||||||
}
|
|
||||||
|
|
||||||
output_a_map.push_str(&a_map);
|
|
||||||
|
|
||||||
let mut map = vec_strings!["-map", v_map, "-map", a_map];
|
|
||||||
|
|
||||||
output_params.append(&mut map);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if output_count > 1 && mode == "hls" {
|
|
||||||
filter[1].push_str(&format!(";[vout0]split={output_count}{output_v_map}"));
|
|
||||||
filter[1].push_str(&format!(";[aout0]asplit={output_count}{output_a_map}"));
|
|
||||||
filter.drain(2..);
|
|
||||||
cmd.append(&mut filter);
|
|
||||||
cmd.append(&mut vec_strings!["-map", "[v_out1]", "-map", "[a_out1]"]);
|
|
||||||
} else if output_count == 1 && mode == "hls" && output_params[0].contains("split") {
|
|
||||||
let out_filter = output_params.remove(0);
|
|
||||||
filter[1].push_str(&format!(";{out_filter}"));
|
|
||||||
filter.drain(2..);
|
|
||||||
cmd.append(&mut filter);
|
|
||||||
} else if output_count > 1 && mode == "stream" {
|
|
||||||
filter[1].push_str(&format!(",split={output_count}{output_v_map}"));
|
|
||||||
cmd.append(&mut filter);
|
|
||||||
cmd.append(&mut vec_strings!["-map", "[v_out1]", "-map", "0:a"]);
|
|
||||||
} else {
|
|
||||||
cmd.append(&mut filter);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
cmd.append(&mut output_params);
|
|
||||||
|
|
||||||
cmd
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn is_remote(path: &str) -> bool {
|
pub fn is_remote(path: &str) -> bool {
|
||||||
Regex::new(r"^https?://.*").unwrap().is_match(path)
|
Regex::new(r"^https?://.*").unwrap().is_match(path)
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
use ffplayout::input::playlist::gen_source;
|
use ffplayout::{input::playlist::gen_source, utils::prepare_output_cmd};
|
||||||
use ffplayout_lib::{
|
use ffplayout_lib::{
|
||||||
utils::{Media, PlayoutConfig},
|
utils::{Media, PlayoutConfig},
|
||||||
vec_strings,
|
vec_strings,
|
||||||
@ -80,3 +80,131 @@ fn dual_audio_input() {
|
|||||||
assert_eq!(media.cmd, Some(vec_strings!["-i", "assets/dual_audio.mp4"]));
|
assert_eq!(media.cmd, Some(vec_strings!["-i", "assets/dual_audio.mp4"]));
|
||||||
assert_eq!(media.filter, test_filter_cmd);
|
assert_eq!(media.filter, test_filter_cmd);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_prepare_output_cmd() {
|
||||||
|
let enc_prefix = vec_strings![
|
||||||
|
"-hide_banner",
|
||||||
|
"-nostats",
|
||||||
|
"-v",
|
||||||
|
"level+error",
|
||||||
|
"-re",
|
||||||
|
"-i",
|
||||||
|
"pipe:0"
|
||||||
|
];
|
||||||
|
let filter = vec_strings![
|
||||||
|
"-filter_complex",
|
||||||
|
"[0:v]null,zmq=b=tcp\\\\://'127.0.0.1\\:5555',drawtext=text=''"
|
||||||
|
];
|
||||||
|
let params = vec_strings![
|
||||||
|
"-c:v",
|
||||||
|
"libx264",
|
||||||
|
"-flags",
|
||||||
|
"+global_header",
|
||||||
|
"-f",
|
||||||
|
"flv",
|
||||||
|
"rtmp://localhost/live/stream",
|
||||||
|
"-s",
|
||||||
|
"512x288",
|
||||||
|
"-c:v",
|
||||||
|
"libx264",
|
||||||
|
"-flags",
|
||||||
|
"+global_header",
|
||||||
|
"-f",
|
||||||
|
"flv",
|
||||||
|
"rtmp://localhost:1937/live/stream"
|
||||||
|
];
|
||||||
|
|
||||||
|
let mut t1_params = enc_prefix.clone();
|
||||||
|
t1_params.append(&mut params.clone());
|
||||||
|
let cmd_two_outs =
|
||||||
|
prepare_output_cmd(enc_prefix.clone(), vec_strings![], params.clone(), "stream");
|
||||||
|
|
||||||
|
assert_eq!(cmd_two_outs, t1_params);
|
||||||
|
|
||||||
|
let mut test_cmd = enc_prefix.clone();
|
||||||
|
let mut test_params = params.clone();
|
||||||
|
let mut t2_filter = filter.clone();
|
||||||
|
t2_filter[1].push_str(",split=2[v_out1][v_out2]");
|
||||||
|
test_cmd.append(&mut t2_filter);
|
||||||
|
|
||||||
|
test_params.insert(0, "-map".to_string());
|
||||||
|
test_params.insert(1, "[v_out1]".to_string());
|
||||||
|
test_params.insert(2, "-map".to_string());
|
||||||
|
test_params.insert(3, "0:a".to_string());
|
||||||
|
|
||||||
|
test_params.insert(11, "-map".to_string());
|
||||||
|
test_params.insert(12, "[v_out2]".to_string());
|
||||||
|
test_params.insert(13, "-map".to_string());
|
||||||
|
test_params.insert(14, "0:a".to_string());
|
||||||
|
|
||||||
|
test_cmd.append(&mut test_params);
|
||||||
|
let cmd_two_outs_with_filter = prepare_output_cmd(enc_prefix, filter, params, "stream");
|
||||||
|
|
||||||
|
assert_eq!(cmd_two_outs_with_filter, test_cmd);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn video_audio_output() {
|
||||||
|
let mut config = PlayoutConfig::new(Some("../assets/ffplayout.yml".to_string()));
|
||||||
|
config.out.mode = "stream".to_string();
|
||||||
|
config.processing.add_logo = false;
|
||||||
|
config.out.output_cmd = Some(vec_strings![
|
||||||
|
"-c:v",
|
||||||
|
"libx264",
|
||||||
|
"-c:a",
|
||||||
|
"aac",
|
||||||
|
"-ar",
|
||||||
|
"44100",
|
||||||
|
"-b:a",
|
||||||
|
"128k",
|
||||||
|
"-flags",
|
||||||
|
"+global_header",
|
||||||
|
"-f",
|
||||||
|
"flv",
|
||||||
|
"rtmp://localhost/live/stream"
|
||||||
|
]);
|
||||||
|
|
||||||
|
let mut enc_cmd = vec![];
|
||||||
|
let enc_filter = vec![];
|
||||||
|
let mut output_cmd = config.out.output_cmd.as_ref().unwrap().clone();
|
||||||
|
|
||||||
|
let enc_prefix = vec_strings![
|
||||||
|
"-hide_banner",
|
||||||
|
"-nostats",
|
||||||
|
"-v",
|
||||||
|
"level+error",
|
||||||
|
"-re",
|
||||||
|
"-i",
|
||||||
|
"pipe:0"
|
||||||
|
];
|
||||||
|
|
||||||
|
enc_cmd.append(&mut output_cmd);
|
||||||
|
|
||||||
|
let enc_cmd = prepare_output_cmd(enc_prefix, enc_filter, enc_cmd, &config.out.mode);
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
@ -50,66 +50,3 @@ fn test_delta() {
|
|||||||
|
|
||||||
assert!(delta < 2.0);
|
assert!(delta < 2.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_prepare_output_cmd() {
|
|
||||||
let enc_prefix = vec_strings![
|
|
||||||
"-hide_banner",
|
|
||||||
"-nostats",
|
|
||||||
"-v",
|
|
||||||
"level+error",
|
|
||||||
"-re",
|
|
||||||
"-i",
|
|
||||||
"pipe:0"
|
|
||||||
];
|
|
||||||
let filter = vec_strings![
|
|
||||||
"-filter_complex",
|
|
||||||
"[0:v]null,zmq=b=tcp\\\\://'127.0.0.1\\:5555',drawtext=text=''"
|
|
||||||
];
|
|
||||||
let params = vec_strings![
|
|
||||||
"-c:v",
|
|
||||||
"libx264",
|
|
||||||
"-flags",
|
|
||||||
"+global_header",
|
|
||||||
"-f",
|
|
||||||
"flv",
|
|
||||||
"rtmp://localhost/live/stream",
|
|
||||||
"-s",
|
|
||||||
"512x288",
|
|
||||||
"-c:v",
|
|
||||||
"libx264",
|
|
||||||
"-flags",
|
|
||||||
"+global_header",
|
|
||||||
"-f",
|
|
||||||
"flv",
|
|
||||||
"rtmp://localhost:1937/live/stream"
|
|
||||||
];
|
|
||||||
|
|
||||||
let mut t1_params = enc_prefix.clone();
|
|
||||||
t1_params.append(&mut params.clone());
|
|
||||||
let cmd_two_outs =
|
|
||||||
prepare_output_cmd(enc_prefix.clone(), vec_strings![], params.clone(), "stream");
|
|
||||||
|
|
||||||
assert_eq!(cmd_two_outs, t1_params);
|
|
||||||
|
|
||||||
let mut test_cmd = enc_prefix.clone();
|
|
||||||
let mut test_params = params.clone();
|
|
||||||
let mut t2_filter = filter.clone();
|
|
||||||
t2_filter[1].push_str(",split=2[v_out1][v_out2]");
|
|
||||||
test_cmd.append(&mut t2_filter);
|
|
||||||
|
|
||||||
test_params.insert(0, "-map".to_string());
|
|
||||||
test_params.insert(1, "[v_out1]".to_string());
|
|
||||||
test_params.insert(2, "-map".to_string());
|
|
||||||
test_params.insert(3, "0:a".to_string());
|
|
||||||
|
|
||||||
test_params.insert(11, "-map".to_string());
|
|
||||||
test_params.insert(12, "[v_out2]".to_string());
|
|
||||||
test_params.insert(13, "-map".to_string());
|
|
||||||
test_params.insert(14, "0:a".to_string());
|
|
||||||
|
|
||||||
test_cmd.append(&mut test_params);
|
|
||||||
let cmd_two_outs_with_filter = prepare_output_cmd(enc_prefix, filter, params, "stream");
|
|
||||||
|
|
||||||
assert_eq!(cmd_two_outs_with_filter, test_cmd);
|
|
||||||
}
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user