hemisphere/src/overlay/obs/scene.py

73 lines
2.3 KiB
Python

import math
import collections
import string
from ..filters import FFmpegGraph, FFmpegChain, FFmpegFilter
from .base import OBSSource
IDENTIFY_MAPPING = collections.defaultdict(lambda: '_', {ord(k): k for k in string.ascii_letters + string.digits})
def identifiery(n):
return n.translate(IDENTIFY_MAPPING)
def deg2rad(n):
return n * (math.pi / 180)
@OBSSource.type('scene')
class OBSSceneSource(OBSSource):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.name = None
self.items = []
def load(self, data):
self.name = data['name']
self.items = data['settings']['items']
def to_ffmpeg(self, scene):
prefix = identifiery(self.name)
i = 1
graph = [FFmpegChain(
FFmpegFilter('color', c='black', s='{}x{}'.format(*scene.dimensions), outs=[prefix + str(i)])
)]
runners = []
for item in self.items:
if not item['visible']:
continue
rs, chains = scene.sources[item['name']].to_ffmpeg(scene)
runners.extend(rs)
c = chains[-1]
if item['scale']['x'] != 1.0 or item['scale']['y'] != 1.0:
c.append(FFmpegFilter('scale',
w='{} * in_w'.format(item['scale']['x']),
h='{} * in_h'.format(item['scale']['y'])
))
if item['crop_top'] != 0 or item['crop_bottom'] != 0 or item['crop_left'] or item['crop_right'] != 0:
c.append(FFmpegFilter('crop',
w='in_w - {} - {}'.format(item['crop_left'], item['crop_right']),
h='in_h - {} - {}'.format(item['crop_top'], item['crop_bottom']),
x=item['crop_left'],
y=item['crop_top']
))
if item['rot'] != 0.0:
c.append(FFmpegFilter('rotate',
angle=deg2rad(item['rot'])
))
c.append(FFmpegFilter('overlay',
eval='init',
x=item['pos']['x'],
y=item['pos']['y'],
ins=[prefix + str(i)],
outs=[prefix + str(i + 1)])
)
i += 1
graph.extend(chains)
return runners, graph