aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--voctocore/default-config.ini1
-rw-r--r--voctocore/lib/distributor.py33
-rw-r--r--voctocore/lib/pipeline.py30
-rw-r--r--voctocore/lib/quadmix.py53
-rw-r--r--voctocore/lib/videomix.py44
5 files changed, 131 insertions, 30 deletions
diff --git a/voctocore/default-config.ini b/voctocore/default-config.ini
index f00f91d..13bae74 100644
--- a/voctocore/default-config.ini
+++ b/voctocore/default-config.ini
@@ -19,5 +19,6 @@ audio=/video/dudel.m4a
[mix]
monitorcaps=video/x-raw,width=1024,height=576
+outputcaps=video/x-raw,width=1280,height=720
[client]
diff --git a/voctocore/lib/distributor.py b/voctocore/lib/distributor.py
new file mode 100644
index 0000000..8282839
--- /dev/null
+++ b/voctocore/lib/distributor.py
@@ -0,0 +1,33 @@
+#!/usr/bin/python3
+import time, logging
+from gi.repository import GLib, Gst
+
+from lib.config import Config
+
+class TimesTwoDistributor(Gst.Bin):
+ log = logging.getLogger('TimesTwoDistributor')
+
+ def __init__(self):
+ super().__init__()
+
+ self.tee = Gst.ElementFactory.make('tee', None)
+ self.queue_a = Gst.ElementFactory.make('queue', 'queue-a')
+ self.queue_b = Gst.ElementFactory.make('queue', 'queue-b')
+
+ self.add(self.tee)
+ self.add(self.queue_a)
+ self.add(self.queue_b)
+
+ self.tee.link(self.queue_a)
+ self.tee.link(self.queue_b)
+
+ # Add Ghost Pads
+ self.add_pad(
+ Gst.GhostPad.new('sink', self.tee.get_static_pad('sink'))
+ )
+ self.add_pad(
+ Gst.GhostPad.new('src_a', self.queue_a.get_static_pad('src'))
+ )
+ self.add_pad(
+ Gst.GhostPad.new('src_b', self.queue_b.get_static_pad('src'))
+ )
diff --git a/voctocore/lib/pipeline.py b/voctocore/lib/pipeline.py
index 112ac3e..b89d2af 100644
--- a/voctocore/lib/pipeline.py
+++ b/voctocore/lib/pipeline.py
@@ -8,9 +8,9 @@ from lib.controlserver import controlServerEntrypoint
# import library components
from lib.config import Config
from lib.quadmix import QuadMix
-# from lib.videomix import VideoMix
+from lib.videomix import VideoMix
# from lib.audiomix import AudioMix
-# from lib.distributor import TimesTwoDistributor
+from lib.distributor import TimesTwoDistributor
from lib.shmsrc import FailsafeShmSrc
class Pipeline(Gst.Pipeline):
@@ -27,8 +27,8 @@ class Pipeline(Gst.Pipeline):
self.quadmixer = QuadMix()
self.add(self.quadmixer)
- # self.videomixer = VideoMix()
- # self.add(self.videomixer)
+ self.videomixer = VideoMix()
+ self.add(self.videomixer)
# self.audiomixer = AudioMix()
# self.add(self.audiomixer)
@@ -51,10 +51,13 @@ class Pipeline(Gst.Pipeline):
self.log.info('Creating video-source %s at socket-path %s', name, socket)
sourcebin = FailsafeShmSrc(socket)
self.add(sourcebin)
- self.quadmixer.add_source(sourcebin)
- # distributor = TimesTwoDistributor(sourcebin)
- # self.add(distributor)
+ distributor = TimesTwoDistributor()
+ self.add(distributor)
+ sourcebin.link(distributor)
+
+ self.quadmixer.add_source(distributor)
+ self.videomixer.add_source(distributor)
# distributor.link(self.quadmixer)
# distributor.link(self.videomixer)
@@ -68,14 +71,18 @@ class Pipeline(Gst.Pipeline):
# tell the quadmix that this were all sources and no more sources will come after this
self.quadmixer.finalize()
+ self.quadmixer.set_active(0)
+ self.videomixer.set_active(0)
+
self.quadmixsink = Gst.ElementFactory.make('autovideosink', 'quadmixsink')
self.quadmixsink.set_property('sync', False)
self.add(self.quadmixsink)
self.quadmixer.link(self.quadmixsink)
- # self.videosink = Gst.ElementFactory.make('autovideosink', 'videosink')
- # self.add(self.videosink)
- # self.videomixer.link(self.videosink)
+ self.videosink = Gst.ElementFactory.make('autovideosink', 'videosink')
+ self.videosink.set_property('sync', False)
+ self.add(self.videosink)
+ self.videomixer.link(self.videosink)
# self.audiosink = Gst.ElementFactory.make('autoaudiosink', 'audiosink')
# self.add(self.audiosink)
@@ -349,7 +356,8 @@ class Pipeline(Gst.Pipeline):
self.log.info("switching quadmix to video-source %u", idx)
self.quadmixer.set_active(idx)
- # todo: switch main switcher
+ self.videomixer.set_active(idx)
+
@controlServerEntrypoint
def fadeVideo(self, videosource):
diff --git a/voctocore/lib/quadmix.py b/voctocore/lib/quadmix.py
index 5115919..6a9384d 100644
--- a/voctocore/lib/quadmix.py
+++ b/voctocore/lib/quadmix.py
@@ -68,8 +68,24 @@ class QuadMix(Gst.Bin):
# iterate over all video-sources
for idx, videosource in enumerate(self.sources):
+ # create a sub-preview-bin
+ previewbin = QuadMixPreview()
+ self.add(previewbin)
+ self.previewbins.append(previewbin)
+
+ previewsink = previewbin.get_static_pad('sink')
+ previewsrc = previewbin.get_static_pad('src')
+
+ srcpad = videosource.get_compatible_pad(previewsink, None)
+ #srcpad.link(previewsink) # linking ghost pads
+ print(videosource.link(previewbin))
+
+ sinkpad = self.mixer.get_request_pad('sink_%u')
+ #previewsrc.link(sinkpad) # linking ghost pads
+ print(previewbin.link(self.mixer))
+
# query the video-source caps and extract its size
- caps = videosource.get_static_pad('src').query_caps(None)
+ caps = srcpad.query_caps(None)
capsstruct = caps.get_structure(0)
srcSize = (
capsstruct.get_int('width')[1],
@@ -93,20 +109,11 @@ class QuadMix(Gst.Bin):
idx, srcSize[0], srcSize[1], f, scaleSize[0], scaleSize[1], cellSize[0], cellSize[1], place[0], place[1], coord[0], coord[1])
# request a pad from the quadmixer and configure x/y position
- sinkpad = self.mixer.get_request_pad('sink_%u')
sinkpad.set_property('xpos', round(coord[0]))
sinkpad.set_property('ypos', round(coord[1]))
- # create a sub-preview-bin
- previewbin = QuadMixPreview(idx, scaleSize)
- self.add(previewbin)
- self.previewbins.append(previewbin)
-
- # link videosource to input of previewbin
- videosource.link(previewbin)
-
- # link the output of the preview-bin to the mixer
- previewbin.get_static_pad('src').link(sinkpad)
+ previewbin.set_size(scaleSize)
+ previewbin.set_idx(idx)
# increment grid position
place[0] += 1
@@ -122,23 +129,21 @@ class QuadMixPreview(Gst.Bin):
log = logging.getLogger('QuadMixPreview')
strokeWidth = 5
- def __init__(self, idx, scaleSize):
+ def __init__(self):
super().__init__()
self.scale = Gst.ElementFactory.make('videoscale', 'scale')
+ self.caps = Gst.ElementFactory.make('capsfilter', 'caps')
self.cropbox = Gst.ElementFactory.make('videobox', 'cropbox')
self.strokebox = Gst.ElementFactory.make('videobox', 'strokebox')
self.textoverlay = Gst.ElementFactory.make('textoverlay', 'textoverlay')
self.add(self.scale)
+ self.add(self.caps)
self.add(self.cropbox)
self.add(self.strokebox)
self.add(self.textoverlay)
- caps = Gst.Caps.new_empty_simple('video/x-raw')
- caps.set_value('width', round(scaleSize[0]))
- caps.set_value('height', round(scaleSize[1]))
-
self.strokebox.set_property('fill', 'green')
self.textoverlay.set_property('color', 0xFFFFFFFF)
@@ -148,7 +153,8 @@ class QuadMixPreview(Gst.Bin):
self.textoverlay.set_property('ypad', 5)
self.textoverlay.set_property('font-desc', 'sans 35')
- self.scale.link_filtered(self.cropbox, caps)
+ self.scale.link(self.caps)
+ self.caps.link(self.cropbox)
self.cropbox.link(self.strokebox)
self.strokebox.link(self.textoverlay)
@@ -162,11 +168,20 @@ class QuadMixPreview(Gst.Bin):
Gst.GhostPad.new('src', self.textoverlay.get_static_pad('src'))
)
+ def set_size(self, scaleSize):
+ caps = Gst.Caps.new_empty_simple('video/x-raw')
+ caps.set_value('width', round(scaleSize[0]))
+ caps.set_value('height', round(scaleSize[1]))
+ self.caps.set_property('caps', caps)
+
+ def set_idx(self, idx):
+ self.textoverlay.set_property('text', str(idx))
+
def set_active(self, active):
self.log.info("switching active-state to %u", active)
for side in ('top', 'left', 'right', 'bottom'):
self.cropbox.set_property(side, self.strokeWidth if active else 0)
self.strokebox.set_property(side, -self.strokeWidth if active else 0)
- def setColor(self, color):
+ def set_color(self, color):
self.strokebox.set_property('fill', color)
diff --git a/voctocore/lib/videomix.py b/voctocore/lib/videomix.py
new file mode 100644
index 0000000..d32dd90
--- /dev/null
+++ b/voctocore/lib/videomix.py
@@ -0,0 +1,44 @@
+#!/usr/bin/python3
+import time, logging
+from gi.repository import GLib, Gst
+
+from lib.config import Config
+
+class VideoMix(Gst.Bin):
+ log = logging.getLogger('VideoMix')
+ sinkpads = []
+
+ def __init__(self):
+ super().__init__()
+
+ self.mixer = Gst.ElementFactory.make('videomixer', 'mixer')
+ self.scale = Gst.ElementFactory.make('videoscale', 'scale')
+ self.conv = Gst.ElementFactory.make('videoconvert', 'conv')
+
+ self.add(self.mixer)
+ self.add(self.scale)
+ self.add(self.conv)
+
+ caps = Gst.Caps.from_string(Config.get('mix', 'outputcaps'))
+ self.mixer.link_filtered(self.scale, caps)
+ self.scale.link(self.conv)
+
+ self.add_pad(
+ Gst.GhostPad.new('src', self.conv.get_static_pad('src'))
+ )
+
+ # I don't know how to create a on-request ghost-pad
+ def add_source(self, src):
+ self.log.info('adding source %s', src.get_name())
+ sinkpad = self.mixer.get_request_pad('sink_%u')
+ sinkpad.set_property('alpha', 1)
+ self.sinkpads.append(sinkpad)
+
+ #srcpad = src.get_compatible_pad(sinkpad, None)
+ #srcpad.link(sinkpad)
+ src.link(self.mixer) # linking ghost pads
+
+ def set_active(self, target):
+ self.log.info('setting source #%u active', target)
+ for idx, sinkpad in enumerate(self.sinkpads):
+ sinkpad.set_property('alpha', int(target == idx))