Skip to content

Commit e852ce3

Browse files
authored
Merge pull request #11 from cansik/data-sharing
Added data-sharing methods and examples
2 parents 136fbe2 + 21cdb93 commit e852ce3

34 files changed

+1571
-651
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ VS2019/Release
1111
VS2019/x64
1212
VS2019/Win32
1313
src/SpoutGL/*.dll
14+
.idea
1415

1516
# Byte-compiled / optimized / DLL files
1617
__pycache__/

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ SpoutGL for Python
44
An unofficial Python wrapper for [Spout](https://leadedge.github.io/) using [pybind11](https://github.com/pybind/pybind11)
55

66
Key features compared to some previous wrappers:
7-
- Covers more of the SpoutGL API, including sendImage/receiveImage and setFrameSync/waitFrameSync
7+
- Covers more of the SpoutGL API, including sendImage/receiveImage, setFrameSync/waitFrameSync and data sharing
88
- pybind11 instead of Boost Python which should make it easier to build for multiple Python versions
99
- pip/wheel support for Python 3.7+ on both 64-bit and 32-bit Windows
1010
- No external dependencies

examples/data/receiver.py

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
import numpy as np
2+
3+
import SpoutGL
4+
from OpenGL import GL
5+
from itertools import repeat
6+
import array
7+
8+
SENDER_NAME = "SpoutGL-test"
9+
10+
with SpoutGL.SpoutReceiver() as receiver:
11+
receiver.setReceiverName(SENDER_NAME)
12+
13+
buffer = None
14+
shared_memory = None
15+
16+
while True:
17+
result = receiver.receiveImage(buffer, GL.GL_RGBA, False, 0)
18+
19+
if receiver.isUpdated():
20+
width = receiver.getSenderWidth()
21+
height = receiver.getSenderHeight()
22+
buffer = array.array('B', repeat(0, width * height * 4))
23+
24+
if buffer and result and not SpoutGL.helpers.isBufferEmpty(buffer):
25+
print("Got bytes", bytes(buffer[0:64]), "...")
26+
27+
# Wait until the next frame is ready
28+
# Wait time is in milliseconds; note that 0 will return immediately
29+
receiver.waitFrameSync(SENDER_NAME, 10000)
30+
print("sync received")
31+
32+
if shared_memory is None:
33+
memory_length = receiver.getMemoryBufferSize(SENDER_NAME)
34+
shared_memory = array.array('B', repeat(0, memory_length))
35+
36+
result = receiver.readMemoryBuffer(SENDER_NAME, shared_memory, len(shared_memory))
37+
if result:
38+
message = bytes(shared_memory).decode().split("\x00")[0]
39+
print(message)

examples/data/sender.py

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import SpoutGL
2+
from itertools import islice, cycle
3+
import time
4+
from OpenGL import GL
5+
from random import randint
6+
7+
TARGET_FPS = 1
8+
SEND_WIDTH = 256
9+
SEND_HEIGHT = 256
10+
SENDER_NAME = "SpoutGL-test"
11+
12+
def randcolor():
13+
return randint(0, 255)
14+
15+
with SpoutGL.SpoutSender() as sender:
16+
sender.setSenderName(SENDER_NAME)
17+
18+
# create shared memory buffer
19+
sender.createMemoryBuffer(SENDER_NAME, 256)
20+
21+
while True:
22+
# Generating bytes in Python is very slow; ideally you should pass in a buffer obtained elsewhere
23+
# or re-use an already allocated array instead of allocating one on the fly
24+
pixels = bytes(islice(cycle([randcolor(), randcolor(), randcolor(), 255]), SEND_WIDTH * SEND_HEIGHT * 3))
25+
26+
result = sender.sendImage(pixels, SEND_WIDTH, SEND_HEIGHT, GL.GL_RGB, False, 0)
27+
print("Send result", result)
28+
29+
# add data to buffer
30+
data = "hello world".encode()
31+
sender.writeMemoryBuffer(SENDER_NAME, data, len(data))
32+
33+
# Indicate that a frame is ready to read
34+
sender.setFrameSync(SENDER_NAME)
35+
36+
# Wait for next send attempt
37+
time.sleep(1./TARGET_FPS)
38+
39+
# cleanup shared buffer
40+
sender.deleteMemoryBuffer(SENDER_NAME)

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010

1111
import sys
1212

13-
__version__ = "0.0.2"
13+
__version__ = "0.0.3"
1414

1515
is_64bits = sys.maxsize > 2**32
1616

src/PySpoutGL.cpp

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,12 @@ PYBIND11_MODULE(_spoutgl, m) {
117117
.def("waitFrameSync", &SpoutSender::WaitFrameSync, py::call_guard<py::gil_scoped_release>())
118118
.def("getCPU", &SpoutSender::GetCPU)
119119
.def("getGLDX", &SpoutSender::GetGLDX)
120+
121+
// data sharing
122+
.def("createMemoryBuffer", &SpoutSender::CreateMemoryBuffer)
123+
.def("writeMemoryBuffer", &SpoutSender::WriteMemoryBuffer)
124+
.def("deleteMemoryBuffer", &SpoutSender::DeleteMemoryBuffer)
125+
.def("getMemoryBufferSize", &SpoutSender::GetMemoryBufferSize)
120126
);
121127

122128
addCommonDefs(py::class_<SpoutReceiver>(m, "SpoutReceiver")
@@ -169,6 +175,27 @@ PYBIND11_MODULE(_spoutgl, m) {
169175
.def("getSenderFrame", &SpoutReceiver::GetSenderFrame)
170176
.def("setFrameSync", &SpoutReceiver::SetFrameSync)
171177
.def("waitFrameSync", &SpoutReceiver::WaitFrameSync, py::arg("senderName"), py::arg("timeout") = 0, py::call_guard<py::gil_scoped_release>())
178+
179+
// data-sharing
180+
.def("readMemoryBuffer", [](SpoutReceiver& receiver, const char *name, std::optional<py::buffer> buffer, int length) {
181+
if (!buffer.has_value()) {
182+
// Buffer cannot be None
183+
throw pybind11::type_error("Must provide a buffer");
184+
}
185+
186+
py::buffer_info bufferInfo(buffer->request());
187+
188+
if (bufferInfo.size * bufferInfo.itemsize < length) {
189+
throw pybind11::buffer_error("Buffer not large enough");
190+
}
191+
192+
if (!PyBuffer_IsContiguous(bufferInfo.view(), 'C')) {
193+
throw pybind11::buffer_error("Buffer must be contiguous");
194+
}
195+
196+
return receiver.ReadMemoryBuffer(name, static_cast<char*>(bufferInfo.ptr), length);
197+
})
198+
.def("getMemoryBufferSize", &SpoutReceiver::GetMemoryBufferSize)
172199
);
173200

174201
auto enums = m.def_submodule("enums", "Re-export of supported OpenGL format enums as integers");
9.5 KB
Binary file not shown.
3.33 KB
Binary file not shown.

vendor/SpoutGL/Binaries/x64/Spout.dll

12 KB
Binary file not shown.

vendor/SpoutGL/Binaries/x64/Spout.lib

3.44 KB
Binary file not shown.

vendor/SpoutGL/Binaries/x64/Spout.pdb

-32 KB
Binary file not shown.

0 commit comments

Comments
 (0)