commit 107e24a13cee98dd52223f5b2e2f0f26a8469f8a Author: sebastian Date: Wed Apr 9 23:13:17 2014 +0200 Initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..6594be4 --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +Snowmix-0.4.2 +images/logo.* +python/virtenv +videos +*.pyc diff --git a/frames/make_frame b/frames/make_frame new file mode 100755 index 0000000..e67ca88 --- /dev/null +++ b/frames/make_frame @@ -0,0 +1,13 @@ +#!/bin/bash + +echo making frame +echo -e "Width : \c" +read width +echo -e "height : \c" +read height +echo $width $height +bytes=`expr $width "*" $height "*" 4` + +MIXERFORMAT='video/x-raw-rgb, bpp=(int)32, depth=(int)32, endianness=(int)4321, format=(fourcc)BGRA, red_mask=(int)65280, green_mask=(int)16711680, blue_mask=(int)-16777216, width=(int)'$width', height=(int)'$height', pixel-aspect-ratio=(fraction)1/1, interlaced=(boolean)false' +gst-launch-0.10 -q videotestsrc ! $MIXERFORMAT ! fdsink fd=1 | dd of="newframe_"$width"x"$height bs=$bytes count=1 + diff --git a/frames/test_1024x768 b/frames/test_1024x768 new file mode 100644 index 0000000..18a66d9 Binary files /dev/null and b/frames/test_1024x768 differ diff --git a/images/background.png b/images/background.png new file mode 100644 index 0000000..b77ec2b Binary files /dev/null and b/images/background.png differ diff --git a/images/mockup.xcf b/images/mockup.xcf new file mode 100644 index 0000000..d0fc185 Binary files /dev/null and b/images/mockup.xcf differ diff --git a/ini/base.ini b/ini/base.ini new file mode 100644 index 0000000..f420780 --- /dev/null +++ b/ini/base.ini @@ -0,0 +1,216 @@ +# Basic Feeds Settings +# Copyright by Peter Maersk-Moller 2012 - All rights reserved +#verbose +require version 0.4.0 + +# Define allowed remote host IP addresses. If omitted then only 127.0.0.1 will be accepted. +system host allow 127.0.0.1 + +# Listen on port 9999 for command control connections +system control port 9999 + +# Set system Geometry to 1024x768 +system geometry 1024 768 ARGB + +# Set system frame rate to 24 +system frame rate 24 + +# Set output control socket +system socket /tmp/mixer1 + +# Set feed idle time - feed 0 will always be idle. If no file is given, +# idle image will be all black. +feed idle 0 1 frames/test_1024x768 +#feed idle 0 1 + +################## +# Input feeds +################## +# Keep size of input feeds to same size as feed 0 +# otherwise things explode. + +feed add 1 Feed #1 +feed geometry 1 1024 768 +feed live 1 +feed idle 1 100 frames/test_1024x768 +feed socket 1 /tmp/feed1 + + +###################### +# Virtual feeds +####################### +# Maximized settings for any feed: +# virtual feed place rect X 20 20 1024 768 0 0 0.0 0.75 0.75 1.0 + +# Feed 1 +# Starts maximized +# Minimized position: 800 20 +# Minimized size: 205 154 +virtual feed add 1 Feed #1 +virtual feed source feed 1 1 +virtual feed place rect 1 20 20 1024 768 0 0 0.0 0.75 0.75 1.0 + +# Feed 2 +# Starts minimized +# Minimized position: 800 231 +# Minimized size: 205 154 +virtual feed add 2 Feed #2 +virtual feed source feed 2 1 +virtual feed place rect 2 800 230 1024 768 0 0 0.0 0.20 0.20 1.0 + +# Feed 3 +# Starts minimized +# Minimized position: 800 442 +# Minimized size: 205 154 +virtual feed add 3 Feed #3 +virtual feed source feed 3 1 +virtual feed place rect 3 800 442 1024 768 0 0 0.0 0.20 0.20 1.0 + + + +command create MinimizeFeed1 + # Since everything from now on is relative, + # we should make sure everthings is where we expect it to be + virtual feed place rect 1 20 20 1024 768 0 0 0.0 0.75 0.75 1.0 + + # The scale and coor commands are nonblocking + virtual feed move scale 1 -0.055 -0.055 10 10 + virtual feed move coor 1 65 0 12 0 + + # Allow Maximizing + command restart MaximizeFeed1 +command end + +command create MaximizeFeed1 + # Since everything from now on is relative, + # we should make sure everthings is where we expect it to be + virtual feed place rect 1 800 20 1024 768 0 0 0.0 0.20 0.20 1.0 + + # The scale and coor commands are nonblocking + virtual feed move scale 1 0.055 0.055 10 10 + virtual feed move coor 1 -65 0 12 0 + + # Allow Minimizing + command restart MinimizeFeed1 +command end + +command create MinimizeFeed2 + # Since everything from now on is relative, + # we should make sure everthings is where we expect it to be + virtual feed place rect 2 20 20 1024 768 0 0 0.0 0.75 0.75 1.0 + + # The scale and coor commands are nonblocking + virtual feed move scale 2 -0.055 -0.055 10 10 + virtual feed move coor 2 65 21 12 10 + + # Allow Maximizing + command restart MaximizeFeed2 +command end + +command create MaximizeFeed2 + # Since everything from now on is relative, + # we should make sure everthings is where we expect it to be + virtual feed place rect 2 800 230 1024 768 0 0 0.0 0.20 0.20 1.0 + + # The scale and coor commands are nonblocking + virtual feed move scale 2 0.055 0.055 10 10 + virtual feed move coor 2 -65 -21 12 10 + + # Allow Minimizing + command restart MinimizeFeed2 +command end + +command create MinimizeFeed3 + # Since everything from now on is relative, + # we should make sure everthings is where we expect it to be + virtual feed place rect 3 20 20 1024 768 0 0 0.0 0.75 0.75 1.0 + + # The scale and coor commands are nonblocking + virtual feed move scale 3 -0.055 -0.055 10 10 + virtual feed move coor 3 65 35 12 12 + + # Allow Maximizing + command restart MaximizeFeed3 +command end + +command create MaximizeFeed3 + # Since everything from now on is relative, + # we should make sure everthings is where we expect it to be + virtual feed place rect 3 800 442 1024 768 0 0 0.0 0.20 0.20 1.0 + + # The scale and coor commands are nonblocking + virtual feed move scale 3 0.055 0.055 10 10 + virtual feed move coor 3 -65 -35 12 12 + + # Allow Minimizing + command restart MinimizeFeed3 +command end + +command create Swap12 + MinimizeFeed1 + MaximizeFeed2 + command restart Swap21 + command restart Swap23 +command end + +command create Swap13 + MinimizeFeed1 + MaximizeFeed3 + command restart Swap31 + command restart Swap32 +command end + +command create Swap21 + MinimizeFeed2 + MaximizeFeed1 + command restart Swap12 + command restart Swap13 +command end + +command create Swap23 + MinimizeFeed2 + MaximizeFeed3 + command restart Swap31 + command restart Swap32 +command end + +command create Swap31 + MinimizeFeed3 + MaximizeFeed1 + command restart Swap12 + command restart Swap13 +command end + + +command create Swap32 + MinimizeFeed3 + MaximizeFeed2 + command restart Swap21 + command restart Swap23 +command end + +stack 0 + +# Load the background +image load 0 images/background.png +image place 0 0 0 0 + +# Load the logo +image load 1 images/logo.png +image place 1 1 24 24 + + +command create Show + overlay image 0 + + overlay virtual feed 1..3 + + overlay image 1 + #overlay text all + loop +command end + +overlay finish Show + + +#montor on \ No newline at end of file diff --git a/python/midi/midibuttonlistener.py b/python/midi/midibuttonlistener.py new file mode 100644 index 0000000..727dc6f --- /dev/null +++ b/python/midi/midibuttonlistener.py @@ -0,0 +1,97 @@ +#!/bin/env python2 + +import rtmidi + +from buttonlistener import ButtonListener + + +class MidiButtonListener(object): + + def __init__(self): + self.midi_in = rtmidi.MidiIn() + self.listeners = {} + + + def _hex_message(self, message): + return map(lambda x: hex(x), message) + + + def _get_listeners(self, type, data1, data2): + if not type in self.listeners.keys(): + return [] + + if not data1 in self.listeners[type].keys(): + return [] + + if not data2 in self.listeners[type][data1].keys(): + return [] + + return self.listeners[type][data1][data2] + + def _enumarate_listeners(self, message_type, message_data1, message_data2): + result = [] + for type in [None, message_type]: + for data1 in [None, message_data1]: + for data2 in [None, message_data2]: + result += self._get_listeners(type,data1,data2) + + return result + + + def add_listener(self, listener, type = None, data1 = None, data2 = None): + + if not type in self.listeners.keys(): + self.listeners[type] = {} + + if not data1 in self.listeners[type].keys(): + self.listeners[type][data1] = {} + + if not data2 in self.listeners[type][data1].keys(): + self.listeners[type][data1][data2] = [] + + self.listeners[type][data1][data2].append(listener) + + + def remove_listener(self, listener, type = None, data1 = None, data2 = None): + if not type in self.listeners.keys(): + raise ValueError("No listener registered for %s" % hex(type)) + + if not data1 in self.listeners[type].keys(): + raise ValueError("No listener registered for %s %s" % (hex(type), hex(data1))) + + if not data2 in self.listeners[type][data1].keys(): + raise ValueError("No listener registered for %s %s" % (hex(type), hex(data1), hex(data2))) + + self.listeners[type][data1][data2].remove(listener) + + + def open(self, name): + input_port = None + for port_number in range(self.midi_in.get_port_count()): + port_name = self.midi_in.get_port_name(port_number) + print "Found port %d: %s" % (port_number, port_name) + if port_name.startswith(name): + input_port = port_number + + if not input_port: + print "No matching midi device found" + raise ValueError("No matching midi device found") + + self.midi_in.open_port(input_port) + + + def process_messages(self): + while(True): + message = self.midi_in.get_message() + if message: + print "Print new message: %s " % self._hex_message(message[0]) + type, data1, data2 = message[0] + for listener in self._enumarate_listeners(type, data1, data2): + listener(type,data1,data2) + + + def close(self): + self.midi_in.close_port() + + + \ No newline at end of file diff --git a/python/midi/midicontrol.py b/python/midi/midicontrol.py new file mode 100644 index 0000000..9daeafc --- /dev/null +++ b/python/midi/midicontrol.py @@ -0,0 +1,22 @@ +#!/bin/env python2 + +import sys + +from midibuttonlistener import MidiButtonListener + +from scenechange import SceneChange + + +INPUT_NAME = "USB Midi" + +buttonlistener = MidiButtonListener() + +buttonlistener.open(INPUT_NAME) + +sc = SceneChange() + +buttonlistener.add_listener(sc.bind_switch(1),0xb9,0x08) +buttonlistener.add_listener(sc.bind_switch(2),0xb9,0x0a) +buttonlistener.add_listener(sc.bind_switch(3),0xb9,0x0b) + +buttonlistener.process_messages() \ No newline at end of file diff --git a/python/midi/scenechange.py b/python/midi/scenechange.py new file mode 100644 index 0000000..0580ba8 --- /dev/null +++ b/python/midi/scenechange.py @@ -0,0 +1,20 @@ +#!/bin/env python2 +import socket + +class SceneChange(object): + + def __init__(self): + self.cur_scene = 1 + self.snowmix_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + self.snowmix_socket.connect(("localhost", 9999)) + + + def switch_to(self, next_scene): + if self.cur_scene != next_scene: + cmd = "Swap%d%d\n" % (self.cur_scene, next_scene) + print cmd + self.snowmix_socket.send(cmd) + self.cur_scene = next_scene + + def bind_switch(self, next_scene): + return lambda type, data1, data2: self.switch_to(next_scene) \ No newline at end of file diff --git a/scripts/cam1.sh b/scripts/cam1.sh new file mode 100755 index 0000000..cbc4364 --- /dev/null +++ b/scripts/cam1.sh @@ -0,0 +1,2 @@ + #!/bin/bash + ./cam2feed.sh /tmp/feed1 "http://gstreamer:GlytEnru@192.168.50.100/videostream.cgi?rate=0" \ No newline at end of file diff --git a/scripts/cam2feed.sh b/scripts/cam2feed.sh new file mode 100755 index 0000000..8831189 --- /dev/null +++ b/scripts/cam2feed.sh @@ -0,0 +1,28 @@ +#!/bin/bash +# Deliver a webcam video as input feed + +if [ -z "$1" -o -z "$2" ]; then + echo "Usage $0 " + exit +fi + +CONTROL_PIPE="$1" +MIXERFORMAT='video/x-raw-rgb, bpp=(int)32, depth=32, endianness=(int)4321, red_mask=(int)65280, green_mask=(int)16711680, blue_mask=(int)-16777216, width=(int)1024, height=(int)768, framerate=(fraction)24/1, pixel-aspect-ratio=(fraction)1/1, interlaced=(boolean)false' +SRC="souphttpsrc location=$2 ! jpegdec ! videorate" +SHMSIZE='shm-size=10000000' +SHMOPTION="wait-for-connection=0" +SHMSINK1="shmsink socket-path=$CONTROL_PIPE $SHMSIZE $SHMOPTION" +SCALE='ffmpegcolorspace ! videoscale ! ffmpegcolorspace' + + +while true ; do + # Remove the named pipe if it exist + rm -f $CONTROL_PIPE + gst-launch-0.10 -v \ + $SRC ! \ + $SCALE ! \ + $MIXERFORMAT ! \ + $SHMSINK1 + sleep 2 +done +exit diff --git a/scripts/camtest.sh b/scripts/camtest.sh new file mode 100644 index 0000000..4df471d --- /dev/null +++ b/scripts/camtest.sh @@ -0,0 +1,4 @@ +MIXERCAPS='video/x-raw-rgb, bpp=(int)32, depth=32, endianness=(int)4321, red_mask=(int)65280, green_mask=(int)16711680, blue_mask=(int)-16777216, width=(int)1024, height=(int)768, framerate=(fraction)24/1, pixel-aspect-ratio=(fraction)1/1, interlaced=(boolean)false' + + +gst-launch-0.10 -v souphttpsrc location=http://schumb:frederik@192.168.11.10/videostream.cgi?rate=0 ! jpegdec ! ffmpegcolorspace ! videoscale ! ffmpegcolorspace ! $MIXERCAPS ! ximagesink diff --git a/scripts/output2screen b/scripts/output2screen new file mode 100755 index 0000000..f4d2a60 --- /dev/null +++ b/scripts/output2screen @@ -0,0 +1,47 @@ +#!/bin/bash +# Deliver mixer1 output to screen. +# Taken from the original snowmix sources + +tmpfile=/tmp/output2screen.tmp.$$ +echo 'system info' | nc 127.0.0.1 9999 >$tmpfile +geometry=`grep 'STAT: System geometry' $tmpfile |cut -f3 -d: |cut -f2 -d' '|tr 'x' ' '` +framerate=`grep 'STAT: Frame rate' $tmpfile |cut -f3 -d: |cut -f2 -d' '` +ctrsocket=`grep 'STAT: Output ctr socket' $tmpfile |cut -f3 -d: |cut -f2 -d' '` + +rm $tmpfile + +VIDEOCONVERT=ffmpegcolorspace +VIDEO=video/x-raw-rgb +AUDIO=audio/x-raw-int + + +frameratefraction() +{ + echo $1 | awk '{ rate=$1 ; + factor=1; + intrate=int(rate); + while (factor*rate > intrate) { + factor = factor * 10; + intrate = int(rate*factor); + } + printf("%d/%d\n",intrate,factor); + }' +} +ratefraction=`frameratefraction $framerate` + +width=`echo $geometry |cut -f1 -d' '` +height=`echo $geometry |cut -f2 -d' '` + +MIXERFORMAT=$VIDEO', bpp=(int)32, depth=(int)32, endianness=(int)4321, format=(fourcc)BGRA, red_mask=(int)65280, green_mask=(int)16711680, blue_mask=(int)-16777216, width=(int)'$width', height=(int)'$height', framerate=(fraction)'$ratefraction', pixel-aspect-ratio=(fraction)1/1, interlaced=(boolean)false' +OUTPUTFORMAT=$VIDEO', width=1024, height=768' + + +while true ; do + gst-launch-0.10 -v shmsrc socket-path=$ctrsocket do-timestamp=true is-live=true ! \ + $MIXERFORMAT ! \ + videoscale ! \ + $OUTPUTFORMAT ! \ + $VIDEOCONVERT ! \ + ximagesink + sleep 2 +done diff --git a/scripts/stopmixer.sh b/scripts/stopmixer.sh new file mode 100755 index 0000000..38faa89 --- /dev/null +++ b/scripts/stopmixer.sh @@ -0,0 +1,2 @@ +#!/bin/bash +echo quit | nc localhost 9999 \ No newline at end of file diff --git a/scripts/testvideo.sh b/scripts/testvideo.sh new file mode 100644 index 0000000..e243fd3 --- /dev/null +++ b/scripts/testvideo.sh @@ -0,0 +1 @@ +./video2feed.sh /tmp/feed1 ../videos/LES_TDS_launch.mp4 \ No newline at end of file diff --git a/scripts/video2feed.sh b/scripts/video2feed.sh new file mode 100755 index 0000000..8375577 --- /dev/null +++ b/scripts/video2feed.sh @@ -0,0 +1,26 @@ +#!/bin/bash +# Deliver a video file as input feed + +if [ -z "$1" -o -z "$2" ]; then + echo "Usage $0