0.24.0-beta5
- reorganize help - switch back to beta version - add docs for closed cations - unify playlist/playlist-root argument - colorize ads - add vtt_* to update config handler - update packages - add -muxpreload 0 and -muxdelay 0 to default settings
This commit is contained in:
parent
7af0d9a352
commit
7bfaa4a2d0
106
Cargo.lock
generated
106
Cargo.lock
generated
@ -549,9 +549,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "async-trait"
|
name = "async-trait"
|
||||||
version = "0.1.82"
|
version = "0.1.83"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a27b8a3a6e1a44fa4c8baf1f653e4172e81486d4941f2237e20dc2d0cf4ddff1"
|
checksum = "721cae7de5c34fbb2acd27e21e6d2cf7b886dce0c27388d46c4e6c47ea4318dd"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
@ -582,9 +582,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "autocfg"
|
name = "autocfg"
|
||||||
version = "1.3.0"
|
version = "1.4.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0"
|
checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "awc"
|
name = "awc"
|
||||||
@ -793,9 +793,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "clap"
|
name = "clap"
|
||||||
version = "4.5.17"
|
version = "4.5.18"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3e5a21b8495e732f1b3c364c9949b201ca7bae518c502c80256c96ad79eaf6ac"
|
checksum = "b0956a43b323ac1afaffc053ed5c4b7c1f1800bacd1683c353aabbb752515dd3"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"clap_builder",
|
"clap_builder",
|
||||||
"clap_derive",
|
"clap_derive",
|
||||||
@ -803,9 +803,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "clap_builder"
|
name = "clap_builder"
|
||||||
version = "4.5.17"
|
version = "4.5.18"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8cf2dd12af7a047ad9d6da2b6b249759a22a7abc0f474c1dae1777afa4b21a73"
|
checksum = "4d72166dd41634086d5803a47eb71ae740e61d84709c36f3c34110173db3961b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anstream",
|
"anstream",
|
||||||
"anstyle",
|
"anstyle",
|
||||||
@ -815,9 +815,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "clap_derive"
|
name = "clap_derive"
|
||||||
version = "4.5.13"
|
version = "4.5.18"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "501d359d5f3dcaf6ecdeee48833ae73ec6e42723a1e52419c79abf9507eec0a0"
|
checksum = "4ac6a0c7b1a9e9a5186361f67dfa1b88213572f427fb9ab038efb2bd8c582dab"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"heck",
|
"heck",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
@ -1215,7 +1215,7 @@ checksum = "e8c02a5121d4ea3eb16a80748c74f5549a5665e4c21333c6098f283870fbdea6"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ffplayout"
|
name = "ffplayout"
|
||||||
version = "0.24.0-rc1"
|
version = "0.24.0-beta5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"actix-files",
|
"actix-files",
|
||||||
"actix-multipart",
|
"actix-multipart",
|
||||||
@ -1314,9 +1314,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "flate2"
|
name = "flate2"
|
||||||
version = "1.0.33"
|
version = "1.0.34"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "324a1be68054ef05ad64b861cc9eaf1d623d2d8cb25b4bf2cb9cdd902b4bf253"
|
checksum = "a1b589b4dc103969ad3cf85c950899926ec64300a1a46d76c03a6072957036f0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"crc32fast",
|
"crc32fast",
|
||||||
"miniz_oxide",
|
"miniz_oxide",
|
||||||
@ -1697,9 +1697,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hyper-util"
|
name = "hyper-util"
|
||||||
version = "0.1.8"
|
version = "0.1.9"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "da62f120a8a37763efb0cf8fdf264b884c7b8b9ac8660b900c8661030c00e6ba"
|
checksum = "41296eb09f183ac68eec06e03cdbea2e759633d4067b2f6552fc2e009bcad08b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bytes",
|
"bytes",
|
||||||
"futures-channel",
|
"futures-channel",
|
||||||
@ -1710,7 +1710,6 @@ dependencies = [
|
|||||||
"pin-project-lite",
|
"pin-project-lite",
|
||||||
"socket2",
|
"socket2",
|
||||||
"tokio",
|
"tokio",
|
||||||
"tower",
|
|
||||||
"tower-service",
|
"tower-service",
|
||||||
"tracing",
|
"tracing",
|
||||||
]
|
]
|
||||||
@ -2068,9 +2067,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libc"
|
name = "libc"
|
||||||
version = "0.2.158"
|
version = "0.2.159"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d8adc4bb1803a324070e64a98ae98f38934d91957a99cfb3a43dcbc01bc56439"
|
checksum = "561d97a539a36e26a9a5fad1ea11a3039a67714694aaa379433e580854bc3dc5"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libm"
|
name = "libm"
|
||||||
@ -2520,26 +2519,6 @@ version = "2.3.1"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e"
|
checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "pin-project"
|
|
||||||
version = "1.1.5"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "b6bf43b791c5b9e34c3d182969b4abb522f9343702850a2e57f460d00d09b4b3"
|
|
||||||
dependencies = [
|
|
||||||
"pin-project-internal",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "pin-project-internal"
|
|
||||||
version = "1.1.5"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965"
|
|
||||||
dependencies = [
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"syn 2.0.77",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pin-project-lite"
|
name = "pin-project-lite"
|
||||||
version = "0.2.14"
|
version = "0.2.14"
|
||||||
@ -2575,9 +2554,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pkg-config"
|
name = "pkg-config"
|
||||||
version = "0.3.30"
|
version = "0.3.31"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec"
|
checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "powerfmt"
|
name = "powerfmt"
|
||||||
@ -2739,9 +2718,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "redox_syscall"
|
name = "redox_syscall"
|
||||||
version = "0.5.4"
|
version = "0.5.6"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0884ad60e090bf1345b93da0a5de8923c93884cd03f40dfcfddd3b4bee661853"
|
checksum = "355ae415ccd3a04315d3f8246e86d67689ea74d88d915576e1589a351062a13b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 2.6.0",
|
"bitflags 2.6.0",
|
||||||
]
|
]
|
||||||
@ -3089,9 +3068,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde_spanned"
|
name = "serde_spanned"
|
||||||
version = "0.6.7"
|
version = "0.6.8"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "eb5b1b31579f3811bf615c144393417496f152e12ac8b7663bf664f4a815306d"
|
checksum = "87607cb1398ed59d48732e575a4c28a7a8ebf2454b964fe3f224f2afc07909e1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"serde",
|
"serde",
|
||||||
]
|
]
|
||||||
@ -3681,7 +3660,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tests"
|
name = "tests"
|
||||||
version = "0.24.0-rc1"
|
version = "0.24.0-beta5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"actix-rt",
|
"actix-rt",
|
||||||
"actix-test",
|
"actix-test",
|
||||||
@ -3711,18 +3690,18 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "thiserror"
|
name = "thiserror"
|
||||||
version = "1.0.63"
|
version = "1.0.64"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c0342370b38b6a11b6cc11d6a805569958d54cfa061a29969c3b5ce2ea405724"
|
checksum = "d50af8abc119fb8bb6dbabcfa89656f46f84aa0ac7688088608076ad2b459a84"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"thiserror-impl",
|
"thiserror-impl",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "thiserror-impl"
|
name = "thiserror-impl"
|
||||||
version = "1.0.63"
|
version = "1.0.64"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261"
|
checksum = "08904e7672f5eb876eaaf87e0ce17857500934f4981c4a0ab2b4aa98baac7fc3"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
@ -3861,9 +3840,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "toml_edit"
|
name = "toml_edit"
|
||||||
version = "0.22.21"
|
version = "0.22.22"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3b072cee73c449a636ffd6f32bd8de3a9f7119139aff882f44943ce2986dc5cf"
|
checksum = "4ae48d6208a266e853d946088ed816055e556cc6028c5e8e2b84d9fa5dd7c7f5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"indexmap 2.5.0",
|
"indexmap 2.5.0",
|
||||||
"serde",
|
"serde",
|
||||||
@ -3872,27 +3851,6 @@ dependencies = [
|
|||||||
"winnow",
|
"winnow",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "tower"
|
|
||||||
version = "0.4.13"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c"
|
|
||||||
dependencies = [
|
|
||||||
"futures-core",
|
|
||||||
"futures-util",
|
|
||||||
"pin-project",
|
|
||||||
"pin-project-lite",
|
|
||||||
"tokio",
|
|
||||||
"tower-layer",
|
|
||||||
"tower-service",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "tower-layer"
|
|
||||||
version = "0.3.3"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tower-service"
|
name = "tower-service"
|
||||||
version = "0.3.3"
|
version = "0.3.3"
|
||||||
@ -4495,9 +4453,9 @@ checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "winnow"
|
name = "winnow"
|
||||||
version = "0.6.18"
|
version = "0.6.20"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "68a9bda4691f099d435ad181000724da8e5899daa10713c2d432552b9ccd3a6f"
|
checksum = "36c1fec1a2bb5866f07c25f68c26e565c4c200aebb96d7e55710c19d3e8ac49b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"memchr",
|
"memchr",
|
||||||
]
|
]
|
||||||
|
@ -3,7 +3,7 @@ members = ["engine", "tests"]
|
|||||||
resolver = "2"
|
resolver = "2"
|
||||||
|
|
||||||
[workspace.package]
|
[workspace.package]
|
||||||
version = "0.24.0-rc1"
|
version = "0.24.0-beta5"
|
||||||
license = "GPL-3.0"
|
license = "GPL-3.0"
|
||||||
repository = "https://github.com/ffplayout/ffplayout"
|
repository = "https://github.com/ffplayout/ffplayout"
|
||||||
authors = ["Jonathan Baecker <jonbae77@gmail.com>"]
|
authors = ["Jonathan Baecker <jonbae77@gmail.com>"]
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
[![License: GPL v3](https://img.shields.io/badge/License-GPLv3-blue.svg)](https://www.gnu.org/licenses/gpl-3.0)
|
[![License: GPL v3](https://img.shields.io/badge/License-GPLv3-blue.svg)](https://www.gnu.org/licenses/gpl-3.0)
|
||||||
|
|
||||||
## **ffplayout-engine (ffplayout)**
|
![player](/docs/images/player.png)
|
||||||
|
|
||||||
[ffplayout](/ffplayout-engine/README.md) is a 24/7 broadcasting solution. It can playout a folder containing audio or video clips, or play a *JSON* playlist for each day, keeping the current playlist editable.
|
[ffplayout](/ffplayout-engine/README.md) is a 24/7 broadcasting solution. It can playout a folder containing audio or video clips, or play a *JSON* playlist for each day, keeping the current playlist editable.
|
||||||
|
|
||||||
|
23
docs/closed_captions.md
Normal file
23
docs/closed_captions.md
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
## Closed Captions
|
||||||
|
|
||||||
|
#### Note:
|
||||||
|
**This is only an _experimental feature_. Please be aware that bugs and unexpected behavior may occur. To utilize this feature, a [special patched](https://github.com/jb-alvarado/compile-ffmpeg-osx-linux) version of FFmpeg is required. Importantly, there is currently no official support for this functionality.**
|
||||||
|
|
||||||
|
### Usage
|
||||||
|
**ffplayout** can handle closed captions in WebVTT format for HLS streaming.
|
||||||
|
|
||||||
|
The captions can be embedded in the file, such as in a [Matroska](https://www.matroska.org/technical/subtitles.html) file, or they can be a separate *.vtt file that shares the same filename as the video file. In either case, the processing option **vtt_enable** must be enabled, and the path to the **vtt_dummy** file must exist.
|
||||||
|
|
||||||
|
To encode the closed captions, the **hls** mode needs to be enabled, and specific output parameters must be provided. Here’s an example:
|
||||||
|
|
||||||
|
```
|
||||||
|
-c:v libx264 -crf 23 -x264-params keyint=50:min-keyint=25:scenecut=-1 \
|
||||||
|
-maxrate 1300k -bufsize 2600k -preset faster -tune zerolatency \
|
||||||
|
-profile:v Main -level 3.1 -c:a aac -ar 44100 -b:a 128k -flags +cgop \
|
||||||
|
-muxpreload 0 -muxdelay 0 -f hls -hls_time 6 -hls_list_size 600 \
|
||||||
|
-hls_flags append_list+delete_segments+omit_endlist \
|
||||||
|
-var_stream_map v:0,a:0,s:0,sgroup:subs,name:English,language:en-US,default:YES \
|
||||||
|
-master_pl_name master.m3u8 \
|
||||||
|
-hls_segment_filename \
|
||||||
|
live/stream-%d.ts live/stream.m3u8
|
||||||
|
```
|
@ -211,7 +211,7 @@ pub async fn update_configuration(
|
|||||||
id: i32,
|
id: i32,
|
||||||
config: PlayoutConfig,
|
config: PlayoutConfig,
|
||||||
) -> Result<SqliteQueryResult, sqlx::Error> {
|
) -> Result<SqliteQueryResult, sqlx::Error> {
|
||||||
let query = "UPDATE configurations SET general_stop_threshold = $2, mail_subject = $3, mail_smtp = $4, mail_addr = $5, mail_pass = $6, mail_recipient = $7, mail_starttls = $8, mail_level = $9, mail_interval = $10, logging_ffmpeg_level = $11, logging_ingest_level = $12, logging_detect_silence = $13, logging_ignore = $14, processing_mode = $15, processing_audio_only = $16, processing_copy_audio = $17, processing_copy_video = $18, processing_width = $19, processing_height = $20, processing_aspect = $21, processing_fps = $22, processing_add_logo = $23, processing_logo = $24, processing_logo_scale = $25, processing_logo_opacity = $26, processing_logo_position = $27, processing_audio_tracks = $28, processing_audio_track_index = $29, processing_audio_channels = $30, processing_volume = $31, processing_filter = $32, ingest_enable = $33, ingest_param = $34, ingest_filter = $35, playlist_day_start = $36, playlist_length = $37, playlist_infinit = $38, storage_filler = $39, storage_extensions = $40, storage_shuffle = $41, text_add = $42, text_from_filename = $43, text_font = $44, text_style = $45, text_regex = $46, task_enable = $47, task_path = $48, output_mode = $49, output_param = $50 WHERE id = $1";
|
let query = "UPDATE configurations SET general_stop_threshold = $2, mail_subject = $3, mail_smtp = $4, mail_addr = $5, mail_pass = $6, mail_recipient = $7, mail_starttls = $8, mail_level = $9, mail_interval = $10, logging_ffmpeg_level = $11, logging_ingest_level = $12, logging_detect_silence = $13, logging_ignore = $14, processing_mode = $15, processing_audio_only = $16, processing_copy_audio = $17, processing_copy_video = $18, processing_width = $19, processing_height = $20, processing_aspect = $21, processing_fps = $22, processing_add_logo = $23, processing_logo = $24, processing_logo_scale = $25, processing_logo_opacity = $26, processing_logo_position = $27, processing_audio_tracks = $28, processing_audio_track_index = $29, processing_audio_channels = $30, processing_volume = $31, processing_filter = $32, processing_vtt_enable = $33, processing_vtt_dummy = $34, ingest_enable = $35, ingest_param = $36, ingest_filter = $37, playlist_day_start = $38, playlist_length = $39, playlist_infinit = $40, storage_filler = $41, storage_extensions = $42, storage_shuffle = $43, text_add = $44, text_from_filename = $45, text_font = $46, text_style = $47, text_regex = $48, task_enable = $49, task_path = $50, output_mode = $51, output_param = $52 WHERE id = $1";
|
||||||
|
|
||||||
sqlx::query(query)
|
sqlx::query(query)
|
||||||
.bind(id)
|
.bind(id)
|
||||||
@ -246,6 +246,8 @@ pub async fn update_configuration(
|
|||||||
.bind(config.processing.audio_channels)
|
.bind(config.processing.audio_channels)
|
||||||
.bind(config.processing.volume)
|
.bind(config.processing.volume)
|
||||||
.bind(config.processing.custom_filter)
|
.bind(config.processing.custom_filter)
|
||||||
|
.bind(config.processing.vtt_enable)
|
||||||
|
.bind(config.processing.vtt_dummy)
|
||||||
.bind(config.ingest.enable)
|
.bind(config.ingest.enable)
|
||||||
.bind(config.ingest.input_param)
|
.bind(config.ingest.input_param)
|
||||||
.bind(config.ingest.custom_filter)
|
.bind(config.ingest.custom_filter)
|
||||||
|
@ -625,6 +625,10 @@ pub fn loop_image(config: &PlayoutConfig, node: &Media) -> Vec<String> {
|
|||||||
.storage_path
|
.storage_path
|
||||||
.join(config.processing.vtt_dummy.clone().unwrap_or_default());
|
.join(config.processing.vtt_dummy.clone().unwrap_or_default());
|
||||||
|
|
||||||
|
if node.seek > 0.5 {
|
||||||
|
source_cmd.append(&mut vec_strings!["-ss", node.seek]);
|
||||||
|
}
|
||||||
|
|
||||||
if vtt_file.is_file() {
|
if vtt_file.is_file() {
|
||||||
source_cmd.append(&mut vec_strings![
|
source_cmd.append(&mut vec_strings![
|
||||||
"-i",
|
"-i",
|
||||||
@ -732,6 +736,10 @@ pub fn seek_and_length(config: &PlayoutConfig, node: &mut Media) -> Vec<String>
|
|||||||
.storage_path
|
.storage_path
|
||||||
.join(config.processing.vtt_dummy.clone().unwrap_or_default());
|
.join(config.processing.vtt_dummy.clone().unwrap_or_default());
|
||||||
|
|
||||||
|
if node.seek > 0.5 {
|
||||||
|
source_cmd.append(&mut vec_strings!["-ss", node.seek]);
|
||||||
|
}
|
||||||
|
|
||||||
if vtt_file.is_file() {
|
if vtt_file.is_file() {
|
||||||
if loop_count > 1 {
|
if loop_count > 1 {
|
||||||
source_cmd.append(&mut vec_strings!["-stream_loop", loop_count]);
|
source_cmd.append(&mut vec_strings!["-stream_loop", loop_count]);
|
||||||
|
@ -30,7 +30,12 @@ use crate::utils::db_path;
|
|||||||
#[derive(Parser, Debug, Clone)]
|
#[derive(Parser, Debug, Clone)]
|
||||||
#[clap(version,
|
#[clap(version,
|
||||||
about = "ffplayout - 24/7 broadcasting solution",
|
about = "ffplayout - 24/7 broadcasting solution",
|
||||||
long_about = None)]
|
long_about = Some("ffplayout - 24/7 broadcasting solution\n
|
||||||
|
Stream dynamic playlists or folder contents with the power of ffmpeg.
|
||||||
|
The target can be an HLS playlist, rtmp/srt/udp server, desktop player
|
||||||
|
or any other output supported by ffmpeg.\n
|
||||||
|
ffplayout also provides a web frontend and API to control streaming,
|
||||||
|
manage config, files, text overlay, etc. "))]
|
||||||
pub struct Args {
|
pub struct Args {
|
||||||
#[clap(
|
#[clap(
|
||||||
short,
|
short,
|
||||||
@ -43,20 +48,6 @@ pub struct Args {
|
|||||||
#[clap(short, long, help_heading = Some("Initial Setup"), help = "Add a global admin user")]
|
#[clap(short, long, help_heading = Some("Initial Setup"), help = "Add a global admin user")]
|
||||||
pub add: bool,
|
pub add: bool,
|
||||||
|
|
||||||
#[clap(long, env, help_heading = Some("Initial Setup"), help = "Playlist root path")]
|
|
||||||
pub playlist_root: Option<String>,
|
|
||||||
|
|
||||||
#[clap(long, env, help_heading = Some("Initial Setup"), help = "Storage root path")]
|
|
||||||
pub storage_root: Option<String>,
|
|
||||||
|
|
||||||
#[clap(
|
|
||||||
long,
|
|
||||||
env,
|
|
||||||
help_heading = Some("Initial Setup"),
|
|
||||||
help = "Share storage root across channels, important for running in Container"
|
|
||||||
)]
|
|
||||||
pub shared_storage: bool,
|
|
||||||
|
|
||||||
#[clap(short, long, help_heading = Some("Initial Setup"), help = "Create admin user")]
|
#[clap(short, long, help_heading = Some("Initial Setup"), help = "Create admin user")]
|
||||||
pub username: Option<String>,
|
pub username: Option<String>,
|
||||||
|
|
||||||
@ -66,18 +57,31 @@ pub struct Args {
|
|||||||
#[clap(short, long, help_heading = Some("Initial Setup"), help = "Admin password")]
|
#[clap(short, long, help_heading = Some("Initial Setup"), help = "Admin password")]
|
||||||
pub password: Option<String>,
|
pub password: Option<String>,
|
||||||
|
|
||||||
#[clap(long, env, help_heading = Some("Initial Setup"), help = "Logging path")]
|
#[clap(long, env, help_heading = Some("Initial Setup"), help = "Storage root path")]
|
||||||
|
pub storage: Option<String>,
|
||||||
|
|
||||||
|
#[clap(
|
||||||
|
long,
|
||||||
|
env,
|
||||||
|
help_heading = Some("Initial Setup"),
|
||||||
|
help = "Share storage across channels, important for running in Containers"
|
||||||
|
)]
|
||||||
|
pub shared_storage: bool,
|
||||||
|
|
||||||
|
#[clap(long, env, help_heading = Some("Initial Setup / General"), help = "Logging path")]
|
||||||
pub log_path: Option<PathBuf>,
|
pub log_path: Option<PathBuf>,
|
||||||
|
|
||||||
#[clap(long, env, help_heading = Some("Initial Setup"), help = "Path to public files, also HLS playlists")]
|
#[clap(long, env, help_heading = Some("Initial Setup / General"), help = "Path to public files, also HLS playlists")]
|
||||||
pub public: Option<String>,
|
pub public: Option<String>,
|
||||||
|
|
||||||
|
#[clap(long, help_heading = Some("Initial Setup / Playlist"), help = "Path to playlist, or playlist root folder.")]
|
||||||
|
pub playlist: Option<String>,
|
||||||
|
|
||||||
#[clap(long, env, help_heading = Some("General"), help = "Path to database file")]
|
#[clap(long, env, help_heading = Some("General"), help = "Path to database file")]
|
||||||
pub db: Option<PathBuf>,
|
pub db: Option<PathBuf>,
|
||||||
|
|
||||||
#[clap(
|
#[clap(
|
||||||
long,
|
long,
|
||||||
env,
|
|
||||||
help_heading = Some("General"),
|
help_heading = Some("General"),
|
||||||
help = "Drop database. WARNING: this will delete all configurations!"
|
help = "Drop database. WARNING: this will delete all configurations!"
|
||||||
)]
|
)]
|
||||||
@ -110,6 +114,27 @@ pub struct Args {
|
|||||||
#[clap(short, env, long, help_heading = Some("General"), help = "Listen on IP:PORT, like: 127.0.0.1:8787")]
|
#[clap(short, env, long, help_heading = Some("General"), help = "Listen on IP:PORT, like: 127.0.0.1:8787")]
|
||||||
pub listen: Option<String>,
|
pub listen: Option<String>,
|
||||||
|
|
||||||
|
#[clap(
|
||||||
|
long,
|
||||||
|
env,
|
||||||
|
help_heading = Some("General"),
|
||||||
|
help = "Override logging level: trace, debug, println, warn, eprintln"
|
||||||
|
)]
|
||||||
|
pub log_level: Option<String>,
|
||||||
|
|
||||||
|
#[clap(long, env, help_heading = Some("General"), help = "Log to console")]
|
||||||
|
pub log_to_console: bool,
|
||||||
|
|
||||||
|
#[clap(
|
||||||
|
short,
|
||||||
|
long,
|
||||||
|
env,
|
||||||
|
help_heading = Some("General / Playout"),
|
||||||
|
help = "Channels by ids to process (for export config, foreground running, etc.)",
|
||||||
|
num_args = 1..,
|
||||||
|
)]
|
||||||
|
pub channels: Option<Vec<i32>>,
|
||||||
|
|
||||||
#[clap(
|
#[clap(
|
||||||
short,
|
short,
|
||||||
long,
|
long,
|
||||||
@ -123,9 +148,6 @@ pub struct Args {
|
|||||||
#[clap(long, help_heading = Some("Playlist"), help = "Optional path list for playlist generations", num_args = 1..)]
|
#[clap(long, help_heading = Some("Playlist"), help = "Optional path list for playlist generations", num_args = 1..)]
|
||||||
pub paths: Option<Vec<PathBuf>>,
|
pub paths: Option<Vec<PathBuf>>,
|
||||||
|
|
||||||
#[clap(long, help_heading = Some("Playlist"), help = "Path to playlist, or playlist root folder.")]
|
|
||||||
pub playlist: Option<PathBuf>,
|
|
||||||
|
|
||||||
#[clap(
|
#[clap(
|
||||||
short,
|
short,
|
||||||
long,
|
long,
|
||||||
@ -134,22 +156,12 @@ pub struct Args {
|
|||||||
)]
|
)]
|
||||||
pub start: Option<String>,
|
pub start: Option<String>,
|
||||||
|
|
||||||
#[clap(short = 'T', long, help_heading = Some("Playlist"), help = "JSON Template file for generating playlist")]
|
#[clap(short = 'T', long, help_heading = Some("Playlist"), help = "JSON template file for generating playlist")]
|
||||||
pub template: Option<PathBuf>,
|
pub template: Option<PathBuf>,
|
||||||
|
|
||||||
#[clap(long, help_heading = Some("Playlist"), help = "Only validate given playlist")]
|
#[clap(long, help_heading = Some("Playlist"), help = "Only validate given playlist")]
|
||||||
pub validate: bool,
|
pub validate: bool,
|
||||||
|
|
||||||
#[clap(
|
|
||||||
short,
|
|
||||||
long,
|
|
||||||
env,
|
|
||||||
help_heading = Some("Playout"),
|
|
||||||
help = "Channels by ids to process (for foreground, etc.)",
|
|
||||||
num_args = 1..,
|
|
||||||
)]
|
|
||||||
pub channels: Option<Vec<i32>>,
|
|
||||||
|
|
||||||
#[clap(long, env, help_heading = Some("Playout"), help = "Run playout without webserver and frontend.")]
|
#[clap(long, env, help_heading = Some("Playout"), help = "Run playout without webserver and frontend.")]
|
||||||
pub foreground: bool,
|
pub foreground: bool,
|
||||||
|
|
||||||
@ -159,17 +171,6 @@ pub struct Args {
|
|||||||
#[clap(long, env, help_heading = Some("Playout"), help = "Keep log file for given days")]
|
#[clap(long, env, help_heading = Some("Playout"), help = "Keep log file for given days")]
|
||||||
pub log_backup_count: Option<usize>,
|
pub log_backup_count: Option<usize>,
|
||||||
|
|
||||||
#[clap(
|
|
||||||
long,
|
|
||||||
env,
|
|
||||||
help_heading = Some("Playout"),
|
|
||||||
help = "Override logging level: trace, debug, println, warn, eprintln"
|
|
||||||
)]
|
|
||||||
pub log_level: Option<String>,
|
|
||||||
|
|
||||||
#[clap(long, env, help_heading = Some("Playout"), help = "Log to console")]
|
|
||||||
pub log_to_console: bool,
|
|
||||||
|
|
||||||
#[clap(short, long, help_heading = Some("Playout"), help = "Set output mode: desktop, hls, null, stream")]
|
#[clap(short, long, help_heading = Some("Playout"), help = "Set output mode: desktop, hls, null, stream")]
|
||||||
pub output: Option<OutputMode>,
|
pub output: Option<OutputMode>,
|
||||||
|
|
||||||
@ -393,8 +394,8 @@ pub async fn run_args(pool: &Pool<Sqlite>) -> Result<(), i32> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if !args.init
|
if !args.init
|
||||||
&& args.storage_root.is_some()
|
&& args.storage.is_some()
|
||||||
&& args.playlist_root.is_some()
|
&& args.playlist.is_some()
|
||||||
&& args.public.is_some()
|
&& args.public.is_some()
|
||||||
&& args.log_path.is_some()
|
&& args.log_path.is_some()
|
||||||
{
|
{
|
||||||
@ -404,9 +405,9 @@ pub async fn run_args(pool: &Pool<Sqlite>) -> Result<(), i32> {
|
|||||||
id: 0,
|
id: 0,
|
||||||
secret: None,
|
secret: None,
|
||||||
logging_path: args.log_path.unwrap().to_string_lossy().to_string(),
|
logging_path: args.log_path.unwrap().to_string_lossy().to_string(),
|
||||||
playlist_root: args.playlist_root.unwrap(),
|
playlist_root: args.playlist.unwrap(),
|
||||||
public_root: args.public.unwrap(),
|
public_root: args.public.unwrap(),
|
||||||
storage_root: args.storage_root.unwrap(),
|
storage_root: args.storage.unwrap(),
|
||||||
shared_storage: args.shared_storage,
|
shared_storage: args.shared_storage,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -851,7 +851,7 @@ pub async fn get_config(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if let Some(playlist) = args.playlist {
|
if let Some(playlist) = args.playlist {
|
||||||
config.channel.playlist_path = playlist;
|
config.channel.playlist_path = PathBuf::from(&playlist);
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(folder) = args.folder {
|
if let Some(folder) = args.folder {
|
||||||
|
@ -15,12 +15,10 @@
|
|||||||
class="form-control w-full"
|
class="form-control w-full"
|
||||||
:class="[typeof prop === 'boolean' && 'flex-row', name.toString() !== 'help_text' && 'mt-2']"
|
:class="[typeof prop === 'boolean' && 'flex-row', name.toString() !== 'help_text' && 'mt-2']"
|
||||||
>
|
>
|
||||||
<!-- TODO: vtt_ check is temporary, needs to be removed when is done implemented -->
|
|
||||||
<template
|
<template
|
||||||
v-if="
|
v-if="
|
||||||
name.toString() !== 'startInSec' &&
|
name.toString() !== 'startInSec' &&
|
||||||
name.toString() !== 'lengthInSec' &&
|
name.toString() !== 'lengthInSec' &&
|
||||||
!name.startsWith('vtt_') &&
|
|
||||||
!(name.toString() === 'path' && key.toString() === 'storage')
|
!(name.toString() === 'path' && key.toString() === 'storage')
|
||||||
"
|
"
|
||||||
>
|
>
|
||||||
|
@ -78,7 +78,7 @@
|
|||||||
'!bg-lime-500/30':
|
'!bg-lime-500/30':
|
||||||
playlistStore.playoutIsRunning && listDate === todayDate && index === currentIndex,
|
playlistStore.playoutIsRunning && listDate === todayDate && index === currentIndex,
|
||||||
'!bg-amber-600/40': element.overtime,
|
'!bg-amber-600/40': element.overtime,
|
||||||
'text-base-content/50': element.category === 'advertisement',
|
'text-blue-300': element.category === 'advertisement',
|
||||||
}"
|
}"
|
||||||
>
|
>
|
||||||
<td v-if="!configStore.playout.playlist.infinit" class="ps-4 py-2 text-left">
|
<td v-if="!configStore.playout.playlist.infinit" class="ps-4 py-2 text-left">
|
||||||
|
@ -138,7 +138,7 @@ CREATE TABLE
|
|||||||
task_path TEXT NOT NULL DEFAULT "",
|
task_path TEXT NOT NULL DEFAULT "",
|
||||||
output_help TEXT NOT NULL DEFAULT "The final playout compression. Set the settings to your needs. 'mode' has the options 'desktop', 'hls', 'null', 'stream'. Use 'stream' and adjust 'output_param:' settings when you want to stream to a rtmp/rtsp/srt/... server.\nIn production don't serve hls playlist with ffplayout, use nginx or another web server!",
|
output_help TEXT NOT NULL DEFAULT "The final playout compression. Set the settings to your needs. 'mode' has the options 'desktop', 'hls', 'null', 'stream'. Use 'stream' and adjust 'output_param:' settings when you want to stream to a rtmp/rtsp/srt/... server.\nIn production don't serve hls playlist with ffplayout, use nginx or another web server!",
|
||||||
output_mode TEXT NOT NULL DEFAULT "hls",
|
output_mode TEXT NOT NULL DEFAULT "hls",
|
||||||
output_param TEXT NOT NULL DEFAULT "-c:v libx264 -crf 23 -x264-params keyint=50:min-keyint=25:scenecut=-1 -maxrate 1300k -bufsize 2600k -preset faster -tune zerolatency -profile:v Main -level 3.1 -c:a aac -ar 44100 -b:a 128k -flags +cgop -f hls -hls_time 6 -hls_list_size 600 -hls_flags append_list+delete_segments+omit_endlist -hls_segment_filename live/stream-%d.ts live/stream.m3u8",
|
output_param TEXT NOT NULL DEFAULT "-c:v libx264 -crf 23 -x264-params keyint=50:min-keyint=25:scenecut=-1 -maxrate 1300k -bufsize 2600k -preset faster -tune zerolatency -profile:v Main -level 3.1 -c:a aac -ar 44100 -b:a 128k -flags +cgop -muxpreload 0 -muxdelay 0 -f hls -hls_time 6 -hls_list_size 600 -hls_flags append_list+delete_segments+omit_endlist -hls_segment_filename live/stream-%d.ts live/stream.m3u8",
|
||||||
FOREIGN KEY (channel_id) REFERENCES channels (id) ON UPDATE CASCADE ON DELETE CASCADE
|
FOREIGN KEY (channel_id) REFERENCES channels (id) ON UPDATE CASCADE ON DELETE CASCADE
|
||||||
);
|
);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user