aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--voctocore/README.md4
-rw-r--r--voctocore/lib/backgroundsource.py51
-rw-r--r--voctocore/lib/pipeline.py4
-rw-r--r--voctocore/lib/videomix.py52
-rwxr-xr-xvoctocore/scripts/av-source-background.sh6
-rwxr-xr-xvoctocore/scripts/demo-cube-files.sh1
-rwxr-xr-xvoctocore/scripts/demo-cube.sh1
-rwxr-xr-xvoctocore/scripts/demo-local.sh1
8 files changed, 99 insertions, 21 deletions
diff --git a/voctocore/README.md b/voctocore/README.md
index a2a1510..f01f765 100644
--- a/voctocore/README.md
+++ b/voctocore/README.md
@@ -1,6 +1,8 @@
# Server-Pipeline Structure
````
- /-> VideoMix
+16000 BackgroundSource
+ \
+ --> VideoMix
/ \
/ \ /-> StreamBlanker -> StreamOutputPort 15000
/ ------> OutputPort 11000
diff --git a/voctocore/lib/backgroundsource.py b/voctocore/lib/backgroundsource.py
new file mode 100644
index 0000000..1f3da54
--- /dev/null
+++ b/voctocore/lib/backgroundsource.py
@@ -0,0 +1,51 @@
+#!/usr/bin/python3
+import logging
+from gi.repository import Gst
+
+from lib.config import Config
+from lib.tcpsingleconnection import TCPSingleConnection
+
+class BackgroundSource(TCPSingleConnection):
+ def __init__(self, port):
+ self.log = logging.getLogger('BackgroundSource')
+ super().__init__(port)
+
+ def on_accepted(self, conn, addr):
+ pipeline = """
+ fdsrc fd={fd} !
+ matroskademux !
+ {vcaps} !
+ intervideosink channel=mixer_background
+ """.format(
+ fd=conn.fileno(),
+ vcaps=Config.get('mix', 'videocaps')
+ )
+
+ self.log.debug('Launching Source-Pipeline:\n%s', pipeline)
+ self.receiverPipeline = Gst.parse_launch(pipeline)
+
+ self.log.debug('Binding End-of-Stream-Signal on Source-Pipeline')
+ self.receiverPipeline.bus.add_signal_watch()
+ self.receiverPipeline.bus.connect("message::eos", self.on_eos)
+ self.receiverPipeline.bus.connect("message::error", self.on_error)
+
+ self.receiverPipeline.set_state(Gst.State.PLAYING)
+
+
+ def on_eos(self, bus, message):
+ self.log.debug('Received End-of-Stream-Signal on Source-Pipeline')
+ if self.currentConnection is not None:
+ self.disconnect()
+
+ def on_error(self, bus, message):
+ self.log.debug('Received Error-Signal on Source-Pipeline')
+ (error, debug) = message.parse_error()
+ self.log.debug('Error-Details: #%u: %s', error.code, debug)
+
+ if self.currentConnection is not None:
+ self.disconnect()
+
+ def disconnect(self):
+ self.receiverPipeline.set_state(Gst.State.NULL)
+ self.receiverPipeline = None
+ self.close_connection()
diff --git a/voctocore/lib/pipeline.py b/voctocore/lib/pipeline.py
index 9addca0..a45ea53 100644
--- a/voctocore/lib/pipeline.py
+++ b/voctocore/lib/pipeline.py
@@ -7,6 +7,7 @@ from lib.config import Config
from lib.avsource import AVSource
from lib.avrawoutput import AVRawOutput
from lib.avpreviewoutput import AVPreviewOutput
+from lib.backgroundsource import BackgroundSource
from lib.videomix import VideoMix
from lib.audiomix import AudioMix
@@ -56,6 +57,9 @@ class Pipeline(object):
self.log.info('Creating Videmixer')
self.amix = AudioMix()
+ port = 16000
+ self.bgsrc = BackgroundSource(port)
+
port = 11000
self.log.info('Creating Mixer-Output at tcp-port %u', port)
self.mixout = AVRawOutput('mix_out', port)
diff --git a/voctocore/lib/videomix.py b/voctocore/lib/videomix.py
index d5349c5..1bee90a 100644
--- a/voctocore/lib/videomix.py
+++ b/voctocore/lib/videomix.py
@@ -26,6 +26,10 @@ class VideoMix(object):
queue !
tee name=tee
+ intervideosrc channel=mixer_background !
+ {caps} !
+ mix.
+
tee. ! queue ! intervideosink channel=video_mix_out
""".format(
caps=self.caps
@@ -63,6 +67,9 @@ class VideoMix(object):
self.sourceB = 1
self.updateMixerState()
+ bgMixerpad = self.mixingPipeline.get_by_name('mix').get_static_pad('sink_0')
+ bgMixerpad.set_property('zorder', 0)
+
self.log.debug('Launching Mixing-Pipeline')
self.mixingPipeline.set_state(Gst.State.PLAYING)
@@ -87,6 +94,12 @@ class VideoMix(object):
elif self.compositeMode == CompositeModes.picture_in_picture:
self.updateMixerStatePictureInPicture()
+ def getMixerpadAndCapsfilter(self, idx):
+ # mixerpad 0 = background
+ mixerpad = self.mixingPipeline.get_by_name('mix').get_static_pad('sink_%u' % (idx+1))
+ capsfilter = self.mixingPipeline.get_by_name('caps_%u' % idx)
+ return mixerpad, capsfilter
+
def updateMixerStateFullscreen(self):
self.log.info('Updating Mixer-State for Fullscreen-Composition')
@@ -94,15 +107,15 @@ class VideoMix(object):
for idx, name in enumerate(self.names):
alpha = int(idx == self.sourceA)
+ mixerpad, capsfilter = self.getMixerpadAndCapsfilter(idx)
- self.log.debug('Setting Mixerpad %u to x/y=0 and alpha=%0.2f', idx, alpha)
- mixerpad = self.mixingPipeline.get_by_name('mix').get_static_pad('sink_%u' % idx)
- mixerpad.set_property('alpha', alpha )
+ self.log.debug('Setting Mixerpad %u to x/y=0 and alpha=%0.2f, zorder=%u', idx, alpha, 1)
+ mixerpad.set_property('alpha', alpha)
mixerpad.set_property('xpos', 0)
mixerpad.set_property('ypos', 0)
+ mixerpad.set_property('zorder', 1)
self.log.debug('Resetting Scaler %u to non-scaling', idx)
- capsfilter = self.mixingPipeline.get_by_name('caps_%u' % idx)
capsfilter.set_property('caps', noScaleCaps)
def updateMixerStateSideBySideEqual(self):
@@ -129,25 +142,26 @@ class VideoMix(object):
noScaleCaps = Gst.Caps.from_string('video/x-raw')
for idx, name in enumerate(self.names):
- mixerpad = self.mixingPipeline.get_by_name('mix').get_static_pad('sink_%u' % idx)
- capsfilter = self.mixingPipeline.get_by_name('caps_%u' % idx)
+ mixerpad, capsfilter = self.getMixerpadAndCapsfilter(idx)
if idx == self.sourceA:
mixerpad.set_property('alpha', 1)
mixerpad.set_property('xpos', xa)
mixerpad.set_property('ypos', y)
+ mixerpad.set_property('zorder', 1)
capsfilter.set_property('caps', scaleCaps)
- self.log.debug('Setting Mixerpad %u to x/y=%u/%u and alpha=%0.2f', idx, xa, y, 1)
+ self.log.debug('Setting Mixerpad %u to x/y=%u/%u and alpha=%0.2f, zorder=%u', idx, xa, y, 1, 1)
self.log.debug('Setting Scaler %u to %u/%u', idx, targetWidth, targetHeight)
elif idx == self.sourceB:
mixerpad.set_property('alpha', 1)
mixerpad.set_property('xpos', xb)
mixerpad.set_property('ypos', y)
+ mixerpad.set_property('zorder', 1)
capsfilter.set_property('caps', scaleCaps)
- self.log.debug('Setting Mixerpad %u to x/y=%u/%u and alpha=%0.2f', idx, xb, y, 1)
+ self.log.debug('Setting Mixerpad %u to x/y=%u/%u and alpha=%0.2f, zorder=%u', idx, xb, y, 1, 1)
self.log.debug('Setting Scaler %u to %u/%u', idx, targetWidth, targetHeight)
else:
@@ -210,27 +224,26 @@ class VideoMix(object):
noScaleCaps = Gst.Caps.from_string('video/x-raw')
for idx, name in enumerate(self.names):
- mixerpad = self.mixingPipeline.get_by_name('mix').get_static_pad('sink_%u' % idx)
- capsfilter = self.mixingPipeline.get_by_name('caps_%u' % idx)
+ mixerpad, capsfilter = self.getMixerpadAndCapsfilter(idx)
if idx == self.sourceA:
mixerpad.set_property('alpha', 1)
mixerpad.set_property('xpos', apos[1])
mixerpad.set_property('ypos', apos[1])
- mixerpad.set_property('zorder', 0)
+ mixerpad.set_property('zorder', 1)
capsfilter.set_property('caps', aCaps)
- self.log.debug('Setting Mixerpad %u to x/y=%u/%u and alpha=%0.2f, zorder=%u', idx, apos[0], apos[1], 1, 0)
+ self.log.debug('Setting Mixerpad %u to x/y=%u/%u and alpha=%0.2f, zorder=%u', idx, apos[0], apos[1], 1, 1)
self.log.debug('Setting Scaler %u to %u/%u', idx, asize[0], asize[1])
elif idx == self.sourceB:
mixerpad.set_property('alpha', 1)
mixerpad.set_property('xpos', bpos[0])
mixerpad.set_property('ypos', bpos[1])
- mixerpad.set_property('zorder', 1)
+ mixerpad.set_property('zorder', 2)
capsfilter.set_property('caps', bCaps)
- self.log.debug('Setting Mixerpad %u to x/y=%u/%u, alpha=%0.2f, zorder=%u', idx, bpos[0], bpos[1], 1, 1)
+ self.log.debug('Setting Mixerpad %u to x/y=%u/%u, alpha=%0.2f, zorder=%u', idx, bpos[0], bpos[1], 1, 2)
self.log.debug('Setting Scaler %u to %u/%u', idx, bsize[0], bsize[1])
else:
@@ -272,27 +285,26 @@ class VideoMix(object):
noScaleCaps = Gst.Caps.from_string('video/x-raw')
for idx, name in enumerate(self.names):
- mixerpad = self.mixingPipeline.get_by_name('mix').get_static_pad('sink_%u' % idx)
- capsfilter = self.mixingPipeline.get_by_name('caps_%u' % idx)
+ mixerpad, capsfilter = self.getMixerpadAndCapsfilter(idx)
if idx == self.sourceA:
mixerpad.set_property('alpha', 1)
mixerpad.set_property('xpos', 0)
mixerpad.set_property('ypos', 0)
- mixerpad.set_property('zorder', 0)
+ mixerpad.set_property('zorder', 1)
capsfilter.set_property('caps', noScaleCaps)
- self.log.debug('Setting Mixerpad %u to x/y=%u/%u and alpha=%0.2f, zorder=%u', idx, 0, 0, 1, 0)
+ self.log.debug('Setting Mixerpad %u to x/y=%u/%u and alpha=%0.2f, zorder=%u', idx, 0, 0, 1, 1)
self.log.debug('Resetting Scaler %u to non-scaling', idx)
elif idx == self.sourceB:
mixerpad.set_property('alpha', 1)
mixerpad.set_property('xpos', pippos[0])
mixerpad.set_property('ypos', pippos[1])
- mixerpad.set_property('zorder', 1)
+ mixerpad.set_property('zorder', 2)
capsfilter.set_property('caps', scaleCaps)
- self.log.debug('Setting Mixerpad %u to x/y=%u/%u, alpha=%0.2f, zorder=%u', idx, pippos[0], pippos[1], 1, 1)
+ self.log.debug('Setting Mixerpad %u to x/y=%u/%u, alpha=%0.2f, zorder=%u', idx, pippos[0], pippos[1], 1, 2)
self.log.debug('Setting Scaler %u to %u/%u', idx, pipsize[0], pipsize[1])
else:
diff --git a/voctocore/scripts/av-source-background.sh b/voctocore/scripts/av-source-background.sh
new file mode 100755
index 0000000..d978135
--- /dev/null
+++ b/voctocore/scripts/av-source-background.sh
@@ -0,0 +1,6 @@
+#!/bin/sh
+gst-launch-1.0 \
+ videotestsrc pattern=ball !\
+ video/x-raw,format=I420,width=1280,height=720,framerate=25/1,pixel-aspect-ratio=1/1 !\
+ matroskamux !\
+ tcpclientsink host=localhost port=16000
diff --git a/voctocore/scripts/demo-cube-files.sh b/voctocore/scripts/demo-cube-files.sh
index 5573c3c..404e3dc 100755
--- a/voctocore/scripts/demo-cube-files.sh
+++ b/voctocore/scripts/demo-cube-files.sh
@@ -6,6 +6,7 @@ echo "PID=$PID"
sleep 1
./av-source-cam1.sh &
./av-source-cam2.sh &
+./av-source-background.sh &
./av-record-output-ffmpeg-timestamps.sh &
./av-stream-hd.sh &
./demo-cycle-modes.sh &
diff --git a/voctocore/scripts/demo-cube.sh b/voctocore/scripts/demo-cube.sh
index 43a7e03..d38adfe 100755
--- a/voctocore/scripts/demo-cube.sh
+++ b/voctocore/scripts/demo-cube.sh
@@ -6,6 +6,7 @@ echo "PID=$PID"
sleep 1
./av-source-bmd-cam1.sh &
./av-source-bmd-cam2.sh &
+./av-source-background.sh &
./av-record-output-ffmpeg-timestamps.sh &
./av-stream-hd.sh &
./demo-cycle-modes.sh &
diff --git a/voctocore/scripts/demo-local.sh b/voctocore/scripts/demo-local.sh
index 4839e69..4cf11f1 100755
--- a/voctocore/scripts/demo-local.sh
+++ b/voctocore/scripts/demo-local.sh
@@ -6,6 +6,7 @@ echo "PID=$PID"
sleep 1
./av-source-cam1.sh &
./av-source-cam2.sh &
+./av-source-background.sh &
./av-record-output-ffmpeg.sh &
#./av-stream-hd.sh &
./demo-cycle-modes.sh &