fix v_in in custom filter, add audio only mode
This commit is contained in:
parent
f3cd45af3c
commit
537f664c06
@ -57,6 +57,7 @@ processing:
|
|||||||
With 'custom_filter' it is possible, to apply further filters. The filter outputs
|
With 'custom_filter' it is possible, to apply further filters. The filter outputs
|
||||||
should end with [c_v_out] for video filter, and [c_a_out] for audio filter.
|
should end with [c_v_out] for video filter, and [c_a_out] for audio filter.
|
||||||
mode: playlist
|
mode: playlist
|
||||||
|
audio_only: false
|
||||||
width: 1024
|
width: 1024
|
||||||
height: 576
|
height: 576
|
||||||
aspect: 1.778
|
aspect: 1.778
|
||||||
|
@ -23,7 +23,7 @@ pub fn output(config: &PlayoutConfig, log_format: &str) -> process::Child {
|
|||||||
"ffplayout"
|
"ffplayout"
|
||||||
];
|
];
|
||||||
|
|
||||||
if config.text.add_text && !config.text.text_from_filename {
|
if config.text.add_text && !config.text.text_from_filename && !config.processing.audio_only {
|
||||||
if let Some(socket) = config.text.zmq_stream_socket.clone() {
|
if let Some(socket) = config.text.zmq_stream_socket.clone() {
|
||||||
debug!(
|
debug!(
|
||||||
"Using drawtext filter, listening on address: <yellow>{}</>",
|
"Using drawtext filter, listening on address: <yellow>{}</>",
|
||||||
|
@ -35,5 +35,9 @@ pub fn filter_node(filter: &str) -> (String, String) {
|
|||||||
error!("Custom filter is not well formatted, use correct out link names (\"[c_v_out]\" and/or \"[c_a_out]\"). Filter skipped!")
|
error!("Custom filter is not well formatted, use correct out link names (\"[c_v_out]\" and/or \"[c_a_out]\"). Filter skipped!")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if filter.starts_with("[v_in]") {
|
||||||
|
video_filter = format!("[v_in]{video_filter}");
|
||||||
|
}
|
||||||
|
|
||||||
(video_filter, audio_filter)
|
(video_filter, audio_filter)
|
||||||
}
|
}
|
||||||
|
@ -138,7 +138,10 @@ impl Filters {
|
|||||||
let mut cmd = vec![];
|
let mut cmd = vec![];
|
||||||
|
|
||||||
if !a_chain.is_empty() {
|
if !a_chain.is_empty() {
|
||||||
f_chain.push(';');
|
if !f_chain.is_empty() {
|
||||||
|
f_chain.push(';');
|
||||||
|
}
|
||||||
|
|
||||||
f_chain.push_str(&a_chain);
|
f_chain.push_str(&a_chain);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -153,7 +156,7 @@ impl Filters {
|
|||||||
pub fn map(&mut self) -> Vec<String> {
|
pub fn map(&mut self) -> Vec<String> {
|
||||||
let mut o_map = self.output_map.clone();
|
let mut o_map = self.output_map.clone();
|
||||||
|
|
||||||
if self.video_last == -1 {
|
if self.video_last == -1 && !self.video_chain.is_empty() {
|
||||||
let v_map = "0:v".to_string();
|
let v_map = "0:v".to_string();
|
||||||
|
|
||||||
if !o_map.contains(&v_map) {
|
if !o_map.contains(&v_map) {
|
||||||
@ -412,9 +415,19 @@ 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(node: &mut Media, chain: &mut Filters, config: &PlayoutConfig) {
|
fn realtime(
|
||||||
|
node: &mut Media,
|
||||||
|
chain: &mut Filters,
|
||||||
|
config: &PlayoutConfig,
|
||||||
|
filter_type: FilterType,
|
||||||
|
) {
|
||||||
if config.general.generate.is_none() && config.out.mode == HLS {
|
if config.general.generate.is_none() && config.out.mode == HLS {
|
||||||
let mut speed_filter = "realtime=speed=1".to_string();
|
let prefix = match filter_type {
|
||||||
|
Audio => "a",
|
||||||
|
Video => "",
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut speed_filter = format!("{prefix}realtime=speed=1");
|
||||||
|
|
||||||
if let Some(begin) = &node.begin {
|
if let Some(begin) = &node.begin {
|
||||||
let (delta, _) = get_delta(config, begin);
|
let (delta, _) = get_delta(config, begin);
|
||||||
@ -424,12 +437,12 @@ fn realtime(node: &mut Media, chain: &mut Filters, config: &PlayoutConfig) {
|
|||||||
let speed = duration / (duration + delta);
|
let speed = duration / (duration + delta);
|
||||||
|
|
||||||
if speed > 0.0 && speed < 1.1 && delta < config.general.stop_threshold {
|
if speed > 0.0 && speed < 1.1 && delta < config.general.stop_threshold {
|
||||||
speed_filter = format!("realtime=speed={speed}");
|
speed_filter = format!("{prefix}realtime=speed={speed}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
chain.add_filter(&speed_filter, 0, Video);
|
chain.add_filter(&speed_filter, 0, filter_type);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -504,54 +517,62 @@ pub fn filter_chains(
|
|||||||
let mut filters = Filters::new(config.processing.audio_tracks, 0);
|
let mut filters = Filters::new(config.processing.audio_tracks, 0);
|
||||||
|
|
||||||
if node.unit == Encoder {
|
if node.unit == Encoder {
|
||||||
add_text(node, &mut filters, config, filter_chain);
|
if !config.processing.audio_only {
|
||||||
|
add_text(node, &mut filters, config, filter_chain);
|
||||||
|
}
|
||||||
|
|
||||||
if let Some(f) = config.out.output_filter.clone() {
|
if let Some(f) = config.out.output_filter.clone() {
|
||||||
process_output_filters(config, &mut filters, &f)
|
process_output_filters(config, &mut filters, &f)
|
||||||
} else if config.out.output_count > 1 {
|
} else if config.out.output_count > 1 && !config.processing.audio_only {
|
||||||
split_filter(&mut filters, config.out.output_count, 0, Video);
|
split_filter(&mut filters, config.out.output_count, 0, Video);
|
||||||
}
|
}
|
||||||
|
|
||||||
return filters;
|
return filters;
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(probe) = node.probe.as_ref() {
|
if !config.processing.audio_only {
|
||||||
if Path::new(&node.audio).is_file() {
|
if let Some(probe) = node.probe.as_ref() {
|
||||||
filters.audio_position = 1;
|
if Path::new(&node.audio).is_file() {
|
||||||
|
filters.audio_position = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(v_stream) = &probe.video_streams.get(0) {
|
||||||
|
let aspect = aspect_calc(&v_stream.display_aspect_ratio, config);
|
||||||
|
let frame_per_sec = fps_calc(&v_stream.r_frame_rate, 1.0);
|
||||||
|
|
||||||
|
deinterlace(&v_stream.field_order, &mut filters);
|
||||||
|
pad(aspect, &mut filters, v_stream, config);
|
||||||
|
fps(frame_per_sec, &mut filters, config);
|
||||||
|
scale(
|
||||||
|
v_stream.width,
|
||||||
|
v_stream.height,
|
||||||
|
aspect,
|
||||||
|
&mut filters,
|
||||||
|
config,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
extend_video(node, &mut filters);
|
||||||
|
} else {
|
||||||
|
fps(0.0, &mut filters, config);
|
||||||
|
scale(None, None, 1.0, &mut filters, config);
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(v_stream) = &probe.video_streams.get(0) {
|
add_text(node, &mut filters, config, filter_chain);
|
||||||
let aspect = aspect_calc(&v_stream.display_aspect_ratio, config);
|
fade(node, &mut filters, 0, Video);
|
||||||
let frame_per_sec = fps_calc(&v_stream.r_frame_rate, 1.0);
|
overlay(node, &mut filters, config);
|
||||||
|
realtime(node, &mut filters, config, Video);
|
||||||
deinterlace(&v_stream.field_order, &mut filters);
|
|
||||||
pad(aspect, &mut filters, v_stream, config);
|
|
||||||
fps(frame_per_sec, &mut filters, config);
|
|
||||||
scale(
|
|
||||||
v_stream.width,
|
|
||||||
v_stream.height,
|
|
||||||
aspect,
|
|
||||||
&mut filters,
|
|
||||||
config,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
extend_video(node, &mut filters);
|
|
||||||
} else {
|
|
||||||
fps(0.0, &mut filters, config);
|
|
||||||
scale(None, None, 1.0, &mut filters, config);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
add_text(node, &mut filters, config, filter_chain);
|
|
||||||
fade(node, &mut filters, 0, Video);
|
|
||||||
overlay(node, &mut filters, config);
|
|
||||||
realtime(node, &mut filters, config);
|
|
||||||
|
|
||||||
let (proc_vf, proc_af) = custom::filter_node(&config.processing.custom_filter);
|
let (proc_vf, proc_af) = custom::filter_node(&config.processing.custom_filter);
|
||||||
let (list_vf, list_af) = custom::filter_node(&node.custom_filter);
|
let (list_vf, list_af) = custom::filter_node(&node.custom_filter);
|
||||||
|
|
||||||
custom(&proc_vf, &mut filters, 0, Video);
|
if config.processing.audio_only {
|
||||||
custom(&list_vf, &mut filters, 0, Video);
|
realtime(node, &mut filters, config, Audio);
|
||||||
|
} else {
|
||||||
|
custom(&proc_vf, &mut filters, 0, Video);
|
||||||
|
custom(&list_vf, &mut filters, 0, Video);
|
||||||
|
}
|
||||||
|
|
||||||
for i in 0..config.processing.audio_tracks {
|
for i in 0..config.processing.audio_tracks {
|
||||||
if node
|
if node
|
||||||
|
@ -19,7 +19,7 @@ pub const IMAGE_FORMAT: [&str; 21] = [
|
|||||||
];
|
];
|
||||||
|
|
||||||
// Some well known errors can be safely ignore
|
// Some well known errors can be safely ignore
|
||||||
pub const FFMPEG_IGNORE_ERRORS: [&str; 10] = [
|
pub const FFMPEG_IGNORE_ERRORS: [&str; 11] = [
|
||||||
"ac-tex damaged",
|
"ac-tex damaged",
|
||||||
"codec s302m, is muxed as a private data stream",
|
"codec s302m, is muxed as a private data stream",
|
||||||
"corrupt decoded frame in stream",
|
"corrupt decoded frame in stream",
|
||||||
@ -30,6 +30,7 @@ pub const FFMPEG_IGNORE_ERRORS: [&str; 10] = [
|
|||||||
"skipped MB in I-frame at",
|
"skipped MB in I-frame at",
|
||||||
"Thread message queue blocking",
|
"Thread message queue blocking",
|
||||||
"Warning MVs not available",
|
"Warning MVs not available",
|
||||||
|
"frame size not set",
|
||||||
];
|
];
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize, Clone, Eq, PartialEq)]
|
#[derive(Debug, Serialize, Deserialize, Clone, Eq, PartialEq)]
|
||||||
@ -156,6 +157,8 @@ pub struct Logging {
|
|||||||
pub struct Processing {
|
pub struct Processing {
|
||||||
pub help_text: String,
|
pub help_text: String,
|
||||||
pub mode: ProcessMode,
|
pub mode: ProcessMode,
|
||||||
|
#[serde(default)]
|
||||||
|
pub audio_only: bool,
|
||||||
pub width: i64,
|
pub width: i64,
|
||||||
pub height: i64,
|
pub height: i64,
|
||||||
pub aspect: f64,
|
pub aspect: f64,
|
||||||
@ -328,24 +331,30 @@ impl PlayoutConfig {
|
|||||||
(config.processing.width * config.processing.height / 16) / 2
|
(config.processing.width * config.processing.height / 16) / 2
|
||||||
);
|
);
|
||||||
|
|
||||||
let mut process_cmd = vec_strings![
|
let mut process_cmd = vec_strings![];
|
||||||
"-pix_fmt",
|
|
||||||
"yuv420p",
|
if config.processing.audio_only {
|
||||||
"-r",
|
process_cmd.append(&mut vec_strings!["-vn"]);
|
||||||
&config.processing.fps,
|
} else {
|
||||||
"-c:v",
|
process_cmd.append(&mut vec_strings![
|
||||||
"mpeg2video",
|
"-pix_fmt",
|
||||||
"-g",
|
"yuv420p",
|
||||||
"1",
|
"-r",
|
||||||
"-b:v",
|
&config.processing.fps,
|
||||||
&bitrate,
|
"-c:v",
|
||||||
"-minrate",
|
"mpeg2video",
|
||||||
&bitrate,
|
"-g",
|
||||||
"-maxrate",
|
"1",
|
||||||
&bitrate,
|
"-b:v",
|
||||||
"-bufsize",
|
&bitrate,
|
||||||
&buff_size
|
"-minrate",
|
||||||
];
|
&bitrate,
|
||||||
|
"-maxrate",
|
||||||
|
&bitrate,
|
||||||
|
"-bufsize",
|
||||||
|
&buff_size
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
process_cmd.append(&mut pre_audio_codec(
|
process_cmd.append(&mut pre_audio_codec(
|
||||||
config.processing.add_loudnorm,
|
config.processing.add_loudnorm,
|
||||||
|
Loading…
Reference in New Issue
Block a user