Merge pull request #589 from jb-alvarado/master

v0.21.0-beta3
This commit is contained in:
jb-alvarado 2024-04-11 10:27:03 +00:00 committed by GitHub
commit b39d70f2fc
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
11 changed files with 108 additions and 44 deletions

8
Cargo.lock generated
View File

@ -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",

View File

@ -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 <jonbae77@gmail.com>"]

View File

@ -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

View File

@ -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)**

57
docs/advanced_settings.md Normal file
View File

@ -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!

View File

@ -1,4 +1,4 @@
### Possible endpoints
## Possible endpoints
Run the API thru the systemd service, or like:

View File

@ -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 <yellow>{}</> seconds", *shift);
time_sec += *shift;
info!("Shift playlist start for <yellow>{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

View File

@ -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);

View File

@ -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,18 +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(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(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);
@ -340,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),
}
}
@ -350,11 +361,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
)
};

View File

@ -59,6 +59,8 @@ pub struct Filters {
pub drawtext_from_file: Option<String>,
pub drawtext_from_zmq: Option<String>,
pub aevalsrc: Option<String>,
pub afade_in: Option<String>,
pub afade_out: Option<String>,
pub apad: Option<String>,
pub volume: Option<String>,
pub split: Option<String>,

View File

@ -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!(