From b85be0cb822d0b276e96fe6a1f1dd2b85b0796be Mon Sep 17 00:00:00 2001 From: jb-alvarado Date: Thu, 11 Apr 2024 12:19:45 +0200 Subject: [PATCH] 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,