diff options
author | Christian Pointner <equinox@spreadspace.org> | 2018-01-29 01:22:23 +0100 |
---|---|---|
committer | Christian Pointner <equinox@spreadspace.org> | 2018-01-29 01:22:23 +0100 |
commit | 87196b9f546dd52324242587be51402332f53ac3 (patch) | |
tree | c7a34987f264958dd715a26e78076a4e64a1c989 | |
parent | porter get created now (diff) |
hasic streamer support works now
-rw-r--r-- | src/examples/elevate2018.json | 138 | ||||
-rwxr-xr-x | src/flufigut.py | 96 |
2 files changed, 214 insertions, 20 deletions
diff --git a/src/examples/elevate2018.json b/src/examples/elevate2018.json new file mode 100644 index 0000000..c006310 --- /dev/null +++ b/src/examples/elevate2018.json @@ -0,0 +1,138 @@ +{ + "globals":{ + "templates": "default", + "version": "0.10.1", + "name": "elevate-live", + "description": "Live from Elevate Festival 2018", + "manager": { + "machine": "telesto", + "host": "109.73.158.69", + "port": 7531, + "transport": "ssl" + }, + "admin": { + "username": "equinox", + "password": "change-me" + }, + "stats": { + "rrd": { + "directory": "/var/lib/flumotion/rrd" + } + }, + "resolutions": { + "720p25": { "width": 1280, "height": 720, "rate": "25/1" }, + "480p25": { "width": 854, "height": 480, "rate": "25/1" }, + "360p25": { "width": 640, "height": 360, "rate": "25/1" }, + "240p25": { "width": 426, "height": 240, "rate": "25/1" } + }, + "formats": { + "flash": { "muxer": "flv", "video": "h264", "audio": "aac", "samplerate": 44100 }, + "webm": { "muxer": "webm", "video": "vp8", "audio": "vorbis" }, + "ogg": { "muxer": "ogg", "video": "theora", "audio": "vorbis" }, + "mp3": { "muxer": "mp3", "video": "null", "audio": "mp3" }, + "rec": { "muxer": "mkv", "video": "mjpeg", "audio": "raw" } + }, + "profiles": { + "high": { "video": "720p25", "audio": 160 }, + "medium": { "video": "480p25", "audio": 128 }, + "low": { "video": "360p25", "audio": 96 }, + "mini": { "video": "240p25", "audio": 64 }, + "full": { "video": "720p25", "audio": 0 } + }, + "bitrates": { + "h264": { "720p25": 1800, "480p25": 1000, "360p25": 600, "240p25": 300 }, + "vp8": { "720p25": 1800, "480p25": 1000, "360p25": 600, "240p25": 300 }, + "mjpeg": { "720p25": 95 } + }, + "workers": { + "telesto": [ "input-sdi-orig", "resize-sdi-orig", "resample-sdi-orig", + "encoder-sdi-orig-vorbis-160", "encoder-sdi-orig-vorbis-128", "encoder-sdi-orig-vorbis-96", "encoder-sdi-orig-vorbis-64", + "encoder-sdi-orig-aac-160", "encoder-sdi-orig-aac-128", "encoder-sdi-orig-aac-96", "encoder-sdi-orig-aac-64", + "encoder-sdi-orig-mp3-160", "encoder-sdi-orig-mp3-128", "encoder-sdi-orig-mp3-96", "encoder-sdi-orig-mp3-64", + "encoder-sdi-orig-h264-720p25", "encoder-sdi-orig-h264-480p25", "encoder-sdi-orig-h264-240p25", + "encoder-sdi-orig-mjpeg-720p25", "muxer-avr-rec-full", "encoder-sdi-orig-raw-0" ], + "calypso": [ "encoder-sdi-orig-vp8-720p25", "encoder-sdi-orig-vp8-480p25", "encoder-sdi-orig-vp8-360p25", "encoder-sdi-orig-vp8-240p25", + "encoder-sdi-orig-h264-360p25", + "muxer-av-orig-webm-high", "muxer-av-orig-webm-medium", "muxer-av-orig-webm-low", "muxer-av-orig-webm-mini", + "muxer-av-orig-flash-high", "muxer-av-orig-flash-medium", "muxer-av-orig-flash-low", "muxer-av-orig-flash-mini", + "muxer-audio-orig-ogg-high", "muxer-audio-orig-ogg-medium", "muxer-audio-orig-ogg-low", "muxer-audio-orig-ogg-mini", + "muxer-audio-orig-mp3-high", "muxer-audio-orig-mp3-medium", "muxer-audio-orig-mp3-low", "muxer-audio-orig-mp3-mini", + "streamer-local1", "recorder-av", "recorder-audio" ], + "elemc00": [ "repeater-pub" ], + "elemc01": [ "streamer-pub1" ], + "elemc02": [ "streamer-pub2" ] + } + }, + "inputs": { + "sdi-orig": { + "type": "decklink", + "master": true, + "properties": { + "resolution": "720p25", + "samplerate": 48000, + "device": 0, + "connection": 0, + "audio-input": 0, + "mode": 10 + } + } + }, + "muxes": { + "av-orig": { + "video": "sdi-orig:video", + "audio": "sdi-orig:audio", + "formats": { + "flash": [ "high", "medium", "low", "mini" ], + "webm": [ "high", "medium", "low", "mini" ] + } + }, + "avr": { + "video": "sdi-orig:video", + "audio": "sdi-orig:audio", + "formats": { + "rec": [ "full" ] + } + }, + "audio-orig": { + "audio": "sdi-orig:audio", + "formats": { + "ogg": [ "high", "medium", "low", "mini" ], + "mp3": [ "high", "medium", "low", "mini" ] + } + } + }, + "streams": { + "local": { + "muxes": [ "av-orig", "audio-orig" ], + "type": "http", "count": 1, + "port": 8000, + "max-con": 100, "burst-on-connect": 5, + "hostname": "elevate-feed.spreadspace.org", + }, + "public": { + "muxes": [ "av-orig", "audio-orig" ], + "type": "http", "count": 2, + "port": 8000, "interface": "localhost", + "max-bw": 290000000, "burst-on-connect": 5, + "hostname": "elevate-live%i.spreadspace.org", "repeater": True, + } + }, + "records": { + "av": { + "muxes": { + "avr": { "format": "rec", "profile": "full" } + }, + "directory": "/srv/elevate2017/", + "filename": "av-orig %Y-%m-%d %H-%M-%S" + }, + "audio": { + "muxes": { + "audio-orig": { "format": "ogg", "profile": "high" } + }, + "directory": "/srv/elevate2017/", + "filename": "audio-orig %Y-%m-%d %H-%M-%S" + } + + } + +} diff --git a/src/flufigut.py b/src/flufigut.py index 4d8dbbe..72e9e7b 100755 --- a/src/flufigut.py +++ b/src/flufigut.py @@ -84,11 +84,13 @@ class Description: class Porter: - def __init__(self, name): + def __init__(self, name, interface, port): self.name = name + self.interface = interface + self.port = port self.socket_path = rand_string() self.username = rand_string(size=12) - self.password = rand_string(size=12) + self.password = rand_string(size=20) class Planet: @@ -266,17 +268,17 @@ class Planet: # # streams - def __create_porter(self, comp_name_base, port, interface=None): - porter_name = 'port-%s-%i' % (comp_name_base, port) + def __create_porter(self, stream, idx, port, interface=None): + comp_name = 'port-%s%i-%i' % (stream, idx + 1, port) addr = '*:%i' % (port) if interface: - porter_name = 'port-%s-%s-%i' % (comp_name_base, interface, port) + comp_name = 'port-%s%i-%s-%i' % (stream, idx + 1, interface, port) addr = '%s:%i' % (interface, port) - porter = Porter(porter_name) + porter = Porter(comp_name, interface, port) self.atmosphere[porter.name] = { 'type': "porter", - 'desc': "Porter for %s on %s" % (comp_name_base, addr), + 'desc': "Porter for %s%i on %s" % (stream, idx + 1, addr), 'worker': None, 'properties': { 'port': port, @@ -290,23 +292,77 @@ class Planet: return porter - def __generate_stream_instance(self, stream_name, stream, idx, globals): - port = stream['port'] - comp_name_base = "%s%i" % (stream_name, idx + 1) - porter = self.__create_porter(comp_name_base, port) - porter_localdup = None - if 'localdup' in stream: - porter_localdump = self.__create_porter(comp_name_base, stream['localdup']['port'], "localhost") + def __generate_stream_mux_repeater(self, stream, mux, format, profile, feeder): + comp_name = 'repeater-%s-%s-%s-%s' % (stream, mux, format, profile) + + if comp_name in self.flow['repeaters']: + return comp_name + + self.flow['repeaters'][comp_name] = { + 'type': 'repeater', + 'desc': "repeater for %s (%s %s-%s)" % (stream, mux, format, profile), + 'worker': None, + 'feeder': feeder, + } + return comp_name + + def __generate_stream_mux_instance(self, stream_name, stream, mux, format, profile, idx, cnt, porter, globals): + muxer_feed = 'muxer-%s-%s-%s' % (mux, format, profile) + feeder = muxer_feed + if 'repeater' in stream: + feeder = self.__generate_stream_mux_repeater(stream_name, mux, format, profile, muxer_feed) + + comp_name = '%s-%s%i-%s-%s-%s' % (stream['type'], stream_name, idx + 1, mux, format, profile) + mount_point = '/%s-%s-%s.%s' % (mux, format, profile, globals['formats'][format]['muxer']) + if cnt > 1: + hostname = stream['hostname'] % (idx + 1) + if idx != 0: + hostname_next = stream['hostname'] % (idx) + else: + hostname_next = stream['hostname'] % (cnt) + else: + hostname = stream['hostname'] - def _generate_streams(self, streams, globals): + self.flow['streamers'][comp_name] = { + 'type': "%s-stream" % stream['type'], + 'desc': "%s streamer for %s %s-%s (part %i of %i in %s cluster)" % (stream['type'], mux, format, profile, idx + 1, cnt, stream_name), + 'worker': None, + 'feeder': feeder, + 'properties': { + 'description': globals['description'], + 'type': 'slave', + 'porter-socket-path': porter.socket_path, + 'porter-username': porter.username, + 'porter-password': porter.password, + 'mount-point': mount_point, + 'hostname': hostname, + 'port': porter.port, + } + } + + # TODO: add support for max-con, max-bw and burst-on-connect! + # TODO: add stats!! + + def __generate_stream_instance(self, stream_name, stream, idx, cnt, muxes, globals): + port = stream['port'] + interface = None + if 'interface' in stream: + interface = stream['interface'] + porter = self.__create_porter(stream_name, idx, port, interface) + for mux_name in stream['muxes']: + for format_name, format in muxes[mux_name]['formats'].items(): + for profile_name in format: + self.__generate_stream_mux_instance(stream_name, stream, mux_name, format_name, profile_name, + idx, cnt, porter, globals) + + def _generate_streams(self, streams, muxes, globals): self.flow['repeaters'] = {} self.flow['streamers'] = {} for stream_name, stream in streams.items(): - streamer_cnt = stream['count'] - for idx in range(streamer_cnt): - print(stream) - self.__generate_stream_instance(stream_name, stream, idx, globals) + cnt = stream['count'] + for idx in range(cnt): + self.__generate_stream_instance(stream_name, stream, idx, cnt, muxes, globals) # # records @@ -338,7 +394,7 @@ class Planet: def generate(self, desc): self._generate_inputs(desc.inputs, desc.globals) self._generate_muxes(desc.muxes, desc.inputs, desc.globals) - self._generate_streams(desc.streams, desc.globals) + self._generate_streams(desc.streams, desc.muxes, desc.globals) self._generate_records(desc.records, desc.globals) |