rocket-welder-sdk 1.0.4__py3-none-any.whl → 1.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- rocket_welder_sdk/__init__.py +30 -4
- rocket_welder_sdk/bytes_size.py +234 -0
- rocket_welder_sdk/connection_string.py +232 -0
- rocket_welder_sdk/controllers.py +609 -0
- rocket_welder_sdk/gst_metadata.py +240 -0
- rocket_welder_sdk/py.typed +2 -0
- rocket_welder_sdk/rocket_welder_client.py +170 -0
- rocket_welder_sdk-1.1.0.dist-info/METADATA +496 -0
- rocket_welder_sdk-1.1.0.dist-info/RECORD +11 -0
- rocket_welder_sdk/client.py +0 -183
- rocket_welder_sdk/rocket_welder_sdk/__init__.py +0 -20
- rocket_welder_sdk/rocket_welder_sdk/client.py +0 -326
- rocket_welder_sdk/rocket_welder_sdk/connection_string.py +0 -190
- rocket_welder_sdk/rocket_welder_sdk/exceptions.py +0 -23
- rocket_welder_sdk/rocket_welder_sdk/gst_caps.py +0 -224
- rocket_welder_sdk/rocket_welder_sdk/gst_metadata.py +0 -43
- rocket_welder_sdk-1.0.4.dist-info/METADATA +0 -36
- rocket_welder_sdk-1.0.4.dist-info/RECORD +0 -12
- {rocket_welder_sdk-1.0.4.dist-info → rocket_welder_sdk-1.1.0.dist-info}/WHEEL +0 -0
- {rocket_welder_sdk-1.0.4.dist-info → rocket_welder_sdk-1.1.0.dist-info}/top_level.txt +0 -0
|
@@ -1,224 +0,0 @@
|
|
|
1
|
-
"""
|
|
2
|
-
GStreamer caps parsing for video format information
|
|
3
|
-
|
|
4
|
-
Mirrors the C# implementation with Python idioms.
|
|
5
|
-
"""
|
|
6
|
-
|
|
7
|
-
from dataclasses import dataclass
|
|
8
|
-
from typing import Optional, Tuple
|
|
9
|
-
import re
|
|
10
|
-
import numpy as np
|
|
11
|
-
import cv2
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
@dataclass(frozen=True)
|
|
15
|
-
class GstCaps:
|
|
16
|
-
"""
|
|
17
|
-
Readonly GStreamer caps configuration
|
|
18
|
-
|
|
19
|
-
Mirrors C# readonly record struct with IParsable interface.
|
|
20
|
-
"""
|
|
21
|
-
width: int
|
|
22
|
-
height: int
|
|
23
|
-
format: str
|
|
24
|
-
framerate: Optional[Tuple[int, int]] = None
|
|
25
|
-
|
|
26
|
-
@classmethod
|
|
27
|
-
def parse(cls, s: str, provider=None) -> 'GstCaps':
|
|
28
|
-
"""
|
|
29
|
-
Parse GStreamer caps string (equivalent to IParsable<T>.Parse in C#)
|
|
30
|
-
|
|
31
|
-
Args:
|
|
32
|
-
s: Caps string like "video/x-raw,format=RGB,width=640,height=480,framerate=30/1"
|
|
33
|
-
provider: Not used, kept for API compatibility with C#
|
|
34
|
-
|
|
35
|
-
Returns:
|
|
36
|
-
GstCaps instance
|
|
37
|
-
|
|
38
|
-
Raises:
|
|
39
|
-
ValueError: If caps format is invalid
|
|
40
|
-
"""
|
|
41
|
-
if not s:
|
|
42
|
-
raise ValueError("Caps string cannot be empty")
|
|
43
|
-
|
|
44
|
-
# Remove video/x-raw prefix if present
|
|
45
|
-
if s.startswith("video/x-raw"):
|
|
46
|
-
s = s[len("video/x-raw"):].lstrip(",")
|
|
47
|
-
|
|
48
|
-
# Parse key=value pairs
|
|
49
|
-
params = {}
|
|
50
|
-
for part in s.split(","):
|
|
51
|
-
if "=" in part:
|
|
52
|
-
key, value = part.split("=", 1)
|
|
53
|
-
params[key.strip()] = value.strip()
|
|
54
|
-
|
|
55
|
-
# Extract required fields
|
|
56
|
-
if "width" not in params:
|
|
57
|
-
raise ValueError("Missing 'width' in caps")
|
|
58
|
-
if "height" not in params:
|
|
59
|
-
raise ValueError("Missing 'height' in caps")
|
|
60
|
-
|
|
61
|
-
# Handle GStreamer type annotations like "(int)640"
|
|
62
|
-
width_str = params["width"]
|
|
63
|
-
if width_str.startswith("(int)"):
|
|
64
|
-
width_str = width_str[5:]
|
|
65
|
-
width = int(width_str)
|
|
66
|
-
|
|
67
|
-
height_str = params["height"]
|
|
68
|
-
if height_str.startswith("(int)"):
|
|
69
|
-
height_str = height_str[5:]
|
|
70
|
-
height = int(height_str)
|
|
71
|
-
format_str = params.get("format", "RGB")
|
|
72
|
-
|
|
73
|
-
# Parse framerate if present
|
|
74
|
-
framerate = None
|
|
75
|
-
if "framerate" in params:
|
|
76
|
-
framerate_str = params["framerate"]
|
|
77
|
-
# Handle GStreamer type annotations like "(fraction)30/1"
|
|
78
|
-
if framerate_str.startswith("(fraction)"):
|
|
79
|
-
framerate_str = framerate_str[10:]
|
|
80
|
-
fr_match = re.match(r"(\d+)/(\d+)", framerate_str)
|
|
81
|
-
if fr_match:
|
|
82
|
-
framerate = (int(fr_match.group(1)), int(fr_match.group(2)))
|
|
83
|
-
|
|
84
|
-
return cls(
|
|
85
|
-
width=width,
|
|
86
|
-
height=height,
|
|
87
|
-
format=format_str,
|
|
88
|
-
framerate=framerate
|
|
89
|
-
)
|
|
90
|
-
|
|
91
|
-
@classmethod
|
|
92
|
-
def try_parse(cls, s: str, provider=None) -> tuple[bool, Optional['GstCaps']]:
|
|
93
|
-
"""
|
|
94
|
-
Try to parse caps string (equivalent to IParsable<T>.TryParse in C#)
|
|
95
|
-
|
|
96
|
-
Args:
|
|
97
|
-
s: Caps string to parse
|
|
98
|
-
provider: Not used, kept for API compatibility
|
|
99
|
-
|
|
100
|
-
Returns:
|
|
101
|
-
Tuple of (success, GstCaps or None)
|
|
102
|
-
"""
|
|
103
|
-
try:
|
|
104
|
-
result = cls.parse(s, provider)
|
|
105
|
-
return True, result
|
|
106
|
-
except (ValueError, KeyError):
|
|
107
|
-
return False, None
|
|
108
|
-
|
|
109
|
-
@classmethod
|
|
110
|
-
def from_simple(cls, width: int, height: int, format_str: str = "RGB") -> 'GstCaps':
|
|
111
|
-
"""
|
|
112
|
-
Create from simple parameters
|
|
113
|
-
|
|
114
|
-
Args:
|
|
115
|
-
width: Frame width
|
|
116
|
-
height: Frame height
|
|
117
|
-
format_str: Pixel format (RGB, BGR, GRAY8, etc.)
|
|
118
|
-
|
|
119
|
-
Returns:
|
|
120
|
-
GstCaps instance
|
|
121
|
-
"""
|
|
122
|
-
return cls(width=width, height=height, format=format_str)
|
|
123
|
-
|
|
124
|
-
def get_opencv_dtype(self) -> int:
|
|
125
|
-
"""
|
|
126
|
-
Get OpenCV data type for the format
|
|
127
|
-
|
|
128
|
-
Returns:
|
|
129
|
-
OpenCV dtype constant
|
|
130
|
-
"""
|
|
131
|
-
# Map GStreamer formats to OpenCV types
|
|
132
|
-
format_map = {
|
|
133
|
-
"RGB": cv2.CV_8UC3,
|
|
134
|
-
"BGR": cv2.CV_8UC3,
|
|
135
|
-
"RGBA": cv2.CV_8UC4,
|
|
136
|
-
"BGRA": cv2.CV_8UC4,
|
|
137
|
-
"GRAY8": cv2.CV_8UC1,
|
|
138
|
-
"GRAY16_LE": cv2.CV_16UC1,
|
|
139
|
-
"GRAY16_BE": cv2.CV_16UC1,
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
return format_map.get(self.format, cv2.CV_8UC3)
|
|
143
|
-
|
|
144
|
-
def get_channels(self) -> int:
|
|
145
|
-
"""
|
|
146
|
-
Get number of channels for the format
|
|
147
|
-
|
|
148
|
-
Returns:
|
|
149
|
-
Number of channels
|
|
150
|
-
"""
|
|
151
|
-
if self.format in ["RGB", "BGR"]:
|
|
152
|
-
return 3
|
|
153
|
-
elif self.format in ["RGBA", "BGRA"]:
|
|
154
|
-
return 4
|
|
155
|
-
elif self.format.startswith("GRAY"):
|
|
156
|
-
return 1
|
|
157
|
-
else:
|
|
158
|
-
return 3 # Default to 3 channels
|
|
159
|
-
|
|
160
|
-
def get_numpy_dtype(self) -> np.dtype:
|
|
161
|
-
"""
|
|
162
|
-
Get NumPy data type for the format
|
|
163
|
-
|
|
164
|
-
Returns:
|
|
165
|
-
NumPy dtype
|
|
166
|
-
"""
|
|
167
|
-
if "16" in self.format:
|
|
168
|
-
return np.dtype(np.uint16)
|
|
169
|
-
else:
|
|
170
|
-
return np.dtype(np.uint8)
|
|
171
|
-
|
|
172
|
-
def create_mat(self, data_ptr: memoryview) -> np.ndarray:
|
|
173
|
-
"""
|
|
174
|
-
Create OpenCV Mat from data pointer without copying (zero-copy)
|
|
175
|
-
|
|
176
|
-
Args:
|
|
177
|
-
data_ptr: Memory view of the frame data
|
|
178
|
-
|
|
179
|
-
Returns:
|
|
180
|
-
NumPy array that wraps the data (no copy)
|
|
181
|
-
"""
|
|
182
|
-
# Calculate expected size
|
|
183
|
-
channels = self.get_channels()
|
|
184
|
-
dtype = self.get_numpy_dtype()
|
|
185
|
-
expected_size = self.width * self.height * channels * dtype.itemsize
|
|
186
|
-
|
|
187
|
-
# Create numpy array from memoryview (zero-copy)
|
|
188
|
-
# The memoryview directly points to shared memory
|
|
189
|
-
flat_array = np.frombuffer(data_ptr, dtype=dtype, count=self.width * self.height * channels)
|
|
190
|
-
|
|
191
|
-
# Reshape to image dimensions
|
|
192
|
-
if channels == 1:
|
|
193
|
-
return flat_array.reshape((self.height, self.width))
|
|
194
|
-
else:
|
|
195
|
-
return flat_array.reshape((self.height, self.width, channels))
|
|
196
|
-
|
|
197
|
-
def create_mat_from_buffer(self, buffer: bytes) -> np.ndarray:
|
|
198
|
-
"""
|
|
199
|
-
Create OpenCV Mat from byte buffer (makes a copy)
|
|
200
|
-
|
|
201
|
-
Args:
|
|
202
|
-
buffer: Byte buffer containing frame data
|
|
203
|
-
|
|
204
|
-
Returns:
|
|
205
|
-
NumPy array (copy of data)
|
|
206
|
-
"""
|
|
207
|
-
channels = self.get_channels()
|
|
208
|
-
dtype = self.get_numpy_dtype()
|
|
209
|
-
|
|
210
|
-
# Create numpy array from bytes
|
|
211
|
-
flat_array = np.frombuffer(buffer, dtype=dtype)
|
|
212
|
-
|
|
213
|
-
# Reshape to image dimensions
|
|
214
|
-
if channels == 1:
|
|
215
|
-
return flat_array.reshape((self.height, self.width))
|
|
216
|
-
else:
|
|
217
|
-
return flat_array.reshape((self.height, self.width, channels))
|
|
218
|
-
|
|
219
|
-
def __str__(self) -> str:
|
|
220
|
-
"""String representation as GStreamer caps"""
|
|
221
|
-
caps = f"video/x-raw,format={self.format},width={self.width},height={self.height}"
|
|
222
|
-
if self.framerate:
|
|
223
|
-
caps += f",framerate={self.framerate[0]}/{self.framerate[1]}"
|
|
224
|
-
return caps
|
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
"""GStreamer metadata structure matching the JSON written by GStreamer plugins"""
|
|
2
|
-
|
|
3
|
-
from dataclasses import dataclass
|
|
4
|
-
from typing import Optional
|
|
5
|
-
import json
|
|
6
|
-
|
|
7
|
-
from .gst_caps import GstCaps
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
@dataclass
|
|
11
|
-
class GstMetadata:
|
|
12
|
-
"""Metadata structure that matches the JSON written by GStreamer plugins"""
|
|
13
|
-
|
|
14
|
-
type: str
|
|
15
|
-
version: str
|
|
16
|
-
caps: GstCaps
|
|
17
|
-
element_name: str
|
|
18
|
-
|
|
19
|
-
@classmethod
|
|
20
|
-
def from_json(cls, json_str: str) -> 'GstMetadata':
|
|
21
|
-
"""Deserialize from JSON string"""
|
|
22
|
-
data = json.loads(json_str)
|
|
23
|
-
|
|
24
|
-
# Parse caps string to GstCaps
|
|
25
|
-
caps = GstCaps.parse(data['caps'])
|
|
26
|
-
|
|
27
|
-
return cls(
|
|
28
|
-
type=data['type'],
|
|
29
|
-
version=data['version'],
|
|
30
|
-
caps=caps,
|
|
31
|
-
element_name=data['element_name']
|
|
32
|
-
)
|
|
33
|
-
|
|
34
|
-
def to_json(self) -> str:
|
|
35
|
-
"""Serialize to JSON string"""
|
|
36
|
-
# Convert GstCaps back to string for JSON
|
|
37
|
-
data = {
|
|
38
|
-
'type': self.type,
|
|
39
|
-
'version': self.version,
|
|
40
|
-
'caps': self.caps.caps_string if self.caps.caps_string else str(self.caps),
|
|
41
|
-
'element_name': self.element_name
|
|
42
|
-
}
|
|
43
|
-
return json.dumps(data)
|
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
Metadata-Version: 2.4
|
|
2
|
-
Name: rocket-welder-sdk
|
|
3
|
-
Version: 1.0.4
|
|
4
|
-
Summary: High-performance video streaming client library for RocketWelder services
|
|
5
|
-
Home-page: https://github.com/modelingevolution/rocket-welder-sdk
|
|
6
|
-
Author: ModelingEvolution
|
|
7
|
-
Classifier: Development Status :: 3 - Alpha
|
|
8
|
-
Classifier: Intended Audience :: Developers
|
|
9
|
-
Classifier: Topic :: Multimedia :: Video
|
|
10
|
-
Classifier: License :: OSI Approved :: MIT License
|
|
11
|
-
Classifier: Programming Language :: Python :: 3
|
|
12
|
-
Classifier: Programming Language :: Python :: 3.8
|
|
13
|
-
Classifier: Programming Language :: Python :: 3.9
|
|
14
|
-
Classifier: Programming Language :: Python :: 3.10
|
|
15
|
-
Classifier: Programming Language :: Python :: 3.11
|
|
16
|
-
Classifier: Programming Language :: Python :: 3.12
|
|
17
|
-
Requires-Python: >=3.8
|
|
18
|
-
Description-Content-Type: text/markdown
|
|
19
|
-
Requires-Dist: numpy>=1.20.0
|
|
20
|
-
Requires-Dist: opencv-python>=4.5.0
|
|
21
|
-
Requires-Dist: zerobuffer-ipc>=1.1.0
|
|
22
|
-
Provides-Extra: dev
|
|
23
|
-
Requires-Dist: pytest>=7.0; extra == "dev"
|
|
24
|
-
Requires-Dist: black>=22.0; extra == "dev"
|
|
25
|
-
Requires-Dist: mypy>=1.0; extra == "dev"
|
|
26
|
-
Dynamic: author
|
|
27
|
-
Dynamic: classifier
|
|
28
|
-
Dynamic: description
|
|
29
|
-
Dynamic: description-content-type
|
|
30
|
-
Dynamic: home-page
|
|
31
|
-
Dynamic: provides-extra
|
|
32
|
-
Dynamic: requires-dist
|
|
33
|
-
Dynamic: requires-python
|
|
34
|
-
Dynamic: summary
|
|
35
|
-
|
|
36
|
-
Client library for RocketWelder video streaming services
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
rocket_welder_sdk/__init__.py,sha256=LT2gnntM29r0IaokaJYOBOIccEcIYZm6FU_t9Eg1pzY,164
|
|
2
|
-
rocket_welder_sdk/client.py,sha256=W4WZdzAJ5eHuDUxQZyR_2rI9i1w2Zxr-UfwcFzKOwDw,5686
|
|
3
|
-
rocket_welder_sdk/rocket_welder_sdk/__init__.py,sha256=ERcy2Q_lIOoCVDIjVM3qGw5n9XRVcme1EtIDr0dilU4,475
|
|
4
|
-
rocket_welder_sdk/rocket_welder_sdk/client.py,sha256=2IBZ4HA2a96WdyaDRxVqXF593FSu48JHrOgBvCo60Pg,11829
|
|
5
|
-
rocket_welder_sdk/rocket_welder_sdk/connection_string.py,sha256=7kxaTjvQKa-SxbmNvExPf9qJJ4ZlMy9temhPUMzPTCc,6584
|
|
6
|
-
rocket_welder_sdk/rocket_welder_sdk/exceptions.py,sha256=sU8s4m0MRJxJttEYrP2biJ2ddDDu4Q6JkM3eeEPa6Eo,478
|
|
7
|
-
rocket_welder_sdk/rocket_welder_sdk/gst_caps.py,sha256=DKcLwkONyYydEV6iewYxIefMBWy_06ynrsiA8xR5lyE,6960
|
|
8
|
-
rocket_welder_sdk/rocket_welder_sdk/gst_metadata.py,sha256=d1d9YQbt2nqkvAE_d4I4LTod-qoBmq-xWyWLZOl3478,1226
|
|
9
|
-
rocket_welder_sdk-1.0.4.dist-info/METADATA,sha256=KjQ9T30u5J15zHyxAlFPQSQeNjBQggGLRqrrCd5a36M,1286
|
|
10
|
-
rocket_welder_sdk-1.0.4.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
11
|
-
rocket_welder_sdk-1.0.4.dist-info/top_level.txt,sha256=2iZvBjnwVCUW-uDE23-eJld5PZ9-mlPI69QiXM5IrTA,18
|
|
12
|
-
rocket_welder_sdk-1.0.4.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|