add tests
This commit is contained in:
parent
bbb0e1371b
commit
87c508be54
26
Cargo.lock
generated
26
Cargo.lock
generated
@ -2743,6 +2743,32 @@ dependencies = [
|
||||
"winapi-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tests"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"crossbeam-channel",
|
||||
"ffplayout",
|
||||
"ffplayout-lib",
|
||||
"ffprobe",
|
||||
"file-rotate",
|
||||
"jsonrpc-http-server",
|
||||
"lettre",
|
||||
"log",
|
||||
"notify",
|
||||
"rand",
|
||||
"regex",
|
||||
"reqwest",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"serde_yaml",
|
||||
"shlex",
|
||||
"simplelog",
|
||||
"time 0.3.14",
|
||||
"walkdir",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "textwrap"
|
||||
version = "0.15.1"
|
||||
|
@ -1,6 +1,6 @@
|
||||
[workspace]
|
||||
members = ["ffplayout-api", "ffplayout-engine", "lib"]
|
||||
default-members = ["ffplayout-api", "ffplayout-engine"]
|
||||
members = ["ffplayout-api", "ffplayout-engine", "lib", "tests"]
|
||||
default-members = ["ffplayout-api", "ffplayout-engine", "tests"]
|
||||
|
||||
[profile.release]
|
||||
opt-level = 3
|
||||
|
@ -42,7 +42,7 @@ pub fn watchman(
|
||||
match res {
|
||||
Create(new_path) => {
|
||||
let index = sources.lock().unwrap().len();
|
||||
let media = Media::new(index, new_path.display().to_string(), false);
|
||||
let media = Media::new(index, &new_path.to_string_lossy(), false);
|
||||
|
||||
if include_file(config.clone(), &new_path) {
|
||||
sources.lock().unwrap().push(media);
|
||||
@ -66,7 +66,7 @@ pub fn watchman(
|
||||
.position(|x| *x.source == old_path.display().to_string())
|
||||
.unwrap();
|
||||
|
||||
let media = Media::new(index, new_path.display().to_string(), false);
|
||||
let media = Media::new(index, &new_path.to_string_lossy(), false);
|
||||
sources.lock().unwrap()[index] = media;
|
||||
|
||||
info!("Rename file: <b><magenta>{old_path:?}</></b> to <b><magenta>{new_path:?}</></b>");
|
||||
|
@ -84,7 +84,7 @@ pub fn ingest_server(
|
||||
let mut buffer: [u8; 65088] = [0; 65088];
|
||||
let mut server_cmd = vec_strings!["-hide_banner", "-nostats", "-v", "level+info"];
|
||||
let stream_input = config.ingest.input_cmd.clone().unwrap();
|
||||
let mut dummy_media = Media::new(0, "Live Stream".to_string(), false);
|
||||
let mut dummy_media = Media::new(0, "Live Stream", false);
|
||||
dummy_media.is_live = Some(true);
|
||||
let mut filters = filter_chains(&config, &mut dummy_media, &Arc::new(Mutex::new(vec![])));
|
||||
|
||||
|
@ -69,7 +69,7 @@ impl CurrentProgram {
|
||||
json_path: json.current_file,
|
||||
json_date: json.date,
|
||||
nodes: current_list,
|
||||
current_node: Media::new(0, String::new(), false),
|
||||
current_node: Media::new(0, "", false),
|
||||
index: global_index,
|
||||
is_terminated,
|
||||
playout_stat,
|
||||
@ -118,7 +118,7 @@ impl CurrentProgram {
|
||||
"Playlist <b><magenta>{}</></b> not exists!",
|
||||
self.json_path.clone().unwrap()
|
||||
);
|
||||
let mut media = Media::new(0, String::new(), false);
|
||||
let mut media = Media::new(0, "", false);
|
||||
media.begin = Some(get_sec());
|
||||
media.duration = DUMMY_LEN;
|
||||
media.out = DUMMY_LEN;
|
||||
@ -304,7 +304,7 @@ impl Iterator for CurrentProgram {
|
||||
current_time += self.config.playlist.length_sec.unwrap() + 1.0;
|
||||
}
|
||||
|
||||
let mut media = Media::new(0, String::new(), false);
|
||||
let mut media = Media::new(0, "", false);
|
||||
media.begin = Some(current_time);
|
||||
media.duration = duration;
|
||||
media.out = duration;
|
||||
@ -357,7 +357,7 @@ impl Iterator for CurrentProgram {
|
||||
// Test if playlist is to early finish,
|
||||
// and if we have to fill it with a placeholder.
|
||||
let index = self.index.load(Ordering::SeqCst);
|
||||
self.current_node = Media::new(index, String::new(), false);
|
||||
self.current_node = Media::new(index, "", false);
|
||||
self.current_node.begin = Some(get_sec());
|
||||
let mut duration = total_delta.abs();
|
||||
|
||||
@ -454,7 +454,7 @@ fn timed_source(
|
||||
}
|
||||
|
||||
/// Generate the source CMD, or when clip not exist, get a dummy.
|
||||
fn gen_source(
|
||||
pub fn gen_source(
|
||||
config: &PlayoutConfig,
|
||||
mut node: Media,
|
||||
filter_chain: &Arc<Mutex<Vec<String>>>,
|
||||
|
4
ffplayout-engine/src/lib.rs
Normal file
4
ffplayout-engine/src/lib.rs
Normal file
@ -0,0 +1,4 @@
|
||||
pub mod input;
|
||||
pub mod output;
|
||||
pub mod rpc;
|
||||
pub mod utils;
|
@ -12,18 +12,10 @@ use serde::{Deserialize, Serialize};
|
||||
use serde_json::json;
|
||||
use simplelog::*;
|
||||
|
||||
pub mod input;
|
||||
pub mod output;
|
||||
pub mod rpc;
|
||||
// #[cfg(test)]
|
||||
// mod tests;
|
||||
pub mod utils;
|
||||
|
||||
use utils::{arg_parse::get_args, get_config};
|
||||
|
||||
use crate::{
|
||||
use ffplayout::{
|
||||
output::{player, write_hls},
|
||||
rpc::json_rpc_server,
|
||||
utils::{arg_parse::get_args, get_config},
|
||||
};
|
||||
|
||||
use ffplayout_lib::utils::{
|
||||
@ -32,7 +24,7 @@ use ffplayout_lib::utils::{
|
||||
};
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
use utils::Args;
|
||||
use ffplayout::utils::Args;
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
use ffplayout_lib::utils::{mock_time, time_now};
|
||||
|
@ -47,7 +47,7 @@ fn ingest_to_hls_server(
|
||||
let mut server_prefix = vec_strings!["-hide_banner", "-nostats", "-v", "level+info"];
|
||||
let stream_input = config.ingest.input_cmd.clone().unwrap();
|
||||
server_prefix.append(&mut stream_input.clone());
|
||||
let mut dummy_media = Media::new(0, "Live Stream".to_string(), false);
|
||||
let mut dummy_media = Media::new(0, "Live Stream", false);
|
||||
dummy_media.is_live = Some(true);
|
||||
|
||||
let mut is_running;
|
||||
|
@ -28,10 +28,7 @@ pub fn filter_node(
|
||||
|
||||
// TODO: in Rust 1.65 use let_chains instead
|
||||
if config.text.text_from_filename && node.is_some() {
|
||||
let source = node
|
||||
.unwrap_or(&Media::new(0, String::new(), false))
|
||||
.source
|
||||
.clone();
|
||||
let source = node.unwrap_or(&Media::new(0, "", false)).source.clone();
|
||||
let regex: Regex = Regex::new(&config.text.regex).unwrap();
|
||||
|
||||
let text: String = match regex.captures(&source) {
|
||||
|
@ -4,6 +4,3 @@ extern crate simplelog;
|
||||
pub mod filter;
|
||||
pub mod macros;
|
||||
pub mod utils;
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
@ -167,7 +167,7 @@ impl PlayerControl {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
current_media: Arc::new(Mutex::new(None)),
|
||||
current_list: Arc::new(Mutex::new(vec![Media::new(0, String::new(), false)])),
|
||||
current_list: Arc::new(Mutex::new(vec![Media::new(0, "", false)])),
|
||||
index: Arc::new(AtomicUsize::new(0)),
|
||||
}
|
||||
}
|
||||
|
@ -49,7 +49,7 @@ impl FolderSource {
|
||||
.filter(|f| f.path().is_file())
|
||||
{
|
||||
if include_file(config.clone(), entry.path()) {
|
||||
let media = Media::new(0, entry.path().display().to_string(), false);
|
||||
let media = Media::new(0, &entry.path().to_string_lossy(), false);
|
||||
media_list.push(media);
|
||||
}
|
||||
}
|
||||
@ -83,7 +83,7 @@ impl FolderSource {
|
||||
config: config.clone(),
|
||||
filter_chain,
|
||||
nodes: current_list,
|
||||
current_node: Media::new(0, String::new(), false),
|
||||
current_node: Media::new(0, "", false),
|
||||
index: global_index,
|
||||
}
|
||||
}
|
||||
|
@ -65,7 +65,7 @@ pub fn generate_playlist(
|
||||
}
|
||||
}
|
||||
};
|
||||
let current_list = Arc::new(Mutex::new(vec![Media::new(0, "".to_string(), false)]));
|
||||
let current_list = Arc::new(Mutex::new(vec![Media::new(0, "", false)]));
|
||||
let index = Arc::new(AtomicUsize::new(0));
|
||||
let playlist_root = Path::new(&config.playlist.path);
|
||||
let mut playlists = vec![];
|
||||
@ -119,7 +119,7 @@ pub fn generate_playlist(
|
||||
playlist_file.display()
|
||||
);
|
||||
|
||||
let mut filler = Media::new(0, config.storage.filler_clip.clone(), true);
|
||||
let mut filler = Media::new(0, &config.storage.filler_clip, true);
|
||||
let filler_length = filler.duration;
|
||||
let mut length = 0.0;
|
||||
let mut round = 0;
|
||||
|
@ -48,7 +48,7 @@ pub fn import_file(
|
||||
let line = line?;
|
||||
|
||||
if !line.starts_with('#') {
|
||||
let item = Media::new(0, line, true);
|
||||
let item = Media::new(0, &line, true);
|
||||
|
||||
playlist.program.push(item);
|
||||
}
|
||||
|
@ -34,7 +34,7 @@ pub struct JsonPlaylist {
|
||||
|
||||
impl JsonPlaylist {
|
||||
fn new(date: String, start: f64) -> Self {
|
||||
let mut media = Media::new(0, String::new(), false);
|
||||
let mut media = Media::new(0, "", false);
|
||||
media.begin = Some(start);
|
||||
media.duration = DUMMY_LEN;
|
||||
media.out = DUMMY_LEN;
|
||||
|
@ -100,12 +100,12 @@ pub struct Media {
|
||||
}
|
||||
|
||||
impl Media {
|
||||
pub fn new(index: usize, src: String, do_probe: bool) -> Self {
|
||||
pub fn new(index: usize, src: &str, do_probe: bool) -> Self {
|
||||
let mut duration = 0.0;
|
||||
let mut probe = None;
|
||||
|
||||
if do_probe && Path::new(&src).is_file() {
|
||||
probe = Some(MediaProbe::new(&src));
|
||||
if do_probe && Path::new(src).is_file() {
|
||||
probe = Some(MediaProbe::new(src));
|
||||
|
||||
if let Some(dur) = probe
|
||||
.as_ref()
|
||||
@ -123,9 +123,9 @@ impl Media {
|
||||
out: duration,
|
||||
duration,
|
||||
category: String::new(),
|
||||
source: src.clone(),
|
||||
source: src.to_string(),
|
||||
audio: String::new(),
|
||||
cmd: Some(vec!["-i".to_string(), src]),
|
||||
cmd: Some(vec_strings!["-i", src]),
|
||||
filter: Some(vec![]),
|
||||
custom_filter: String::new(),
|
||||
probe,
|
||||
|
42
tests/Cargo.toml
Normal file
42
tests/Cargo.toml
Normal file
@ -0,0 +1,42 @@
|
||||
[package]
|
||||
name = "tests"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
publish = false
|
||||
|
||||
[dev-dependencies]
|
||||
ffplayout = { path = "../ffplayout-engine" }
|
||||
# ffplayout-api = { path = "../ffplayout-api" }
|
||||
ffplayout-lib = { path = "../lib" }
|
||||
|
||||
chrono = "0.4"
|
||||
crossbeam-channel = "0.5"
|
||||
ffprobe = "0.3"
|
||||
file-rotate = "0.7.0"
|
||||
jsonrpc-http-server = "18.0"
|
||||
lettre = "0.10"
|
||||
log = "0.4"
|
||||
notify = "4.0"
|
||||
rand = "0.8"
|
||||
regex = "1"
|
||||
reqwest = { version = "0.11", features = ["blocking", "json"] }
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
serde_json = "1.0"
|
||||
serde_yaml = "0.8"
|
||||
shlex = "1.1"
|
||||
simplelog = { version = "^0.12", features = ["paris"] }
|
||||
time = { version = "0.3", features = ["formatting", "macros"] }
|
||||
walkdir = "2"
|
||||
|
||||
[[test]]
|
||||
name = "lib_utils"
|
||||
path = "src/lib_utils.rs"
|
||||
|
||||
[[test]]
|
||||
name = "engine_playlist"
|
||||
path = "src/engine_playlist.rs"
|
||||
|
||||
[[test]]
|
||||
name = "engine_cmd"
|
||||
path = "src/engine_cmd.rs"
|
||||
|
BIN
tests/assets/ad.mp4
Normal file
BIN
tests/assets/ad.mp4
Normal file
Binary file not shown.
BIN
tests/assets/audio.mp3
Normal file
BIN
tests/assets/audio.mp3
Normal file
Binary file not shown.
BIN
tests/assets/av_sync.mp4
Normal file
BIN
tests/assets/av_sync.mp4
Normal file
Binary file not shown.
BIN
tests/assets/dual_audio.mp4
Normal file
BIN
tests/assets/dual_audio.mp4
Normal file
Binary file not shown.
BIN
tests/assets/no_audio.mp4
Normal file
BIN
tests/assets/no_audio.mp4
Normal file
Binary file not shown.
22526
tests/assets/playlist_full.json
Executable file
22526
tests/assets/playlist_full.json
Executable file
File diff suppressed because it is too large
Load Diff
56
tests/assets/playlist_short.json
Normal file
56
tests/assets/playlist_short.json
Normal file
@ -0,0 +1,56 @@
|
||||
{
|
||||
"channel": "Channel 1",
|
||||
"date": "2022-11-01",
|
||||
"program": [
|
||||
{
|
||||
"in": 0.0,
|
||||
"out": 30.0,
|
||||
"duration": 30.0,
|
||||
"source": "tests/assets/av_sync.mp4"
|
||||
},
|
||||
{
|
||||
"in": 0.0,
|
||||
"out": 30.0,
|
||||
"duration": 30.0,
|
||||
"source": "tests/assets/dual_audio.mp4"
|
||||
},
|
||||
{
|
||||
"in": 0.0,
|
||||
"out": 10.0,
|
||||
"duration": 10.0,
|
||||
"source": "tests/assets/short_video.mp4"
|
||||
},
|
||||
{
|
||||
"in": 0.0,
|
||||
"out": 10.0,
|
||||
"duration": 10.0,
|
||||
"source": "tests/assets/still.jpg"
|
||||
},
|
||||
{
|
||||
"in": 0.0,
|
||||
"out": 10.0,
|
||||
"duration": 10.0,
|
||||
"source": "tests/assets/short_audio.mp4"
|
||||
},
|
||||
{
|
||||
"in": 0.0,
|
||||
"out": 30.0,
|
||||
"duration": 30.0,
|
||||
"source": "tests/assets/no_audio.mp4"
|
||||
},
|
||||
{
|
||||
"in": 0.0,
|
||||
"out": 10.0,
|
||||
"duration": 10.0,
|
||||
"source": "tests/assets/still.jpg",
|
||||
"audio": "tests/assets/audio.mp3"
|
||||
},
|
||||
{
|
||||
"in": 0.0,
|
||||
"out": 25.0,
|
||||
"duration": 25.0,
|
||||
"source": "tests/assets/ad.mp4",
|
||||
"category": "advertisement"
|
||||
}
|
||||
]
|
||||
}
|
BIN
tests/assets/short_audio.mp4
Normal file
BIN
tests/assets/short_audio.mp4
Normal file
Binary file not shown.
BIN
tests/assets/short_video.mp4
Normal file
BIN
tests/assets/short_video.mp4
Normal file
Binary file not shown.
BIN
tests/assets/still.jpg
Normal file
BIN
tests/assets/still.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 202 KiB |
BIN
tests/assets/with_audio.mp4
Normal file
BIN
tests/assets/with_audio.mp4
Normal file
Binary file not shown.
82
tests/src/engine_cmd.rs
Normal file
82
tests/src/engine_cmd.rs
Normal file
@ -0,0 +1,82 @@
|
||||
use ffplayout::input::playlist::gen_source;
|
||||
use ffplayout_lib::{
|
||||
utils::{Media, PlayoutConfig},
|
||||
vec_strings,
|
||||
};
|
||||
use std::sync::{Arc, Mutex};
|
||||
|
||||
#[test]
|
||||
fn video_audio_input() {
|
||||
let mut config = PlayoutConfig::new(Some("../assets/ffplayout.yml".to_string()));
|
||||
config.out.mode = "stream".to_string();
|
||||
config.processing.logo = "../assets/logo.png".to_string();
|
||||
|
||||
let media_obj = Media::new(0, "assets/with_audio.mp4", true);
|
||||
let media = gen_source(&config, media_obj, &Arc::new(Mutex::new(vec![])));
|
||||
|
||||
let test_filter_cmd = Some(
|
||||
vec_strings![
|
||||
"-filter_complex",
|
||||
"[0:v:0]scale=1024:576,null[v];movie=../assets/logo.png: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]",
|
||||
"-map",
|
||||
"[vout0]",
|
||||
"-map",
|
||||
"[aout0]"
|
||||
],
|
||||
);
|
||||
|
||||
assert_eq!(media.cmd, Some(vec_strings!["-i", "assets/with_audio.mp4"]));
|
||||
assert_eq!(media.filter, test_filter_cmd);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn dual_audio_aevalsrc_input() {
|
||||
let mut config = PlayoutConfig::new(Some("../assets/ffplayout.yml".to_string()));
|
||||
config.out.mode = "stream".to_string();
|
||||
config.processing.audio_tracks = 2;
|
||||
config.processing.add_logo = false;
|
||||
|
||||
let media_obj = Media::new(0, "assets/with_audio.mp4", true);
|
||||
let media = gen_source(&config, media_obj, &Arc::new(Mutex::new(vec![])));
|
||||
|
||||
let test_filter_cmd = Some(
|
||||
vec_strings![
|
||||
"-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]",
|
||||
"-map",
|
||||
"[vout0]",
|
||||
"-map",
|
||||
"[aout0]",
|
||||
"-map",
|
||||
"[aout1]"
|
||||
],
|
||||
);
|
||||
|
||||
assert_eq!(media.cmd, Some(vec_strings!["-i", "assets/with_audio.mp4"]));
|
||||
assert_eq!(media.filter, test_filter_cmd);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn dual_audio_input() {
|
||||
let mut config = PlayoutConfig::new(Some("../assets/ffplayout.yml".to_string()));
|
||||
config.out.mode = "stream".to_string();
|
||||
config.processing.audio_tracks = 2;
|
||||
config.processing.add_logo = false;
|
||||
|
||||
let media_obj = Media::new(0, "assets/dual_audio.mp4", true);
|
||||
let media = gen_source(&config, media_obj, &Arc::new(Mutex::new(vec![])));
|
||||
|
||||
let test_filter_cmd = Some(vec_strings![
|
||||
"-filter_complex",
|
||||
"[0:v:0]scale=1024:576[vout0];[0:a:0]anull[aout0];[0:a:1]anull[aout1]",
|
||||
"-map",
|
||||
"[vout0]",
|
||||
"-map",
|
||||
"[aout0]",
|
||||
"-map",
|
||||
"[aout1]"
|
||||
]);
|
||||
|
||||
assert_eq!(media.cmd, Some(vec_strings!["-i", "assets/dual_audio.mp4"]));
|
||||
assert_eq!(media.filter, test_filter_cmd);
|
||||
}
|
@ -3,13 +3,11 @@ use std::{
|
||||
time::Duration,
|
||||
};
|
||||
|
||||
#[cfg(test)]
|
||||
use crate::output::player;
|
||||
#[cfg(test)]
|
||||
use ffplayout_lib::utils::*;
|
||||
#[cfg(test)]
|
||||
use simplelog::*;
|
||||
|
||||
use ffplayout::output::player;
|
||||
use ffplayout_lib::utils::*;
|
||||
|
||||
fn timed_kill(sec: u64, mut proc_ctl: ProcessControl) {
|
||||
sleep(Duration::from_secs(sec));
|
||||
|
@ -2,8 +2,7 @@
|
||||
use chrono::prelude::*;
|
||||
|
||||
#[cfg(test)]
|
||||
use crate::utils::*;
|
||||
use crate::vec_strings;
|
||||
use ffplayout_lib::{utils::*, vec_strings};
|
||||
|
||||
#[test]
|
||||
fn mock_date_time() {
|
Loading…
Reference in New Issue
Block a user