diff options
-rwxr-xr-x | voctocore/experiments/failovertest.py | 59 | ||||
-rw-r--r-- | voctocore/experiments/gstreamer-shm-pipe.txt | 13 | ||||
-rwxr-xr-x | voctocore/experiments/intervideo.py | 128 | ||||
-rw-r--r-- | voctocore/experiments/shmsrc.py | 115 | ||||
-rwxr-xr-x | voctocore/experiments/startuptest/startuptest.py | 59 | ||||
-rw-r--r-- | voctocore/experiments/startuptest/testbin.py | 41 | ||||
-rwxr-xr-x | voctocore/experiments/test-audio.sh | 2 | ||||
-rwxr-xr-x | voctocore/experiments/test-av-sync.sh | 24 | ||||
-rwxr-xr-x | voctocore/experiments/test-grabber-src1.sh | 11 | ||||
-rwxr-xr-x | voctocore/experiments/test-grabber-src2.sh | 11 | ||||
-rwxr-xr-x | voctocore/experiments/test-video.sh | 2 | ||||
-rw-r--r-- | voctocore/experiments/testframes/dead-1024x576.rgba | bin | 2359296 -> 0 bytes | |||
-rw-r--r-- | voctocore/experiments/testframes/dead-1920x1080.rgba | bin | 8294400 -> 0 bytes | |||
-rwxr-xr-x | voctocore/experiments/testframes/make_frames | 4 | ||||
-rwxr-xr-x | voctocore/experiments/video-grabber-src.sh | 29 | ||||
-rw-r--r-- | voctocore/experiments/videodisplay.py | 50 |
16 files changed, 156 insertions, 392 deletions
diff --git a/voctocore/experiments/failovertest.py b/voctocore/experiments/failovertest.py deleted file mode 100755 index deb665b..0000000 --- a/voctocore/experiments/failovertest.py +++ /dev/null @@ -1,59 +0,0 @@ -#!/usr/bin/python3 -import gi, time - -# import GStreamer and GTK-Helper classes -gi.require_version('Gst', '1.0') -from gi.repository import GLib, Gst, GObject - -# init GObject before importing local classes -GObject.threads_init() -Gst.init(None) - -from videodisplay import VideomixerWithDisplay -from shmsrc import ShmSrc - -class Example: - def __init__(self): - self.mainloop = GObject.MainLoop() - self.pipeline = Gst.Pipeline() - - self.bus = self.pipeline.get_bus() - self.bus.add_signal_watch() - self.bus.connect('message::eos', self.on_eos) - self.bus.connect('message::error', self.on_error) - - self.addTest('/tmp/v-cam2') - self.addTest('/tmp/v-cam1') - - def addTest(self, socket): - self.mixdisplay = VideomixerWithDisplay() - self.videoconvert = Gst.ElementFactory.make('videoconvert', None) - self.grabbersrc = ShmSrc(socket, Gst.Caps.from_string('video/x-raw,width=1280,height=720,framerate=25/1,format=RGBx')) - - # Add elements to pipeline - self.pipeline.add(self.grabbersrc) - self.pipeline.add(self.videoconvert) - self.pipeline.add(self.mixdisplay) - self.grabbersrc.link(self.videoconvert) - self.videoconvert.link(self.mixdisplay) - - def run(self): - self.pipeline.set_state(Gst.State.PAUSED) - time.sleep(0.5) - self.pipeline.set_state(Gst.State.PLAYING) - self.mainloop.run() - - def kill(self): - self.pipeline.set_state(Gst.State.NULL) - self.mainloop.quit() - - def on_eos(self, bus, msg): - print('on_eos()') - #self.kill() - - def on_error(self, bus, msg): - print('on_error():', msg.parse_error()) - #self.kill() - -example = Example() -example.run() diff --git a/voctocore/experiments/gstreamer-shm-pipe.txt b/voctocore/experiments/gstreamer-shm-pipe.txt deleted file mode 100644 index d4a9767..0000000 --- a/voctocore/experiments/gstreamer-shm-pipe.txt +++ /dev/null @@ -1,13 +0,0 @@ -# works with gstreamer 1.4 - will probably not work with lower versions - -# video/audio-src -gst-launch-1.0 -vm uridecodebin uri=file:///home/peter/avsync.mp4 name=src \ -src. ! video/x-raw,format=I420,width=1280,height=720,framerate=25/1 ! queue ! shmsink sync=true socket-path=/tmp/sock-v wait-for-connection=false shm-size=100000000 \ -src. ! audio/x-raw,format=S16LE,layout=interleaved,rate=44100,channels=2 ! queue ! shmsink sync=true socket-path=/tmp/sock-a wait-for-connection=false shm-size=10000000 - -# video sink -gst-launch-1.0 -vm shmsrc is-live=true do-timestamp=true socket-path=/tmp/sock-v ! video/x-raw,format=I420,width=1280,height=720,framerate=25/1 ! videomixer ! ximagesink - -# audio sink -gst-launch-1.0 -vm shmsrc is-live=true do-timestamp=true socket-path=/tmp/sock-a ! audio/x-raw,format=S16LE,layout=interleaved,rate=44100,channels=2 ! alsasink - diff --git a/voctocore/experiments/intervideo.py b/voctocore/experiments/intervideo.py new file mode 100755 index 0000000..ac5cac1 --- /dev/null +++ b/voctocore/experiments/intervideo.py @@ -0,0 +1,128 @@ +#!/usr/bin/python3 +import gi, time +import socket + +# import GStreamer and GTK-Helper classes +gi.require_version('Gst', '1.0') +from gi.repository import GLib, Gst, GObject + +# init GObject before importing local classes +GObject.threads_init() +Gst.init(None) + +class Example: + def __init__(self): + self.mainloop = GObject.MainLoop() + self.vsink = Gst.parse_launch('intervideosrc channel=video ! video/x-raw,height=600,width=800,format=I420,framerate=25/1 ! timeoverlay ! videoconvert ! ximagesink') + self.vsource = None + + self.asink = Gst.parse_launch('interaudiosrc channel=audio ! audio/x-raw,format=S16LE,layout=interleaved,rate=48000,channels=2 ! autoaudiosink') + self.asource = None + + + # Create the server, binding to localhost on port 5000 + vsock = socket.socket(socket.AF_INET6) + vsock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + vsock.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_V6ONLY, False) + vsock.bind(('::', 5000)) + vsock.listen(1) + + # register socket for callback inside the GTK-Mainloop + GObject.io_add_watch(vsock, GObject.IO_IN, self.connection_handler_video) + + + + # Create the server, binding to localhost on port 6000 + asock = socket.socket(socket.AF_INET6) + asock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + asock.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_V6ONLY, False) + asock.bind(('::', 6000)) + asock.listen(1) + + # register socket for callback inside the GTK-Mainloop + GObject.io_add_watch(asock, GObject.IO_IN, self.connection_handler_audio) + + + + def connection_handler_video(self, sock, *args): + '''Asynchronous connection listener. Starts a handler for each connection.''' + if self.vsource: + return False + + conn, addr = sock.accept() + print("Connection from", addr) + + self.vsource = Gst.parse_launch('appsrc name=a ! gdpdepay ! video/x-raw,height=600,width=800,format=I420,framerate=25/1 ! timeoverlay halignment=right ! intervideosink channel=video') + self.vsource.set_state(Gst.State.PLAYING) + + # register data-received handler inside the GTK-Mainloop + GObject.io_add_watch(conn, GObject.IO_IN, self.data_handler_video) + return True + + def data_handler_video(self, conn, *args): + '''Asynchronous data handler. Processes data-blocks line from the socket.''' + blob = conn.recv(10000000) # >1920x1080x3 + if not len(blob): + print("Connection closed.") + self.vsource.set_state(Gst.State.NULL) + self.vsource = None + return False + + print("Video-Blob of %u bytes" % len(blob)) + buf = Gst.Buffer.new_wrapped(blob) + self.vsource.get_by_name('a').emit('push-buffer', buf) + return True + + + + def connection_handler_audio(self, sock, *args): + '''Asynchronous connection listener. Starts a handler for each connection.''' + if self.asource: + return False + + conn, addr = sock.accept() + print("Connection from", addr) + + self.asource = Gst.parse_launch('appsrc name=a ! gdpdepay ! audio/x-raw,format=S16LE,layout=interleaved,rate=48000,channels=2 ! interaudiosink channel=audio') + self.asource.set_state(Gst.State.PLAYING) + + # register data-received handler inside the GTK-Mainloop + GObject.io_add_watch(conn, GObject.IO_IN, self.data_handler_audio) + return True + + def data_handler_audio(self, conn, *args): + '''Asynchronous data handler. Processes data-blocks line from the socket.''' + blob = conn.recv(10000000) # >1920x1080x3 + if not len(blob): + print("Connection closed.") + self.asource.set_state(Gst.State.NULL) + self.asource = None + return False + + print("Audio-Blob of %u bytes" % len(blob)) + buf = Gst.Buffer.new_wrapped(blob) + self.asource.get_by_name('a').emit('push-buffer', buf) + return True + + + + def run(self): + self.vsink.set_state(Gst.State.PLAYING) + self.asink.set_state(Gst.State.PLAYING) + self.mainloop.run() + + def kill(self): + self.vsink.set_state(Gst.State.NULL) + self.asink.set_state(Gst.State.NULL) + self.mainloop.quit() + + def on_eos(self, bus, msg): + print('on_eos()') + #self.kill() + + def on_error(self, bus, msg): + print('on_error():', msg.parse_error()) + #self.kill() + +example = Example() +example.run() diff --git a/voctocore/experiments/shmsrc.py b/voctocore/experiments/shmsrc.py deleted file mode 100644 index 742767b..0000000 --- a/voctocore/experiments/shmsrc.py +++ /dev/null @@ -1,115 +0,0 @@ -#!/usr/bin/python3 -import time -from gi.repository import GLib, Gst - -class ShmSrc(Gst.Bin): - last_buffer_arrived = 0 - is_in_failstate = True - - def __init__(self, socket, caps): - super().__init__() - - # Create elements - self.shmsrc = Gst.ElementFactory.make('shmsrc', None) - self.identity1 = Gst.ElementFactory.make('identity', None) - self.identity2 = Gst.ElementFactory.make('identity', None) - self.switch = Gst.ElementFactory.make('input-selector', None) - self.failsrc = Gst.ElementFactory.make('videotestsrc', None) - - # Add elements to Bin - self.add(self.shmsrc) - self.add(self.identity1) - self.add(self.identity2) - self.add(self.switch) - self.add(self.failsrc) - - # Get Switcher-Pads - self.goodpad = self.switch.get_request_pad('sink_%u') - self.failpad = self.switch.get_request_pad('sink_%u') - - # Set properties - self.shmsrc.set_property('socket-path', socket) - self.shmsrc.set_property('is-live', True) - self.shmsrc.set_property('do-timestamp', True) - #self.identity1.set_property('sync', True) - self.identity2.set_property('sync', True) - self.switch.set_property('active-pad', self.failpad) - self.failsrc.set_property('pattern', 'snow') - - # Link elements - self.shmsrc.link_filtered(self.identity1, caps) - self.identity1.get_static_pad('src').link(self.goodpad) - - self.failsrc.link_filtered(self.identity2, caps) - self.identity2.get_static_pad('src').link(self.failpad) - - # Install pad probes - self.shmsrc.get_static_pad('src').add_probe(Gst.PadProbeType.BLOCK | Gst.PadProbeType.EVENT_DOWNSTREAM, self.event_probe, None) - self.shmsrc.get_static_pad('src').add_probe(Gst.PadProbeType.BLOCK | Gst.PadProbeType.BUFFER, self.data_probe, None) - - # Install Watchdog - GLib.timeout_add(500, self.watchdog) - - # Add Ghost Pads - self.add_pad( - Gst.GhostPad.new('sink', self.switch.get_static_pad('src')) - ) - - def do_handle_message(self, msg): - if msg.type == Gst.MessageType.ERROR: - print("do_handle_message(): dropping error") - return - - print("do_handle_message()", msg.src, msg.type) - Gst.Bin.do_handle_message(self, msg) - - def event_probe(self, pad, info, ud): - e = info.get_event() - if e.type == Gst.EventType.EOS: - self.switch_to_failstate() - return Gst.PadProbeReturn.DROP - - return Gst.PadProbeReturn.PASS - - - def data_probe(self, pad, info, ud): - self.last_buffer_arrived = time.time() - self.switch_to_goodstate() - return Gst.PadProbeReturn.PASS - - def watchdog(self): - if self.last_buffer_arrived + 0.1 < time.time(): - print("watchdog()::timeout") - self.switch_to_failstate() - - if self.last_buffer_arrived + 3 < time.time() and round(time.time() % 3) == 0: - print("watchdog()::restart") - self.restart() - - return True - - def restart(self): - self.shmsrc.set_state(Gst.State.NULL) - - # this somehow solves parts of the multi-output-timestamping-issue - # starting the 2nd src n seconds after the program started freezes it for n seconds - self.shmsrc.set_start_time(0) - self.shmsrc.set_base_time(self.get_parent().get_base_time()) - - self.shmsrc.set_state(Gst.State.PLAYING) - - def switch_to_goodstate(self): - if not self.is_in_failstate: - return - - print("switch_to_goodstate()") - self.is_in_failstate = False - self.switch.set_property('active-pad', self.goodpad) - - def switch_to_failstate(self): - if self.is_in_failstate: - return - - print("switch_to_failstate()") - self.is_in_failstate = True - self.switch.set_property('active-pad', self.failpad) diff --git a/voctocore/experiments/startuptest/startuptest.py b/voctocore/experiments/startuptest/startuptest.py deleted file mode 100755 index 58e676a..0000000 --- a/voctocore/experiments/startuptest/startuptest.py +++ /dev/null @@ -1,59 +0,0 @@ -#!/usr/bin/python3 - -# Example for the startup-problem -# -# The Pipeline will start but the test-image will be still, as long as no -# ShmSink at /tmp/grabber-v is present (run ../test-grabber-src.sh in another shell) -# -# Even though the ShmSrc is not linked to anything and logically not required for -# the videotestsrc or the ximagesink, the whole pipeline won't startup when this element -# fails to start. -# -# once the pipeline is running, it does not matter what happens to the ShmSink on the -# other end, because the TestBin filters all EOS and ERROR Messages coming from the ShmSrc, -# but somehow this is not enough to make the pipeline start in an error-condition.. -# - -import gi, time - -# import GStreamer and GTK-Helper classes -gi.require_version('Gst', '1.0') -from gi.repository import GLib, Gst, GObject - -# init GObject before importing local classes -GObject.threads_init() -Gst.init(None) - -from testbin import TestBin - -class Example: - def __init__(self): - self.mainloop = GObject.MainLoop() - self.pipeline = Gst.Pipeline() - - self.src = Gst.ElementFactory.make('videotestsrc', None) - self.sink = Gst.ElementFactory.make('ximagesink', None) - - self.testbin = TestBin() - - # Add elements to pipeline - self.pipeline.add(self.testbin) - self.pipeline.add(self.src) - self.pipeline.add(self.sink) - - self.src.link(self.sink) - - def run(self): - print("PAUSED") - self.pipeline.set_state(Gst.State.PAUSED) - time.sleep(0.1) - print("PLAYING") - self.pipeline.set_state(Gst.State.PLAYING) - self.mainloop.run() - - def kill(self): - self.pipeline.set_state(Gst.State.NULL) - self.mainloop.quit() - -example = Example() -example.run() diff --git a/voctocore/experiments/startuptest/testbin.py b/voctocore/experiments/startuptest/testbin.py deleted file mode 100644 index e234b55..0000000 --- a/voctocore/experiments/startuptest/testbin.py +++ /dev/null @@ -1,41 +0,0 @@ -#!/usr/bin/python3 -import time -from gi.repository import GLib, Gst - -class TestBin(Gst.Bin): - def __init__(self): - super().__init__() - self.set_name('testbin') - - # Create elements - self.shmsrc = Gst.ElementFactory.make('shmsrc', None) - - # Add elements to Bin - self.add(self.shmsrc) - - self.shmsrc.set_property('socket-path', '/tmp/grabber-v') - self.shmsrc.set_property('is-live', True) - self.shmsrc.set_property('do-timestamp', True) - - # Install pad probes - self.shmsrc.get_static_pad('src').add_probe(Gst.PadProbeType.BLOCK | Gst.PadProbeType.EVENT_DOWNSTREAM, self.event_probe, None) - self.shmsrc.get_static_pad('src').add_probe(Gst.PadProbeType.BLOCK | Gst.PadProbeType.BUFFER, self.data_probe, None) - - def do_handle_message(self, msg): - if msg.type == Gst.MessageType.ERROR: - print("do_handle_message(): dropping error") - return - - print("do_handle_message()", msg.src, msg.type) - Gst.Bin.do_handle_message(self, msg) - - def event_probe(self, pad, info, ud): - e = info.get_event() - if e.type == Gst.EventType.EOS: - return Gst.PadProbeReturn.DROP - - return Gst.PadProbeReturn.PASS - - def data_probe(self, pad, info, ud): - self.last_buffer_arrived = time.time() - return Gst.PadProbeReturn.PASS diff --git a/voctocore/experiments/test-audio.sh b/voctocore/experiments/test-audio.sh new file mode 100755 index 0000000..bd51bb8 --- /dev/null +++ b/voctocore/experiments/test-audio.sh @@ -0,0 +1,2 @@ +#!/bin/sh +gst-launch-1.0 audiotestsrc ! audio/x-raw,format=S16LE,layout=interleaved,rate=48000,channels=2 ! gdppay ! tcpclientsink host=localhost port=6000 diff --git a/voctocore/experiments/test-av-sync.sh b/voctocore/experiments/test-av-sync.sh new file mode 100755 index 0000000..13851d7 --- /dev/null +++ b/voctocore/experiments/test-av-sync.sh @@ -0,0 +1,24 @@ +#!/bin/sh +gst-launch-1.0 -vm \ + uridecodebin \ + uri=http://c3voc.mazdermind.de/avsync.mp4 \ + name=src \ + \ + src. !\ + queue !\ + videoconvert !\ + videorate !\ + videoscale !\ + video/x-raw,height=600,width=800,format=I420,framerate=25/1 ! \ + timeoverlay valignment=bottom ! \ + gdppay ! \ + tcpclientsink host=localhost port=5000 \ + \ + src. !\ + queue !\ + audioconvert !\ + audioresample !\ + audiorate !\ + audio/x-raw,format=S16LE,layout=interleaved,rate=48000,channels=2 !\ + gdppay !\ + tcpclientsink host=localhost port=6000 diff --git a/voctocore/experiments/test-grabber-src1.sh b/voctocore/experiments/test-grabber-src1.sh deleted file mode 100755 index ea46328..0000000 --- a/voctocore/experiments/test-grabber-src1.sh +++ /dev/null @@ -1,11 +0,0 @@ -#!/bin/sh -gst-launch-1.0 -vm \ - videotestsrc pattern=ball background-color=0xff0000ff !\ - video/x-raw,width=1280,height=720,framerate=25/1,format=RGBx !\ - progressreport update-freq=1 !\ - queue !\ - shmsink \ - sync=true \ - socket-path=/tmp/v-cam1 \ - wait-for-connection=false \ - shm-size=100000000 diff --git a/voctocore/experiments/test-grabber-src2.sh b/voctocore/experiments/test-grabber-src2.sh deleted file mode 100755 index 0315f46..0000000 --- a/voctocore/experiments/test-grabber-src2.sh +++ /dev/null @@ -1,11 +0,0 @@ -#!/bin/sh -gst-launch-1.0 -vm \ - videotestsrc pattern=ball background-color=0x00ff00ff !\ - video/x-raw,width=1280,height=720,framerate=25/1,format=RGBx !\ - progressreport update-freq=1 !\ - queue !\ - shmsink \ - sync=true \ - socket-path=/tmp/v-cam2 \ - wait-for-connection=false \ - shm-size=100000000 diff --git a/voctocore/experiments/test-video.sh b/voctocore/experiments/test-video.sh new file mode 100755 index 0000000..b152b9f --- /dev/null +++ b/voctocore/experiments/test-video.sh @@ -0,0 +1,2 @@ +#!/bin/sh +gst-launch-1.0 videotestsrc ! video/x-raw,height=600,width=800 ! timeoverlay valignment=bottom ! gdppay ! tcpclientsink host=localhost port=5000 diff --git a/voctocore/experiments/testframes/dead-1024x576.rgba b/voctocore/experiments/testframes/dead-1024x576.rgba Binary files differdeleted file mode 100644 index b23e073..0000000 --- a/voctocore/experiments/testframes/dead-1024x576.rgba +++ /dev/null diff --git a/voctocore/experiments/testframes/dead-1920x1080.rgba b/voctocore/experiments/testframes/dead-1920x1080.rgba Binary files differdeleted file mode 100644 index aa06442..0000000 --- a/voctocore/experiments/testframes/dead-1920x1080.rgba +++ /dev/null diff --git a/voctocore/experiments/testframes/make_frames b/voctocore/experiments/testframes/make_frames deleted file mode 100755 index 088e27e..0000000 --- a/voctocore/experiments/testframes/make_frames +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/bash - -gst-launch-1.0 -q videotestsrc num-buffers=1 pattern=smpte100 ! video/x-raw,format=RGBA,width=1024,height=576 ! filesink location = dead-1024x576.rgba -gst-launch-1.0 -q videotestsrc num-buffers=1 pattern=smpte100 ! video/x-raw,format=RGBA,width=1920,height=1080 ! filesink location = dead-1920x1080.rgba diff --git a/voctocore/experiments/video-grabber-src.sh b/voctocore/experiments/video-grabber-src.sh deleted file mode 100755 index e592940..0000000 --- a/voctocore/experiments/video-grabber-src.sh +++ /dev/null @@ -1,29 +0,0 @@ -#!/bin/sh -gst-launch-1.0 \ - uridecodebin \ - uri=http://video.blendertestbuilds.de/download.blender.org/ED/ED_1280.avi \ - name=src \ - \ - src. !\ - queue !\ - progressreport !\ - videoconvert !\ - videorate !\ - videoscale !\ - video/x-raw,format=RGBx,width=1280,height=720,framerate=25/1 !\ - shmsink \ - sync=true \ - socket-path=/tmp/voctomix-sockets/v-cam1 \ - wait-for-connection=false \ - shm-size=100000000 - \ - src. !\ - queue !\ - audioconvert !\ - audiorate !\ - audio/x-raw,format=S16LE,layout=interleaved,rate=44100,channels=2 !\ - shmsink \ - sync=true \ - socket-path=/tmp/voctomix-sockets/a-cam1 \ - wait-for-connection=false \ - shm-size=10000000 diff --git a/voctocore/experiments/videodisplay.py b/voctocore/experiments/videodisplay.py deleted file mode 100644 index 17ef653..0000000 --- a/voctocore/experiments/videodisplay.py +++ /dev/null @@ -1,50 +0,0 @@ -#!/usr/bin/python3 -from gi.repository import GObject, Gst - -class VideomixerWithDisplay(Gst.Bin): - def __init__(self): - super().__init__() - - # Create elements - self.secondsrc = Gst.ElementFactory.make('videotestsrc', None) - self.mixer = Gst.ElementFactory.make('compositor', None) - self.ident = Gst.ElementFactory.make('identity', None) - self.q1 = Gst.ElementFactory.make('queue', None) - self.q2 = Gst.ElementFactory.make('queue', None) - self.display = Gst.ElementFactory.make('ximagesink', None) - - # Add elements to Bin - self.add(self.secondsrc) - self.add(self.mixer) - self.add(self.ident) - self.add(self.display) - self.add(self.q1) - self.add(self.q2) - - # Set properties - self.secondsrc.set_property('pattern', 'ball') - self.ident.set_property('sync', True) - self.display.set_property('sync', False) - - # Request Pads - self.firstpad = self.mixer.get_request_pad('sink_%u') - self.secondpad = self.mixer.get_request_pad('sink_%u') - - # Set pad-properties - self.secondpad.set_property('alpha', 0.75) - self.secondpad.set_property('xpos', 50) - self.secondpad.set_property('ypos', 50) - - # Link elements - self.q1.get_static_pad('src').link(self.firstpad) - - self.q2.get_static_pad('src').link(self.secondpad) - self.secondsrc.link_filtered(self.ident, Gst.Caps.from_string('video/x-raw,width=400,height=400,framerate=25/1,format=RGBx')) - self.ident.link(self.q2) - - self.mixer.link(self.display) - - # Add Ghost Pads - self.add_pad( - Gst.GhostPad.new('sink', self.q1.get_static_pad('sink')) - ) |