From 4559b8f400da068623d1fa08a4a126fa8ded2117 Mon Sep 17 00:00:00 2001 From: MaZderMind Date: Sat, 23 May 2015 14:52:23 +0200 Subject: mixer background --- voctocore/README.md | 4 ++- voctocore/lib/backgroundsource.py | 51 ++++++++++++++++++++++++++++++ voctocore/lib/pipeline.py | 4 +++ voctocore/lib/videomix.py | 52 +++++++++++++++++++------------ voctocore/scripts/av-source-background.sh | 6 ++++ voctocore/scripts/demo-cube-files.sh | 1 + voctocore/scripts/demo-cube.sh | 1 + voctocore/scripts/demo-local.sh | 1 + 8 files changed, 99 insertions(+), 21 deletions(-) create mode 100644 voctocore/lib/backgroundsource.py create mode 100755 voctocore/scripts/av-source-background.sh 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 & -- cgit v1.2.3