modularize output

This commit is contained in:
jb-alvarado 2020-06-07 20:08:54 +02:00
parent 9af5a67530
commit fbfb9a7712
9 changed files with 404 additions and 179 deletions

View File

@ -19,15 +19,9 @@
# ------------------------------------------------------------------------------
import os
from subprocess import PIPE, Popen
from threading import Thread
from pydoc import locate
from ffplayout.folder import GetSourceFromFolder, MediaStore, MediaWatcher
from ffplayout.playlist import GetSourceFromPlaylist
from ffplayout.utils import (_ff, _log, _playlist, _playout, _pre_comp, _text,
ffmpeg_stderr_reader, get_date, messenger,
pre_audio_codec, stdin_args, terminate_processes,
validate_ffmpeg_libs)
from ffplayout.utils import _playout, validate_ffmpeg_libs
try:
if os.name != 'posix':
@ -36,9 +30,6 @@ try:
except ImportError:
print('colorama import failed, no colored console output on windows...')
_WINDOWS = os.name == 'nt'
COPY_BUFSIZE = 1024 * 1024 if _WINDOWS else 65424
# ------------------------------------------------------------------------------
# main functions
@ -49,105 +40,15 @@ def main():
pipe ffmpeg pre-process to final ffmpeg post-process,
or play with ffplay
"""
year = get_date(False).split('-')[0]
overlay = []
ff_pre_settings = [
'-pix_fmt', 'yuv420p', '-r', str(_pre_comp.fps),
'-c:v', 'mpeg2video', '-intra',
'-b:v', '{}k'.format(_pre_comp.v_bitrate),
'-minrate', '{}k'.format(_pre_comp.v_bitrate),
'-maxrate', '{}k'.format(_pre_comp.v_bitrate),
'-bufsize', '{}k'.format(_pre_comp.v_bufsize)
] + pre_audio_codec() + ['-f', 'mpegts', '-']
for output in os.listdir('ffplayout/output'):
if os.path.isfile(os.path.join('ffplayout/output', output)) \
and output != '__init__.py':
mode = os.path.splitext(output)[0]
if mode == _playout.mode:
output = locate('ffplayout.output.{}.output'.format(mode))
if _text.add_text:
messenger.info('Using drawtext node, listening on address: {}'.format(
_text.address
))
overlay = [
'-vf',
"null,zmq=b=tcp\\\\://'{}',drawtext=text='':fontfile='{}'".format(
_text.address.replace(':', '\\:'), _text.fontfile)
]
try:
if _playout.preview or stdin_args.desktop:
# preview playout to player
_ff.encoder = Popen([
'ffplay', '-hide_banner', '-nostats', '-i', 'pipe:0'
] + overlay, stderr=PIPE, stdin=PIPE, stdout=None)
else:
_ff.encoder = Popen([
'ffmpeg', '-v', _log.ff_level.lower(), '-hide_banner',
'-nostats', '-re', '-thread_queue_size', '256', '-i', 'pipe:0'
] + overlay + [
'-metadata', 'service_name=' + _playout.name,
'-metadata', 'service_provider=' + _playout.provider,
'-metadata', 'year={}'.format(year)
] + _playout.post_comp_param + [_playout.out_addr],
stdin=PIPE, stderr=PIPE)
enc_err_thread = Thread(target=ffmpeg_stderr_reader,
args=(_ff.encoder.stderr, False))
enc_err_thread.daemon = True
enc_err_thread.start()
if _playlist.mode and not stdin_args.folder:
watcher = None
get_source = GetSourceFromPlaylist()
else:
messenger.info('Start folder mode')
media = MediaStore()
watcher = MediaWatcher(media)
get_source = GetSourceFromFolder(media)
try:
for src_cmd in get_source.next():
messenger.debug('src_cmd: "{}"'.format(src_cmd))
if src_cmd[0] == '-i':
current_file = src_cmd[1]
else:
current_file = src_cmd[3]
messenger.info('Play: "{}"'.format(current_file))
with Popen([
'ffmpeg', '-v', _log.ff_level.lower(), '-hide_banner',
'-nostats'] + src_cmd + ff_pre_settings,
stdout=PIPE, stderr=PIPE) as _ff.decoder:
dec_err_thread = Thread(target=ffmpeg_stderr_reader,
args=(_ff.decoder.stderr, True))
dec_err_thread.daemon = True
dec_err_thread.start()
while True:
buf = _ff.decoder.stdout.read(COPY_BUFSIZE)
if not buf:
break
_ff.encoder.stdin.write(buf)
except BrokenPipeError:
messenger.error('Broken Pipe!')
terminate_processes(watcher)
except SystemExit:
messenger.info('Got close command')
terminate_processes(watcher)
except KeyboardInterrupt:
messenger.warning('Program terminated')
terminate_processes(watcher)
# close encoder when nothing is to do anymore
if _ff.encoder.poll() is None:
_ff.encoder.terminate()
finally:
if _ff.encoder.poll() is None:
_ff.encoder.terminate()
_ff.encoder.wait()
output()
if __name__ == '__main__':

View File

@ -31,16 +31,18 @@ logging:
log_level: "DEBUG"
ffmpeg_level: "ERROR"
pre_compress:
helptext: Settings for the pre-compression. All clips get prepared in that way,
pre_process:
helptext: Settings for the pre_process. All clips get prepared in that way,
so the input for the final compression is unique. '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 'number:number',
for example '100:-1' for proportional scaling. With 'logo_opacity' logo can
become transparent. With 'logo_filter' 'overlay=W-w-12:12' you can modify
the logo position. With 'use_loudnorm' you can activate single pass EBU R128
loudness normalization. 'loud_*' can adjust the loudnorm filter. [Output is
always progressive!]
loudness normalization. 'loud_*' can adjust the loudnorm filter. 'output_count'
sets the outputs for the filtering, > 1 gives the option to use the same filters
for multiple outputs. This outputs can be taken in 'ffmpeg_param', names will be
vout2, vout3; aout2, aout2 etc.
width: 1024
height: 576
aspect: 1.778
@ -54,6 +56,7 @@ pre_compress:
loud_I: -18
loud_TP: -1.5
loud_LRA: 11
output_count: 1
playlist:
helptext: Set 'playlist_mode' to 'False' if you want to play clips from the [STORAGE]
@ -84,18 +87,21 @@ text:
helptext: Overlay text in combination with libzmq for remote text manipulation.
On windows fontfile path need to be like this 'C\:/WINDOWS/fonts/DejaVuSans.ttf'.
In a standard environment the filter drawtext node is Parsed_drawtext_2.
'over_pre' if True text will be overlay in pre processing. Continue same text
over multiple files is in that mode not possible.
add_text: False
over_pre: False
bind_address: "127.0.0.1:5555"
fontfile: "/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf"
out:
helptext: The final playout post compression. Set the settings to your needs.
'preview' works only on a desktop system with ffplay!! Set it to 'True', if
you need it.
preview: False
helptext: The final playout compression. Set the settings to your needs.
'mode' has the standard options 'desktop', 'hls', 'stream'. Self made outputs
can be define, by adding script in output folder with an 'output' function inside.
mode: 'stream'
service_name: "Live Stream"
service_provider: "example.org"
post_ffmpeg_param: >-
ffmpeg_param: >-
-c:v libx264
-crf 23
-x264-params keyint=50:min-keyint=25:scenecut=-1
@ -108,5 +114,4 @@ out:
-ar 44100
-b:a 128k
-flags +global_header
-f flv
out_addr: "rtmp://localhost/live/stream"
-f flv "rtmp://localhost/live/stream"

View File

@ -21,13 +21,25 @@ import math
import os
import re
from .utils import _pre_comp
from .utils import _pre, _text
# ------------------------------------------------------------------------------
# building filters,
# when is needed add individuell filters to match output format
# ------------------------------------------------------------------------------
def text_filter():
filter_chain = []
if _text.add_text and _text.over_pre:
filter_chain = [
"null,zmq=b=tcp\\\\://'{}',drawtext=text='':fontfile='{}'".format(
_text.address.replace(':', '\\:'), _text.fontfile)]
return filter_chain
def deinterlace_filter(probe):
"""
when material is interlaced,
@ -50,15 +62,15 @@ def pad_filter(probe):
filter_chain = []
if not math.isclose(probe.video[0]['aspect'],
_pre_comp.aspect, abs_tol=0.03):
if probe.video[0]['aspect'] < _pre_comp.aspect:
_pre.aspect, abs_tol=0.03):
if probe.video[0]['aspect'] < _pre.aspect:
filter_chain.append(
'pad=ih*{}/{}/sar:ih:(ow-iw)/2:(oh-ih)/2'.format(_pre_comp.w,
_pre_comp.h))
elif probe.video[0]['aspect'] > _pre_comp.aspect:
'pad=ih*{}/{}/sar:ih:(ow-iw)/2:(oh-ih)/2'.format(_pre.w,
_pre.h))
elif probe.video[0]['aspect'] > _pre.aspect:
filter_chain.append(
'pad=iw:iw*{}/{}/sar:(ow-iw)/2:(oh-ih)/2'.format(_pre_comp.h,
_pre_comp.w))
'pad=iw:iw*{}/{}/sar:(ow-iw)/2:(oh-ih)/2'.format(_pre.h,
_pre.w))
return filter_chain
@ -69,8 +81,8 @@ def fps_filter(probe):
"""
filter_chain = []
if probe.video[0]['fps'] != _pre_comp.fps:
filter_chain.append('fps={}'.format(_pre_comp.fps))
if probe.video[0]['fps'] != _pre.fps:
filter_chain.append('fps={}'.format(_pre.fps))
return filter_chain
@ -82,13 +94,13 @@ def scale_filter(probe):
"""
filter_chain = []
if int(probe.video[0]['width']) != _pre_comp.w or \
int(probe.video[0]['height']) != _pre_comp.h:
filter_chain.append('scale={}:{}'.format(_pre_comp.w, _pre_comp.h))
if int(probe.video[0]['width']) != _pre.w or \
int(probe.video[0]['height']) != _pre.h:
filter_chain.append('scale={}:{}'.format(_pre.w, _pre.h))
if not math.isclose(probe.video[0]['aspect'],
_pre_comp.aspect, abs_tol=0.03):
filter_chain.append('setdar=dar={}'.format(_pre_comp.aspect))
_pre.aspect, abs_tol=0.03):
filter_chain.append('setdar=dar={}'.format(_pre.aspect))
return filter_chain
@ -115,27 +127,27 @@ def overlay_filter(duration, ad, ad_last, ad_next):
when ad is comming next fade logo out,
when clip before was an ad fade logo in
"""
logo_filter = '[v]null[logo]'
logo_filter = '[v]null'
scale_filter = ''
if _pre_comp.add_logo and os.path.isfile(_pre_comp.logo) and not ad:
if _pre.add_logo and os.path.isfile(_pre.logo) and not ad:
logo_chain = []
if _pre_comp.logo_scale and \
re.match(r'\d+:-?\d+', _pre_comp.logo_scale):
scale_filter = 'scale={},'.format(_pre_comp.logo_scale)
if _pre.logo_scale and \
re.match(r'\d+:-?\d+', _pre.logo_scale):
scale_filter = 'scale={},'.format(_pre.logo_scale)
logo_extras = 'format=rgba,{}colorchannelmixer=aa={}'.format(
scale_filter, _pre_comp.logo_opacity)
scale_filter, _pre.logo_opacity)
loop = 'loop=loop=-1:size=1:start=0'
logo_chain.append(
'movie={},{},{}'.format(_pre_comp.logo, loop, logo_extras))
'movie={},{},{}'.format(_pre.logo, loop, logo_extras))
if ad_last:
logo_chain.append('fade=in:st=0:d=1.0:alpha=1')
if ad_next:
logo_chain.append('fade=out:st={}:d=1.0:alpha=1'.format(
duration - 1))
logo_filter = '{}[l];[v][l]{}:shortest=1[logo]'.format(
','.join(logo_chain), _pre_comp.logo_filter)
logo_filter = '{}[l];[v][l]{}:shortest=1'.format(
','.join(logo_chain), _pre.logo_filter)
return logo_filter
@ -161,9 +173,9 @@ def add_loudnorm(probe):
"""
loud_filter = []
if probe.audio and _pre_comp.add_loudnorm:
if probe.audio and _pre.add_loudnorm:
loud_filter = [('loudnorm=I={}:TP={}:LRA={}').format(
_pre_comp.loud_i, _pre_comp.loud_tp, _pre_comp.loud_lra)]
_pre.loud_i, _pre.loud_tp, _pre.loud_lra)]
return loud_filter
@ -175,7 +187,7 @@ def extend_audio(probe, duration):
pad_filter = []
if probe.audio and 'duration' in probe.audio[0] and \
duration > float(probe.audio[0]['duration']) + 0.3:
duration > float(probe.audio[0]['duration']) + 0.1:
pad_filter.append('apad=whole_dur={}'.format(duration))
return pad_filter
@ -189,25 +201,45 @@ def extend_video(probe, duration, target_duration):
if 'duration' in probe.video[0] and \
target_duration < duration > float(
probe.video[0]['duration']) + 0.3:
probe.video[0]['duration']) + 0.1:
pad_filter.append('tpad=stop_mode=add:stop_duration={}'.format(
duration - float(probe.video[0]['duration'])))
return pad_filter
def split_filter(filter_type):
map_node = []
filter_prefix = ''
if filter_type == 'a':
filter_prefix = 'a'
if _pre.output_count > 1:
for num in range(_pre.output_count):
map_node.append('[{}out{}]'.format(filter_type, num + 1))
filter = ',{}split={}{}'.format(filter_prefix, _pre.output_count,
''.join(map_node))
else:
filter = '[{}out1]'.format(filter_type)
return filter
def build_filtergraph(duration, seek, out, ad, ad_last, ad_next, probe, msg):
"""
build final filter graph, with video and audio chain
"""
video_chain = []
audio_chain = []
video_map = ['-map', '[logo]']
if out > duration:
seek = 0
if probe.video[0]:
video_chain += text_filter()
video_chain += deinterlace_filter(probe)
video_chain += pad_filter(probe)
video_chain += fps_filter(probe)
@ -229,17 +261,16 @@ def build_filtergraph(duration, seek, out, ad, ad_last, ad_next, probe, msg):
video_filter = 'null[v]'
logo_filter = overlay_filter(out - seek, ad, ad_last, ad_next)
v_split = split_filter('v')
video_map = ['-map', '[vout1]']
video_filter = [
'-filter_complex', '[0:v]{};{}'.format(
video_filter, logo_filter)]
'-filter_complex', '[0:v]{};{}{}'.format(
video_filter, logo_filter, v_split)]
if audio_chain:
audio_filter = [
'-filter_complex', '{}[a]'.format(','.join(audio_chain))]
audio_map = ['-map', '[a]']
else:
audio_filter = []
audio_map = ['-map', '0:a']
a_split = split_filter('a')
audio_map = ['-map', '[aout1]']
audio_filter = [
'-filter_complex', '{}{}'.format(','.join(audio_chain), a_split)]
if probe.video[0]:
return video_filter + audio_filter + video_map + audio_map

View File

104
ffplayout/output/desktop.py Normal file
View File

@ -0,0 +1,104 @@
import os
from subprocess import PIPE, Popen
from threading import Thread
from ffplayout.folder import GetSourceFromFolder, MediaStore, MediaWatcher
from ffplayout.playlist import GetSourceFromPlaylist
from ffplayout.utils import (_ff, _log, _playlist, _pre, _text,
ffmpeg_stderr_reader, messenger, pre_audio_codec,
stdin_args, terminate_processes)
_WINDOWS = os.name == 'nt'
COPY_BUFSIZE = 1024 * 1024 if _WINDOWS else 65424
def output():
"""
this output is for playing on desktop with ffplay
"""
overlay = []
ff_pre_settings = [
'-pix_fmt', 'yuv420p', '-r', str(_pre.fps),
'-c:v', 'mpeg2video', '-intra',
'-b:v', '{}k'.format(_pre.v_bitrate),
'-minrate', '{}k'.format(_pre.v_bitrate),
'-maxrate', '{}k'.format(_pre.v_bitrate),
'-bufsize', '{}k'.format(_pre.v_bufsize)
] + pre_audio_codec() + ['-f', 'mpegts', '-']
if _text.add_text and not _text.over_pre:
messenger.info('Using drawtext node, listening on address: {}'.format(
_text.address
))
overlay = [
'-vf',
"null,zmq=b=tcp\\\\://'{}',drawtext=text='':fontfile='{}'".format(
_text.address.replace(':', '\\:'), _text.fontfile)
]
try:
_ff.encoder = Popen([
'ffplay', '-hide_banner', '-nostats', '-i', 'pipe:0'
] + overlay, stderr=PIPE, stdin=PIPE, stdout=None)
enc_err_thread = Thread(target=ffmpeg_stderr_reader,
args=(_ff.encoder.stderr, False))
enc_err_thread.daemon = True
enc_err_thread.start()
if _playlist.mode and not stdin_args.folder:
watcher = None
get_source = GetSourceFromPlaylist()
else:
messenger.info('Start folder mode')
media = MediaStore()
watcher = MediaWatcher(media)
get_source = GetSourceFromFolder(media)
try:
for src_cmd in get_source.next():
messenger.debug('src_cmd: "{}"'.format(src_cmd))
if src_cmd[0] == '-i':
current_file = src_cmd[1]
else:
current_file = src_cmd[3]
messenger.info('Play: "{}"'.format(current_file))
with Popen([
'ffmpeg', '-v', _log.ff_level.lower(), '-hide_banner',
'-nostats'] + src_cmd + ff_pre_settings,
stdout=PIPE, stderr=PIPE) as _ff.decoder:
dec_err_thread = Thread(target=ffmpeg_stderr_reader,
args=(_ff.decoder.stderr, True))
dec_err_thread.daemon = True
dec_err_thread.start()
while True:
buf = _ff.decoder.stdout.read(COPY_BUFSIZE)
if not buf:
break
_ff.encoder.stdin.write(buf)
except BrokenPipeError:
messenger.error('Broken Pipe!')
terminate_processes(watcher)
except SystemExit:
messenger.info('Got close command')
terminate_processes(watcher)
except KeyboardInterrupt:
messenger.warning('Program terminated')
terminate_processes(watcher)
# close encoder when nothing is to do anymore
if _ff.encoder.poll() is None:
_ff.encoder.terminate()
finally:
if _ff.encoder.poll() is None:
_ff.encoder.terminate()
_ff.encoder.wait()

72
ffplayout/output/hls.py Normal file
View File

@ -0,0 +1,72 @@
from subprocess import PIPE, Popen
from threading import Thread
from ffplayout.folder import GetSourceFromFolder, MediaStore, MediaWatcher
from ffplayout.playlist import GetSourceFromPlaylist
from ffplayout.utils import (_ff, _log, _playlist, _playout,
ffmpeg_stderr_reader, get_date, messenger,
stdin_args, terminate_processes)
def output():
"""
this output is hls output, no preprocess is needed.
"""
year = get_date(False).split('-')[0]
try:
if _playlist.mode and not stdin_args.folder:
watcher = None
get_source = GetSourceFromPlaylist()
else:
messenger.info('Start folder mode')
media = MediaStore()
watcher = MediaWatcher(media)
get_source = GetSourceFromFolder(media)
try:
for src_cmd in get_source.next():
messenger.debug('src_cmd: "{}"'.format(src_cmd))
if src_cmd[0] == '-i':
current_file = src_cmd[1]
else:
current_file = src_cmd[3]
messenger.info('Play: "{}"'.format(current_file))
cmd = [
'ffmpeg', '-v', _log.ff_level.lower(), '-hide_banner',
'-nostats', '-re', '-thread_queue_size', '256'
] + src_cmd + [
'-metadata', 'service_name=' + _playout.name,
'-metadata', 'service_provider=' + _playout.provider,
'-metadata', 'year={}'.format(year)
] + _playout.ffmpeg_param
_ff.encoder = Popen(cmd, stdin=PIPE, stderr=PIPE)
enc_thread = Thread(target=ffmpeg_stderr_reader,
args=(_ff.encoder.stderr, True))
enc_thread.daemon = True
enc_thread.start()
enc_thread.join()
except BrokenPipeError:
messenger.error('Broken Pipe!')
terminate_processes(watcher)
except SystemExit:
messenger.info('Got close command')
terminate_processes(watcher)
except KeyboardInterrupt:
messenger.warning('Program terminated')
terminate_processes(watcher)
# close encoder when nothing is to do anymore
if _ff.encoder.poll() is None:
_ff.encoder.terminate()
finally:
if _ff.encoder.poll() is None:
_ff.encoder.terminate()
_ff.encoder.wait()

111
ffplayout/output/stream.py Normal file
View File

@ -0,0 +1,111 @@
import os
from subprocess import PIPE, Popen
from threading import Thread
from ffplayout.folder import GetSourceFromFolder, MediaStore, MediaWatcher
from ffplayout.playlist import GetSourceFromPlaylist
from ffplayout.utils import (_ff, _log, _playlist, _playout, _pre, _text,
ffmpeg_stderr_reader, get_date, messenger,
pre_audio_codec, stdin_args, terminate_processes)
_WINDOWS = os.name == 'nt'
COPY_BUFSIZE = 1024 * 1024 if _WINDOWS else 65424
def output():
"""
this output is for streaming to a target address,
like rtmp, rtp, svt, etc.
"""
year = get_date(False).split('-')[0]
overlay = []
ff_pre_settings = [
'-pix_fmt', 'yuv420p', '-r', str(_pre.fps),
'-c:v', 'mpeg2video', '-intra',
'-b:v', '{}k'.format(_pre.v_bitrate),
'-minrate', '{}k'.format(_pre.v_bitrate),
'-maxrate', '{}k'.format(_pre.v_bitrate),
'-bufsize', '{}k'.format(_pre.v_bufsize)
] + pre_audio_codec() + ['-f', 'mpegts', '-']
if _text.add_text and not _text.over_pre:
messenger.info('Using drawtext node, listening on address: {}'.format(
_text.address
))
overlay = [
'-vf',
"null,zmq=b=tcp\\\\://'{}',drawtext=text='':fontfile='{}'".format(
_text.address.replace(':', '\\:'), _text.fontfile)
]
try:
_ff.encoder = Popen([
'ffmpeg', '-v', _log.ff_level.lower(), '-hide_banner',
'-nostats', '-re', '-thread_queue_size', '256', '-i', 'pipe:0'
] + overlay + [
'-metadata', 'service_name=' + _playout.name,
'-metadata', 'service_provider=' + _playout.provider,
'-metadata', 'year={}'.format(year)
] + _playout.ffmpeg_param, stdin=PIPE, stderr=PIPE)
enc_err_thread = Thread(target=ffmpeg_stderr_reader,
args=(_ff.encoder.stderr, False))
enc_err_thread.daemon = True
enc_err_thread.start()
if _playlist.mode and not stdin_args.folder:
watcher = None
get_source = GetSourceFromPlaylist()
else:
messenger.info('Start folder mode')
media = MediaStore()
watcher = MediaWatcher(media)
get_source = GetSourceFromFolder(media)
try:
for src_cmd in get_source.next():
messenger.debug('src_cmd: "{}"'.format(src_cmd))
if src_cmd[0] == '-i':
current_file = src_cmd[1]
else:
current_file = src_cmd[3]
messenger.info('Play: "{}"'.format(current_file))
with Popen([
'ffmpeg', '-v', _log.ff_level.lower(), '-hide_banner',
'-nostats'] + src_cmd + ff_pre_settings,
stdout=PIPE, stderr=PIPE) as _ff.decoder:
dec_err_thread = Thread(target=ffmpeg_stderr_reader,
args=(_ff.decoder.stderr, True))
dec_err_thread.daemon = True
dec_err_thread.start()
while True:
buf = _ff.decoder.stdout.read(COPY_BUFSIZE)
if not buf:
break
_ff.encoder.stdin.write(buf)
except BrokenPipeError:
messenger.error('Broken Pipe!')
terminate_processes(watcher)
except SystemExit:
messenger.info('Got close command')
terminate_processes(watcher)
except KeyboardInterrupt:
messenger.warning('Program terminated')
terminate_processes(watcher)
# close encoder when nothing is to do anymore
if _ff.encoder.poll() is None:
_ff.encoder.terminate()
finally:
if _ff.encoder.poll() is None:
_ff.encoder.terminate()
_ff.encoder.wait()

View File

@ -224,7 +224,7 @@ class GetSourceFromPlaylist:
if self.clip_nodes is None:
self.eof_handling(
'No valid playlist:\n{}'.format(self.json_file), True, 300)
'No valid playlist:\n{}'.format(self.json_file), True, 30)
yield self.src_cmd + self.filtergraph
continue

View File

@ -113,7 +113,7 @@ def get_time(time_format):
_general = SimpleNamespace()
_mail = SimpleNamespace()
_log = SimpleNamespace()
_pre_comp = SimpleNamespace()
_pre = SimpleNamespace()
_playlist = SimpleNamespace()
_storage = SimpleNamespace()
_text = SimpleNamespace()
@ -178,15 +178,16 @@ def load_config():
_mail.recip = cfg['mail']['recipient']
_mail.level = cfg['mail']['mail_level']
_pre_comp.add_logo = cfg['pre_compress']['add_logo']
_pre_comp.logo = cfg['pre_compress']['logo']
_pre_comp.logo_scale = cfg['pre_compress']['logo_scale']
_pre_comp.logo_filter = cfg['pre_compress']['logo_filter']
_pre_comp.logo_opacity = cfg['pre_compress']['logo_opacity']
_pre_comp.add_loudnorm = cfg['pre_compress']['add_loudnorm']
_pre_comp.loud_i = cfg['pre_compress']['loud_I']
_pre_comp.loud_tp = cfg['pre_compress']['loud_TP']
_pre_comp.loud_lra = cfg['pre_compress']['loud_LRA']
_pre.add_logo = cfg['pre_process']['add_logo']
_pre.logo = cfg['pre_process']['logo']
_pre.logo_scale = cfg['pre_process']['logo_scale']
_pre.logo_filter = cfg['pre_process']['logo_filter']
_pre.logo_opacity = cfg['pre_process']['logo_opacity']
_pre.add_loudnorm = cfg['pre_process']['add_loudnorm']
_pre.loud_i = cfg['pre_process']['loud_I']
_pre.loud_tp = cfg['pre_process']['loud_TP']
_pre.loud_lra = cfg['pre_process']['loud_LRA']
_pre.output_count = cfg['pre_process']['output_count']
_playlist.mode = cfg['playlist']['playlist_mode']
_playlist.path = cfg['playlist']['path']
@ -199,6 +200,7 @@ def load_config():
_storage.shuffle = cfg['storage']['shuffle']
_text.add_text = cfg['text']['add_text']
_text.over_pre = cfg['text']['over_pre']
_text.address = cfg['text']['bind_address']
_text.fontfile = cfg['text']['fontfile']
@ -209,18 +211,17 @@ def load_config():
_log.level = cfg['logging']['log_level']
_log.ff_level = cfg['logging']['ffmpeg_level']
_pre_comp.w = cfg['pre_compress']['width']
_pre_comp.h = cfg['pre_compress']['height']
_pre_comp.aspect = cfg['pre_compress']['aspect']
_pre_comp.fps = cfg['pre_compress']['fps']
_pre_comp.v_bitrate = cfg['pre_compress']['width'] * 50
_pre_comp.v_bufsize = cfg['pre_compress']['width'] * 50 / 2
_pre.w = cfg['pre_process']['width']
_pre.h = cfg['pre_process']['height']
_pre.aspect = cfg['pre_process']['aspect']
_pre.fps = cfg['pre_process']['fps']
_pre.v_bitrate = cfg['pre_process']['width'] * 50
_pre.v_bufsize = cfg['pre_process']['width'] * 50 / 2
_playout.preview = cfg['out']['preview']
_playout.mode = cfg['out']['mode']
_playout.name = cfg['out']['service_name']
_playout.provider = cfg['out']['service_provider']
_playout.post_comp_param = cfg['out']['post_ffmpeg_param'].split(' ')
_playout.out_addr = cfg['out']['out_addr']
_playout.ffmpeg_param = cfg['out']['ffmpeg_param'].split(' ')
_init.load = False
@ -782,7 +783,7 @@ def gen_dummy(duration):
return [
'-f', 'lavfi', '-i',
'color=c={}:s={}x{}:d={}:r={},format=pix_fmts=yuv420p'.format(
color, _pre_comp.w, _pre_comp.h, duration, _pre_comp.fps
color, _pre.w, _pre.h, duration, _pre.fps
),
'-f', 'lavfi', '-i', 'anoisesrc=d={}:c=pink:r=48000:a=0.05'.format(
duration)
@ -989,7 +990,7 @@ def pre_audio_codec():
s302m has higher quality, but is experimental
and works not well together with the loudnorm filter
"""
if _pre_comp.add_loudnorm:
if _pre.add_loudnorm:
acodec = 'libtwolame' if 'libtwolame' in FF_LIBS['libs'] else 'mp2'
return ['-c:a', acodec, '-b:a', '384k', '-ar', '48000', '-ac', '2']
else: