rocket-welder-sdk 0.0.1__tar.gz → 1.0.0__tar.gz
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-1.0.0/PKG-INFO +410 -0
- rocket_welder_sdk-1.0.0/rocket_welder_sdk/__init__.py +8 -0
- rocket_welder_sdk-1.0.0/rocket_welder_sdk/client.py +183 -0
- rocket_welder_sdk-1.0.0/rocket_welder_sdk.egg-info/PKG-INFO +410 -0
- {rocket_welder_sdk-0.0.1 → rocket_welder_sdk-1.0.0}/rocket_welder_sdk.egg-info/SOURCES.txt +3 -6
- rocket_welder_sdk-1.0.0/rocket_welder_sdk.egg-info/requires.txt +8 -0
- rocket_welder_sdk-1.0.0/rocket_welder_sdk.egg-info/top_level.txt +1 -0
- {rocket_welder_sdk-0.0.1 → rocket_welder_sdk-1.0.0}/setup.cfg +4 -4
- rocket_welder_sdk-1.0.0/setup.py +46 -0
- rocket_welder_sdk-0.0.1/PKG-INFO +0 -51
- rocket_welder_sdk-0.0.1/README.md +0 -35
- rocket_welder_sdk-0.0.1/rocket_welder_camera/__init__.py +0 -0
- rocket_welder_sdk-0.0.1/rocket_welder_camera/camera.py +0 -76
- rocket_welder_sdk-0.0.1/rocket_welder_sdk.egg-info/PKG-INFO +0 -51
- rocket_welder_sdk-0.0.1/rocket_welder_sdk.egg-info/requires.txt +0 -3
- rocket_welder_sdk-0.0.1/rocket_welder_sdk.egg-info/top_level.txt +0 -2
- rocket_welder_sdk-0.0.1/setup.py +0 -33
- rocket_welder_sdk-0.0.1/tests/__init__.py +0 -0
- rocket_welder_sdk-0.0.1/tests/test_camera.py +0 -36
- {rocket_welder_sdk-0.0.1 → rocket_welder_sdk-1.0.0}/rocket_welder_sdk.egg-info/dependency_links.txt +0 -0
|
@@ -0,0 +1,410 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: rocket-welder-sdk
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: Client library for RocketWelder video streaming services
|
|
5
|
+
Home-page: https://github.com/modelingevolution/rocket-welder-sdk
|
|
6
|
+
Author: RocketWelder
|
|
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.0.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
|
+
# Rocket Welder SDK
|
|
37
|
+
|
|
38
|
+
Multi-language client libraries for interacting with RocketWelder video streaming services.
|
|
39
|
+
|
|
40
|
+
## Overview
|
|
41
|
+
|
|
42
|
+
The Rocket Welder SDK provides high-performance video streaming capabilities for containerized applications. It offers native client libraries in C++, C#, and Python, enabling seamless integration with RocketWelder video streaming pipelines.
|
|
43
|
+
|
|
44
|
+
## Features
|
|
45
|
+
|
|
46
|
+
- **High Performance**: Optimized for minimal latency and maximum throughput
|
|
47
|
+
- **Multi-Language Support**: Native libraries for C++, C#, and Python
|
|
48
|
+
- **Protocol Flexibility**: Support for multiple streaming protocols via connection strings
|
|
49
|
+
- **Container-Ready**: Designed for Docker/Kubernetes deployments
|
|
50
|
+
- **Simple Integration**: Easy-to-use API with minimal configuration
|
|
51
|
+
|
|
52
|
+
## Client Libraries
|
|
53
|
+
|
|
54
|
+
| Language | Package Manager | Package Name |
|
|
55
|
+
|----------|----------------|--------------|
|
|
56
|
+
| C++ | vcpkg | rocket-welder-sdk |
|
|
57
|
+
| C# | NuGet | RocketWelder.SDK |
|
|
58
|
+
| Python | pip | rocket-welder-sdk |
|
|
59
|
+
|
|
60
|
+
## Connection String Format
|
|
61
|
+
|
|
62
|
+
The SDK uses URI-style connection strings to specify data sources and protocols:
|
|
63
|
+
|
|
64
|
+
```
|
|
65
|
+
protocol://[host[:port]]/[path][?param1=value1¶m2=value2]
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
### Supported Protocols
|
|
69
|
+
|
|
70
|
+
#### Shared Memory (High-Performance Local)
|
|
71
|
+
```
|
|
72
|
+
shm://<buffer_name>
|
|
73
|
+
shm://<buffer_name>?buffer_size=10MB&metadata_size=1024KB
|
|
74
|
+
shm://<buffer_name>?mode=duplex&buffer_size=10MB
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
**Optional Parameters:**
|
|
78
|
+
- `mode`: Communication mode (`duplex` for bidirectional/mutable, `oneway` for one-way communication; default: `duplex`)
|
|
79
|
+
- `buffer_size`: Size of the data buffer (default: 20MB, supports units: B, KB, MB, GB)
|
|
80
|
+
- `metadata_size`: Size of the metadata buffer (default: 4KB, supports units: B, KB, MB)
|
|
81
|
+
|
|
82
|
+
#### MJPEG over HTTP
|
|
83
|
+
```
|
|
84
|
+
mjpeg+http://192.168.1.100:8080
|
|
85
|
+
mjpeg+http://camera.local:8080
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
#### MJPEG over TCP
|
|
89
|
+
```
|
|
90
|
+
mjpeg+tcp://192.168.1.100:5000
|
|
91
|
+
mjpeg+tcp://camera.local:5000
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
### Environment Variable
|
|
95
|
+
|
|
96
|
+
When deployed in a Rocket Welder container, the connection string is provided via:
|
|
97
|
+
```bash
|
|
98
|
+
CONNECTION_STRING=shm://camera_feed?buffer_size=20MB&metadata_size=4KB
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
## Installation
|
|
102
|
+
|
|
103
|
+
### C++ (vcpkg)
|
|
104
|
+
|
|
105
|
+
```bash
|
|
106
|
+
vcpkg install rocket-welder-sdk
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
### C# (NuGet)
|
|
110
|
+
|
|
111
|
+
```bash
|
|
112
|
+
dotnet add package RocketWelder.SDK
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
### Python (pip)
|
|
116
|
+
|
|
117
|
+
```bash
|
|
118
|
+
pip install rocket-welder-sdk
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
## Usage Examples
|
|
122
|
+
|
|
123
|
+
### C++
|
|
124
|
+
|
|
125
|
+
```cpp
|
|
126
|
+
#include <rocket_welder/client.hpp>
|
|
127
|
+
#include <opencv2/opencv.hpp>
|
|
128
|
+
|
|
129
|
+
int main(int argc, char* argv[]) {
|
|
130
|
+
// Best practice: use from() which:
|
|
131
|
+
// 1. Checks environment variable (CONNECTION_STRING)
|
|
132
|
+
// 2. Overrides with command line args if provided
|
|
133
|
+
auto client = rocket_welder::Client::from(argc, argv);
|
|
134
|
+
|
|
135
|
+
// Or specify connection string directly
|
|
136
|
+
auto client = rocket_welder::Client::from_connection_string(
|
|
137
|
+
"shm://camera_feed?buffer_size=20MB&metadata_size=4KB"
|
|
138
|
+
);
|
|
139
|
+
|
|
140
|
+
// Process frames as OpenCV Mat (mutable by default)
|
|
141
|
+
client.on_frame([](cv::Mat& frame) {
|
|
142
|
+
// Add overlay text - zero copy!
|
|
143
|
+
cv::putText(frame, "Processing", cv::Point(10, 30),
|
|
144
|
+
cv::FONT_HERSHEY_SIMPLEX, 1.0, cv::Scalar(0, 255, 0), 2);
|
|
145
|
+
|
|
146
|
+
// Add timestamp overlay
|
|
147
|
+
auto now = std::chrono::system_clock::now();
|
|
148
|
+
auto time_t = std::chrono::system_clock::to_time_t(now);
|
|
149
|
+
cv::putText(frame, std::ctime(&time_t), cv::Point(10, 60),
|
|
150
|
+
cv::FONT_HERSHEY_SIMPLEX, 0.5, cv::Scalar(255, 255, 255), 1);
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
client.start();
|
|
154
|
+
return 0;
|
|
155
|
+
}
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
### C#
|
|
159
|
+
|
|
160
|
+
```csharp
|
|
161
|
+
using RocketWelder.SDK;
|
|
162
|
+
using OpenCvSharp;
|
|
163
|
+
|
|
164
|
+
class Program
|
|
165
|
+
{
|
|
166
|
+
static void Main(string[] args)
|
|
167
|
+
{
|
|
168
|
+
// Best practice: use From() which:
|
|
169
|
+
// 1. Checks environment variable (CONNECTION_STRING)
|
|
170
|
+
// 2. Overrides with command line args if provided
|
|
171
|
+
var client = RocketWelderClient.From(args);
|
|
172
|
+
|
|
173
|
+
// Or specify connection string directly
|
|
174
|
+
var client = RocketWelderClient.FromConnectionString(
|
|
175
|
+
"shm://camera_feed?buffer_size=20MB&metadata_size=4KB"
|
|
176
|
+
);
|
|
177
|
+
|
|
178
|
+
int frameCount = 0;
|
|
179
|
+
|
|
180
|
+
// Process frames as OpenCV Mat
|
|
181
|
+
client.OnFrame((Mat frame) =>
|
|
182
|
+
{
|
|
183
|
+
// Add overlay text
|
|
184
|
+
Cv2.PutText(frame, "Processing", new Point(10, 30),
|
|
185
|
+
HersheyFonts.HersheySimplex, 1.0, new Scalar(0, 255, 0), 2);
|
|
186
|
+
|
|
187
|
+
// Add frame counter overlay
|
|
188
|
+
Cv2.PutText(frame, $"Frame: {frameCount++}", new Point(10, 60),
|
|
189
|
+
HersheyFonts.HersheySimplex, 0.5, new Scalar(255, 255, 255), 1);
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
client.Start();
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
### Python
|
|
198
|
+
|
|
199
|
+
```python
|
|
200
|
+
import rocket_welder_sdk as rw
|
|
201
|
+
import cv2
|
|
202
|
+
import sys
|
|
203
|
+
|
|
204
|
+
# Best practice: use from_args() which:
|
|
205
|
+
# 1. Checks environment variable (CONNECTION_STRING)
|
|
206
|
+
# 2. Overrides with command line args if provided
|
|
207
|
+
client = rw.Client.from_args(sys.argv)
|
|
208
|
+
|
|
209
|
+
# Or specify connection string directly
|
|
210
|
+
client = rw.Client.from_connection_string("shm://camera_feed?buffer_size=20MB&metadata_size=4KB")
|
|
211
|
+
|
|
212
|
+
# Process frames as numpy arrays (OpenCV compatible)
|
|
213
|
+
@client.on_frame
|
|
214
|
+
def process_frame(frame: np.ndarray):
|
|
215
|
+
# Add overlay text - zero copy!
|
|
216
|
+
cv2.putText(frame, "Processing", (10, 30),
|
|
217
|
+
cv2.FONT_HERSHEY_SIMPLEX, 1.0, (0, 255, 0), 2)
|
|
218
|
+
|
|
219
|
+
# Add timestamp overlay
|
|
220
|
+
from datetime import datetime
|
|
221
|
+
timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
|
222
|
+
cv2.putText(frame, timestamp, (10, 60),
|
|
223
|
+
cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 255, 255), 1)
|
|
224
|
+
|
|
225
|
+
client.start()
|
|
226
|
+
|
|
227
|
+
# Or use iterator pattern
|
|
228
|
+
for frame in client.frames():
|
|
229
|
+
# Each frame is a numpy array
|
|
230
|
+
print(f"Received frame: {frame.shape}")
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
## Docker Integration
|
|
234
|
+
|
|
235
|
+
### C++ Dockerfile
|
|
236
|
+
|
|
237
|
+
```dockerfile
|
|
238
|
+
FROM ubuntu:22.04 AS builder
|
|
239
|
+
|
|
240
|
+
# Install build tools and OpenCV
|
|
241
|
+
RUN apt-get update && apt-get install -y \
|
|
242
|
+
build-essential \
|
|
243
|
+
cmake \
|
|
244
|
+
libopencv-dev
|
|
245
|
+
|
|
246
|
+
# Install Rocket Welder SDK via vcpkg
|
|
247
|
+
RUN vcpkg install rocket-welder-sdk
|
|
248
|
+
|
|
249
|
+
# Build your application
|
|
250
|
+
WORKDIR /app
|
|
251
|
+
COPY . .
|
|
252
|
+
RUN cmake . && make
|
|
253
|
+
|
|
254
|
+
FROM ubuntu:22.04
|
|
255
|
+
RUN apt-get update && apt-get install -y libopencv-dev
|
|
256
|
+
COPY --from=builder /app/my_app /usr/local/bin/
|
|
257
|
+
CMD ["my_app"]
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
### C# Dockerfile
|
|
261
|
+
|
|
262
|
+
```dockerfile
|
|
263
|
+
FROM mcr.microsoft.com/dotnet/sdk:8.0 AS builder
|
|
264
|
+
|
|
265
|
+
WORKDIR /app
|
|
266
|
+
COPY *.csproj ./
|
|
267
|
+
RUN dotnet restore
|
|
268
|
+
|
|
269
|
+
COPY . ./
|
|
270
|
+
RUN dotnet publish -c Release -o out
|
|
271
|
+
|
|
272
|
+
FROM mcr.microsoft.com/dotnet/runtime:8.0
|
|
273
|
+
WORKDIR /app
|
|
274
|
+
COPY --from=builder /app/out .
|
|
275
|
+
CMD ["dotnet", "MyApp.dll"]
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
### Python Dockerfile
|
|
279
|
+
|
|
280
|
+
```dockerfile
|
|
281
|
+
FROM python:3.11-slim
|
|
282
|
+
|
|
283
|
+
# Install OpenCV and other dependencies
|
|
284
|
+
RUN apt-get update && apt-get install -y \
|
|
285
|
+
python3-opencv \
|
|
286
|
+
&& rm -rf /var/lib/apt/lists/*
|
|
287
|
+
|
|
288
|
+
# Install Rocket Welder SDK and ML frameworks
|
|
289
|
+
RUN pip install --no-cache-dir \
|
|
290
|
+
rocket-welder-sdk \
|
|
291
|
+
numpy \
|
|
292
|
+
ultralytics # Example: YOLO
|
|
293
|
+
|
|
294
|
+
WORKDIR /app
|
|
295
|
+
COPY . .
|
|
296
|
+
|
|
297
|
+
CMD ["python", "app.py"]
|
|
298
|
+
```
|
|
299
|
+
|
|
300
|
+
## Protocol Details
|
|
301
|
+
|
|
302
|
+
### Shared Memory Protocol (shm://)
|
|
303
|
+
|
|
304
|
+
High-performance local data transfer between processes:
|
|
305
|
+
|
|
306
|
+
- **Performance**: Minimal latency, maximum throughput
|
|
307
|
+
- **Use Cases**: Local processing, multi-container applications on same host
|
|
308
|
+
|
|
309
|
+
### MJPEG over HTTP (mjpeg+http://)
|
|
310
|
+
|
|
311
|
+
Motion JPEG streaming over HTTP:
|
|
312
|
+
|
|
313
|
+
- **Performance**: Good balance of quality and bandwidth
|
|
314
|
+
- **Advantages**: Wide compatibility, firewall-friendly, browser support
|
|
315
|
+
- **Use Cases**: Network streaming, web applications, remote monitoring
|
|
316
|
+
|
|
317
|
+
### MJPEG over TCP (mjpeg+tcp://)
|
|
318
|
+
|
|
319
|
+
Motion JPEG streaming over raw TCP socket:
|
|
320
|
+
|
|
321
|
+
- **Performance**: Lower latency than HTTP, less protocol overhead
|
|
322
|
+
- **Advantages**: Direct socket connection, minimal overhead, suitable for local networks
|
|
323
|
+
- **Use Cases**: Low-latency streaming, embedded systems, industrial applications
|
|
324
|
+
|
|
325
|
+
## Building from Source
|
|
326
|
+
|
|
327
|
+
### Prerequisites
|
|
328
|
+
|
|
329
|
+
- CMake 3.20+
|
|
330
|
+
- C++20 compiler
|
|
331
|
+
- Python 3.8+ (for Python bindings)
|
|
332
|
+
- .NET 6.0+ SDK (for C# bindings)
|
|
333
|
+
- OpenCV 4.0+ (optional, for image processing)
|
|
334
|
+
|
|
335
|
+
### Build Instructions
|
|
336
|
+
|
|
337
|
+
```bash
|
|
338
|
+
git clone https://github.com/modelingevolution/rocket-welder-sdk.git
|
|
339
|
+
cd rocket-welder-sdk
|
|
340
|
+
|
|
341
|
+
# Build all libraries
|
|
342
|
+
mkdir build && cd build
|
|
343
|
+
cmake ..
|
|
344
|
+
make -j$(nproc)
|
|
345
|
+
|
|
346
|
+
# Run tests
|
|
347
|
+
ctest
|
|
348
|
+
|
|
349
|
+
# Install
|
|
350
|
+
sudo make install
|
|
351
|
+
```
|
|
352
|
+
|
|
353
|
+
## API Reference
|
|
354
|
+
|
|
355
|
+
Detailed API documentation for each language:
|
|
356
|
+
|
|
357
|
+
- [C++ API Reference](docs/cpp-api.md)
|
|
358
|
+
- [C# API Reference](docs/csharp-api.md)
|
|
359
|
+
- [Python API Reference](docs/python-api.md)
|
|
360
|
+
|
|
361
|
+
## Examples
|
|
362
|
+
|
|
363
|
+
See the [examples](examples/) directory for complete working examples:
|
|
364
|
+
|
|
365
|
+
- [Simple Frame Reader](examples/simple-reader/)
|
|
366
|
+
- [Frame Processor](examples/frame-processor/)
|
|
367
|
+
- [Multi-Stream Handler](examples/multi-stream/)
|
|
368
|
+
- [Performance Benchmark](examples/benchmark/)
|
|
369
|
+
|
|
370
|
+
## Contributing
|
|
371
|
+
|
|
372
|
+
Contributions are welcome! Please see [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines.
|
|
373
|
+
|
|
374
|
+
## License
|
|
375
|
+
|
|
376
|
+
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
|
|
377
|
+
|
|
378
|
+
## Support
|
|
379
|
+
|
|
380
|
+
- **Issues**: [GitHub Issues](https://github.com/modelingevolution/rocket-welder-sdk/issues)
|
|
381
|
+
- **Discussions**: [GitHub Discussions](https://github.com/modelingevolution/rocket-welder-sdk/discussions)
|
|
382
|
+
- **Documentation**: [https://docs.rocket-welder.io](https://docs.rocket-welder.io)
|
|
383
|
+
|
|
384
|
+
## Technical Details
|
|
385
|
+
|
|
386
|
+
### GStreamer Integration
|
|
387
|
+
|
|
388
|
+
The SDK integrates with GStreamer pipelines through specialized elements:
|
|
389
|
+
- **zerosink**: Simple sink element for writing video frames
|
|
390
|
+
- **zerobuffer**: Processing element with bidirectional communication using DuplexChannel
|
|
391
|
+
|
|
392
|
+
### Zero-Copy Buffer Technology
|
|
393
|
+
|
|
394
|
+
For shared memory protocol, the SDK uses:
|
|
395
|
+
- **C++**: Zero-Copy-Buffer (via vcpkg) - Returns cv::Mat with zero-copy access
|
|
396
|
+
- **C#**: ZeroBuffer (via NuGet) - Returns OpenCvSharp.Mat with zero-copy access
|
|
397
|
+
- **Python**: zero-buffer (via pip) - Returns numpy arrays compatible with OpenCV
|
|
398
|
+
|
|
399
|
+
The SDK leverages DuplexChannel for bidirectional communication, enabling:
|
|
400
|
+
- Zero-copy frame access as OpenCV Mat objects
|
|
401
|
+
- In-place frame processing without memory allocation
|
|
402
|
+
- Direct memory mapping between producer and consumer
|
|
403
|
+
- Efficient metadata passing alongside frame data
|
|
404
|
+
|
|
405
|
+
This technology enables direct memory access without data duplication, providing maximum performance for local processing scenarios.
|
|
406
|
+
|
|
407
|
+
## Acknowledgments
|
|
408
|
+
|
|
409
|
+
- GStreamer Project for the multimedia framework
|
|
410
|
+
- ZeroBuffer contributors for the zero-copy buffer implementation
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
"""
|
|
2
|
+
RocketWelder client implementation.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import os
|
|
6
|
+
import sys
|
|
7
|
+
import time
|
|
8
|
+
import threading
|
|
9
|
+
from typing import Optional, Callable, Dict, Any, Iterator
|
|
10
|
+
import numpy as np
|
|
11
|
+
import cv2
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class Client:
|
|
15
|
+
"""Client for RocketWelder video streaming services."""
|
|
16
|
+
|
|
17
|
+
def __init__(self, connection_string: str):
|
|
18
|
+
"""
|
|
19
|
+
Initialize client with connection string.
|
|
20
|
+
|
|
21
|
+
Args:
|
|
22
|
+
connection_string: Connection string (e.g., "shm://buffer_name")
|
|
23
|
+
"""
|
|
24
|
+
self.connection_string = connection_string
|
|
25
|
+
self._callback: Optional[Callable[[np.ndarray], None]] = None
|
|
26
|
+
self._callback_with_metadata: Optional[Callable[[np.ndarray, Dict[str, Any]], None]] = None
|
|
27
|
+
self._running = False
|
|
28
|
+
self._thread: Optional[threading.Thread] = None
|
|
29
|
+
|
|
30
|
+
# TODO: Parse connection string
|
|
31
|
+
# TODO: Initialize based on protocol (shm://, mjpeg+http://, etc.)
|
|
32
|
+
|
|
33
|
+
@classmethod
|
|
34
|
+
def from_args(cls, argv: list) -> 'Client':
|
|
35
|
+
"""
|
|
36
|
+
Create client from command line arguments and environment variables.
|
|
37
|
+
Environment variable CONNECTION_STRING is checked first, then overridden by args.
|
|
38
|
+
|
|
39
|
+
Args:
|
|
40
|
+
argv: Command line arguments (typically sys.argv)
|
|
41
|
+
|
|
42
|
+
Returns:
|
|
43
|
+
Client instance
|
|
44
|
+
"""
|
|
45
|
+
# Check environment variable first
|
|
46
|
+
connection_string = os.environ.get('CONNECTION_STRING')
|
|
47
|
+
|
|
48
|
+
# Override with command line args if present
|
|
49
|
+
if argv:
|
|
50
|
+
for arg in argv[1:]: # Skip program name
|
|
51
|
+
if (arg.startswith('shm://') or
|
|
52
|
+
arg.startswith('mjpeg+http://') or
|
|
53
|
+
arg.startswith('mjpeg+tcp://')):
|
|
54
|
+
connection_string = arg
|
|
55
|
+
break
|
|
56
|
+
|
|
57
|
+
return cls(connection_string or 'shm://default')
|
|
58
|
+
|
|
59
|
+
@classmethod
|
|
60
|
+
def from_env(cls) -> 'Client':
|
|
61
|
+
"""
|
|
62
|
+
Create client from environment variable CONNECTION_STRING.
|
|
63
|
+
|
|
64
|
+
Returns:
|
|
65
|
+
Client instance
|
|
66
|
+
"""
|
|
67
|
+
connection_string = os.environ.get('CONNECTION_STRING', 'shm://default')
|
|
68
|
+
return cls(connection_string)
|
|
69
|
+
|
|
70
|
+
@classmethod
|
|
71
|
+
def from_connection_string(cls, connection_string: str) -> 'Client':
|
|
72
|
+
"""
|
|
73
|
+
Create client from a specific connection string.
|
|
74
|
+
|
|
75
|
+
Args:
|
|
76
|
+
connection_string: Connection string
|
|
77
|
+
|
|
78
|
+
Returns:
|
|
79
|
+
Client instance
|
|
80
|
+
"""
|
|
81
|
+
return cls(connection_string)
|
|
82
|
+
|
|
83
|
+
def on_frame(self, callback: Callable) -> Callable:
|
|
84
|
+
"""
|
|
85
|
+
Decorator/method to set frame processing callback.
|
|
86
|
+
|
|
87
|
+
The callback can have one of these signatures:
|
|
88
|
+
- callback(frame: np.ndarray) -> None
|
|
89
|
+
- callback(frame: np.ndarray, metadata: dict) -> None
|
|
90
|
+
|
|
91
|
+
Args:
|
|
92
|
+
callback: Function to process frames
|
|
93
|
+
|
|
94
|
+
Returns:
|
|
95
|
+
The callback function (for decorator usage)
|
|
96
|
+
"""
|
|
97
|
+
import inspect
|
|
98
|
+
sig = inspect.signature(callback)
|
|
99
|
+
param_count = len(sig.parameters)
|
|
100
|
+
|
|
101
|
+
if param_count == 1:
|
|
102
|
+
self._callback = callback
|
|
103
|
+
elif param_count == 2:
|
|
104
|
+
self._callback_with_metadata = callback
|
|
105
|
+
else:
|
|
106
|
+
raise ValueError(f"Callback must have 1 or 2 parameters, got {param_count}")
|
|
107
|
+
|
|
108
|
+
return callback
|
|
109
|
+
|
|
110
|
+
def start(self):
|
|
111
|
+
"""Start frame processing."""
|
|
112
|
+
if self._running:
|
|
113
|
+
return
|
|
114
|
+
|
|
115
|
+
if not self._callback and not self._callback_with_metadata:
|
|
116
|
+
raise RuntimeError("Frame callback must be set before starting")
|
|
117
|
+
|
|
118
|
+
self._running = True
|
|
119
|
+
self._thread = threading.Thread(target=self._process_frames)
|
|
120
|
+
self._thread.daemon = True
|
|
121
|
+
self._thread.start()
|
|
122
|
+
|
|
123
|
+
def stop(self):
|
|
124
|
+
"""Stop frame processing."""
|
|
125
|
+
if not self._running:
|
|
126
|
+
return
|
|
127
|
+
|
|
128
|
+
self._running = False
|
|
129
|
+
if self._thread:
|
|
130
|
+
self._thread.join(timeout=5.0)
|
|
131
|
+
self._thread = None
|
|
132
|
+
|
|
133
|
+
def is_running(self) -> bool:
|
|
134
|
+
"""Check if client is running."""
|
|
135
|
+
return self._running
|
|
136
|
+
|
|
137
|
+
def frames(self) -> Iterator[np.ndarray]:
|
|
138
|
+
"""
|
|
139
|
+
Iterator interface for frame processing.
|
|
140
|
+
|
|
141
|
+
Yields:
|
|
142
|
+
Frame as numpy array
|
|
143
|
+
"""
|
|
144
|
+
# TODO: Implement actual frame reading
|
|
145
|
+
# For now, generate dummy frames for testing
|
|
146
|
+
while True:
|
|
147
|
+
# Create dummy frame
|
|
148
|
+
frame = np.zeros((480, 640, 3), dtype=np.uint8)
|
|
149
|
+
yield frame
|
|
150
|
+
time.sleep(0.033) # ~30 FPS
|
|
151
|
+
|
|
152
|
+
def _process_frames(self):
|
|
153
|
+
"""Internal method to process frames in thread."""
|
|
154
|
+
# TODO: Implement actual frame processing
|
|
155
|
+
# For now, generate dummy frames for testing
|
|
156
|
+
while self._running:
|
|
157
|
+
# Create dummy frame
|
|
158
|
+
frame = np.zeros((480, 640, 3), dtype=np.uint8)
|
|
159
|
+
|
|
160
|
+
# Create dummy metadata
|
|
161
|
+
metadata = {
|
|
162
|
+
'timestamp': time.time(),
|
|
163
|
+
'format': 'BGR',
|
|
164
|
+
'width': 640,
|
|
165
|
+
'height': 480
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
# Call appropriate callback
|
|
169
|
+
if self._callback:
|
|
170
|
+
self._callback(frame)
|
|
171
|
+
elif self._callback_with_metadata:
|
|
172
|
+
self._callback_with_metadata(frame, metadata)
|
|
173
|
+
|
|
174
|
+
time.sleep(0.033) # ~30 FPS
|
|
175
|
+
|
|
176
|
+
def __enter__(self):
|
|
177
|
+
"""Context manager entry."""
|
|
178
|
+
self.start()
|
|
179
|
+
return self
|
|
180
|
+
|
|
181
|
+
def __exit__(self, exc_type, exc_val, exc_tb):
|
|
182
|
+
"""Context manager exit."""
|
|
183
|
+
self.stop()
|