Merge pull request #629 from jb-alvarado/master
switch to toml, update frontend, make title optional
This commit is contained in:
commit
d41a485f40
1
.vscode/settings.json
vendored
1
.vscode/settings.json
vendored
@ -20,6 +20,7 @@
|
||||
"cSpell.words": [
|
||||
"actix",
|
||||
"rsplit",
|
||||
"starttls",
|
||||
"tokio",
|
||||
"uuids"
|
||||
]
|
||||
|
65
Cargo.lock
generated
65
Cargo.lock
generated
@ -1346,13 +1346,13 @@ dependencies = [
|
||||
"sanitize-filename",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"serde_yaml",
|
||||
"simplelog",
|
||||
"sqlx",
|
||||
"static-files",
|
||||
"sysinfo",
|
||||
"tokio",
|
||||
"tokio-stream",
|
||||
"toml_edit",
|
||||
"uuid",
|
||||
]
|
||||
|
||||
@ -1375,11 +1375,11 @@ dependencies = [
|
||||
"reqwest",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"serde_yaml",
|
||||
"shlex",
|
||||
"signal-child",
|
||||
"simplelog",
|
||||
"time",
|
||||
"toml_edit",
|
||||
"walkdir",
|
||||
"winapi",
|
||||
]
|
||||
@ -3068,6 +3068,15 @@ dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_spanned"
|
||||
version = "0.6.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "eb3622f419d1296904700073ea6cc23ad690adbd66f13ea683df73298736f0c1"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_urlencoded"
|
||||
version = "0.7.1"
|
||||
@ -3080,19 +3089,6 @@ dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_yaml"
|
||||
version = "0.9.34+deprecated"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47"
|
||||
dependencies = [
|
||||
"indexmap",
|
||||
"itoa",
|
||||
"ryu",
|
||||
"serde",
|
||||
"unsafe-libyaml",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serial_test"
|
||||
version = "3.1.0"
|
||||
@ -3593,11 +3589,11 @@ dependencies = [
|
||||
"reqwest",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"serde_yaml",
|
||||
"serial_test",
|
||||
"shlex",
|
||||
"simplelog",
|
||||
"time",
|
||||
"toml_edit",
|
||||
"walkdir",
|
||||
]
|
||||
|
||||
@ -3747,6 +3743,28 @@ dependencies = [
|
||||
"tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml_datetime"
|
||||
version = "0.6.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3550f4e9685620ac18a50ed434eb3aec30db8ba93b0287467bca5826ea25baf1"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml_edit"
|
||||
version = "0.22.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d3328d4f68a705b2a4498da1d580585d39a6510f98318a2cec3018a7ec61ddef"
|
||||
dependencies = [
|
||||
"indexmap",
|
||||
"serde",
|
||||
"serde_spanned",
|
||||
"toml_datetime",
|
||||
"winnow",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tower"
|
||||
version = "0.4.13"
|
||||
@ -3861,12 +3879,6 @@ version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "39ec24b3121d976906ece63c9daad25b85969647682eee313cb5779fdd69e14e"
|
||||
|
||||
[[package]]
|
||||
name = "unsafe-libyaml"
|
||||
version = "0.2.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861"
|
||||
|
||||
[[package]]
|
||||
name = "untrusted"
|
||||
version = "0.9.0"
|
||||
@ -4250,6 +4262,15 @@ version = "0.52.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0"
|
||||
|
||||
[[package]]
|
||||
name = "winnow"
|
||||
version = "0.6.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "14b9415ee827af173ebb3f15f9083df5a122eb93572ec28741fb153356ea2578"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winreg"
|
||||
version = "0.52.0"
|
||||
|
37
assets/advanced.toml
Normal file
37
assets/advanced.toml
Normal file
@ -0,0 +1,37 @@
|
||||
# Changing these settings is for advanced users only!
|
||||
# There will be no support or guarantee that it will be stable after changing them.
|
||||
|
||||
[decoder]
|
||||
input_param = ""
|
||||
# output_param get also applied to ingest instance.
|
||||
output_param = ""
|
||||
|
||||
[filters]
|
||||
deinterlace = "" # yadif=0:-1:0
|
||||
pad_scale_w = "" # scale={}:-1
|
||||
pad_scale_h = "" # scale=-1:{}
|
||||
pad_video = "" # pad=max(iw\\,ih*({0}/{1})):ow/({0}/{1}):(ow-iw)/2:(oh-ih)/2
|
||||
fps = "" # fps={}
|
||||
scale = "" # scale={}:{}
|
||||
set_dar = "" # setdar=dar={}
|
||||
fade_in = "" # fade=in:st=0:d=0.5
|
||||
fade_out = "" # fade=out:st={}:d=1.0
|
||||
overlay_logo_scale = "" # scale={}
|
||||
overlay_logo_fade_in = "" # fade=in:st=0:d=1.0:alpha=1
|
||||
overlay_logo_fade_out = "" # fade=out:st={}:d=1.0:alpha=1
|
||||
overlay_logo = "" # null[l];[v][l]overlay={}:shortest=1
|
||||
tpad = "" # tpad=stop_mode=add:stop_duration={}
|
||||
drawtext_from_file = "" # drawtext=text='{}':{}{}
|
||||
drawtext_from_zmq = "" # 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]
|
||||
input_param = ""
|
||||
|
||||
[ingest]
|
||||
input_param = ""
|
@ -1,32 +0,0 @@
|
||||
help: Changing these settings is for advanced users only! There will be no support or guarantee that it will be stable after changing them.
|
||||
decoder:
|
||||
input_param:
|
||||
# output_param get also applied to ingest instance.
|
||||
output_param:
|
||||
filters:
|
||||
deinterlace: # yadif=0:-1:0
|
||||
pad_scale_w: # scale={}:-1
|
||||
pad_scale_h: # scale=-1:{}
|
||||
pad_video: # pad=max(iw\\,ih*({0}/{1})):ow/({0}/{1}):(ow-iw)/2:(oh-ih)/2
|
||||
fps: # fps={}
|
||||
scale: # scale={}:{}
|
||||
set_dar: # setdar=dar={}
|
||||
fade_in: # fade=in:st=0:d=0.5
|
||||
fade_out: # fade=out:st={}:d=1.0
|
||||
overlay_logo_scale: # scale={}
|
||||
overlay_logo_fade_in: # fade=in:st=0:d=1.0:alpha=1
|
||||
overlay_logo_fade_out: # fade=out:st={}:d=1.0:alpha=1
|
||||
overlay_logo: # null[l];[v][l]overlay={}:shortest=1
|
||||
tpad: # tpad=stop_mode=add:stop_duration={}
|
||||
drawtext_from_file: # drawtext=text='{}':{}{}
|
||||
drawtext_from_zmq: # 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:
|
||||
input_param:
|
||||
ingest:
|
||||
input_param:
|
168
assets/ffplayout.toml
Normal file
168
assets/ffplayout.toml
Normal file
@ -0,0 +1,168 @@
|
||||
[general]
|
||||
help_text = """Sometimes it can happen, that a file is corrupt but still playable, \
|
||||
this can produce an streaming error over all following files. The only way \
|
||||
in this case is, to stop ffplayout and start it again. Here we only say when \
|
||||
it stops, the starting process is in your hand. Best way is a systemd service \
|
||||
on linux.
|
||||
'stop_threshold' stop ffplayout, if it is async in time above this \
|
||||
value. A number below 3 can cause unexpected errors."""
|
||||
stop_threshold = 11
|
||||
stat_file = ".ffp_status"
|
||||
|
||||
[rpc_server]
|
||||
help_text = """Run a JSON RPC server, for getting infos about current playing and for some \
|
||||
control functions."""
|
||||
enable = true
|
||||
address = "127.0.0.1:7070"
|
||||
authorization = "av2Kx8g67lF9qj5wEH3ym1bI4cCs"
|
||||
|
||||
[mail]
|
||||
help_text = """Send error messages to email address, like missing playlist; invalid \
|
||||
json format; missing clip path. Leave recipient blank, if you don't need this.
|
||||
'mail_level' can be INFO, WARNING or ERROR.
|
||||
'interval' means seconds until a new mail will be sended."""
|
||||
subject = "Playout Error"
|
||||
smtp_server = "mail.example.org"
|
||||
starttls = true
|
||||
sender_addr = "ffplayout@example.org"
|
||||
sender_pass = "abc123"
|
||||
recipient = ""
|
||||
mail_level = "ERROR"
|
||||
interval = 30
|
||||
|
||||
[logging]
|
||||
help_text = """If 'log_to_file' is true, log to file, when is false log to console.
|
||||
'backup_count' says how long log files will be saved in days.
|
||||
'local_time' to false will set log timestamps to UTC. Path to /var/log/ only \
|
||||
if you run this program as daemon.
|
||||
'level' can be DEBUG, INFO, WARNING, ERROR.
|
||||
'ffmpeg_level/ingest_level' can be INFO, WARNING, ERROR.
|
||||
'detect_silence' logs an error message if the audio line is silent for 15 \
|
||||
seconds during the validation process.
|
||||
'ignore_lines' makes logging to ignore strings that contains matched lines, \
|
||||
in frontend is a semicolon separated list."""
|
||||
log_to_file = true
|
||||
backup_count = 7
|
||||
local_time = true
|
||||
timestamp = true
|
||||
path = "/var/log/ffplayout/"
|
||||
level = "DEBUG"
|
||||
ffmpeg_level = "ERROR"
|
||||
ingest_level = "WARNING"
|
||||
detect_silence = false
|
||||
ignore_lines = [
|
||||
"P sub_mb_type 4 out of range at",
|
||||
"error while decoding MB",
|
||||
"negative number of zero coeffs at",
|
||||
"out of range intra chroma pred mode",
|
||||
"non-existing SPS 0 referenced in buffering period",
|
||||
]
|
||||
|
||||
[processing]
|
||||
help_text = """Default processing for all clips, to have them unique. Mode can be playlist \
|
||||
or folder.
|
||||
'aspect' must be a float number.'logo' is only used if the path exist.
|
||||
'logo_scale' scale the logo to target size, leave it blank when no scaling \
|
||||
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_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
|
||||
copy_video = false
|
||||
width = 1024
|
||||
height = 576
|
||||
aspect = 1.778
|
||||
fps = 25
|
||||
add_logo = true
|
||||
logo = "/usr/share/ffplayout/logo.png"
|
||||
logo_scale = ""
|
||||
logo_opacity = 0.7
|
||||
logo_position = "W-w-12:12"
|
||||
audio_tracks = 1
|
||||
audio_track_index = -1
|
||||
audio_channels = 2
|
||||
volume = 1
|
||||
custom_filter = ""
|
||||
|
||||
[ingest]
|
||||
help_text = """Run a server for a ingest stream. This stream will override the normal streaming \
|
||||
until is done. There is only a very simple authentication mechanism, which check if the \
|
||||
stream name is correct.
|
||||
'custom_filter' can be used in the same way then the one in the process section."""
|
||||
enable = false
|
||||
input_param = "-f live_flv -listen 1 -i rtmp://127.0.0.1:1936/live/stream"
|
||||
custom_filter = ""
|
||||
|
||||
[playlist]
|
||||
help_text = """'path' can be a path to a single file, or a directory. For directory put \
|
||||
only the root folder, for example '/playlists', subdirectories are read by the \
|
||||
program. Subdirectories needs this structure '/playlists/2018/01'.
|
||||
'day_start' means at which time the playlist should start, leave day_start \
|
||||
blank when playlist should always start at the begin. 'length' represent the \
|
||||
target length from playlist, when is blank real length will not consider.
|
||||
'infinit: true' works with single playlist file and loops it infinitely. """
|
||||
path = "/var/lib/ffplayout/playlists"
|
||||
day_start = "05:59:25"
|
||||
length = "24:00:00"
|
||||
infinit = false
|
||||
|
||||
[storage]
|
||||
help_text = """'filler' is for playing instead of a missing file or fill the end to reach 24 \
|
||||
hours, can be a file or folder, it will loop when is necessary.
|
||||
'extensions' search only files with this extension. Set 'shuffle' to 'true' \
|
||||
to pick files randomly."""
|
||||
path = "/var/lib/ffplayout/tv-media"
|
||||
filler = "/var/lib/ffplayout/tv-media/filler/filler.mp4"
|
||||
extensions = ["mp4", "mkv"]
|
||||
shuffle = true
|
||||
|
||||
[text]
|
||||
help_text = """Overlay text in combination with libzmq for remote text manipulation. \
|
||||
On windows fontfile path need to be like this 'C\\:/WINDOWS/fonts/DejaVuSans.ttf'.
|
||||
'text_from_filename' activate the extraction from text of a filename. With 'style' \
|
||||
you can define the drawtext parameters like position, color, etc. Post Text over \
|
||||
API will override this. With 'regex' you can format file names, to get a title from it."""
|
||||
add_text = true
|
||||
text_from_filename = false
|
||||
fontfile = "/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf"
|
||||
style = "x=(w-tw)/2:y=(h-line_h)*0.9:fontsize=24:fontcolor=#ffffff:box=1:boxcolor=#000000:boxborderw=4"
|
||||
regex = "^.+[/\\](.*)(.mp4|.mkv)$"
|
||||
|
||||
[task]
|
||||
help_text = """Run an external program with a given media object. The media object is in json format \
|
||||
and contains all the information about the current clip. The external program can be a script \
|
||||
or a binary, but should only run for a short time."""
|
||||
enable = false
|
||||
path = ""
|
||||
|
||||
[out]
|
||||
help_text = """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.
|
||||
In production don't serve hls playlist with ffpapi, use nginx or another web server!"""
|
||||
mode = "hls"
|
||||
output_param = """\
|
||||
-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 /usr/share/ffplayout/public/live/stream-%d.ts
|
||||
/usr/share/ffplayout/public/live/stream.m3u8"""
|
@ -1,167 +0,0 @@
|
||||
general:
|
||||
help_text: Sometimes it can happen, that a file is corrupt but still playable,
|
||||
this can produce an streaming error over all following files. The only way
|
||||
in this case is, to stop ffplayout and start it again. Here we only say when
|
||||
it stops, the starting process is in your hand. Best way is a systemd service
|
||||
on linux. 'stop_threshold' stop ffplayout, if it is async in time above this
|
||||
value. A number below 3 can cause unexpected errors.
|
||||
stop_threshold: 11
|
||||
stat_file: .ffp_status
|
||||
|
||||
rpc_server:
|
||||
help_text: Run a JSON RPC server, for getting infos about current playing and
|
||||
for some control functions.
|
||||
enable: true
|
||||
address: 127.0.0.1:7070
|
||||
authorization: av2Kx8g67lF9qj5wEH3ym1bI4cCs
|
||||
|
||||
mail:
|
||||
help_text: Send error messages to email address, like missing playlist; invalid
|
||||
json format; missing clip path. Leave recipient blank, if you don't need this.
|
||||
'mail_level' can be INFO, WARNING or ERROR. 'interval' means seconds until
|
||||
a new mail will be sended.
|
||||
subject: Playout Error
|
||||
smtp_server: mail.example.org
|
||||
starttls: true
|
||||
sender_addr: ffplayout@example.org
|
||||
sender_pass: "abc123"
|
||||
recipient:
|
||||
mail_level: ERROR
|
||||
interval: 30
|
||||
|
||||
logging:
|
||||
help_text: If 'log_to_file' is true, log to file, when is false log to console.
|
||||
'backup_count' says how long log files will be saved in days. 'local_time' to
|
||||
false will set log timestamps to UTC. Path to /var/log/ only if you run this
|
||||
program as daemon. 'level' can be DEBUG, INFO, WARNING, ERROR.
|
||||
'ffmpeg_level/ingest_level' can be info, warning, error.
|
||||
'detect_silence' logs an error message if the audio line is silent for 15
|
||||
seconds during the validation process.
|
||||
'ignore_lines' makes logging to ignore strings that contains matched lines,
|
||||
in frontend is a semicolon separated list.
|
||||
log_to_file: true
|
||||
backup_count: 7
|
||||
local_time: true
|
||||
timestamp: true
|
||||
path: /var/log/ffplayout/
|
||||
level: DEBUG
|
||||
ffmpeg_level: error
|
||||
ingest_level: warning
|
||||
detect_silence: false
|
||||
ignore_lines:
|
||||
- P sub_mb_type 4 out of range at
|
||||
- error while decoding MB
|
||||
- negative number of zero coeffs at
|
||||
- out of range intra chroma pred mode
|
||||
- non-existing SPS 0 referenced in buffering period
|
||||
|
||||
processing:
|
||||
help_text: Default processing for all clips, to have them unique. Mode can be playlist
|
||||
or folder. 'aspect' must be a float number. 'logo' is only used if the path exist.
|
||||
'logo_scale' scale the logo to target size, leave it blank when no scaling
|
||||
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_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
|
||||
copy_video: false
|
||||
width: 1024
|
||||
height: 576
|
||||
aspect: 1.778
|
||||
fps: 25
|
||||
add_logo: true
|
||||
logo: /usr/share/ffplayout/logo.png
|
||||
logo_scale:
|
||||
logo_opacity: 0.7
|
||||
logo_position: W-w-12:12
|
||||
audio_tracks: 1
|
||||
audio_track_index: -1
|
||||
audio_channels: 2
|
||||
volume: 1
|
||||
custom_filter:
|
||||
|
||||
ingest:
|
||||
help_text: Run a server for a ingest stream. This stream will override the normal streaming
|
||||
until is done. There is only a very simple authentication mechanism, which check if the
|
||||
stream name is correct. 'custom_filter' can be used in the same way then the one in the
|
||||
process section.
|
||||
enable: false
|
||||
input_param: -f live_flv -listen 1 -i rtmp://127.0.0.1:1936/live/stream
|
||||
custom_filter:
|
||||
|
||||
playlist:
|
||||
help_text: >
|
||||
'path' can be a path to a single file, or a directory. For directory put
|
||||
only the root folder, for example '/playlists', subdirectories are read by the
|
||||
program. Subdirectories needs this structure '/playlists/2018/01'. 'day_start'
|
||||
means at which time the playlist should start, leave day_start blank when playlist
|
||||
should always start at the begin. 'length' represent the target length from
|
||||
playlist, when is blank real length will not consider. 'infinit: true' works with
|
||||
single playlist file and loops it infinitely.
|
||||
path: /var/lib/ffplayout/playlists
|
||||
day_start: "05:59:25"
|
||||
length: "24:00:00"
|
||||
infinit: false
|
||||
|
||||
storage:
|
||||
help_text: >
|
||||
'filler' is for playing instead of a missing file or fill the end to reach 24
|
||||
hours, can be a file or folder, it will loop when is necessary. 'extensions' search
|
||||
only files with this extension. Set 'shuffle' to 'true' to pick files randomly.
|
||||
path: "/var/lib/ffplayout/tv-media"
|
||||
filler: "/var/lib/ffplayout/tv-media/filler/filler.mp4"
|
||||
extensions:
|
||||
- "mp4"
|
||||
- "mkv"
|
||||
shuffle: true
|
||||
|
||||
text:
|
||||
help_text: Overlay text in combination with libzmq for remote text manipulation.
|
||||
On windows fontfile path need to be like this 'C\:/WINDOWS/fonts/DejaVuSans.ttf'.
|
||||
'text_from_filename' activate the extraction from text of a filename. With 'style'
|
||||
you can define the drawtext parameters like position, color, etc. Post Text over
|
||||
API will override this. With 'regex' you can format file names, to get a title from it.
|
||||
add_text: true
|
||||
text_from_filename: false
|
||||
fontfile: "/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf"
|
||||
style: "x=(w-tw)/2:y=(h-line_h)*0.9:fontsize=24:fontcolor=#ffffff:box=1:boxcolor=#000000:boxborderw=4"
|
||||
regex: ^.+[/\\](.*)(.mp4|.mkv)$
|
||||
|
||||
task:
|
||||
help_text: Run an external program with a given media object. The media object is in json format
|
||||
and contains all the information about the current clip. The external program can be a script
|
||||
or a binary, but should only run for a short time.
|
||||
enable: false
|
||||
path:
|
||||
|
||||
out:
|
||||
help_text: 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.
|
||||
In production don't serve hls playlist with ffpapi, use nginx or another web server!
|
||||
mode: hls
|
||||
output_param: >-
|
||||
-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 /usr/share/ffplayout/public/live/stream-%d.ts
|
||||
/usr/share/ffplayout/public/live/stream.m3u8
|
@ -42,13 +42,13 @@ rpassword = "7.2"
|
||||
sanitize-filename = "0.5"
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
serde_json = "1.0"
|
||||
serde_yaml = "0.9"
|
||||
simplelog = { version = "0.12", features = ["paris"] }
|
||||
static-files = "0.2"
|
||||
sysinfo ={ version = "0.30", features = ["linux-netdevs"] }
|
||||
sqlx = { version = "0.7", features = ["runtime-tokio", "sqlite"] }
|
||||
tokio = { version = "1.29", features = ["full"] }
|
||||
tokio-stream = "0.1"
|
||||
toml_edit = {version ="0.22", features = ["serde"]}
|
||||
uuid = "1.8"
|
||||
|
||||
[build-dependencies]
|
||||
|
@ -388,7 +388,7 @@ async fn remove_user(
|
||||
/// "id": 1,
|
||||
/// "name": "Channel 1",
|
||||
/// "preview_url": "http://localhost/live/preview.m3u8",
|
||||
/// "config_path": "/etc/ffplayout/ffplayout.yml",
|
||||
/// "config_path": "/etc/ffplayout/ffplayout.toml",
|
||||
/// "extra_extensions": "jpg,jpeg,png",
|
||||
/// "service": "ffplayout.service",
|
||||
/// "utc_offset": "+120"
|
||||
@ -426,7 +426,7 @@ async fn get_all_channels(pool: web::Data<Pool<Sqlite>>) -> Result<impl Responde
|
||||
///
|
||||
/// ```BASH
|
||||
/// curl -X PATCH http://127.0.0.1:8787/api/channel/1 -H "Content-Type: application/json" \
|
||||
/// -d '{ "id": 1, "name": "Channel 1", "preview_url": "http://localhost/live/stream.m3u8", "config_path": "/etc/ffplayout/ffplayout.yml", "extra_extensions": "jpg,jpeg,png"}' \
|
||||
/// -d '{ "id": 1, "name": "Channel 1", "preview_url": "http://localhost/live/stream.m3u8", "config_path": "/etc/ffplayout/ffplayout.toml", "extra_extensions": "jpg,jpeg,png"}' \
|
||||
/// -H "Authorization: Bearer <TOKEN>"
|
||||
/// ```
|
||||
#[patch("/channel/{id}")]
|
||||
@ -450,7 +450,7 @@ async fn patch_channel(
|
||||
///
|
||||
/// ```BASH
|
||||
/// curl -X POST http://127.0.0.1:8787/api/channel/ -H "Content-Type: application/json" \
|
||||
/// -d '{ "name": "Channel 2", "preview_url": "http://localhost/live/channel2.m3u8", "config_path": "/etc/ffplayout/channel2.yml", "extra_extensions": "jpg,jpeg,png", "service": "ffplayout@channel2.service" }' \
|
||||
/// -d '{ "name": "Channel 2", "preview_url": "http://localhost/live/channel2.m3u8", "config_path": "/etc/ffplayout/channel2.toml", "extra_extensions": "jpg,jpeg,png", "service": "ffplayout@channel2.service" }' \
|
||||
/// -H "Authorization: Bearer <TOKEN>"
|
||||
/// ```
|
||||
#[post("/channel/")]
|
||||
@ -491,7 +491,7 @@ async fn remove_channel(
|
||||
/// curl -X GET http://127.0.0.1:8787/api/playout/config/1 -H 'Authorization: Bearer <TOKEN>'
|
||||
/// ```
|
||||
///
|
||||
/// Response is a JSON object from the ffplayout.yml
|
||||
/// Response is a JSON object from the ffplayout.toml
|
||||
#[get("/playout/config/{id}")]
|
||||
#[protect(any("Role::Admin", "Role::User"), ty = "Role")]
|
||||
async fn get_playout_config(
|
||||
@ -522,17 +522,10 @@ async fn update_playout_config(
|
||||
data: web::Json<PlayoutConfig>,
|
||||
) -> Result<impl Responder, ServiceError> {
|
||||
if let Ok(channel) = handles::select_channel(&pool.into_inner(), &id).await {
|
||||
if let Ok(f) = std::fs::OpenOptions::new()
|
||||
.write(true)
|
||||
.truncate(true)
|
||||
.open(channel.config_path)
|
||||
{
|
||||
serde_yaml::to_writer(f, &data).unwrap();
|
||||
let toml_string = toml_edit::ser::to_string_pretty(&data)?;
|
||||
fs::write(&channel.config_path, toml_string).await?;
|
||||
|
||||
return Ok("Update playout config success.");
|
||||
} else {
|
||||
return Err(ServiceError::InternalServerError);
|
||||
};
|
||||
return Ok("Update playout config success.");
|
||||
};
|
||||
|
||||
Err(ServiceError::InternalServerError)
|
||||
|
@ -99,9 +99,9 @@ pub async fn db_init(domain: Option<String>) -> Result<&'static str, Box<dyn std
|
||||
};
|
||||
|
||||
let config_path = if env::consts::OS == "linux" {
|
||||
"/etc/ffplayout/ffplayout.yml"
|
||||
"/etc/ffplayout/ffplayout.toml"
|
||||
} else {
|
||||
"./assets/ffplayout.yml"
|
||||
"./assets/ffplayout.toml"
|
||||
};
|
||||
|
||||
let query = "CREATE TRIGGER global_row_count
|
||||
|
@ -33,7 +33,7 @@ pub async fn create_channel(
|
||||
};
|
||||
|
||||
let mut config = PlayoutConfig::new(
|
||||
Some(PathBuf::from("/usr/share/ffplayout/ffplayout.yml.orig")),
|
||||
Some(PathBuf::from("/usr/share/ffplayout/ffplayout.toml.orig")),
|
||||
None,
|
||||
);
|
||||
|
||||
@ -48,8 +48,8 @@ pub async fn create_channel(
|
||||
.replace("stream.m3u8", &format!("stream{channel_num}.m3u8"))
|
||||
.replace("stream-%d.ts", &format!("stream{channel_num}-%d.ts"));
|
||||
|
||||
let file = fs::File::create(&target_channel.config_path)?;
|
||||
serde_yaml::to_writer(file, &config).unwrap();
|
||||
let toml_string = toml_edit::ser::to_string(&config)?;
|
||||
fs::write(&target_channel.config_path, toml_string)?;
|
||||
|
||||
let new_channel = handles::insert_channel(conn, target_channel).await?;
|
||||
control_service(conn, &config, new_channel.id, &ServiceCmd::Enable, None).await?;
|
||||
|
@ -88,6 +88,12 @@ impl From<tokio::task::JoinError> for ServiceError {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<toml_edit::ser::Error> for ServiceError {
|
||||
fn from(err: toml_edit::ser::Error) -> ServiceError {
|
||||
ServiceError::BadRequest(err.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<uuid::Error> for ServiceError {
|
||||
fn from(err: uuid::Error) -> ServiceError {
|
||||
ServiceError::BadRequest(err.to_string())
|
||||
|
@ -3,7 +3,7 @@ use std::{
|
||||
error::Error,
|
||||
fmt,
|
||||
fs::{self, metadata, File},
|
||||
io::{stdin, stdout, Write},
|
||||
io::{stdin, stdout, Read, Write},
|
||||
path::{Path, PathBuf},
|
||||
str::FromStr,
|
||||
};
|
||||
@ -274,8 +274,11 @@ pub async fn run_args() -> Result<(), i32> {
|
||||
}
|
||||
|
||||
pub fn read_playout_config(path: &str) -> Result<PlayoutConfig, Box<dyn Error>> {
|
||||
let file = File::open(path)?;
|
||||
let mut config: PlayoutConfig = serde_yaml::from_reader(file)?;
|
||||
let mut file = File::open(path)?;
|
||||
let mut contents = String::new();
|
||||
file.read_to_string(&mut contents)?;
|
||||
|
||||
let mut config: PlayoutConfig = toml_edit::de::from_str(&contents)?;
|
||||
|
||||
config.playlist.start_sec = Some(time_to_sec(&config.playlist.day_start));
|
||||
config.playlist.length_sec = Some(time_to_sec(&config.playlist.length));
|
||||
@ -288,8 +291,9 @@ pub async fn playout_config(
|
||||
channel_id: &i32,
|
||||
) -> Result<(PlayoutConfig, Channel), ServiceError> {
|
||||
if let Ok(channel) = select_channel(conn, channel_id).await {
|
||||
if let Ok(config) = read_playout_config(&channel.config_path.clone()) {
|
||||
return Ok((config, channel));
|
||||
match read_playout_config(&channel.config_path.clone()) {
|
||||
Ok(config) => return Ok((config, channel)),
|
||||
Err(e) => error!("{e}"),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -45,7 +45,7 @@ depends = ""
|
||||
recommends = "sudo"
|
||||
suggests = "ffmpeg"
|
||||
copyright = "Copyright (c) 2022, Jonathan Baecker. All rights reserved."
|
||||
conf-files = ["/etc/ffplayout/ffplayout.yml"]
|
||||
conf-files = ["/etc/ffplayout/ffplayout.toml"]
|
||||
assets = [
|
||||
[
|
||||
"../target/x86_64-unknown-linux-musl/release/ffpapi",
|
||||
@ -78,12 +78,12 @@ assets = [
|
||||
"644",
|
||||
],
|
||||
[
|
||||
"../assets/advanced.yml",
|
||||
"../assets/advanced.toml",
|
||||
"/etc/ffplayout/",
|
||||
"644",
|
||||
],
|
||||
[
|
||||
"../assets/ffplayout.yml",
|
||||
"../assets/ffplayout.toml",
|
||||
"/etc/ffplayout/",
|
||||
"644",
|
||||
],
|
||||
@ -93,8 +93,8 @@ assets = [
|
||||
"644",
|
||||
],
|
||||
[
|
||||
"../assets/ffplayout.yml",
|
||||
"/usr/share/ffplayout/ffplayout.yml.orig",
|
||||
"../assets/ffplayout.toml",
|
||||
"/usr/share/ffplayout/ffplayout.toml.orig",
|
||||
"644",
|
||||
],
|
||||
[
|
||||
@ -154,12 +154,12 @@ assets = [
|
||||
"644",
|
||||
],
|
||||
[
|
||||
"../assets/ffplayout.yml",
|
||||
"../assets/ffplayout.toml",
|
||||
"/etc/ffplayout/",
|
||||
"644",
|
||||
],
|
||||
[
|
||||
"../assets/advanced.yml",
|
||||
"../assets/advanced.toml",
|
||||
"/etc/ffplayout/",
|
||||
"644",
|
||||
],
|
||||
@ -169,8 +169,8 @@ assets = [
|
||||
"644",
|
||||
],
|
||||
[
|
||||
"../assets/ffplayout.yml",
|
||||
"/usr/share/ffplayout/ffplayout.yml.orig",
|
||||
"../assets/ffplayout.toml",
|
||||
"/usr/share/ffplayout/ffplayout.toml.orig",
|
||||
"644",
|
||||
],
|
||||
[
|
||||
@ -202,8 +202,8 @@ license = "GPL-3.0"
|
||||
assets = [
|
||||
{ source = "../target/x86_64-unknown-linux-musl/release/ffpapi", dest = "/usr/bin/ffpapi", mode = "755" },
|
||||
{ source = "../target/x86_64-unknown-linux-musl/release/ffplayout", dest = "/usr/bin/ffplayout", mode = "755" },
|
||||
{ source = "../assets/advanced.yml", dest = "/etc/ffplayout/advanced.yml", mode = "644", config = true },
|
||||
{ source = "../assets/ffplayout.yml", dest = "/etc/ffplayout/ffplayout.yml", mode = "644", config = true },
|
||||
{ source = "../assets/advanced.toml", dest = "/etc/ffplayout/advanced.toml", mode = "644", config = true },
|
||||
{ source = "../assets/ffplayout.toml", dest = "/etc/ffplayout/ffplayout.toml", mode = "644", config = true },
|
||||
{ source = "../assets/ffpapi.service", dest = "/lib/systemd/system/ffpapi.service", mode = "644" },
|
||||
{ source = "../assets/ffplayout.service", dest = "/lib/systemd/system/ffplayout.service", mode = "644" },
|
||||
{ source = "../assets/ffplayout@.service", dest = "/lib/systemd/system/ffplayout@.service", mode = "644" },
|
||||
@ -213,7 +213,7 @@ assets = [
|
||||
{ source = "../assets/ffplayout.1.gz", dest = "/usr/share/man/man1/ffplayout.1.gz", mode = "644", doc = true },
|
||||
{ source = "../LICENSE", dest = "/usr/share/doc/ffplayout/LICENSE", mode = "644" },
|
||||
{ source = "../assets/logo.png", dest = "/usr/share/ffplayout/logo.png", mode = "644" },
|
||||
{ source = "../assets/ffplayout.yml", dest = "/usr/share/ffplayout/ffplayout.yml.orig", mode = "644" },
|
||||
{ source = "../assets/ffplayout.toml", dest = "/usr/share/ffplayout/ffplayout.toml.orig", mode = "644" },
|
||||
{ source = "../assets/ffplayout.conf", dest = "/usr/share/ffplayout/ffplayout.conf.example", mode = "644" },
|
||||
{ source = "../debian/postinst", dest = "/usr/share/ffplayout/postinst", mode = "755" },
|
||||
]
|
||||
|
@ -11,13 +11,13 @@ use ffplayout_lib::utils::{OutputMode, ProcessMode};
|
||||
\n ffplayout (ARGS) [OPTIONS]\n\n Pass channel name only in multi channel environment!",
|
||||
long_about = None)]
|
||||
pub struct Args {
|
||||
#[clap(long, help = "File path to advanced.yml")]
|
||||
#[clap(long, help = "File path to advanced.toml")]
|
||||
pub advanced_config: Option<PathBuf>,
|
||||
|
||||
#[clap(index = 1, value_parser, help = "Channel name")]
|
||||
pub channel: Option<String>,
|
||||
|
||||
#[clap(short, long, help = "File path to ffplayout.yml")]
|
||||
#[clap(short, long, help = "File path to ffplayout.toml")]
|
||||
pub config: Option<PathBuf>,
|
||||
|
||||
#[clap(short, long, help = "File path for logging")]
|
||||
|
@ -25,7 +25,7 @@ use ffplayout_lib::{
|
||||
pub fn get_config(args: Args) -> Result<PlayoutConfig, ProcError> {
|
||||
let cfg_path = match args.channel {
|
||||
Some(c) => {
|
||||
let path = PathBuf::from(format!("/etc/ffplayout/{c}.yml"));
|
||||
let path = PathBuf::from(format!("/etc/ffplayout/{c}.toml"));
|
||||
|
||||
if !path.is_file() {
|
||||
return Err(ProcError::Custom(format!(
|
||||
@ -38,15 +38,15 @@ pub fn get_config(args: Args) -> Result<PlayoutConfig, ProcError> {
|
||||
None => args.config,
|
||||
};
|
||||
|
||||
let mut adv_config_path = PathBuf::from("/etc/ffplayout/advanced.yml");
|
||||
let mut adv_config_path = PathBuf::from("/etc/ffplayout/advanced.toml");
|
||||
|
||||
if let Some(adv_path) = args.advanced_config {
|
||||
adv_config_path = adv_path;
|
||||
} else if !adv_config_path.is_file() {
|
||||
if Path::new("./assets/advanced.yml").is_file() {
|
||||
adv_config_path = PathBuf::from("./assets/advanced.yml")
|
||||
if Path::new("./assets/advanced.toml").is_file() {
|
||||
adv_config_path = PathBuf::from("./assets/advanced.toml")
|
||||
} else if let Some(p) = env::current_exe().ok().as_ref().and_then(|op| op.parent()) {
|
||||
adv_config_path = p.join("advanced.yml")
|
||||
adv_config_path = p.join("advanced.toml")
|
||||
};
|
||||
}
|
||||
|
||||
@ -251,14 +251,21 @@ pub fn prepare_output_cmd(
|
||||
|
||||
/// map media struct to json object
|
||||
pub fn get_media_map(media: Media) -> Value {
|
||||
json!({
|
||||
"title": media.title,
|
||||
let mut obj = json!({
|
||||
"in": media.seek,
|
||||
"out": media.out,
|
||||
"duration": media.duration,
|
||||
"category": media.category,
|
||||
"source": media.source,
|
||||
})
|
||||
});
|
||||
|
||||
if let Some(title) = media.title {
|
||||
obj.as_object_mut()
|
||||
.unwrap()
|
||||
.insert("title".to_string(), Value::String(title));
|
||||
}
|
||||
|
||||
obj
|
||||
}
|
||||
|
||||
/// prepare json object for response
|
||||
|
@ -1 +1 @@
|
||||
Subproject commit 6111c2686d14b3bf33a4c0b29c85672f7e4f4399
|
||||
Subproject commit 05d0ada8e155a9bf858a26fcda219fb39782cf05
|
@ -24,10 +24,10 @@ regex = "1"
|
||||
reqwest = { version = "0.12", default-features = false, features = ["blocking", "json", "rustls-tls"] }
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
serde_json = "1.0"
|
||||
serde_yaml = "0.9"
|
||||
shlex = "1.1"
|
||||
simplelog = { version = "0.12", features = ["paris"] }
|
||||
time = { version = "0.3", features = ["formatting", "macros"] }
|
||||
toml_edit = {version ="0.22", features = ["serde"]}
|
||||
walkdir = "2"
|
||||
|
||||
[target."cfg(windows)".dependencies.winapi]
|
||||
|
@ -1,11 +1,10 @@
|
||||
use std::{fs::File, path::PathBuf};
|
||||
use std::{fs::File, io::Read, path::PathBuf};
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use shlex::split;
|
||||
|
||||
#[derive(Debug, Default, Serialize, Deserialize, Clone)]
|
||||
pub struct AdvancedConfig {
|
||||
pub help: Option<String>,
|
||||
pub decoder: DecoderConfig,
|
||||
pub encoder: EncoderConfig,
|
||||
pub ingest: IngestConfig,
|
||||
@ -66,10 +65,15 @@ impl AdvancedConfig {
|
||||
pub fn new(cfg_path: PathBuf) -> Self {
|
||||
let mut config: AdvancedConfig = Default::default();
|
||||
|
||||
if let Ok(f) = File::open(cfg_path) {
|
||||
config = match serde_yaml::from_reader(f) {
|
||||
Ok(yaml) => yaml,
|
||||
Err(_) => AdvancedConfig::default(),
|
||||
if let Ok(mut file) = File::open(cfg_path) {
|
||||
let mut contents = String::new();
|
||||
|
||||
if let Err(e) = file.read_to_string(&mut contents) {
|
||||
eprintln!("Read advanced config file: {e}")
|
||||
};
|
||||
|
||||
if let Ok(tm) = toml_edit::de::from_str(&contents) {
|
||||
config = tm
|
||||
};
|
||||
|
||||
if let Some(input_parm) = &config.decoder.input_param {
|
||||
|
@ -1,6 +1,7 @@
|
||||
use std::{
|
||||
env, fmt,
|
||||
fs::File,
|
||||
io::Read,
|
||||
path::{Path, PathBuf},
|
||||
process,
|
||||
str::FromStr,
|
||||
@ -365,32 +366,37 @@ fn default_channels() -> u8 {
|
||||
impl PlayoutConfig {
|
||||
/// Read config from YAML file, and set some extra config values.
|
||||
pub fn new(cfg_path: Option<PathBuf>, advanced_path: Option<PathBuf>) -> Self {
|
||||
let mut config_path = PathBuf::from("/etc/ffplayout/ffplayout.yml");
|
||||
let mut config_path = PathBuf::from("/etc/ffplayout/ffplayout.toml");
|
||||
|
||||
if let Some(cfg) = cfg_path {
|
||||
config_path = cfg;
|
||||
}
|
||||
|
||||
if !config_path.is_file() {
|
||||
if Path::new("./assets/ffplayout.yml").is_file() {
|
||||
config_path = PathBuf::from("./assets/ffplayout.yml")
|
||||
if Path::new("./assets/ffplayout.toml").is_file() {
|
||||
config_path = PathBuf::from("./assets/ffplayout.toml")
|
||||
} else if let Some(p) = env::current_exe().ok().as_ref().and_then(|op| op.parent()) {
|
||||
config_path = p.join("ffplayout.yml")
|
||||
config_path = p.join("ffplayout.toml")
|
||||
};
|
||||
}
|
||||
|
||||
let f = match File::open(&config_path) {
|
||||
let mut file = match File::open(&config_path) {
|
||||
Ok(file) => file,
|
||||
Err(_) => {
|
||||
eprintln!(
|
||||
"ffplayout.yml not found!\nPut \"ffplayout.yml\" in \"/etc/playout/\" or beside the executable!"
|
||||
"ffplayout.toml not found!\nPut \"ffplayout.toml\" in \"/etc/playout/\" or beside the executable!"
|
||||
);
|
||||
process::exit(1);
|
||||
}
|
||||
};
|
||||
|
||||
let mut config: PlayoutConfig =
|
||||
serde_yaml::from_reader(f).expect("Could not read config file.");
|
||||
let mut contents = String::new();
|
||||
|
||||
if let Err(e) = file.read_to_string(&mut contents) {
|
||||
eprintln!("Read config file: {e}")
|
||||
};
|
||||
|
||||
let mut config: PlayoutConfig = toml_edit::de::from_str(&contents).unwrap();
|
||||
|
||||
if let Some(adv_path) = advanced_path {
|
||||
config.advanced = Some(AdvancedConfig::new(adv_path))
|
||||
|
@ -65,7 +65,7 @@ pub struct Media {
|
||||
|
||||
#[serde(skip_serializing, skip_deserializing)]
|
||||
pub index: Option<usize>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub title: Option<String>,
|
||||
#[serde(rename = "in")]
|
||||
pub seek: f64,
|
||||
|
@ -23,11 +23,11 @@ regex = "1"
|
||||
reqwest = { version = "0.12", default-features = false, features = ["blocking", "json", "rustls-tls"] }
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
serde_json = "1.0"
|
||||
serde_yaml = "0.9"
|
||||
serial_test = "3.0"
|
||||
shlex = "1.1"
|
||||
simplelog = { version = "^0.12", features = ["paris"] }
|
||||
time = { version = "0.3", features = ["formatting", "macros"] }
|
||||
toml_edit = {version ="0.22", features = ["serde"]}
|
||||
walkdir = "2"
|
||||
|
||||
[[test]]
|
||||
|
@ -8,7 +8,7 @@ use ffplayout_lib::{
|
||||
|
||||
#[test]
|
||||
fn video_audio_input() {
|
||||
let mut config = PlayoutConfig::new(Some(PathBuf::from("../assets/ffplayout.yml")), None);
|
||||
let mut config = PlayoutConfig::new(Some(PathBuf::from("../assets/ffplayout.toml")), None);
|
||||
let player_control = PlayerControl::new();
|
||||
let playout_stat = PlayoutStatus::new();
|
||||
config.out.mode = Stream;
|
||||
@ -37,7 +37,7 @@ fn video_audio_input() {
|
||||
|
||||
#[test]
|
||||
fn video_audio_custom_filter1_input() {
|
||||
let mut config = PlayoutConfig::new(Some(PathBuf::from("../assets/ffplayout.yml")), None);
|
||||
let mut config = PlayoutConfig::new(Some(PathBuf::from("../assets/ffplayout.toml")), None);
|
||||
let player_control = PlayerControl::new();
|
||||
let playout_stat = PlayoutStatus::new();
|
||||
config.out.mode = Stream;
|
||||
@ -64,7 +64,7 @@ fn video_audio_custom_filter1_input() {
|
||||
|
||||
#[test]
|
||||
fn video_audio_custom_filter2_input() {
|
||||
let mut config = PlayoutConfig::new(Some(PathBuf::from("../assets/ffplayout.yml")), None);
|
||||
let mut config = PlayoutConfig::new(Some(PathBuf::from("../assets/ffplayout.toml")), None);
|
||||
let player_control = PlayerControl::new();
|
||||
let playout_stat = PlayoutStatus::new();
|
||||
config.out.mode = Stream;
|
||||
@ -93,7 +93,7 @@ fn video_audio_custom_filter2_input() {
|
||||
|
||||
#[test]
|
||||
fn video_audio_custom_filter3_input() {
|
||||
let mut config = PlayoutConfig::new(Some(PathBuf::from("../assets/ffplayout.yml")), None);
|
||||
let mut config = PlayoutConfig::new(Some(PathBuf::from("../assets/ffplayout.toml")), None);
|
||||
let player_control = PlayerControl::new();
|
||||
let playout_stat = PlayoutStatus::new();
|
||||
config.out.mode = Stream;
|
||||
@ -121,7 +121,7 @@ fn video_audio_custom_filter3_input() {
|
||||
|
||||
#[test]
|
||||
fn dual_audio_aevalsrc_input() {
|
||||
let mut config = PlayoutConfig::new(Some(PathBuf::from("../assets/ffplayout.yml")), None);
|
||||
let mut config = PlayoutConfig::new(Some(PathBuf::from("../assets/ffplayout.toml")), None);
|
||||
let player_control = PlayerControl::new();
|
||||
let playout_stat = PlayoutStatus::new();
|
||||
config.out.mode = Stream;
|
||||
@ -149,7 +149,7 @@ fn dual_audio_aevalsrc_input() {
|
||||
|
||||
#[test]
|
||||
fn dual_audio_input() {
|
||||
let mut config = PlayoutConfig::new(Some(PathBuf::from("../assets/ffplayout.yml")), None);
|
||||
let mut config = PlayoutConfig::new(Some(PathBuf::from("../assets/ffplayout.toml")), None);
|
||||
let player_control = PlayerControl::new();
|
||||
let playout_stat = PlayoutStatus::new();
|
||||
config.out.mode = Stream;
|
||||
@ -176,7 +176,7 @@ fn dual_audio_input() {
|
||||
|
||||
#[test]
|
||||
fn video_separate_audio_input() {
|
||||
let mut config = PlayoutConfig::new(Some(PathBuf::from("../assets/ffplayout.yml")), None);
|
||||
let mut config = PlayoutConfig::new(Some(PathBuf::from("../assets/ffplayout.toml")), None);
|
||||
let player_control = PlayerControl::new();
|
||||
let playout_stat = PlayoutStatus::new();
|
||||
config.out.mode = Stream;
|
||||
@ -213,7 +213,7 @@ fn video_separate_audio_input() {
|
||||
|
||||
#[test]
|
||||
fn video_audio_stream() {
|
||||
let mut config = PlayoutConfig::new(Some(PathBuf::from("../assets/ffplayout.yml")), None);
|
||||
let mut config = PlayoutConfig::new(Some(PathBuf::from("../assets/ffplayout.toml")), None);
|
||||
config.out.mode = Stream;
|
||||
config.processing.add_logo = false;
|
||||
config.out.output_cmd = Some(vec_strings![
|
||||
@ -272,7 +272,7 @@ fn video_audio_stream() {
|
||||
|
||||
#[test]
|
||||
fn video_audio_filter1_stream() {
|
||||
let mut config = PlayoutConfig::new(Some(PathBuf::from("../assets/ffplayout.yml")), None);
|
||||
let mut config = PlayoutConfig::new(Some(PathBuf::from("../assets/ffplayout.toml")), None);
|
||||
config.out.mode = Stream;
|
||||
config.processing.add_logo = false;
|
||||
config.text.add_text = false;
|
||||
@ -347,7 +347,7 @@ fn video_audio_filter1_stream() {
|
||||
|
||||
#[test]
|
||||
fn video_audio_filter2_stream() {
|
||||
let mut config = PlayoutConfig::new(Some(PathBuf::from("../assets/ffplayout.yml")), None);
|
||||
let mut config = PlayoutConfig::new(Some(PathBuf::from("../assets/ffplayout.toml")), None);
|
||||
config.out.mode = Stream;
|
||||
config.processing.add_logo = false;
|
||||
config.text.add_text = true;
|
||||
@ -430,7 +430,7 @@ fn video_audio_filter2_stream() {
|
||||
|
||||
#[test]
|
||||
fn video_audio_filter3_stream() {
|
||||
let mut config = PlayoutConfig::new(Some(PathBuf::from("../assets/ffplayout.yml")), None);
|
||||
let mut config = PlayoutConfig::new(Some(PathBuf::from("../assets/ffplayout.toml")), None);
|
||||
config.out.mode = Stream;
|
||||
config.processing.add_logo = false;
|
||||
config.text.add_text = true;
|
||||
@ -516,7 +516,7 @@ fn video_audio_filter3_stream() {
|
||||
|
||||
#[test]
|
||||
fn video_audio_filter4_stream() {
|
||||
let mut config = PlayoutConfig::new(Some(PathBuf::from("../assets/ffplayout.yml")), None);
|
||||
let mut config = PlayoutConfig::new(Some(PathBuf::from("../assets/ffplayout.toml")), None);
|
||||
config.out.mode = Stream;
|
||||
config.processing.add_logo = false;
|
||||
config.text.add_text = true;
|
||||
@ -602,7 +602,7 @@ fn video_audio_filter4_stream() {
|
||||
|
||||
#[test]
|
||||
fn video_dual_audio_stream() {
|
||||
let mut config = PlayoutConfig::new(Some(PathBuf::from("../assets/ffplayout.yml")), None);
|
||||
let mut config = PlayoutConfig::new(Some(PathBuf::from("../assets/ffplayout.toml")), None);
|
||||
config.out.mode = Stream;
|
||||
config.processing.add_logo = false;
|
||||
config.processing.audio_tracks = 2;
|
||||
@ -673,7 +673,7 @@ fn video_dual_audio_stream() {
|
||||
|
||||
#[test]
|
||||
fn video_dual_audio_filter_stream() {
|
||||
let mut config = PlayoutConfig::new(Some(PathBuf::from("../assets/ffplayout.yml")), None);
|
||||
let mut config = PlayoutConfig::new(Some(PathBuf::from("../assets/ffplayout.toml")), None);
|
||||
config.out.mode = Stream;
|
||||
config.processing.add_logo = false;
|
||||
config.processing.audio_tracks = 2;
|
||||
@ -753,7 +753,7 @@ fn video_dual_audio_filter_stream() {
|
||||
|
||||
#[test]
|
||||
fn video_audio_multi_stream() {
|
||||
let mut config = PlayoutConfig::new(Some(PathBuf::from("../assets/ffplayout.yml")), None);
|
||||
let mut config = PlayoutConfig::new(Some(PathBuf::from("../assets/ffplayout.toml")), None);
|
||||
config.out.mode = Stream;
|
||||
config.processing.add_logo = false;
|
||||
config.out.output_cmd = Some(vec_strings![
|
||||
@ -842,7 +842,7 @@ fn video_audio_multi_stream() {
|
||||
|
||||
#[test]
|
||||
fn video_dual_audio_multi_stream() {
|
||||
let mut config = PlayoutConfig::new(Some(PathBuf::from("../assets/ffplayout.yml")), None);
|
||||
let mut config = PlayoutConfig::new(Some(PathBuf::from("../assets/ffplayout.toml")), None);
|
||||
config.out.mode = Stream;
|
||||
config.processing.add_logo = false;
|
||||
config.processing.audio_tracks = 2;
|
||||
@ -956,7 +956,7 @@ fn video_dual_audio_multi_stream() {
|
||||
|
||||
#[test]
|
||||
fn video_audio_text_multi_stream() {
|
||||
let mut config = PlayoutConfig::new(Some(PathBuf::from("../assets/ffplayout.yml")), None);
|
||||
let mut config = PlayoutConfig::new(Some(PathBuf::from("../assets/ffplayout.toml")), None);
|
||||
config.out.mode = Stream;
|
||||
config.processing.add_logo = false;
|
||||
config.text.add_text = true;
|
||||
@ -1069,7 +1069,7 @@ fn video_audio_text_multi_stream() {
|
||||
|
||||
#[test]
|
||||
fn video_dual_audio_multi_filter_stream() {
|
||||
let mut config = PlayoutConfig::new(Some(PathBuf::from("../assets/ffplayout.yml")), None);
|
||||
let mut config = PlayoutConfig::new(Some(PathBuf::from("../assets/ffplayout.toml")), None);
|
||||
config.out.mode = Stream;
|
||||
config.processing.add_logo = false;
|
||||
config.processing.audio_tracks = 2;
|
||||
@ -1198,7 +1198,7 @@ fn video_dual_audio_multi_filter_stream() {
|
||||
|
||||
#[test]
|
||||
fn video_audio_text_filter_stream() {
|
||||
let mut config = PlayoutConfig::new(Some(PathBuf::from("../assets/ffplayout.yml")), None);
|
||||
let mut config = PlayoutConfig::new(Some(PathBuf::from("../assets/ffplayout.toml")), None);
|
||||
config.out.mode = Stream;
|
||||
config.processing.add_logo = false;
|
||||
config.processing.audio_tracks = 1;
|
||||
@ -1320,7 +1320,7 @@ fn video_audio_text_filter_stream() {
|
||||
|
||||
#[test]
|
||||
fn video_audio_hls() {
|
||||
let mut config = PlayoutConfig::new(Some(PathBuf::from("../assets/ffplayout.yml")), None);
|
||||
let mut config = PlayoutConfig::new(Some(PathBuf::from("../assets/ffplayout.toml")), None);
|
||||
let player_control = PlayerControl::new();
|
||||
let playout_stat = PlayoutStatus::new();
|
||||
config.out.mode = HLS;
|
||||
@ -1407,7 +1407,7 @@ fn video_audio_hls() {
|
||||
|
||||
#[test]
|
||||
fn video_audio_sub_meta_hls() {
|
||||
let mut config = PlayoutConfig::new(Some(PathBuf::from("../assets/ffplayout.yml")), None);
|
||||
let mut config = PlayoutConfig::new(Some(PathBuf::from("../assets/ffplayout.toml")), None);
|
||||
let player_control = PlayerControl::new();
|
||||
let playout_stat = PlayoutStatus::new();
|
||||
config.out.mode = HLS;
|
||||
@ -1502,7 +1502,7 @@ fn video_audio_sub_meta_hls() {
|
||||
|
||||
#[test]
|
||||
fn video_multi_audio_hls() {
|
||||
let mut config = PlayoutConfig::new(Some(PathBuf::from("../assets/ffplayout.yml")), None);
|
||||
let mut config = PlayoutConfig::new(Some(PathBuf::from("../assets/ffplayout.toml")), None);
|
||||
let player_control = PlayerControl::new();
|
||||
let playout_stat = PlayoutStatus::new();
|
||||
config.out.mode = HLS;
|
||||
@ -1592,7 +1592,7 @@ fn video_multi_audio_hls() {
|
||||
|
||||
#[test]
|
||||
fn multi_video_audio_hls() {
|
||||
let mut config = PlayoutConfig::new(Some(PathBuf::from("../assets/ffplayout.yml")), None);
|
||||
let mut config = PlayoutConfig::new(Some(PathBuf::from("../assets/ffplayout.toml")), None);
|
||||
let player_control = PlayerControl::new();
|
||||
let playout_stat = PlayoutStatus::new();
|
||||
config.out.mode = HLS;
|
||||
@ -1707,7 +1707,7 @@ fn multi_video_audio_hls() {
|
||||
|
||||
#[test]
|
||||
fn multi_video_multi_audio_hls() {
|
||||
let mut config = PlayoutConfig::new(Some(PathBuf::from("../assets/ffplayout.yml")), None);
|
||||
let mut config = PlayoutConfig::new(Some(PathBuf::from("../assets/ffplayout.toml")), None);
|
||||
let player_control = PlayerControl::new();
|
||||
let playout_stat = PlayoutStatus::new();
|
||||
config.out.mode = HLS;
|
||||
|
@ -40,7 +40,7 @@ fn get_date_tomorrow() {
|
||||
|
||||
#[test]
|
||||
fn test_delta() {
|
||||
let mut config = PlayoutConfig::new(Some(PathBuf::from("../assets/ffplayout.yml")), None);
|
||||
let mut config = PlayoutConfig::new(Some(PathBuf::from("../assets/ffplayout.toml")), None);
|
||||
config.mail.recipient = "".into();
|
||||
config.processing.mode = Playlist;
|
||||
config.playlist.day_start = "00:00:00".into();
|
||||
|
Loading…
Reference in New Issue
Block a user