From 1924392ce2e3f2020d95a6f41fa368179fd6834c Mon Sep 17 00:00:00 2001 From: jb-alvarado Date: Wed, 10 Apr 2024 16:49:31 +0200 Subject: [PATCH 1/3] format float --- ffplayout-engine/src/input/playlist.rs | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/ffplayout-engine/src/input/playlist.rs b/ffplayout-engine/src/input/playlist.rs index a87fe01e..b3c24e55 100644 --- a/ffplayout-engine/src/input/playlist.rs +++ b/ffplayout-engine/src/input/playlist.rs @@ -217,18 +217,16 @@ impl CurrentProgram { // On init or reload we need to seek for the current clip. fn get_current_clip(&mut self) { let mut time_sec = self.get_current_time(); - let shift = self.playout_stat.time_shift.lock().unwrap(); + let shift = *self.playout_stat.time_shift.lock().unwrap(); if *self.playout_stat.current_date.lock().unwrap() == *self.playout_stat.date.lock().unwrap() - && *shift != 0.0 + && shift != 0.0 { - info!("Shift playlist start for {} seconds", *shift); - time_sec += *shift; + info!("Shift playlist start for {shift:.3} seconds"); + time_sec += shift; } - drop(shift); - if self.config.playlist.infinit && self.json_playlist.length.unwrap() < 86400.0 && time_sec > self.json_playlist.length.unwrap() + self.start_sec From 4dee46857c6aaf9033c6fd817a3e6c2358b5808e Mon Sep 17 00:00:00 2001 From: jb-alvarado Date: Wed, 10 Apr 2024 21:53:48 +0200 Subject: [PATCH 2/3] !Braking change in config!, fix little issues with advanced settings --- assets/ffplayout.yml | 10 +++++----- lib/src/filter/mod.rs | 13 ++++++++----- lib/src/utils/config.rs | 6 +----- 3 files changed, 14 insertions(+), 15 deletions(-) diff --git a/assets/ffplayout.yml b/assets/ffplayout.yml index 0c264f8b..aedbc527 100644 --- a/assets/ffplayout.yml +++ b/assets/ffplayout.yml @@ -62,10 +62,10 @@ processing: is needed, format is 'width:height', for example '100:-1' for proportional scaling. With 'logo_opacity' logo can become transparent. With 'audio_tracks' it is possible to configure how many audio tracks should be processed. 'audio_channels' - can be use, if audio has more channels then only stereo. With 'logo_filter' - 'overlay=W-w-12:12' you can modify the logo position. 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. + can be use, if audio has more channels then only stereo. With 'logo_position' in format + 'x:y' you set the logo position. 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. mode: playlist audio_only: false copy_audio: false @@ -78,7 +78,7 @@ processing: logo: /usr/share/ffplayout/logo.png logo_scale: logo_opacity: 0.7 - logo_filter: overlay=W-w-12:12 + logo_position: W-w-12:12 audio_tracks: 1 audio_track_index: -1 audio_channels: 2 diff --git a/lib/src/filter/mod.rs b/lib/src/filter/mod.rs index 289026d9..26b50ae8 100644 --- a/lib/src/filter/mod.rs +++ b/lib/src/filter/mod.rs @@ -314,7 +314,7 @@ fn fade(node: &mut Media, chain: &mut Filters, nr: i32, filter_type: FilterType) if node.seek > 0.0 || node.unit == Ingest { let fade_in = match &ADVANCED_CONFIG.decoder.filters.fade_in { - Some(fade) => custom_format(fade, &[t]), + Some(fade) => custom_format(&format!("{t}{fade}"), &[t]), None => format!("{t}fade=in:st=0:d=0.5"), }; @@ -323,7 +323,10 @@ fn fade(node: &mut Media, chain: &mut Filters, nr: i32, filter_type: FilterType) if (node.out != node.duration && node.out - node.seek > 1.0) || fade_audio { let fade_out = match &ADVANCED_CONFIG.decoder.filters.fade_out { - Some(fade) => custom_format(fade, &[t, &(node.out - node.seek - 1.0).to_string()]), + Some(fade) => custom_format( + &format!("{t}{fade}"), + &[t, &(node.out - node.seek - 1.0).to_string()], + ), None => format!("{t}fade=out:st={}:d=1.0", (node.out - node.seek - 1.0)), }; @@ -350,11 +353,11 @@ fn overlay(node: &mut Media, chain: &mut Filters, config: &PlayoutConfig) { &config.processing.logo.replace('\\', "/").replace(':', "\\\\:"), &config.processing.logo_opacity.to_string(), &scale.to_string(), - &config.processing.logo_filter, + &config.processing.logo_position, ]), None => format!( - "null[v];movie={}:loop=0,setpts=N/(FRAME_RATE*TB),format=rgba,colorchannelmixer=aa={}{scale}[l];[v][l]{}:shortest=1", - config.processing.logo.replace('\\', "/").replace(':', "\\\\:"), config.processing.logo_opacity, config.processing.logo_filter + "null[v];movie={}:loop=0,setpts=N/(FRAME_RATE*TB),format=rgba,colorchannelmixer=aa={}{scale}[l];[v][l]overlay={}:shortest=1", + config.processing.logo.replace('\\', "/").replace(':', "\\\\:"), config.processing.logo_opacity, config.processing.logo_position ) }; diff --git a/lib/src/utils/config.rs b/lib/src/utils/config.rs index 997b7286..4e881550 100644 --- a/lib/src/utils/config.rs +++ b/lib/src/utils/config.rs @@ -253,7 +253,7 @@ pub struct Processing { pub logo: String, pub logo_scale: String, pub logo_opacity: f32, - pub logo_filter: String, + pub logo_position: String, #[serde(default = "default_tracks")] pub audio_tracks: i32, #[serde(default = "default_channels")] @@ -435,10 +435,6 @@ impl PlayoutConfig { } else if config.processing.copy_video { process_cmd.append(&mut vec_strings!["-c:v", "copy"]); } else if let Some(decoder_cmd) = &ADVANCED_CONFIG.decoder.output_cmd { - if !decoder_cmd.contains(&"-r".to_string()) { - process_cmd.append(&mut vec_strings!["-r", &config.processing.fps]); - } - process_cmd.append(&mut decoder_cmd.clone()); } else { let bitrate = format!( From b85be0cb822d0b276e96fe6a1f1dd2b85b0796be Mon Sep 17 00:00:00 2001 From: jb-alvarado Date: Thu, 11 Apr 2024 12:19:45 +0200 Subject: [PATCH 3/3] add doc for advanced settings, add separate fade filter for audio, support advanced parameter for stream mode --- Cargo.lock | 8 ++-- Cargo.toml | 2 +- docs/README.md | 2 + docs/advanced_settings.md | 57 +++++++++++++++++++++++++++ docs/api.md | 2 +- ffplayout-engine/src/output/stream.rs | 18 ++++----- lib/src/filter/mod.rs | 32 +++++++++------ lib/src/utils/advanced_config.rs | 2 + 8 files changed, 95 insertions(+), 28 deletions(-) create mode 100644 docs/advanced_settings.md diff --git a/Cargo.lock b/Cargo.lock index 22505c4f..fbd571d3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1217,7 +1217,7 @@ checksum = "658bd65b1cf4c852a3cc96f18a8ce7b5640f6b703f905c7d74532294c2a63984" [[package]] name = "ffplayout" -version = "0.21.0-beta2" +version = "0.21.0-beta3" dependencies = [ "chrono", "clap", @@ -1239,7 +1239,7 @@ dependencies = [ [[package]] name = "ffplayout-api" -version = "0.21.0-beta2" +version = "0.21.0-beta3" dependencies = [ "actix-files", "actix-multipart", @@ -1278,7 +1278,7 @@ dependencies = [ [[package]] name = "ffplayout-lib" -version = "0.21.0-beta2" +version = "0.21.0-beta3" dependencies = [ "chrono", "crossbeam-channel", @@ -3458,7 +3458,7 @@ dependencies = [ [[package]] name = "tests" -version = "0.21.0-beta2" +version = "0.21.0-beta3" dependencies = [ "chrono", "crossbeam-channel", diff --git a/Cargo.toml b/Cargo.toml index 8336c4db..92dc0570 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,7 +4,7 @@ default-members = ["ffplayout-api", "ffplayout-engine", "tests"] resolver = "2" [workspace.package] -version = "0.21.0-beta2" +version = "0.21.0-beta3" license = "GPL-3.0" repository = "https://github.com/ffplayout/ffplayout" authors = ["Jonathan Baecker "] diff --git a/docs/README.md b/docs/README.md index 53bf1be1..83d11b8d 100644 --- a/docs/README.md +++ b/docs/README.md @@ -48,3 +48,5 @@ Control the engine, playlist and config with a ~REST API ### **[Stream Copy](/docs/stream_copy.md)** Copy audio and or video stream + +### **[Advanced Settings](/docs/advanced_settings.md)** diff --git a/docs/advanced_settings.md b/docs/advanced_settings.md new file mode 100644 index 00000000..3a8275e0 --- /dev/null +++ b/docs/advanced_settings.md @@ -0,0 +1,57 @@ +## Advanced settings + +Within **/etc/ffplayout/advanced.yml** you can control all ffmpeg inputs/decoder output and filters. + +> **_Note:_** Changing these settings is for advanced users only! There will be no support or guarantee that it will work and be stable after changing them! + +For changing this settings you need to have knowledge about hardware encoding with ffmpeg. Good starting points are: + +- [HWAccelIntro](https://trac.ffmpeg.org/wiki/HWAccelIntro) +- [VAAPI](https://trac.ffmpeg.org/wiki/Hardware/VAAPI) +- [QuickSync](https://trac.ffmpeg.org/wiki/Hardware/QuickSync) + +### Example config + +Here an example with Intel QuickSync: + +```YAML +help: Changing these settings is for advanced users only! There will be no support or guarantee that ffplayout will be stable after changing them. +decoder: + input_param: -hwaccel qsv -init_hw_device qsv=hw -filter_hw_device hw -hwaccel_output_format qsv + # output_param get also applied to ingest instance. + output_param: -c:v mpeg2_qsv -g 1 -b:v 50000k -minrate 50000k -maxrate 50000k -bufsize 25000k -c:a s302m -strict -2 -sample_fmt s16 -ar 48000 -ac 2 + filters: + deinterlace: deinterlace_qsv + pad_scale_w: scale_qsv={}:-1, + pad_scale_h: scale_qsv=-1:{}, + pad_video: 'null' # 'pad=max(iw\\,ih*({0}/{1})):ow/({0}/{1}):(ow-iw)/2:(oh-ih)/2' + fps: vpp_qsv=framerate=25 + scale: scale_qsv={}:{} + set_dar: 'null' # setdar=dar={} + fade_in: 'null' # fade=in:st=0:d=0.5 + fade_out: 'null' # fade=out:st={}:d=1.0 + overlay_logo_scale: 'scale_qsv={}' + overlay_logo: null[v];movie={}:loop=0,setpts=N/(FRAME_RATE*TB),format=rgba,colorchannelmixer=aa={}{},hwupload=extra_hw_frames=64,format=qsv[l];[v][l]overlay_qsv={}:shortest=1 + overlay_logo_fade_in: 'null' # ',fade=in:st=0:d=1.0:alpha=1' + overlay_logo_fade_out: 'null' # ',fade=out:st={}:d=1.0:alpha=1' + tpad: 'null' # tpad=stop_mode=add:stop_duration={} + drawtext_from_file: hwdownload,format=nv12,drawtext=text='{}':{}{} # drawtext=text='{}':{}{} + drawtext_from_zmq: hwdownload,format=nv12,zmq=b=tcp\\://'{}',drawtext@dyntext={} # zmq=b=tcp\\\\://'{}',drawtext@dyntext={} + aevalsrc: # aevalsrc=0:channel_layout=stereo:duration={}:sample_rate=48000 + afade_in: # afade=in:st=0:d=0.5 + afade_out: # afade=out:st={}:d=1.0 + apad: # apad=whole_dur={} + volume: # volume={} + split: # split={}{} +encoder: + # use `-hwaccel vulkan` when output mode is desktop + input_param: -hwaccel qsv -init_hw_device qsv=hw -filter_hw_device hw -hwaccel_output_format qsv +ingest: + input_param: -hwaccel qsv -init_hw_device qsv=hw -filter_hw_device hw -hwaccel_output_format qsv +``` + +--- + +**At the moment this function is _experimental_, if you think you found a bug: check full decoder/encoder/ingest command with ffmpeg in terminal. When there the command works you can open a bug report issue.** + +Please don't open issues for general command line helps! diff --git a/docs/api.md b/docs/api.md index b66be182..531403cc 100644 --- a/docs/api.md +++ b/docs/api.md @@ -1,4 +1,4 @@ -### Possible endpoints +## Possible endpoints Run the API thru the systemd service, or like: diff --git a/ffplayout-engine/src/output/stream.rs b/ffplayout-engine/src/output/stream.rs index b53016a6..a9c1e66e 100644 --- a/ffplayout-engine/src/output/stream.rs +++ b/ffplayout-engine/src/output/stream.rs @@ -5,7 +5,7 @@ use simplelog::*; use crate::utils::prepare_output_cmd; use ffplayout_lib::{ utils::{Media, PlayoutConfig, ProcessUnit::*}, - vec_strings, + vec_strings, ADVANCED_CONFIG, }; /// Streaming Output @@ -16,15 +16,13 @@ pub fn output(config: &PlayoutConfig, log_format: &str) -> process::Child { media.unit = Encoder; media.add_filter(config, &None); - let enc_prefix = vec_strings![ - "-hide_banner", - "-nostats", - "-v", - log_format, - "-re", - "-i", - "pipe:0" - ]; + let mut enc_prefix = vec_strings!["-hide_banner", "-nostats", "-v", log_format]; + + if let Some(input_cmd) = &ADVANCED_CONFIG.encoder.input_cmd { + enc_prefix.append(&mut input_cmd.clone()); + } + + enc_prefix.append(&mut vec_strings!["-re", "-i", "pipe:0"]); let enc_cmd = prepare_output_cmd(config, enc_prefix, &media.filter); diff --git a/lib/src/filter/mod.rs b/lib/src/filter/mod.rs index 26b50ae8..5438a78c 100644 --- a/lib/src/filter/mod.rs +++ b/lib/src/filter/mod.rs @@ -216,9 +216,8 @@ fn pad(aspect: f64, chain: &mut Filters, v_stream: &ffprobe::Stream, config: &Pl let pad = match &ADVANCED_CONFIG.decoder.filters.pad_video { Some(pad_video) => custom_format( - pad_video, + &format!("{scale}{pad_video}"), &[ - &scale, &config.processing.width.to_string(), &config.processing.height.to_string(), ], @@ -313,21 +312,28 @@ fn fade(node: &mut Media, chain: &mut Filters, nr: i32, filter_type: FilterType) } if node.seek > 0.0 || node.unit == Ingest { - let fade_in = match &ADVANCED_CONFIG.decoder.filters.fade_in { - Some(fade) => custom_format(&format!("{t}{fade}"), &[t]), - None => format!("{t}fade=in:st=0:d=0.5"), + let mut fade_in = format!("{t}fade=in:st=0:d=0.5"); + + if t == "a" { + if let Some(fade) = &ADVANCED_CONFIG.decoder.filters.afade_in { + fade_in = custom_format(fade, &[t]); + } + } else if let Some(fade) = &ADVANCED_CONFIG.decoder.filters.fade_in { + fade_in = custom_format(fade, &[t]); }; chain.add_filter(&fade_in, nr, filter_type); } if (node.out != node.duration && node.out - node.seek > 1.0) || fade_audio { - let fade_out = match &ADVANCED_CONFIG.decoder.filters.fade_out { - Some(fade) => custom_format( - &format!("{t}{fade}"), - &[t, &(node.out - node.seek - 1.0).to_string()], - ), - None => format!("{t}fade=out:st={}:d=1.0", (node.out - node.seek - 1.0)), + let mut fade_out = format!("{t}fade=out:st={}:d=1.0", (node.out - node.seek - 1.0)); + + if t == "a" { + if let Some(fade) = &ADVANCED_CONFIG.decoder.filters.afade_out { + fade_out = custom_format(fade, &[t]); + } + } else if let Some(fade) = &ADVANCED_CONFIG.decoder.filters.fade_out { + fade_out = custom_format(fade, &[t]); }; chain.add_filter(&fade_out, nr, filter_type); @@ -343,7 +349,9 @@ fn overlay(node: &mut Media, chain: &mut Filters, config: &PlayoutConfig) { if !config.processing.logo_scale.is_empty() { scale = match &ADVANCED_CONFIG.decoder.filters.overlay_logo_scale { - Some(logo_scale) => custom_format(logo_scale, &[&config.processing.logo_scale]), + Some(logo_scale) => { + custom_format(&format!(",{logo_scale}"), &[&config.processing.logo_scale]) + } None => format!(",scale={}", config.processing.logo_scale), } } diff --git a/lib/src/utils/advanced_config.rs b/lib/src/utils/advanced_config.rs index 1f5a6d01..24017ed3 100644 --- a/lib/src/utils/advanced_config.rs +++ b/lib/src/utils/advanced_config.rs @@ -59,6 +59,8 @@ pub struct Filters { pub drawtext_from_file: Option, pub drawtext_from_zmq: Option, pub aevalsrc: Option, + pub afade_in: Option, + pub afade_out: Option, pub apad: Option, pub volume: Option, pub split: Option,