diff options
author | Jonas Smedegaard <dr@jones.dk> | 2017-02-28 15:10:39 +0100 |
---|---|---|
committer | Jonas Smedegaard <dr@jones.dk> | 2017-02-28 15:10:39 +0100 |
commit | cb42a9ad193179c527b44eccd3ca3ac59d573386 (patch) | |
tree | 8967af004209c8d7f159e45e5807979c7ca5953f | |
parent | 6ce57b47f050c39fbf28f4af639ef19608a74cfa (diff) |
Add composition Matrix Two-by-two.
-rwxr-xr-x | example-scripts/control-server/demo-cycle-modes.sh | 3 | ||||
-rwxr-xr-x | example-scripts/control-server/set-audio-cam3.sh | 9 | ||||
-rwxr-xr-x | example-scripts/control-server/set-audio-cam4.sh | 9 | ||||
-rwxr-xr-x | example-scripts/control-server/set-composite-matrix-two-by-two.sh | 9 | ||||
-rwxr-xr-x | example-scripts/gstreamer/source-videotestsrc-as-cam3.sh | 19 | ||||
-rwxr-xr-x | example-scripts/gstreamer/source-videotestsrc-as-cam4.sh | 19 | ||||
-rwxr-xr-x | example-scripts/misc/benchmark.sh | 2 | ||||
-rwxr-xr-x | example-scripts/misc/demo-local.sh | 2 | ||||
-rwxr-xr-x | example-scripts/misc/perf.sh | 2 | ||||
-rw-r--r-- | example-scripts/systemd-units/voctomix-cam3-source.service | 14 | ||||
-rw-r--r-- | example-scripts/systemd-units/voctomix-cam4-source.service | 14 | ||||
-rw-r--r-- | voctocore/default-config.ini | 11 | ||||
-rw-r--r-- | voctocore/lib/videomix.py | 81 | ||||
-rw-r--r-- | voctogui/lib/shortcuts.py | 3 | ||||
-rw-r--r-- | voctogui/lib/toolbar/composition.py | 3 | ||||
-rw-r--r-- | voctogui/ui/composite-matrix-two-by-two.svg | 95 | ||||
-rw-r--r-- | voctogui/ui/voctogui.ui | 19 |
17 files changed, 311 insertions, 3 deletions
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 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> + +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + width="32" + height="32" + id="svg3052" + version="1.1" + inkscape:version="0.92.1 r15371" + sodipodi:docname="composite-matrix-two-by-two.svg"> + <defs + id="defs3054" /> + <sodipodi:namedview + id="base" + pagecolor="#ffffff" + bordercolor="#666666" + borderopacity="1.0" + inkscape:pageopacity="0.0" + inkscape:pageshadow="2" + inkscape:zoom="50.440484" + inkscape:cx="12.946897" + inkscape:cy="15.006196" + inkscape:document-units="px" + inkscape:current-layer="g3943" + showgrid="false" + inkscape:window-width="1680" + inkscape:window-height="1005" + inkscape:window-x="0" + inkscape:window-y="45" + inkscape:window-maximized="0" /> + <metadata + id="metadata3057"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + <dc:title /> + </cc:Work> + </rdf:RDF> + </metadata> + <g + inkscape:label="Layer 1" + inkscape:groupmode="layer" + id="layer1" + transform="translate(0,-1020.3622)"> + <rect + style="color:#000000;fill:none;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:0.10000000000000001;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" + id="rect3062" + width="30" + height="16.875" + x="1" + y="1027.9247" /> + <g + id="g3943" + transform="matrix(0.9768158,0,0,0.9768158,0.70836066,24.02723)"> + <rect + y="1027.8325" + x="0.37704754" + height="8.57582" + width="15.245902" + id="rect3062-3" + style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#0000ff;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:0.25409836;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate" /> + <rect + y="1027.8325" + x="15.686207" + height="8.57582" + width="15.245902" + id="rect3062-3-8" + style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#ff0000;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:0.25409836;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate" /> + <rect + style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#00ff00;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:0.25409836;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate" + id="rect3690" + width="15.245902" + height="8.57582" + x="0.37704754" + y="1036.4083" /> + <rect + style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#ffff00;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:0.25409836;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate" + id="rect3692" + width="15.245902" + height="8.57582" + x="15.686207" + y="1036.4083" /> + </g> + </g> +</svg> 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 @@ <property name="can_focus">False</property> <property name="pixbuf">composite-fullscreen.svg</property> </object> + <object class="GtkImage" id="img-composite-matrix-two-by-two"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="pixbuf">composite-matrix-two-by-two.svg</property> + </object> <object class="GtkImage" id="img-composite-picture-in-picture"> <property name="visible">True</property> <property name="can_focus">False</property> @@ -103,6 +108,20 @@ </packing> </child> <child> + <object class="GtkRadioToolButton" id="composite-matrix-two-by-two"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="label" translatable="yes">Matrix Two-by-two</property> + <property name="use_underline">True</property> + <property name="icon_widget">img-composite-matrix-two-by-two</property> + <property name="group">composite-fullscreen</property> + </object> + <packing> + <property name="expand">False</property> + <property name="homogeneous">True</property> + </packing> + </child> + <child> <object class="GtkSeparatorToolItem" id="s1"> <property name="visible">True</property> <property name="can_focus">False</property> |