Merge pull request #144 from jb-alvarado/master

better support for HLS multiple resolutions
This commit is contained in:
jb-alvarado 2022-06-30 09:42:37 +02:00 committed by GitHub
commit 6df3f69c99
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 108 additions and 35 deletions

28
Cargo.lock generated
View File

@ -287,9 +287,9 @@ dependencies = [
[[package]] [[package]]
name = "argon2" name = "argon2"
version = "0.4.0" version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a27e27b63e4a34caee411ade944981136fdfa535522dc9944d6700196cbd899f" checksum = "db4ce4441f99dbd377ca8a8f57b698c44d0d6e712d8329b5040da5a64aa1ce73"
dependencies = [ dependencies = [
"base64ct", "base64ct",
"blake2", "blake2",
@ -636,9 +636,9 @@ dependencies = [
[[package]] [[package]]
name = "clap" name = "clap"
version = "3.2.6" version = "3.2.7"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9f1fe12880bae935d142c8702d500c63a4e8634b6c3c57ad72bf978fc7b6249a" checksum = "5b7b16274bb247b45177db843202209b12191b631a14a9d06e41b3777d6ecf14"
dependencies = [ dependencies = [
"atty", "atty",
"bitflags", "bitflags",
@ -653,9 +653,9 @@ dependencies = [
[[package]] [[package]]
name = "clap_derive" name = "clap_derive"
version = "3.2.6" version = "3.2.7"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ed6db9e867166a43a53f7199b5e4d1f522a1e5bd626654be263c999ce59df39a" checksum = "759bf187376e1afa7b85b959e6a664a3e7a95203415dba952ad19139e798f902"
dependencies = [ dependencies = [
"heck", "heck",
"proc-macro-error", "proc-macro-error",
@ -666,9 +666,9 @@ dependencies = [
[[package]] [[package]]
name = "clap_lex" name = "clap_lex"
version = "0.2.3" version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "87eba3c8c7f42ef17f6c659fc7416d0f4758cd3e58861ee63c5fa4a4dde649e4" checksum = "2850f2f5a82cbf437dd5af4d49848fbdfc27c157c3d010345776f952765261c5"
dependencies = [ dependencies = [
"os_str_bytes", "os_str_bytes",
] ]
@ -1009,7 +1009,7 @@ dependencies = [
[[package]] [[package]]
name = "ffplayout" name = "ffplayout"
version = "0.10.1" version = "0.10.2"
dependencies = [ dependencies = [
"clap", "clap",
"crossbeam-channel 0.5.5", "crossbeam-channel 0.5.5",
@ -1056,7 +1056,7 @@ dependencies = [
[[package]] [[package]]
name = "ffplayout-lib" name = "ffplayout-lib"
version = "0.10.1" version = "0.10.2"
dependencies = [ dependencies = [
"chrono 0.4.20-beta.1", "chrono 0.4.20-beta.1",
"crossbeam-channel 0.5.5", "crossbeam-channel 0.5.5",
@ -2150,9 +2150,9 @@ dependencies = [
[[package]] [[package]]
name = "password-hash" name = "password-hash"
version = "0.4.1" version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e029e94abc8fb0065241c308f1ac6bc8d20f450e8f7c5f0b25cd9b8d526ba294" checksum = "7676374caaee8a325c9e7a2ae557f216c5563a171d6997b0ef8a65af35147700"
dependencies = [ dependencies = [
"base64ct", "base64ct",
"rand_core 0.6.3", "rand_core 0.6.3",
@ -2542,9 +2542,9 @@ dependencies = [
[[package]] [[package]]
name = "semver" name = "semver"
version = "1.0.10" version = "1.0.11"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a41d061efea015927ac527063765e73601444cdc344ba855bc7bd44578b25e1c" checksum = "3d92beeab217753479be2f74e54187a6aed4c125ff0703a866c3147a02f0c6dd"
[[package]] [[package]]
name = "serde" name = "serde"

View File

@ -118,7 +118,7 @@ out:
help_text: The final playout compression. Set the settings to your needs. 'mode' help_text: The final playout compression. Set the settings to your needs. 'mode'
has the options 'desktop', 'hls', 'null', 'stream'. has the options 'desktop', 'hls', 'null', 'stream'.
'preview' works only in streaming output and creates a separate preview stream. 'preview' works only in streaming output and creates a separate preview stream.
mode: 'stream' mode: stream
preview: false preview: false
preview_param: >- preview_param: >-
-s 512x288 -s 512x288

View File

@ -14,33 +14,33 @@ For example you want to stream different resolutions, you could apply this outpu
... ...
output_param: >- output_param: >-
-c:v libx264 -c:v:0 libx264
-crf 23 -crf 23
-x264-params keyint=50:min-keyint=25:scenecut=-1 -x264-params keyint=50:min-keyint=25:scenecut=-1
-maxrate 1300k -maxrate:0 1300k
-bufsize 2600k -bufsize:0 2600k
-preset faster -preset faster
-tune zerolatency -tune zerolatency
-profile:v Main -profile:v Main
-level 3.1 -level 3.1
-c:a aac -c:a:0 aac
-ar 44100 -ar:0 44100
-b:a 128k -b:a:0 128k
-flags +global_header -flags +global_header
-f flv rtmp://example.org/live/stream-high -f flv rtmp://example.org/live/stream-high
-s 960x540 -s 960x540
-c:v libx264 -c:v:1 libx264
-crf 23 -crf 23
-x264-params keyint=50:min-keyint=25:scenecut=-1 -x264-params keyint=50:min-keyint=25:scenecut=-1
-maxrate 1000k -maxrate:1 1000k
-bufsize 1800k -bufsize:1 1800k
-preset faster -preset faster
-tune zerolatency -tune zerolatency
-profile:v Main -profile:v Main
-level 3.1 -level 3.1
-c:a aac -c:a:1 aac
-ar 44100 -ar:1 44100
-b:a 128k -b:a:1 128k
-flags +global_header -flags +global_header
-f flv rtmp://example.org/live/stream-low -f flv rtmp://example.org/live/stream-low
``` ```
@ -59,6 +59,67 @@ In desktop mode you will get your picture on screen. For this you need a desktop
In this mode you can output directly to a hls playlist. The nice thing here is, that ffplayout need less resources then in streaming mode. In this mode you can output directly to a hls playlist. The nice thing here is, that ffplayout need less resources then in streaming mode.
**HLS multiple outputs example:**
```YAML
...
output_param: >-
-filter_complex [0:v]split=3[v1_out][v2][v3];[v2]scale=w=960:h=540[v2_out];[v3]scale=w=640:h=360[v3_out];[0:a]asplit=3[a1][a2][a3]
-map [v1_out]
-map [a1]
-c:v:0 libx264
-crf 23
-x264-params keyint=50:min-keyint=25:scenecut=-1
-maxrate:0 2000k
-bufsize:0 3200k
-preset faster
-tune zerolatency
-profile:v Main
-flags +cgop
-c:a:0 aac
-ar:0 44100
-b:a:0 128k
-map [v2_out]
-map [a2]
-c:v:1 libx264
-crf 23
-x264-params keyint=50:min-keyint=25:scenecut=-1
-maxrate:1 1100k
-bufsize:1 2200k
-preset faster
-tune zerolatency
-profile:v Main
-flags +cgop
-c:a:1 aac
-ar:1 44100
-b:a:1 96k
-map [v3_out]
-map [a3]
-c:v:2 libx264
-crf 23
-x264-params keyint=50:min-keyint=25:scenecut=-1
-maxrate:2 800k
-bufsize:2 1400k
-preset faster
-tune zerolatency
-profile:v Main
-flags +cgop
-c:a:2 aac
-ar:2 44100
-b:a:2 64k
-f hls
-hls_time 6
-hls_list_size 600
-hls_flags append_list+delete_segments+omit_endlist+program_date_time
-hls_segment_filename /var/www/html/live/stream_%v-%d.ts
-master_pl_name master.m3u8
-var_stream_map "v:0,a:0,name:720p v:1,a:1,name:540p v:2,a:2,name:360p"
/var/www/html/live/stream_%v.m3u8
```
The using of **-filter_complex** and *mapping* is very limited, don't use it in situations other then for splitting the outputs.
#### Activating Output #### Activating Output
To use one of the outputs you need to edit the **ffplayout.yml** config, here under **out** set your **mode** and use the different **output** options. To use one of the outputs you need to edit the **ffplayout.yml** config, here under **out** set your **mode** and use the different **output** options.

View File

@ -4,7 +4,7 @@ description = "24/7 playout based on rust and ffmpeg"
license = "GPL-3.0" license = "GPL-3.0"
authors = ["Jonathan Baecker jonbae77@gmail.com"] authors = ["Jonathan Baecker jonbae77@gmail.com"]
readme = "README.md" readme = "README.md"
version = "0.10.1" version = "0.10.2"
edition = "2021" edition = "2021"
[dependencies] [dependencies]

View File

@ -4,7 +4,7 @@ description = "Library for ffplayout"
license = "GPL-3.0" license = "GPL-3.0"
authors = ["Jonathan Baecker jonbae77@gmail.com"] authors = ["Jonathan Baecker jonbae77@gmail.com"]
readme = "README.md" readme = "README.md"
version = "0.10.1" version = "0.10.2"
edition = "2021" edition = "2021"
[dependencies] [dependencies]

View File

@ -423,10 +423,6 @@ pub fn seek_and_length(src: String, seek: f64, out: f64, duration: f64) -> Vec<S
source_cmd source_cmd
} }
pub fn format_log_line(line: String, level: &str) -> String {
line.replace(&format!("[{level: >5}] "), "")
}
/// Prepare output parameters /// Prepare output parameters
/// ///
/// seek for multiple outputs and add mapping for it /// seek for multiple outputs and add mapping for it
@ -446,8 +442,15 @@ pub fn prepare_output_cmd(
if !filter.is_empty() { if !filter.is_empty() {
output_params.clear(); output_params.clear();
for (i, param) in params.iter().enumerate() { for (i, p) in params.iter().enumerate() {
let mut param = p.clone();
param = param.replace("[0:v]", "[vout1]");
param = param.replace("[0:a]", "[aout1]");
if param != "-filter_complex" {
output_params.push(param.clone()); output_params.push(param.clone());
}
if i > 0 if i > 0
&& !param.starts_with('-') && !param.starts_with('-')
@ -477,6 +480,11 @@ pub fn prepare_output_cmd(
filter.drain(2..); filter.drain(2..);
cmd.append(&mut filter); cmd.append(&mut filter);
cmd.append(&mut vec_strings!["-map", "[v_out1]", "-map", "[a_out1]"]); cmd.append(&mut vec_strings!["-map", "[v_out1]", "-map", "[a_out1]"]);
} else if output_count == 1 && mode == "hls" && output_params[0].contains("split") {
let out_filter = output_params.remove(0);
filter[1].push_str(format!(";{out_filter}").as_str());
filter.drain(2..);
cmd.append(&mut filter);
} else if output_count > 1 && mode == "stream" { } else if output_count > 1 && mode == "stream" {
filter[1].push_str(format!(",split={output_count}{output_v_map}").as_str()); filter[1].push_str(format!(",split={output_count}{output_v_map}").as_str());
cmd.append(&mut filter); cmd.append(&mut filter);
@ -506,6 +514,10 @@ pub fn valid_source(source: &str) -> bool {
Path::new(&source).is_file() Path::new(&source).is_file()
} }
pub fn format_log_line(line: String, level: &str) -> String {
line.replace(&format!("[{level: >5}] "), "")
}
/// Read ffmpeg stderr decoder and encoder instance /// Read ffmpeg stderr decoder and encoder instance
/// and log the output. /// and log the output.
pub fn stderr_reader(buffer: BufReader<ChildStderr>, suffix: &str) -> Result<(), Error> { pub fn stderr_reader(buffer: BufReader<ChildStderr>, suffix: &str) -> Result<(), Error> {