Merge pull request #144 from jb-alvarado/master
better support for HLS multiple resolutions
This commit is contained in:
commit
6df3f69c99
28
Cargo.lock
generated
28
Cargo.lock
generated
@ -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"
|
||||||
|
@ -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
|
||||||
|
@ -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.
|
||||||
|
@ -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]
|
||||||
|
@ -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]
|
||||||
|
@ -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> {
|
||||||
|
Loading…
Reference in New Issue
Block a user