Merge pull request #77 from ffplayout/master

update
This commit is contained in:
jb-alvarado 2020-12-19 22:14:28 +01:00 committed by GitHub
commit 677a3ddb0a
9 changed files with 65 additions and 36 deletions

View File

@ -6,7 +6,7 @@
The purpose with ffplayout is to provide a 24/7 broadcasting solution that plays a *json* playlist for every day, while keeping the current playlist editable.
**Check [ffplayout-gui](https://github.com/ffplayout/ffplayout-gui): web-based GUI for ffplayout**
**Check [ffplayout-frontend](https://github.com/ffplayout/ffplayout-frontend): web-based GUI for ffplayout**
**Features**
-----

View File

@ -21,7 +21,7 @@
import os
from pydoc import locate
from ffplayout.utils import _playout, validate_ffmpeg_libs
from ffplayout.utils import _playout, stdin_args, validate_ffmpeg_libs
try:
if os.name != 'posix':
@ -37,18 +37,25 @@ except ImportError:
def main():
"""
pipe ffmpeg pre-process to final ffmpeg post-process,
or play with ffplay
play out depending on output mode
"""
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 stdin_args.mode:
output = locate('ffplayout.output.{}.output'.format(stdin_args.mode))
output()
output()
else:
script_dir = os.path.dirname(os.path.abspath(__file__))
output_dir = os.path.join(script_dir, 'ffplayout', 'output')
for output in os.listdir(output_dir):
if os.path.isfile(os.path.join(output_dir, output)) \
and output != '__init__.py':
mode = os.path.splitext(output)[0]
if mode == _playout.mode:
output = locate('ffplayout.output.{}.output'.format(mode))
output()
if __name__ == '__main__':

View File

@ -119,12 +119,11 @@ out:
-b:a 128k
stream_output: >-
-flags +global_header
-f flv "rtmp://localhost/live/stream"
-f flv rtmp://localhost/live/stream
hls_output: >-
-flags +cgop
-f hls
-hls_time 6
-hls_list_size 600
-hls_delete_threshold 30
-hls_flags append_list+delete_segments+omit_endlist+program_date_time
/var/www/srs/live/stream.m3u8
-hls_segment_filename /var/www/srs/live/stream-%09d.ts /var/www/srs/live/stream.m3u8

View File

@ -31,11 +31,14 @@ from .utils import _global, _pre, _text
def text_filter():
filter_chain = []
font = ''
if _text.add_text and _text.over_pre:
if _text.fontfile and os.path.isfile(_text.fontfile):
font = ":fontfile='{}'".format(_text.fontfile)
filter_chain = [
"null,zmq=b=tcp\\\\://'{}',drawtext=text='':fontfile='{}'".format(
_text.address.replace(':', '\\:'), _text.fontfile)]
"null,zmq=b=tcp\\\\://'{}',drawtext=text=''{}".format(
_text.address.replace(':', '\\:'), font)]
return filter_chain

View File

@ -26,13 +26,13 @@ from watchdog.events import PatternMatchingEventHandler
from watchdog.observers import Observer
from .filters import build_filtergraph
from .utils import MediaProbe, _storage, messenger, stdin_args
from .utils import MediaProbe, _current, _ff, _storage, messenger, stdin_args
# ------------------------------------------------------------------------------
# folder watcher
# ------------------------------------------------------------------------------
class MediaStore:
"""
fill media list for playing
@ -84,9 +84,10 @@ class MediaWatcher:
def __init__(self, media):
self._media = media
self.extensions = ['*{}'.format(ext) for ext in _storage.extensions]
self.event_handler = PatternMatchingEventHandler(
patterns=_storage.extensions)
patterns=self.extensions)
self.event_handler.on_created = self.on_created
self.event_handler.on_moved = self.on_moved
self.event_handler.on_deleted = self.on_deleted
@ -115,12 +116,18 @@ class MediaWatcher:
messenger.info('Move file from "{}" to "{}"'.format(event.src_path,
event.dest_path))
if _current.clip == event.src_path:
_ff.decoder.terminate()
def on_deleted(self, event):
self._media.remove(event.src_path)
messenger.info(
'Remove file from media list: "{}"'.format(event.src_path))
if _current.clip == event.src_path:
_ff.decoder.terminate()
def stop(self):
self.observer.stop()
self.observer.join()

View File

@ -4,7 +4,7 @@ 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,
from ffplayout.utils import (_current, _ff, _log, _playlist, _pre, _text,
ffmpeg_stderr_reader, messenger, pre_audio_codec,
stdin_args, terminate_processes)
@ -64,6 +64,7 @@ def output():
else:
current_file = src_cmd[3]
_current.clip = current_file
messenger.info('Play: "{}"'.format(current_file))
with Popen([

View File

@ -6,7 +6,7 @@ from threading import Thread
from ffplayout.folder import GetSourceFromFolder, MediaStore, MediaWatcher
from ffplayout.playlist import GetSourceFromPlaylist
from ffplayout.utils import (_ff, _log, _playlist, _playout,
from ffplayout.utils import (_current, _ff, _log, _playlist, _playout,
ffmpeg_stderr_reader, get_date, messenger,
stdin_args, terminate_processes)
@ -61,6 +61,7 @@ def output():
else:
current_file = src_cmd[3]
_current.clip = current_file
messenger.info('Play: "{}"'.format(current_file))
cmd = [
'ffmpeg', '-v', _log.ff_level.lower(), '-hide_banner',

View File

@ -4,8 +4,8 @@ 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,
from ffplayout.utils import (_current, _ff, _log, _playlist, _playout, _pre,
_text, ffmpeg_stderr_reader, get_date, messenger,
pre_audio_codec, stdin_args, terminate_processes)
_WINDOWS = os.name == 'nt'
@ -72,6 +72,7 @@ def output():
else:
current_file = src_cmd[3]
_current.clip = current_file
messenger.info('Play: "{}"'.format(current_file))
with Popen([

View File

@ -33,6 +33,7 @@ from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.utils import formatdate
from logging.handlers import TimedRotatingFileHandler
from shutil import which
from subprocess import STDOUT, CalledProcessError, check_output
from threading import Thread
from types import SimpleNamespace
@ -51,10 +52,6 @@ stdin_parser.add_argument(
'-c', '--config', help='file path to ffplayout.conf'
)
stdin_parser.add_argument(
'-d', '--desktop', help='preview on desktop', action='store_true'
)
stdin_parser.add_argument(
'-f', '--folder', help='play folder content'
)
@ -67,6 +64,10 @@ stdin_parser.add_argument(
'-i', '--loop', help='loop playlist infinitely', action='store_true'
)
stdin_parser.add_argument(
'-m', '--mode', help='set output mode: desktop, hls, stream'
)
stdin_parser.add_argument(
'-p', '--playlist', help='path from playlist'
)
@ -121,6 +122,7 @@ _playout = SimpleNamespace()
_init = SimpleNamespace(load=True)
_ff = SimpleNamespace(decoder=None, encoder=None)
_current = SimpleNamespace(clip=None)
_global = SimpleNamespace(time_delta=0)
@ -216,8 +218,9 @@ def load_config():
_pre.h = cfg['processing']['height']
_pre.aspect = cfg['processing']['aspect']
_pre.fps = cfg['processing']['fps']
_pre.v_bitrate = cfg['processing']['width'] * 50
_pre.v_bufsize = cfg['processing']['width'] * 50 / 2
_pre.v_bitrate = cfg['processing']['width'] * \
cfg['processing']['height'] / 10
_pre.v_bufsize = _pre.v_bitrate / 2
_pre.realtime = cfg['processing']['use_realtime']
_playout.mode = cfg['out']['mode']
@ -448,14 +451,26 @@ messenger = Messenger()
# ------------------------------------------------------------------------------
# check ffmpeg libs
# check binaries and ffmpeg libs
# ------------------------------------------------------------------------------
def is_in_system(name):
"""
Check whether name is on PATH and marked as executable
"""
if which(name) is None:
messenger.error('{} is not found on system'.format(name))
sys.exit(1)
def ffmpeg_libs():
"""
check which external libs are compiled in ffmpeg,
for using them later
"""
is_in_system('ffmpeg')
is_in_system('ffprobe')
cmd = ['ffmpeg', '-filters']
libs = []
filters = []
@ -491,10 +506,6 @@ def validate_ffmpeg_libs():
if 'libfdk-aac' not in FF_LIBS['libs']:
playout_logger.warning(
'ffmpeg contains no libfdk-aac! No high quality aac...')
if 'libtwolame' not in FF_LIBS['libs']:
playout_logger.warning(
'ffmpeg contains no libtwolame!'
' Loudness correction use mp2 audio codec...')
if 'tpad' not in FF_LIBS['filters']:
playout_logger.error('ffmpeg contains no tpad filter!')
if 'zmq' not in FF_LIBS['filters']:
@ -1000,7 +1011,6 @@ def pre_audio_codec():
and works not well together with the loudnorm filter
"""
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']
return ['-c:a', 'mp2', '-b:a', '384k', '-ar', '48000', '-ac', '2']
else:
return ['-c:a', 's302m', '-strict', '-2', '-ar', '48000', '-ac', '2']