From 1353c75413f7b660939a48d09f17a18f75015e0d Mon Sep 17 00:00:00 2001 From: MaZderMind Date: Sat, 23 May 2015 13:40:51 +0200 Subject: Picture-in-Picture composition mode --- voctocore/default-config.ini | 4 ++ voctocore/lib/videomix.py | 66 ++++++++++++++++++++++ voctocore/scripts/demo-cycle-modes.sh | 6 +- .../scripts/set-composite-picture-in-picture.sh | 2 + 4 files changed, 77 insertions(+), 1 deletion(-) create mode 100755 voctocore/scripts/set-composite-picture-in-picture.sh (limited to 'voctocore') diff --git a/voctocore/default-config.ini b/voctocore/default-config.ini index eb2de84..df361b1 100644 --- a/voctocore/default-config.ini +++ b/voctocore/default-config.ini @@ -15,6 +15,10 @@ sources=cam1,cam2,grabber ;bsize=320x180 ;bpos=948/528 +[picture-in-picture] +;pipsize=320x180 +;pippos=948/528 + [previews] ; disable if ui & server run on the same computer and exchange uncompressed video frames enabled=true diff --git a/voctocore/lib/videomix.py b/voctocore/lib/videomix.py index 53e1d03..6508346 100644 --- a/voctocore/lib/videomix.py +++ b/voctocore/lib/videomix.py @@ -9,6 +9,7 @@ class CompositeModes(Enum): fullscreen = 0 side_by_side_equal = 1 side_by_side_preview = 2 + picture_in_picture = 3 class VideoMix(object): log = logging.getLogger('VideoMix') @@ -83,6 +84,9 @@ class VideoMix(object): elif self.compositeMode == CompositeModes.side_by_side_preview: self.updateMixerStateSideBySidePreview() + elif self.compositeMode == CompositeModes.picture_in_picture: + self.updateMixerStatePictureInPicture() + def updateMixerStateFullscreen(self): self.log.info('Updating Mixer-State for Fullscreen-Composition') @@ -238,6 +242,68 @@ class VideoMix(object): self.log.debug('Setting Mixerpad %u to x/y=%u/%u and alpha=%0.2f', idx, 0, 0, 0) self.log.debug('Resetting Scaler %u to non-scaling', idx) + def updateMixerStatePictureInPicture(self): + self.log.info('Updating Mixer-State for Picture-in-Picture-Composition') + + width, height = self.getInputVideoSize() + self.log.debug('Video-Size parsed as %ux%u', width, height) + + try: + pipsize = [int(i) for i in Config.get('picture-in-picture', 'pipsize').split('x', 1)] + self.log.debug('PIP-Size configured to %ux%u', pipsize[0], pipsize[1]) + except: + pipsize = [ + int(width / 4), # 25% + int(height / 4) # 25% + ] + self.log.debug('PIP-Size calculated to %ux%u', pipsize[0], pipsize[1]) + + try: + pippos = [int(i) for i in Config.get('picture-in-picture', 'pippos').split('/', 1)] + self.log.debug('PIP-Position configured to %u/%u', pippos[0], pippos[1]) + except: + pippos = [ + width - pipsize[0] - int(width / 100), # 1% + height - pipsize[1] -int(width / 100) # 1% + ] + self.log.debug('PIP-Position calculated to %u/%u', pippos[0], pippos[1]) + + scaleCaps = Gst.Caps.from_string('video/x-raw,width=%u,height=%u' % tuple(pipsize)) + 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) + + if idx == self.sourceA: + mixerpad.set_property('alpha', 1) + mixerpad.set_property('xpos', 0) + mixerpad.set_property('ypos', 0) + mixerpad.set_property('zorder', 0) + 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('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) + 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 Scaler %u to %u/%u', idx, pipsize[0], pipsize[1]) + + else: + mixerpad.set_property('alpha', 0) + mixerpad.set_property('xpos', 0) + mixerpad.set_property('ypos', 0) + capsfilter.set_property('caps', noScaleCaps) + + self.log.debug('Setting Mixerpad %u to x/y=%u/%u and alpha=%0.2f', idx, 0, 0, 0) + self.log.debug('Resetting Scaler %u to non-scaling', idx) + def setVideoSourceA(self, source): # swap if required if self.sourceB == source: diff --git a/voctocore/scripts/demo-cycle-modes.sh b/voctocore/scripts/demo-cycle-modes.sh index 264bdfa..da5fdb8 100755 --- a/voctocore/scripts/demo-cycle-modes.sh +++ b/voctocore/scripts/demo-cycle-modes.sh @@ -1,8 +1,12 @@ while true; do - ./set-composite-side-by-side-preview.sh + ./set-composite-picture-in-picture.sh sleep 10 ./set-video-cam2.sh sleep 10 + ./set-composite-side-by-side-preview.sh + sleep 10 + ./set-video-cam1.sh + sleep 10 ./set-composite-side-by-side-equal.sh sleep 10 ./set-audio-cam2.sh diff --git a/voctocore/scripts/set-composite-picture-in-picture.sh b/voctocore/scripts/set-composite-picture-in-picture.sh new file mode 100755 index 0000000..eae3bea --- /dev/null +++ b/voctocore/scripts/set-composite-picture-in-picture.sh @@ -0,0 +1,2 @@ +#!/bin/sh +echo set_composite_mode picture_in_picture | nc -q0 localhost 9999 -- cgit v1.2.3