From cb42a9ad193179c527b44eccd3ca3ac59d573386 Mon Sep 17 00:00:00 2001 From: Jonas Smedegaard Date: Tue, 28 Feb 2017 15:10:39 +0100 Subject: Add composition Matrix Two-by-two. --- example-scripts/control-server/demo-cycle-modes.sh | 3 + example-scripts/control-server/set-audio-cam3.sh | 9 ++ example-scripts/control-server/set-audio-cam4.sh | 9 ++ .../set-composite-matrix-two-by-two.sh | 9 ++ .../gstreamer/source-videotestsrc-as-cam3.sh | 19 +++++ .../gstreamer/source-videotestsrc-as-cam4.sh | 19 +++++ example-scripts/misc/benchmark.sh | 2 + example-scripts/misc/demo-local.sh | 2 + example-scripts/misc/perf.sh | 2 + .../systemd-units/voctomix-cam3-source.service | 14 ++++ .../systemd-units/voctomix-cam4-source.service | 14 ++++ voctocore/default-config.ini | 11 +++ voctocore/lib/videomix.py | 81 +++++++++++++++++- voctogui/lib/shortcuts.py | 3 +- voctogui/lib/toolbar/composition.py | 3 +- voctogui/ui/composite-matrix-two-by-two.svg | 95 ++++++++++++++++++++++ voctogui/ui/voctogui.ui | 19 +++++ 17 files changed, 311 insertions(+), 3 deletions(-) create mode 100755 example-scripts/control-server/set-audio-cam3.sh create mode 100755 example-scripts/control-server/set-audio-cam4.sh create mode 100755 example-scripts/control-server/set-composite-matrix-two-by-two.sh create mode 100755 example-scripts/gstreamer/source-videotestsrc-as-cam3.sh create mode 100755 example-scripts/gstreamer/source-videotestsrc-as-cam4.sh create mode 100644 example-scripts/systemd-units/voctomix-cam3-source.service create mode 100644 example-scripts/systemd-units/voctomix-cam4-source.service create mode 100644 voctogui/ui/composite-matrix-two-by-two.svg diff --git a/example-scripts/control-server/demo-cycle-modes.sh b/example-scripts/control-server/demo-cycle-modes.sh index 7440cf1..ab9cdbd 100755 --- a/example-scripts/control-server/demo-cycle-modes.sh +++ b/example-scripts/control-server/demo-cycle-modes.sh @@ -35,6 +35,9 @@ while true; do ./set-video-cam2.sh ./set-audio-cam2.sh sleep 10 + echo "composite-matrix-two-by-two" + ./set-composite-matrix-two-by-two.sh + sleep 10 echo "composite-picture-in-picture" ./set-composite-picture-in-picture.sh sleep 10 diff --git a/example-scripts/control-server/set-audio-cam3.sh b/example-scripts/control-server/set-audio-cam3.sh new file mode 100755 index 0000000..b591879 --- /dev/null +++ b/example-scripts/control-server/set-audio-cam3.sh @@ -0,0 +1,9 @@ +#!/bin/sh + +confdir="`dirname "$0"`/../" +. $confdir/default-config.sh +if [ -f $confdir/config.sh ]; then + . $confdir/config.sh +fi + +echo set_audio cam3 | nc -q0 $MIXHOST 9999 diff --git a/example-scripts/control-server/set-audio-cam4.sh b/example-scripts/control-server/set-audio-cam4.sh new file mode 100755 index 0000000..2dd26a8 --- /dev/null +++ b/example-scripts/control-server/set-audio-cam4.sh @@ -0,0 +1,9 @@ +#!/bin/sh + +confdir="`dirname "$0"`/../" +. $confdir/default-config.sh +if [ -f $confdir/config.sh ]; then + . $confdir/config.sh +fi + +echo set_audio cam4 | nc -q0 $MIXHOST 9999 diff --git a/example-scripts/control-server/set-composite-matrix-two-by-two.sh b/example-scripts/control-server/set-composite-matrix-two-by-two.sh new file mode 100755 index 0000000..1ea81c6 --- /dev/null +++ b/example-scripts/control-server/set-composite-matrix-two-by-two.sh @@ -0,0 +1,9 @@ +#!/bin/sh + +confdir="`dirname "$0"`/../" +. $confdir/default-config.sh +if [ -f $confdir/config.sh ]; then + . $confdir/config.sh +fi + +echo set_composite_mode matrix_two_by_two | nc -q0 $MIXHOST 9999 diff --git a/example-scripts/gstreamer/source-videotestsrc-as-cam3.sh b/example-scripts/gstreamer/source-videotestsrc-as-cam3.sh new file mode 100755 index 0000000..85787b2 --- /dev/null +++ b/example-scripts/gstreamer/source-videotestsrc-as-cam3.sh @@ -0,0 +1,19 @@ +#!/bin/sh + +confdir="`dirname "$0"`/../" +. $confdir/default-config.sh +if [ -f $confdir/config.sh ]; then + . $confdir/config.sh +fi + +gst-launch-1.0 \ + videotestsrc pattern=ball foreground-color=0x000000ff background-color=0x00000044 !\ + video/x-raw,format=I420,width=$WIDTH,height=$HEIGHT,framerate=$FRAMERATE/1,pixel-aspect-ratio=1/1 ! \ + mux. \ + \ + audiotestsrc freq=660 !\ + audio/x-raw,format=S16LE,channels=2,layout=interleaved,rate=$AUDIORATE !\ + mux. \ + \ + matroskamux name=mux !\ + tcpclientsink host=$MIXHOST port=10002 diff --git a/example-scripts/gstreamer/source-videotestsrc-as-cam4.sh b/example-scripts/gstreamer/source-videotestsrc-as-cam4.sh new file mode 100755 index 0000000..6bee2f3 --- /dev/null +++ b/example-scripts/gstreamer/source-videotestsrc-as-cam4.sh @@ -0,0 +1,19 @@ +#!/bin/sh + +confdir="`dirname "$0"`/../" +. $confdir/default-config.sh +if [ -f $confdir/config.sh ]; then + . $confdir/config.sh +fi + +gst-launch-1.0 \ + videotestsrc pattern=ball foreground-color=0x00ffff00 background-color=0x00444400 !\ + video/x-raw,format=I420,width=$WIDTH,height=$HEIGHT,framerate=$FRAMERATE/1,pixel-aspect-ratio=1/1 ! \ + mux. \ + \ + audiotestsrc freq=770 !\ + audio/x-raw,format=S16LE,channels=2,layout=interleaved,rate=$AUDIORATE !\ + mux. \ + \ + matroskamux name=mux !\ + tcpclientsink host=$MIXHOST port=10003 diff --git a/example-scripts/misc/benchmark.sh b/example-scripts/misc/benchmark.sh index c60f897..2ca879c 100755 --- a/example-scripts/misc/benchmark.sh +++ b/example-scripts/misc/benchmark.sh @@ -7,6 +7,8 @@ sleep 1 ../control-server/set-composite-side-by-side-equal.sh >/dev/null 2>/dev/null ../gstreamer/source-videotestsrc-as-cam1.sh >/dev/null 2>/dev/null & ../gstreamer/source-videotestsrc-as-cam2.sh >/dev/null 2>/dev/null & +../gstreamer/source-videotestsrc-as-cam3.sh >/dev/null 2>/dev/null & +../gstreamer/source-videotestsrc-as-cam4.sh >/dev/null 2>/dev/null & ../gstreamer/source-videotestsrc-as-grabber.sh >/dev/null 2>/dev/null & ../gstreamer/source-videotestsrc-as-background-loop.sh >/dev/null 2>/dev/null & pidstat -p $PID 1 & diff --git a/example-scripts/misc/demo-local.sh b/example-scripts/misc/demo-local.sh index f985fb1..95a97ce 100755 --- a/example-scripts/misc/demo-local.sh +++ b/example-scripts/misc/demo-local.sh @@ -12,6 +12,8 @@ echo "PID=$PID" sleep 1 ../ffmpeg/source-testvideo-as-cam1.sh >/dev/null 2>/dev/null & ../ffmpeg/source-testvideo-as-cam2.sh >/dev/null 2>/dev/null & +../ffmpeg/source-testvideo-as-cam3.sh >/dev/null 2>/dev/null & +../ffmpeg/source-testvideo-as-cam4.sh >/dev/null 2>/dev/null & ../ffmpeg/source-background-loop.sh & ../ffmpeg/av-record-output-ffmpeg.sh & #../ffmpeg/stream-hd.sh & diff --git a/example-scripts/misc/perf.sh b/example-scripts/misc/perf.sh index c20f10b..9a03c19 100755 --- a/example-scripts/misc/perf.sh +++ b/example-scripts/misc/perf.sh @@ -7,6 +7,8 @@ sleep 1 ../control-server/set-composite-side-by-side-equal.sh >/dev/null 2>/dev/null ../gstreamer/source-videotestsrc-as-cam1.sh >/dev/null 2>/dev/null & ../gstreamer/source-videotestsrc-as-cam2.sh >/dev/null 2>/dev/null & +../gstreamer/source-videotestsrc-as-cam3.sh >/dev/null 2>/dev/null & +../gstreamer/source-videotestsrc-as-cam4.sh >/dev/null 2>/dev/null & ../gstreamer/source-videotestsrc-as-grabber.sh >/dev/null 2>/dev/null & ../gstreamer/source-videotestsrc-as-background-loop.sh >/dev/null 2>/dev/null & sudo perf top -g -p $PID diff --git a/example-scripts/systemd-units/voctomix-cam3-source.service b/example-scripts/systemd-units/voctomix-cam3-source.service new file mode 100644 index 0000000..3d941bc --- /dev/null +++ b/example-scripts/systemd-units/voctomix-cam3-source.service @@ -0,0 +1,14 @@ +[Unit] +Description = voctomix test-video-source cam3 +After = voctomix-voctocore.service +Requires = voctomix-voctocore.service + +[Service] +Type = simple +ExecStart = /usr/share/doc/voctomix/example-scripts/gstreamer/source-videotestsrc-as-cam3.sh +Restart = always +RestartSec = 1s +StartLimitInterval = 0 + +[Install] +WantedBy = voctomix-voctocore.service diff --git a/example-scripts/systemd-units/voctomix-cam4-source.service b/example-scripts/systemd-units/voctomix-cam4-source.service new file mode 100644 index 0000000..202c111 --- /dev/null +++ b/example-scripts/systemd-units/voctomix-cam4-source.service @@ -0,0 +1,14 @@ +[Unit] +Description = voctomix test-video-source cam4 +After = voctomix-voctocore.service +Requires = voctomix-voctocore.service + +[Service] +Type = simple +ExecStart = /usr/share/doc/voctomix/example-scripts/gstreamer/source-videotestsrc-as-cam4.sh +Restart = always +RestartSec = 1s +StartLimitInterval = 0 + +[Install] +WantedBy = voctomix-voctocore.service diff --git a/voctocore/default-config.ini b/voctocore/default-config.ini index d5f69e9..3341b80 100644 --- a/voctocore/default-config.ini +++ b/voctocore/default-config.ini @@ -60,6 +60,17 @@ mix_out=10000 ;default-a=grabber ;default-b=cam1 +[matrix-two-by-two] +; defaults to 1% of the video width +;gutter=12 + +; if configured, switching to the matrix-2x2 mode will automatically select these +; sources. if not configured, it will not change the last set sources +;default-a=cam1 +;default-b=cam2 +;default-c=cam3 +;default-d=cam4 + [previews] ; disable if ui & server run on the same computer and can exchange uncompressed video frames enabled=false diff --git a/voctocore/lib/videomix.py b/voctocore/lib/videomix.py index 38432e8..e7c0233 100644 --- a/voctocore/lib/videomix.py +++ b/voctocore/lib/videomix.py @@ -12,6 +12,7 @@ class CompositeModes(Enum): side_by_side_equal = 1 side_by_side_preview = 2 picture_in_picture = 3 + matrix_two_by_two = 4 class PadState(object): @@ -98,6 +99,8 @@ class VideoMix(object): self.compositeMode = CompositeModes.fullscreen self.sourceA = 0 self.sourceB = 1 + self.sourceC = 2 + self.sourceD = 3 self.recalculateMixerState() self.applyMixerState() @@ -129,6 +132,9 @@ class VideoMix(object): elif self.compositeMode == CompositeModes.picture_in_picture: self.recalculateMixerStatePictureInPicture() + elif self.compositeMode == CompositeModes.matrix_two_by_two: + self.recalculateMixerStateMatrixTwoByTwo() + self.log.debug('Marking Pad-State as Dirty') self.padStateDirty = True @@ -322,6 +328,62 @@ class VideoMix(object): else: pad.alpha = 0 + def recalculateMixerStateMatrixTwoByTwo(self): + self.log.info('Updating Mixer-State for ' + 'Matrix-Two-by-two-Composition') + + width, height = self.getInputVideoSize() + self.log.debug('Video-Size parsed as %ux%u', width, height) + + try: + gutter = Config.getint('matrix-two-by-two', 'gutter') + self.log.debug('Gutter configured to %u', gutter) + except: + gutter = int(width / 100) + self.log.debug('Gutter calculated to %u', gutter) + + targetWidth = int((width - gutter) / 2) + #targetHeight = int(targetWidth / width * height) + targetHeight = int((height - gutter) / 2) + + self.log.debug('Video-Size calculated to %ux%u', + targetWidth, targetHeight) + + xa = 0 + xb = width - targetWidth + y1 = 0 + y2 = height - targetHeight + + for idx, name in enumerate(self.names): + pad = self.padState[idx] + pad.reset() + + pad.width = targetWidth + pad.height = targetHeight + + if idx == self.sourceA: + pad.xpos = xa + pad.ypos = y1 + pad.zorder = 1 + + elif idx == self.sourceB: + pad.xpos = xb + pad.ypos = y1 + pad.zorder = 2 + + elif idx == self.sourceC: + pad.xpos = xa + pad.ypos = y2 + pad.zorder = 3 + + elif idx == self.sourceD: + pad.xpos = xb + pad.ypos = y2 + pad.zorder = 4 + + else: + pad.alpha = 0 + def applyMixerState(self): for idx, state in enumerate(self.padState): # mixerpad 0 = background @@ -346,7 +408,8 @@ class VideoMix(object): CompositeModes.fullscreen: 'fullscreen', CompositeModes.side_by_side_equal: 'side-by-side-equal', CompositeModes.side_by_side_preview: 'side-by-side-preview', - CompositeModes.picture_in_picture: 'picture-in-picture' + CompositeModes.picture_in_picture: 'picture-in-picture', + CompositeModes.matrix_two_by_two: 'matrix-two-by-two' } compositeModeName = self.compositeMode.name @@ -368,6 +431,22 @@ class VideoMix(object): except Exception as e: pass + try: + defSource = Config.get(sectionName, 'default-c') + self.setVideoSourceC(self.names.index(defSource)) + self.log.info('Changing sourceC to default of Mode %s: %s', + compositeModeName, defSource) + except Exception as e: + pass + + try: + defSource = Config.get(sectionName, 'default-d') + self.setVideoSourceD(self.names.index(defSource)) + self.log.info('Changing sourceD to default of Mode %s: %s', + compositeModeName, defSource) + except Exception as e: + pass + def on_handoff(self, object, buffer): if self.padStateDirty: self.padStateDirty = False diff --git a/voctogui/lib/shortcuts.py b/voctogui/lib/shortcuts.py index d5fbc91..5ad2bbf 100644 --- a/voctogui/lib/shortcuts.py +++ b/voctogui/lib/shortcuts.py @@ -25,7 +25,8 @@ if hasattr(Gtk, "ShortcutsWindow"): for accel, desc in [("F1", "Select fullscreen mode"), ("F2", "Select Picture in Picture mode"), ("F3", "Select Side-by-Side Equal mode"), - ("F4", "Select Side-by-Side Preview mode")]: + ("F4", "Select Side-by-Side Preview mode"), + ("F5", "Select Matrix Two-by-two mode")]: short = Gtk.ShortcutsShortcut(title=desc, accelerator=accel) short.show() compose_group.add(short) diff --git a/voctogui/lib/toolbar/composition.py b/voctogui/lib/toolbar/composition.py index b55254a..3cf5797 100644 --- a/voctogui/lib/toolbar/composition.py +++ b/voctogui/lib/toolbar/composition.py @@ -17,7 +17,8 @@ class CompositionToolbarController(object): 'fullscreen', 'picture_in_picture', 'side_by_side_equal', - 'side_by_side_preview' + 'side_by_side_preview', + 'matrix_two_by_two' ] self.composite_btns = {} diff --git a/voctogui/ui/composite-matrix-two-by-two.svg b/voctogui/ui/composite-matrix-two-by-two.svg new file mode 100644 index 0000000..2086be2 --- /dev/null +++ b/voctogui/ui/composite-matrix-two-by-two.svg @@ -0,0 +1,95 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + diff --git a/voctogui/ui/voctogui.ui b/voctogui/ui/voctogui.ui index 0e0c447..53e3129 100644 --- a/voctogui/ui/voctogui.ui +++ b/voctogui/ui/voctogui.ui @@ -12,6 +12,11 @@ False composite-fullscreen.svg + + True + False + composite-matrix-two-by-two.svg + True False @@ -102,6 +107,20 @@ True + + + True + False + Matrix Two-by-two + True + img-composite-matrix-two-by-two + composite-fullscreen + + + False + True + + True -- cgit v1.2.3