From 43a3a967f3c5d32829b27111e8bc23183cbb14b3 Mon Sep 17 00:00:00 2001 From: maybites Date: Sun, 18 Dec 2022 21:17:16 +0100 Subject: [PATCH] added syphon support - sadly with a bad performance --- __init__.py | 2 +- fbs/FrameBufferSharingServer.py | 36 +++++++++++++++++++++++ fbs/__init__.py | 0 fbs/spout/SpoutServer.py | 52 +++++++++++++++++++++++++++++++++ fbs/spout/__init__.py | 0 fbs/syphon/SyphonServer.py | 33 +++++++++++++++++++++ fbs/syphon/__init__.py | 0 operators.py | 35 ++++++++++++---------- pip_importer.py | 3 +- 9 files changed, 144 insertions(+), 17 deletions(-) create mode 100644 fbs/FrameBufferSharingServer.py create mode 100644 fbs/__init__.py create mode 100644 fbs/spout/SpoutServer.py create mode 100644 fbs/spout/__init__.py create mode 100644 fbs/syphon/SyphonServer.py create mode 100644 fbs/syphon/__init__.py diff --git a/__init__.py b/__init__.py index c21b2cb..2ddca91 100644 --- a/__init__.py +++ b/__init__.py @@ -53,7 +53,7 @@ def register(): ui.register() except ModuleNotFoundError: print( - "Spout addon isn't available, install required module via Properties > Addons > Spout" + "Addon isn't available, install required module via Properties > Addons > Spout" ) diff --git a/fbs/FrameBufferSharingServer.py b/fbs/FrameBufferSharingServer.py new file mode 100644 index 0000000..1f1bb7d --- /dev/null +++ b/fbs/FrameBufferSharingServer.py @@ -0,0 +1,36 @@ +from abc import ABC, abstractmethod +from sys import platform +from typing import Optional, Any + +import numpy as np + +class FrameBufferSharingServer(ABC): + def __init__(self, name: str): + self.name = name + + @abstractmethod + def send_texture(self, texture_id: int, width: int, height: int, is_flipped: bool = False): + pass + + @abstractmethod + def can_memory_buffer(self): + pass + + @abstractmethod + def create_memory_buffer(self, texture_name: str, size: int): + pass + + @abstractmethod + def write_memory_buffer(self, texture_name: str, buffer): + pass + + @staticmethod + def create(name: str): + if platform.startswith("darwin"): + from spyphon.fbs.syphon.SyphonServer import SyphonServer + return SyphonServer(name) + elif platform.startswith("win"): + from spyphon.fbs.spout.SpoutServer import SpoutServer + return SpoutServer(name) + else: + raise Exception(f"Platform {platform} is not supported!") diff --git a/fbs/__init__.py b/fbs/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/fbs/spout/SpoutServer.py b/fbs/spout/SpoutServer.py new file mode 100644 index 0000000..507e0e4 --- /dev/null +++ b/fbs/spout/SpoutServer.py @@ -0,0 +1,52 @@ +import logging +from argparse import ArgumentParser, Namespace +from typing import Optional + +import SpoutGL +import numpy as np +import bgl + +from spyphon.fbs.FrameBufferSharingServer import FrameBufferSharingServer + + +class SpoutServer(FrameBufferSharingServer): + def __init__(self, name: str = "SpoutServer"): + super().__init__(name) + self.ctx: Optional[SpoutGL.SpoutSender] = None + + def setup(self): + # setup spout + self.ctx = SpoutGL.SpoutSender() + self.ctx.setSenderName(self.name) + + def send_texture(self, texture_id: int, width: int, height: int, is_flipped: bool = False): + success = self.ctx.sendTexture( + texture_id, bgl.GL_TEXTURE_2D, width, height, is_flipped, 0) + + if not success: + logging.warning("Could not send spout texture.") + return + + self.ctx.setFrameSync(self.name) + + def can_memory_buffer(self): + return True + + def create_memory_buffer(self, texture_name: str, size: int): + success = self.ctx.createMemoryBuffer(texture_name, size) + + if not success: + logging.warning("Could not create memory buffer.") + + return + + def write_memory_buffer(self, texture_name: str, buffer): + success = self.ctx.writeMemoryBuffer(texture_name, buffer, len(buffer)) + + if not success: + logging.warning("Could not write memory buffer.") + + return + + def release(self): + self.ctx.releaseSender() diff --git a/fbs/spout/__init__.py b/fbs/spout/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/fbs/syphon/SyphonServer.py b/fbs/syphon/SyphonServer.py new file mode 100644 index 0000000..f374d76 --- /dev/null +++ b/fbs/syphon/SyphonServer.py @@ -0,0 +1,33 @@ +from argparse import Namespace, ArgumentParser +from typing import Optional, Any + +import numpy as np +import syphonpy + +import logging + +from spyphon.fbs.FrameBufferSharingServer import FrameBufferSharingServer + + +class SyphonServer(FrameBufferSharingServer): + def __init__(self, name: str = "SyphonServer"): + super().__init__(name) + + self.ctx: Optional[syphonpy.SyphonServer] = None + + def setup(self): + # setup spout + self.ctx = syphonpy.SyphonServer(self.name) + if self.ctx.error_state(): + logging.error("error in Syphonserver") + + def send_texture(self, texture_id: int, width: int, height: int, is_flipped: bool = False): + self.ctx.publish_frame_texture(texture_id, + syphonpy.MakeRect(0, 0, width, height), + syphonpy.MakeSize(width, height), is_flipped) + + def can_memory_buffer(self): + return False + + def release(self): + self.ctx.stop() diff --git a/fbs/syphon/__init__.py b/fbs/syphon/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/operators.py b/operators.py index 7d88ce7..ebd6e38 100644 --- a/operators.py +++ b/operators.py @@ -6,10 +6,12 @@ import json from dataclasses import dataclass + try: - import SpoutGL + + from spout.fbs.FrameBufferSharingServer import FrameBufferSharingServer except ModuleNotFoundError as ex: - print(f"Could not load SpoutGL: {ex}") + print(f"Could not load FrameSharingModule: {ex}") import uuid @@ -48,7 +50,7 @@ def handler(scene, depsgraph): # function for the draw handler to capture the texture from the perspective of the camera -def texshare_capture(self, context, camera, object, space, region, scene, layer, offscreen, spoutSender, showPreview, frame_metadata_buffer): +def texshare_capture(self, context, camera, object, space, region, scene, layer, offscreen, spyphonSender, showPreview, frame_metadata_buffer): dWIDTH = camera.texshare.capture_width dHEIGHT = camera.texshare.capture_height applyCM = camera.texshare.applyColorManagmentSettings @@ -75,12 +77,12 @@ def texshare_capture(self, context, camera, object, space, region, scene, layer, buffer = frame_metadata_buffer.content - spoutSender.writeMemoryBuffer(camera.name, buffer, len(buffer)) + #if spyphonSender.can_memory_buffer() == True: + # spyphonSender.write_memory_buffer(camera.name, buffer, len(buffer)) - spoutSender.sendTexture(offscreen.color_texture, bgl.GL_TEXTURE_2D, dWIDTH, dHEIGHT, True, 0) - spoutSender.setFrameSync(camera.name) - - + spyphonSender.send_texture(offscreen.color_texture, dWIDTH, dHEIGHT, True) + + # main function called when the settings 'enable' property is changed def texshare_main(self, context): global db_drawHandle @@ -95,15 +97,18 @@ def texshare_main(self, context): if context.camera.texshare.enable == 1 and dbID not in db_drawHandle: # first we create a unique identifier for the reference db dicts dbID = str(uuid.uuid1()) + updateDraw = False dWIDTH = guivars.capture_width dHEIGHT = guivars.capture_height # create a new spout sender instance - spoutSender = SpoutGL.SpoutSender() - spoutSender.setSenderName(context.camera.name) - - spoutSender.createMemoryBuffer(context.camera.name, 1024) + spyphonSender = FrameBufferSharingServer.create(context.camera.name) + spyphonSender.setup() + + #if spyphonSender.can_memory_buffer() == True: + ## spyphonSender.create_memory_buffer(context.camera.name, 1024) + # create a off screen renderer offscreen = gpu.types.GPUOffScreen(dWIDTH, dHEIGHT) @@ -133,7 +138,7 @@ def texshare_main(self, context): frame_metadata_buffer = FrameMetDataBuffer("test") # collect all the arguments to pass to the draw handler - args = (self, context, context.camera, context.object, mySpace, myRegion, myScene, myLayer, offscreen, spoutSender, guivars.preview, frame_metadata_buffer) + args = (self, context, context.camera, context.object, mySpace, myRegion, myScene, myLayer, offscreen, spyphonSender, guivars.preview, frame_metadata_buffer) frameHandler = frame_metadata(context.camera.name, frame_metadata_buffer) bpy.app.handlers.depsgraph_update_post.append(frameHandler) @@ -145,13 +150,13 @@ def texshare_main(self, context): # store the references inside the db-dicts db_frameHandle[dbID] = frameHandler db_drawHandle[dbID] = drawhandle - db_spoutInstances[dbID] = spoutSender + db_spoutInstances[dbID] = spyphonSender # if streaming has been disabled and my ID is still stored in the db if context.camera.texshare.enable == 0 and dbID in db_drawHandle: bpy.app.handlers.depsgraph_update_post.remove(db_frameHandle[dbID]) bpy.types.SpaceView3D.draw_handler_remove(db_drawHandle[dbID], 'WINDOW') - db_spoutInstances[dbID].releaseSender() + db_spoutInstances[dbID].release() #removing my ID db_drawHandle.pop(dbID, None) dbID == "off" diff --git a/pip_importer.py b/pip_importer.py index 51f1ffd..f9affeb 100644 --- a/pip_importer.py +++ b/pip_importer.py @@ -178,7 +178,8 @@ def draw(self, context): if package._registered: row.label(text="Registered", icon="CHECKMARK") module = sys.modules[package.module] - row.label(text="Path: " + module.__path__[0]) + if hasattr(module, '__path__'): + row.label(text="Path: " + module.__path__[0]) row.operator( Pip_Refresh_package.bl_idname, text="refresh",