summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--voctocore/quadmix-bg.pngbin0 -> 336733 bytes
-rw-r--r--voctocore/videomix.py64
2 files changed, 57 insertions, 7 deletions
diff --git a/voctocore/quadmix-bg.png b/voctocore/quadmix-bg.png
new file mode 100644
index 0000000..55ec3b5
--- /dev/null
+++ b/voctocore/quadmix-bg.png
Binary files differ
diff --git a/voctocore/videomix.py b/voctocore/videomix.py
index 8cc3cb9..6d3cca8 100644
--- a/voctocore/videomix.py
+++ b/voctocore/videomix.py
@@ -5,6 +5,7 @@ from gi.repository import GLib, Gst
class Videomix:
decoder = []
mixerpads = []
+ monitorSize = (1024, 576)
def __init__(self):
self.pipeline = Gst.Pipeline()
@@ -21,7 +22,7 @@ class Videomix:
camberabin.get_by_name('audio_src').link(self.pipeline.get_by_name('liveaudio'))
# inject a ×2 distributor and link one end to the live-mixer
- distributor = self.createDistributor(camberabin.get_by_name('video_src'))
+ distributor = self.createDistributor(camberabin.get_by_name('video_src'), camberabin.get_name())
distributor.get_by_name('a').link(self.pipeline.get_by_name('livevideo'))
# collect the other end to add it later to the quadmix
@@ -40,6 +41,7 @@ class Videomix:
pad = livevideo.get_static_pad('sink_1')
pad.set_property('alpha', 0.5)
+ Gst.debug_bin_to_dot_file(self.pipeline, Gst.DebugGraphDetails.ALL, 'test')
self.pipeline.set_state(Gst.State.PLAYING)
def createMixer(self):
@@ -47,25 +49,71 @@ class Videomix:
videomixer name=livevideo ! autovideosink
input-selector name=liveaudio ! autoaudiosink
- videomixer name=quadmix ! autovideosink
+ filesrc location=quadmix-bg.png ! decodebin ! imagefreeze ! videomixer name=quadmix ! autovideosink
""", False)
+ mixerbin.set_name('mixerbin')
self.pipeline.add(mixerbin)
return mixerbin
def addVideosToQuadmix(self, videosources, quadmix):
count = len(videosources)
- rows = math.ceil(math.sqrt(count))
- cols = math.ceil(count / rows)
- for videosource in videosources:
+ place = [0, 0]
+ grid = [0, 0]
+ grid[0] = math.ceil(math.sqrt(count))
+ grid[1] = math.ceil(count / grid[0])
+
+ cellSize = (self.monitorSize[0] / grid[0], self.monitorSize[1] / grid[1])
+ print("showing {} videosources in a {}×{} grid in a {}×{} px window, which gives cells of {}×{} px per videosource".format(
+ count, grid[0], grid[1], self.monitorSize[0], self.monitorSize[1], cellSize[0], cellSize[1]))
+
+ for idx, videosource in enumerate(videosources):
+ caps = videosource.get_static_pad('src').query_caps(None)
+ capsstruct = caps.get_structure(0)
+ srcSize = (
+ capsstruct.get_int('width')[1],
+ capsstruct.get_int('height')[1],
+ )
+
+ f = max(srcSize[0] / cellSize[0], srcSize[1] / cellSize[1])
+ scaleSize = (
+ srcSize[0] / f,
+ srcSize[1] / f,
+ )
+
+ coord = (
+ place[0] * cellSize[0] + (cellSize[0] - scaleSize[0]) / 2,
+ place[1] * cellSize[1] + (cellSize[1] - scaleSize[1]) / 2,
+ )
+
+ print("placing videosrc {} of size {}×{} scaled by {} to {}×{} in a cell {}×{} px cell ({}/{}) at position ({}/{})".format(
+ idx, srcSize[0], srcSize[1], f, scaleSize[0], scaleSize[1], cellSize[0], cellSize[1], place[0], place[1], coord[0], coord[1]))
+
+ scalecaps = Gst.Caps.new_empty_simple('video/x-raw')
+ scalecaps.set_value('width', round(scaleSize[0]))
+ scalecaps.set_value('height', round(scaleSize[1]))
+
+ scaler = Gst.ElementFactory.make('videoscale', 'quadmix-scaler({})'.format(idx))
+ self.pipeline.add(scaler)
+ videosource.link(scaler)
+
# define size somewhere, scale and place here
- videosource.link(quadmix)
+ sinkpad = quadmix.get_request_pad('sink_%u')
+ sinkpad.set_property('xpos', round(coord[0]))
+ sinkpad.set_property('ypos', round(coord[1]))
+ scaler.link_filtered(quadmix, scalecaps)
+
+ place[0] += 1
+ if place[0] >= grid[0]:
+ place[1] += 1
+ place[0] = 0
- def createDistributor(self, videosource):
+ def createDistributor(self, videosource, name):
distributor = Gst.parse_bin_from_description("""
tee name=t
t. ! queue name=a
t. ! queue name=b
""", False)
+ distributor.set_name('distributor({0})'.format(name))
self.pipeline.add(distributor)
videosource.link(distributor.get_by_name('t'))
@@ -80,6 +128,7 @@ class Videomix:
input. ! videoconvert ! videoscale ! videorate ! video/x-raw,width=1024,height=576,framerate=25/1 ! identity name=video_src
input. ! audioconvert name=audio_src
""", False)
+ camberabin.set_name('dummy-camberabin({0})'.format(uri))
# configure camera input
camberabin.get_by_name('input').set_property('uri', uri)
@@ -98,6 +147,7 @@ class Videomix:
input. ! videoconvert ! videoscale ! videorate ! video/x-raw,width=1920,height=1080,framerate=25/1 ! identity name=video_src
input. ! audioconvert name=audio_src
""", False)
+ camberabin.set_name('camberabin({0})'.format(cam))
# configure camera input
camberabin.get_by_name('input').set_property('subdevice', cam)