parent
9c23bc322a
commit
c85e5503b4
@ -47,7 +47,8 @@ processing:
|
|||||||
or folder. 'aspect' must be a float number. 'logo' is only used if the path exist.
|
or folder. 'aspect' must be a float number. 'logo' is only used if the path exist.
|
||||||
'logo_scale' scale the logo to target size, leave it blank when no scaling
|
'logo_scale' scale the logo to target size, leave it blank when no scaling
|
||||||
is needed, format is 'number:number', for example '100:-1' for proportional
|
is needed, format is 'number:number', for example '100:-1' for proportional
|
||||||
scaling. With 'logo_opacity' logo can become transparent. With 'logo_filter'
|
scaling. With 'logo_opacity' logo can become transparent. With 'audio_tracks' it
|
||||||
|
is possible to configure how many audio tracks should be processed. With 'logo_filter'
|
||||||
'overlay=W-w-12:12' you can modify the logo position. With 'use_loudnorm'
|
'overlay=W-w-12:12' you can modify the logo position. With 'use_loudnorm'
|
||||||
you can activate single pass EBU R128 loudness normalization. 'loud_*' can
|
you can activate single pass EBU R128 loudness normalization. 'loud_*' can
|
||||||
adjust the loudnorm filter. With 'custom_filter' it is possible, to apply further
|
adjust the loudnorm filter. With 'custom_filter' it is possible, to apply further
|
||||||
@ -63,6 +64,7 @@ processing:
|
|||||||
logo_scale:
|
logo_scale:
|
||||||
logo_opacity: 0.7
|
logo_opacity: 0.7
|
||||||
logo_filter: overlay=W-w-12:12
|
logo_filter: overlay=W-w-12:12
|
||||||
|
audio_tracks: 1
|
||||||
add_loudnorm: false
|
add_loudnorm: false
|
||||||
loudnorm_ingest: false
|
loudnorm_ingest: false
|
||||||
loud_i: -18
|
loud_i: -18
|
||||||
|
@ -5,10 +5,12 @@ use std::{
|
|||||||
|
|
||||||
use simplelog::*;
|
use simplelog::*;
|
||||||
|
|
||||||
pub mod a_loudnorm;
|
mod a_loudnorm;
|
||||||
pub mod custom_filter;
|
mod custom_filter;
|
||||||
pub mod v_drawtext;
|
pub mod v_drawtext;
|
||||||
|
|
||||||
|
// get_delta
|
||||||
|
use self::custom_filter::custom_filter;
|
||||||
use crate::utils::{fps_calc, get_delta, is_close, Media, MediaProbe, PlayoutConfig};
|
use crate::utils::{fps_calc, get_delta, is_close, Media, MediaProbe, PlayoutConfig};
|
||||||
|
|
||||||
#[derive(Clone, Copy, PartialEq)]
|
#[derive(Clone, Copy, PartialEq)]
|
||||||
@ -19,58 +21,54 @@ enum FilterType {
|
|||||||
|
|
||||||
use FilterType::*;
|
use FilterType::*;
|
||||||
|
|
||||||
use self::custom_filter::custom_filter;
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
struct Filters {
|
struct Filters {
|
||||||
audio_chain: Option<String>,
|
chain: String,
|
||||||
video_chain: Option<String>,
|
map: Vec<String>,
|
||||||
audio_map: String,
|
typ: String,
|
||||||
video_map: String,
|
pos: i32,
|
||||||
|
last: i32,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Filters {
|
impl Filters {
|
||||||
fn new() -> Self {
|
pub fn new(typ: String, pos: i32) -> Self {
|
||||||
Filters {
|
Filters {
|
||||||
audio_chain: None,
|
chain: String::new(),
|
||||||
video_chain: None,
|
map: vec![],
|
||||||
audio_map: "0:a".to_string(),
|
typ,
|
||||||
video_map: "0:v".to_string(),
|
pos,
|
||||||
|
last: -1,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_filter(&mut self, filter: &str, codec_type: FilterType) {
|
pub fn add_filter(&mut self, filter: &str, track_nr: i32) {
|
||||||
match codec_type {
|
if self.last != track_nr {
|
||||||
Audio => match &self.audio_chain {
|
// start new filter chain
|
||||||
Some(ac) => {
|
let mut selector = String::new();
|
||||||
if filter.starts_with(';') || filter.starts_with('[') {
|
let mut sep = String::new();
|
||||||
self.audio_chain = Some(format!("{ac}{filter}"))
|
if !self.chain.is_empty() {
|
||||||
} else {
|
selector = format!("[{}out{}]", self.typ, self.last);
|
||||||
self.audio_chain = Some(format!("{ac},{filter}"))
|
sep = ";".to_string()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.chain.push_str(selector.as_str());
|
||||||
|
|
||||||
|
if !filter.is_empty() {
|
||||||
|
if filter.starts_with("aevalsrc") {
|
||||||
|
self.chain.push_str(format!("{sep}{filter}").as_str());
|
||||||
|
} else {
|
||||||
|
self.chain.push_str(
|
||||||
|
format!("{sep}[{}:{}:{track_nr}]{filter}", self.pos, self.typ).as_str(),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
None => {
|
|
||||||
if filter.contains("aevalsrc") || filter.contains("anoisesrc") {
|
self.map.push(format!("[{}out{track_nr}]", self.typ));
|
||||||
self.audio_chain = Some(filter.to_string());
|
self.last = track_nr;
|
||||||
} else {
|
}
|
||||||
self.audio_chain = Some(format!("[{}]{filter}", self.audio_map.clone()));
|
} else if filter.starts_with(';') || filter.starts_with('[') {
|
||||||
}
|
self.chain.push_str(filter);
|
||||||
self.audio_map = "[aout1]".to_string();
|
} else {
|
||||||
}
|
self.chain.push_str(format!(",{filter}").as_str())
|
||||||
},
|
|
||||||
Video => match &self.video_chain {
|
|
||||||
Some(vc) => {
|
|
||||||
if filter.starts_with(';') || filter.starts_with('[') {
|
|
||||||
self.video_chain = Some(format!("{vc}{filter}"))
|
|
||||||
} else {
|
|
||||||
self.video_chain = Some(format!("{vc},{filter}"))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
None => {
|
|
||||||
self.video_chain = Some(format!("[0:v]{filter}"));
|
|
||||||
self.video_map = "[vout1]".to_string();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -78,7 +76,7 @@ impl Filters {
|
|||||||
fn deinterlace(field_order: &Option<String>, chain: &mut Filters) {
|
fn deinterlace(field_order: &Option<String>, chain: &mut Filters) {
|
||||||
if let Some(order) = field_order {
|
if let Some(order) = field_order {
|
||||||
if order != "progressive" {
|
if order != "progressive" {
|
||||||
chain.add_filter("yadif=0:-1:0", Video)
|
chain.add_filter("yadif=0:-1:0", 0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -99,14 +97,14 @@ fn pad(aspect: f64, chain: &mut Filters, v_stream: &ffprobe::Stream, config: &Pl
|
|||||||
"{scale}pad=max(iw\\,ih*({0}/{1})):ow/({0}/{1}):(ow-iw)/2:(oh-ih)/2",
|
"{scale}pad=max(iw\\,ih*({0}/{1})):ow/({0}/{1}):(ow-iw)/2:(oh-ih)/2",
|
||||||
config.processing.width, config.processing.height
|
config.processing.width, config.processing.height
|
||||||
),
|
),
|
||||||
Video,
|
0,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fps(fps: f64, chain: &mut Filters, config: &PlayoutConfig) {
|
fn fps(fps: f64, chain: &mut Filters, config: &PlayoutConfig) {
|
||||||
if fps != config.processing.fps {
|
if fps != config.processing.fps {
|
||||||
chain.add_filter(&format!("fps={}", config.processing.fps), Video)
|
chain.add_filter(&format!("fps={}", config.processing.fps), 0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -125,14 +123,14 @@ fn scale(
|
|||||||
"scale={}:{}",
|
"scale={}:{}",
|
||||||
config.processing.width, config.processing.height
|
config.processing.width, config.processing.height
|
||||||
),
|
),
|
||||||
Video,
|
0,
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
chain.add_filter("null", Video);
|
chain.add_filter("null", 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
if !is_close(aspect, config.processing.aspect, 0.03) {
|
if !is_close(aspect, config.processing.aspect, 0.03) {
|
||||||
chain.add_filter(&format!("setdar=dar={}", config.processing.aspect), Video)
|
chain.add_filter(&format!("setdar=dar={}", config.processing.aspect), 0)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
chain.add_filter(
|
chain.add_filter(
|
||||||
@ -140,13 +138,13 @@ fn scale(
|
|||||||
"scale={}:{}",
|
"scale={}:{}",
|
||||||
config.processing.width, config.processing.height
|
config.processing.width, config.processing.height
|
||||||
),
|
),
|
||||||
Video,
|
0,
|
||||||
);
|
);
|
||||||
chain.add_filter(&format!("setdar=dar={}", config.processing.aspect), Video)
|
chain.add_filter(&format!("setdar=dar={}", config.processing.aspect), 0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fade(node: &mut Media, chain: &mut Filters, codec_type: FilterType) {
|
fn fade(node: &mut Media, chain: &mut Filters, codec_type: FilterType, nr: i32) {
|
||||||
let mut t = "";
|
let mut t = "";
|
||||||
|
|
||||||
if codec_type == Audio {
|
if codec_type == Audio {
|
||||||
@ -154,13 +152,13 @@ fn fade(node: &mut Media, chain: &mut Filters, codec_type: FilterType) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if node.seek > 0.0 || node.is_live == Some(true) {
|
if node.seek > 0.0 || node.is_live == Some(true) {
|
||||||
chain.add_filter(&format!("{t}fade=in:st=0:d=0.5"), codec_type)
|
chain.add_filter(&format!("{t}fade=in:st=0:d=0.5"), nr)
|
||||||
}
|
}
|
||||||
|
|
||||||
if node.out != node.duration && node.out - node.seek - 1.0 > 0.0 {
|
if node.out != node.duration && node.out - node.seek - 1.0 > 0.0 {
|
||||||
chain.add_filter(
|
chain.add_filter(
|
||||||
&format!("{t}fade=out:st={}:d=1.0", (node.out - node.seek - 1.0)),
|
&format!("{t}fade=out:st={}:d=1.0", (node.out - node.seek - 1.0)),
|
||||||
codec_type,
|
nr,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -185,7 +183,7 @@ fn overlay(node: &mut Media, chain: &mut Filters, config: &PlayoutConfig) {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
chain.add_filter(&logo_chain, Video);
|
chain.add_filter(&logo_chain, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -203,7 +201,7 @@ fn extend_video(node: &mut Media, chain: &mut Filters) {
|
|||||||
"tpad=stop_mode=add:stop_duration={}",
|
"tpad=stop_mode=add:stop_duration={}",
|
||||||
(node.out - node.seek) - (video_duration - node.seek)
|
(node.out - node.seek) - (video_duration - node.seek)
|
||||||
),
|
),
|
||||||
Video,
|
0,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -221,28 +219,19 @@ fn add_text(
|
|||||||
{
|
{
|
||||||
let filter = v_drawtext::filter_node(config, Some(node), filter_chain);
|
let filter = v_drawtext::filter_node(config, Some(node), filter_chain);
|
||||||
|
|
||||||
chain.add_filter(&filter, Video);
|
chain.add_filter(&filter, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_audio(node: &mut Media, chain: &mut Filters) {
|
fn add_audio(node: &Media, chain: &mut Filters, nr: i32) {
|
||||||
if node
|
let audio = format!(
|
||||||
.probe
|
"aevalsrc=0:channel_layout=stereo:duration={}:sample_rate=48000",
|
||||||
.as_ref()
|
node.out - node.seek
|
||||||
.and_then(|p| p.audio_streams.get(0))
|
);
|
||||||
.is_none()
|
chain.add_filter(&audio, nr);
|
||||||
&& !Path::new(&node.audio).is_file()
|
|
||||||
{
|
|
||||||
warn!("Clip <b><magenta>{}</></b> has no audio!", node.source);
|
|
||||||
let audio = format!(
|
|
||||||
"aevalsrc=0:channel_layout=stereo:duration={}:sample_rate=48000",
|
|
||||||
node.out - node.seek
|
|
||||||
);
|
|
||||||
chain.add_filter(&audio, Audio);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn extend_audio(node: &mut Media, chain: &mut Filters) {
|
fn extend_audio(node: &mut Media, chain: &mut Filters, nr: i32) {
|
||||||
let probe = if Path::new(&node.audio).is_file() {
|
let probe = if Path::new(&node.audio).is_file() {
|
||||||
Some(MediaProbe::new(&node.audio))
|
Some(MediaProbe::new(&node.audio))
|
||||||
} else {
|
} else {
|
||||||
@ -256,22 +245,22 @@ fn extend_audio(node: &mut Media, chain: &mut Filters) {
|
|||||||
.and_then(|a| a.parse::<f64>().ok())
|
.and_then(|a| a.parse::<f64>().ok())
|
||||||
{
|
{
|
||||||
if node.out - node.seek > audio_duration - node.seek + 0.1 && node.duration >= node.out {
|
if node.out - node.seek > audio_duration - node.seek + 0.1 && node.duration >= node.out {
|
||||||
chain.add_filter(&format!("apad=whole_dur={}", node.out - node.seek), Audio)
|
chain.add_filter(&format!("apad=whole_dur={}", node.out - node.seek), nr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Add single pass loudnorm filter to audio line.
|
/// Add single pass loudnorm filter to audio line.
|
||||||
fn add_loudnorm(chain: &mut Filters, config: &PlayoutConfig) {
|
fn add_loudnorm(chain: &mut Filters, config: &PlayoutConfig, nr: i32) {
|
||||||
if config.processing.add_loudnorm {
|
if config.processing.add_loudnorm {
|
||||||
let loud_filter = a_loudnorm::filter_node(config);
|
let loud_filter = a_loudnorm::filter_node(config);
|
||||||
chain.add_filter(&loud_filter, Audio);
|
chain.add_filter(&loud_filter, nr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn audio_volume(chain: &mut Filters, config: &PlayoutConfig) {
|
fn audio_volume(chain: &mut Filters, config: &PlayoutConfig, nr: i32) {
|
||||||
if config.processing.volume != 1.0 {
|
if config.processing.volume != 1.0 {
|
||||||
chain.add_filter(&format!("volume={}", config.processing.volume), Audio)
|
chain.add_filter(&format!("volume={}", config.processing.volume), nr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -289,7 +278,7 @@ fn aspect_calc(aspect_string: &Option<String>, config: &PlayoutConfig) -> f64 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// This realtime filter is important for HLS output to stay in sync.
|
/// This realtime filter is important for HLS output to stay in sync.
|
||||||
fn realtime_filter(node: &mut Media, chain: &mut Filters, config: &PlayoutConfig) {
|
fn realtime(node: &mut Media, chain: &mut Filters, config: &PlayoutConfig) {
|
||||||
if config.general.generate.is_none() && &config.out.mode.to_lowercase() == "hls" {
|
if config.general.generate.is_none() && &config.out.mode.to_lowercase() == "hls" {
|
||||||
let mut speed_filter = "realtime=speed=1".to_string();
|
let mut speed_filter = "realtime=speed=1".to_string();
|
||||||
|
|
||||||
@ -306,19 +295,13 @@ fn realtime_filter(node: &mut Media, chain: &mut Filters, config: &PlayoutConfig
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
chain.add_filter(&speed_filter, Video);
|
chain.add_filter(&speed_filter, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn custom(filter: &str, chain: &mut Filters) {
|
fn custom(filter: &str, chain: &mut Filters, nr: i32) {
|
||||||
let (video_filter, audio_filter) = custom_filter(filter);
|
if !filter.is_empty() {
|
||||||
|
chain.add_filter(filter, nr);
|
||||||
if !video_filter.is_empty() {
|
|
||||||
chain.add_filter(&video_filter, Video);
|
|
||||||
}
|
|
||||||
|
|
||||||
if !audio_filter.is_empty() {
|
|
||||||
chain.add_filter(&audio_filter, Audio);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -327,76 +310,94 @@ pub fn filter_chains(
|
|||||||
node: &mut Media,
|
node: &mut Media,
|
||||||
filter_chain: &Arc<Mutex<Vec<String>>>,
|
filter_chain: &Arc<Mutex<Vec<String>>>,
|
||||||
) -> Vec<String> {
|
) -> Vec<String> {
|
||||||
let mut filters = Filters::new();
|
let mut a_filters = Filters::new("a".into(), 0);
|
||||||
|
let mut v_filters = Filters::new("v".into(), 0);
|
||||||
|
|
||||||
if let Some(probe) = node.probe.as_ref() {
|
if let Some(probe) = node.probe.as_ref() {
|
||||||
if probe.audio_streams.get(0).is_none() || Path::new(&node.audio).is_file() {
|
if Path::new(&node.audio).is_file() {
|
||||||
filters.audio_map = "1:a".to_string();
|
a_filters.pos = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(v_stream) = &probe.video_streams.get(0) {
|
if let Some(v_stream) = &probe.video_streams.get(0) {
|
||||||
let aspect = aspect_calc(&v_stream.display_aspect_ratio, config);
|
let aspect = aspect_calc(&v_stream.display_aspect_ratio, config);
|
||||||
let frame_per_sec = fps_calc(&v_stream.r_frame_rate, 1.0);
|
let frame_per_sec = fps_calc(&v_stream.r_frame_rate, 1.0);
|
||||||
|
|
||||||
deinterlace(&v_stream.field_order, &mut filters);
|
deinterlace(&v_stream.field_order, &mut v_filters);
|
||||||
pad(aspect, &mut filters, v_stream, config);
|
pad(aspect, &mut v_filters, v_stream, config);
|
||||||
fps(frame_per_sec, &mut filters, config);
|
fps(frame_per_sec, &mut v_filters, config);
|
||||||
scale(
|
scale(
|
||||||
v_stream.width,
|
v_stream.width,
|
||||||
v_stream.height,
|
v_stream.height,
|
||||||
aspect,
|
aspect,
|
||||||
&mut filters,
|
&mut v_filters,
|
||||||
config,
|
config,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
extend_video(node, &mut filters);
|
extend_video(node, &mut v_filters);
|
||||||
|
|
||||||
add_audio(node, &mut filters);
|
|
||||||
extend_audio(node, &mut filters);
|
|
||||||
} else {
|
} else {
|
||||||
fps(0.0, &mut filters, config);
|
fps(0.0, &mut v_filters, config);
|
||||||
scale(None, None, 1.0, &mut filters, config);
|
scale(None, None, 1.0, &mut v_filters, config);
|
||||||
}
|
}
|
||||||
|
|
||||||
add_text(node, &mut filters, config, filter_chain);
|
add_text(node, &mut v_filters, config, filter_chain);
|
||||||
fade(node, &mut filters, Video);
|
fade(node, &mut v_filters, Video, 0);
|
||||||
overlay(node, &mut filters, config);
|
overlay(node, &mut v_filters, config);
|
||||||
realtime_filter(node, &mut filters, config);
|
realtime(node, &mut v_filters, config);
|
||||||
|
|
||||||
// add at least anull filter, for correct filter construction,
|
let (proc_vf, proc_af) = custom_filter(&config.processing.custom_filter);
|
||||||
// is important for split filter in HLS mode
|
let (list_vf, list_af) = custom_filter(&node.custom_filter);
|
||||||
filters.add_filter("anull", Audio);
|
|
||||||
|
|
||||||
add_loudnorm(&mut filters, config);
|
custom(&proc_vf, &mut v_filters, 0);
|
||||||
fade(node, &mut filters, Audio);
|
custom(&list_vf, &mut v_filters, 0);
|
||||||
audio_volume(&mut filters, config);
|
|
||||||
|
|
||||||
custom(&config.processing.custom_filter, &mut filters);
|
for i in 0..config.processing.audio_tracks {
|
||||||
custom(&node.custom_filter, &mut filters);
|
if node
|
||||||
|
.probe
|
||||||
|
.as_ref()
|
||||||
|
.and_then(|p| p.audio_streams.get(i as usize))
|
||||||
|
.is_some()
|
||||||
|
{
|
||||||
|
extend_audio(node, &mut a_filters, i);
|
||||||
|
} else if !node.is_live.unwrap_or(false) {
|
||||||
|
warn!(
|
||||||
|
"Missing audio track (id {i}) from <b><magenta>{}</></b>",
|
||||||
|
node.source
|
||||||
|
);
|
||||||
|
add_audio(node, &mut a_filters, i);
|
||||||
|
}
|
||||||
|
// add at least anull filter, for correct filter construction,
|
||||||
|
// is important for split filter in HLS mode
|
||||||
|
a_filters.add_filter("anull", i);
|
||||||
|
|
||||||
|
add_loudnorm(&mut a_filters, config, i);
|
||||||
|
fade(node, &mut a_filters, Audio, i);
|
||||||
|
audio_volume(&mut a_filters, config, i);
|
||||||
|
|
||||||
|
custom(&proc_af, &mut v_filters, i);
|
||||||
|
custom(&list_af, &mut v_filters, i);
|
||||||
|
}
|
||||||
|
|
||||||
|
// close filters
|
||||||
|
a_filters.add_filter("", 999);
|
||||||
|
v_filters.add_filter("", 999);
|
||||||
|
|
||||||
let mut filter_cmd = vec![];
|
let mut filter_cmd = vec![];
|
||||||
let mut filter_str: String = String::new();
|
let mut filter_str: String = String::new();
|
||||||
let mut filter_map: Vec<String> = vec![];
|
let mut filter_map: Vec<String> = vec![];
|
||||||
|
|
||||||
if let Some(v_filters) = filters.video_chain {
|
v_filters.map.append(&mut a_filters.map);
|
||||||
filter_str.push_str(v_filters.as_str());
|
|
||||||
filter_str.push_str(filters.video_map.clone().as_str());
|
for map in &v_filters.map {
|
||||||
filter_map.append(&mut vec!["-map".to_string(), filters.video_map]);
|
filter_map.append(&mut vec!["-map".to_string(), map.clone()]);
|
||||||
} else {
|
|
||||||
filter_map.append(&mut vec!["-map".to_string(), "0:v".to_string()]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(a_filters) = filters.audio_chain {
|
filter_str.push_str(&v_filters.chain);
|
||||||
if filter_str.len() > 10 {
|
|
||||||
filter_str.push(';')
|
if filter_str.len() > 10 {
|
||||||
}
|
filter_str.push(';')
|
||||||
filter_str.push_str(a_filters.as_str());
|
|
||||||
filter_str.push_str(filters.audio_map.clone().as_str());
|
|
||||||
filter_map.append(&mut vec!["-map".to_string(), filters.audio_map]);
|
|
||||||
} else {
|
|
||||||
filter_map.append(&mut vec!["-map".to_string(), filters.audio_map]);
|
|
||||||
}
|
}
|
||||||
|
filter_str.push_str(&a_filters.chain);
|
||||||
|
|
||||||
if filter_str.len() > 10 {
|
if filter_str.len() > 10 {
|
||||||
filter_cmd.push("-filter_complex".to_string());
|
filter_cmd.push("-filter_complex".to_string());
|
||||||
|
@ -99,6 +99,8 @@ pub struct Processing {
|
|||||||
pub logo_scale: String,
|
pub logo_scale: String,
|
||||||
pub logo_opacity: f32,
|
pub logo_opacity: f32,
|
||||||
pub logo_filter: String,
|
pub logo_filter: String,
|
||||||
|
#[serde(default)]
|
||||||
|
pub audio_tracks: i32,
|
||||||
pub add_loudnorm: bool,
|
pub add_loudnorm: bool,
|
||||||
pub loudnorm_ingest: bool,
|
pub loudnorm_ingest: bool,
|
||||||
pub loud_i: f32,
|
pub loud_i: f32,
|
||||||
@ -234,6 +236,10 @@ impl PlayoutConfig {
|
|||||||
config.processing.add_logo = false;
|
config.processing.add_logo = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if config.processing.audio_tracks < 1 {
|
||||||
|
config.processing.audio_tracks = 1
|
||||||
|
}
|
||||||
|
|
||||||
// We set the decoder settings here, so we only define them ones.
|
// We set the decoder settings here, so we only define them ones.
|
||||||
let mut settings = vec_strings![
|
let mut settings = vec_strings![
|
||||||
"-pix_fmt",
|
"-pix_fmt",
|
||||||
|
@ -535,18 +535,18 @@ pub fn gen_dummy(config: &PlayoutConfig, duration: f64) -> (String, Vec<String>)
|
|||||||
"color=c={color}:s={}x{}:d={duration}",
|
"color=c={color}:s={}x{}:d={duration}",
|
||||||
config.processing.width, config.processing.height
|
config.processing.width, config.processing.height
|
||||||
);
|
);
|
||||||
let cmd: Vec<String> = vec![
|
let cmd: Vec<String> = vec_strings![
|
||||||
"-f".to_string(),
|
"-f",
|
||||||
"lavfi".to_string(),
|
"lavfi",
|
||||||
"-i".to_string(),
|
"-i",
|
||||||
format!(
|
format!(
|
||||||
"{source}:r={},format=pix_fmts=yuv420p",
|
"{source}:r={},format=pix_fmts=yuv420p",
|
||||||
config.processing.fps
|
config.processing.fps
|
||||||
),
|
),
|
||||||
"-f".to_string(),
|
"-f",
|
||||||
"lavfi".to_string(),
|
"lavfi",
|
||||||
"-i".to_string(),
|
"-i",
|
||||||
format!("anoisesrc=d={duration}:c=pink:r=48000:a=0.3"),
|
format!("anoisesrc=d={duration}:c=pink:r=48000:a=0.3")
|
||||||
];
|
];
|
||||||
|
|
||||||
(source, cmd)
|
(source, cmd)
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
#!/usr/bin/bash
|
#!/usr/bin/bash
|
||||||
|
|
||||||
source $(dirname "$0")/man_create.sh
|
source $(dirname "$0")/man_create.sh
|
||||||
|
target=$1
|
||||||
|
|
||||||
echo "build frontend"
|
echo "build frontend"
|
||||||
echo
|
echo
|
||||||
@ -14,7 +15,11 @@ mv dist ../public
|
|||||||
|
|
||||||
cd ..
|
cd ..
|
||||||
|
|
||||||
targets=("x86_64-unknown-linux-musl" "aarch64-unknown-linux-gnu" "x86_64-pc-windows-gnu" "x86_64-apple-darwin" "aarch64-apple-darwin")
|
if [[ -n $target ]]; then
|
||||||
|
targets=($target)
|
||||||
|
else
|
||||||
|
targets=("x86_64-unknown-linux-musl" "aarch64-unknown-linux-gnu" "x86_64-pc-windows-gnu" "x86_64-apple-darwin" "aarch64-apple-darwin")
|
||||||
|
fi
|
||||||
|
|
||||||
IFS="= "
|
IFS="= "
|
||||||
while read -r name value; do
|
while read -r name value; do
|
||||||
@ -68,10 +73,14 @@ for target in "${targets[@]}"; do
|
|||||||
echo ""
|
echo ""
|
||||||
done
|
done
|
||||||
|
|
||||||
cargo deb --target=x86_64-unknown-linux-musl -p ffplayout --manifest-path=ffplayout-engine/Cargo.toml -o ffplayout_${version}_amd64.deb
|
if [[ -z $target ]] || [[ $target == "x86_64-unknown-linux-musl" ]]; then
|
||||||
cargo deb --target=aarch64-unknown-linux-gnu --variant=arm64 -p ffplayout --manifest-path=ffplayout-engine/Cargo.toml -o ffplayout_${version}_arm64.deb
|
cargo deb --target=x86_64-unknown-linux-musl -p ffplayout --manifest-path=ffplayout-engine/Cargo.toml -o ffplayout_${version}_amd64.deb
|
||||||
|
cd ffplayout-engine
|
||||||
|
cargo generate-rpm --target=x86_64-unknown-linux-musl -o ../ffplayout-${version}-1.x86_64.rpm
|
||||||
|
|
||||||
cd ffplayout-engine
|
cd ..
|
||||||
cargo generate-rpm --target=x86_64-unknown-linux-musl -o ../ffplayout-${version}-1.x86_64.rpm
|
fi
|
||||||
|
|
||||||
cd ..
|
if [[ -z $target ]] || [[ $target == "aarch64-unknown-linux-gnu" ]]; then
|
||||||
|
cargo deb --target=aarch64-unknown-linux-gnu --variant=arm64 -p ffplayout --manifest-path=ffplayout-engine/Cargo.toml -o ffplayout_${version}_arm64.deb
|
||||||
|
fi
|
Loading…
Reference in New Issue
Block a user