matrice-streaming 0.1.14__py3-none-any.whl → 0.1.65__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.
- matrice_streaming/__init__.py +44 -32
- matrice_streaming/streaming_gateway/camera_streamer/__init__.py +68 -1
- matrice_streaming/streaming_gateway/camera_streamer/async_camera_worker.py +1388 -0
- matrice_streaming/streaming_gateway/camera_streamer/async_ffmpeg_worker.py +966 -0
- matrice_streaming/streaming_gateway/camera_streamer/camera_streamer.py +188 -24
- matrice_streaming/streaming_gateway/camera_streamer/device_detection.py +507 -0
- matrice_streaming/streaming_gateway/camera_streamer/encoding_pool_manager.py +136 -0
- matrice_streaming/streaming_gateway/camera_streamer/ffmpeg_camera_streamer.py +1048 -0
- matrice_streaming/streaming_gateway/camera_streamer/ffmpeg_config.py +192 -0
- matrice_streaming/streaming_gateway/camera_streamer/ffmpeg_worker_manager.py +470 -0
- matrice_streaming/streaming_gateway/camera_streamer/gstreamer_camera_streamer.py +1368 -0
- matrice_streaming/streaming_gateway/camera_streamer/gstreamer_worker.py +1063 -0
- matrice_streaming/streaming_gateway/camera_streamer/gstreamer_worker_manager.py +546 -0
- matrice_streaming/streaming_gateway/camera_streamer/message_builder.py +60 -15
- matrice_streaming/streaming_gateway/camera_streamer/nvdec.py +1330 -0
- matrice_streaming/streaming_gateway/camera_streamer/nvdec_worker_manager.py +412 -0
- matrice_streaming/streaming_gateway/camera_streamer/platform_pipelines.py +680 -0
- matrice_streaming/streaming_gateway/camera_streamer/stream_statistics.py +111 -4
- matrice_streaming/streaming_gateway/camera_streamer/video_capture_manager.py +223 -27
- matrice_streaming/streaming_gateway/camera_streamer/worker_manager.py +694 -0
- matrice_streaming/streaming_gateway/debug/__init__.py +27 -2
- matrice_streaming/streaming_gateway/debug/benchmark.py +727 -0
- matrice_streaming/streaming_gateway/debug/debug_gstreamer_gateway.py +599 -0
- matrice_streaming/streaming_gateway/debug/debug_streaming_gateway.py +245 -95
- matrice_streaming/streaming_gateway/debug/debug_utils.py +29 -0
- matrice_streaming/streaming_gateway/debug/test_videoplayback.py +318 -0
- matrice_streaming/streaming_gateway/dynamic_camera_manager.py +656 -39
- matrice_streaming/streaming_gateway/metrics_reporter.py +676 -139
- matrice_streaming/streaming_gateway/streaming_action.py +71 -20
- matrice_streaming/streaming_gateway/streaming_gateway.py +1026 -78
- matrice_streaming/streaming_gateway/streaming_gateway_utils.py +175 -20
- matrice_streaming/streaming_gateway/streaming_status_listener.py +89 -0
- {matrice_streaming-0.1.14.dist-info → matrice_streaming-0.1.65.dist-info}/METADATA +1 -1
- matrice_streaming-0.1.65.dist-info/RECORD +56 -0
- matrice_streaming-0.1.14.dist-info/RECORD +0 -38
- {matrice_streaming-0.1.14.dist-info → matrice_streaming-0.1.65.dist-info}/WHEEL +0 -0
- {matrice_streaming-0.1.14.dist-info → matrice_streaming-0.1.65.dist-info}/licenses/LICENSE.txt +0 -0
- {matrice_streaming-0.1.14.dist-info → matrice_streaming-0.1.65.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,318 @@
|
|
|
1
|
+
"""Benchmark all 4 streaming modes with videoplayback.mp4.
|
|
2
|
+
|
|
3
|
+
This script tests and compares performance across all streaming modes:
|
|
4
|
+
- Mode 1: CameraStreamer (single-threaded OpenCV)
|
|
5
|
+
- Mode 2: WorkerManager (multi-process OpenCV)
|
|
6
|
+
- Mode 3: GStreamerCameraStreamer (single-threaded GStreamer)
|
|
7
|
+
- Mode 4: GStreamerWorkerManager (multi-process GStreamer)
|
|
8
|
+
|
|
9
|
+
Usage:
|
|
10
|
+
python -m matrice_streaming.streaming_gateway.debug.test_videoplayback
|
|
11
|
+
|
|
12
|
+
Or run directly (from project root):
|
|
13
|
+
python src/matrice_streaming/streaming_gateway/debug/test_videoplayback.py
|
|
14
|
+
|
|
15
|
+
With custom options:
|
|
16
|
+
python src/matrice_streaming/streaming_gateway/debug/test_videoplayback.py --duration 60 --fps 30
|
|
17
|
+
"""
|
|
18
|
+
import sys
|
|
19
|
+
from pathlib import Path
|
|
20
|
+
|
|
21
|
+
# Add src to path for direct execution - must be before other imports
|
|
22
|
+
# Path: debug -> streaming_gateway -> matrice_streaming -> src
|
|
23
|
+
_script_dir = Path(__file__).resolve().parent
|
|
24
|
+
_src_dir = _script_dir.parent.parent.parent # Goes to src/
|
|
25
|
+
_project_dir = _src_dir.parent # Goes to py_streaming/
|
|
26
|
+
_common_src = _project_dir / "py_common" / "src" # py_common/src for matrice_common
|
|
27
|
+
|
|
28
|
+
if str(_src_dir) not in sys.path:
|
|
29
|
+
sys.path.insert(0, str(_src_dir))
|
|
30
|
+
if _common_src.exists() and str(_common_src) not in sys.path:
|
|
31
|
+
sys.path.insert(0, str(_common_src))
|
|
32
|
+
|
|
33
|
+
import os
|
|
34
|
+
import time
|
|
35
|
+
import logging
|
|
36
|
+
import argparse
|
|
37
|
+
from typing import Dict, Any, List, Optional
|
|
38
|
+
|
|
39
|
+
logging.basicConfig(
|
|
40
|
+
level=logging.INFO,
|
|
41
|
+
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
|
|
42
|
+
)
|
|
43
|
+
logger = logging.getLogger(__name__)
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def benchmark_mode(
|
|
47
|
+
mode_name: str,
|
|
48
|
+
gateway,
|
|
49
|
+
duration_seconds: int = 30
|
|
50
|
+
) -> Dict[str, Any]:
|
|
51
|
+
"""Benchmark a single streaming mode.
|
|
52
|
+
|
|
53
|
+
Args:
|
|
54
|
+
mode_name: Name of the streaming mode
|
|
55
|
+
gateway: Gateway instance to benchmark
|
|
56
|
+
duration_seconds: How long to run the benchmark
|
|
57
|
+
|
|
58
|
+
Returns:
|
|
59
|
+
Dictionary with benchmark results
|
|
60
|
+
"""
|
|
61
|
+
print(f"\n{'='*60}")
|
|
62
|
+
print(f"Benchmarking {mode_name}")
|
|
63
|
+
print(f"{'='*60}")
|
|
64
|
+
|
|
65
|
+
# Start streaming
|
|
66
|
+
start_time = time.time()
|
|
67
|
+
success = gateway.start_streaming(block=False)
|
|
68
|
+
|
|
69
|
+
if not success:
|
|
70
|
+
print(f"Failed to start {mode_name}")
|
|
71
|
+
return {
|
|
72
|
+
'mode': mode_name,
|
|
73
|
+
'success': False,
|
|
74
|
+
'error': 'Failed to start streaming',
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
# Run for specified duration
|
|
78
|
+
print(f"Running for {duration_seconds} seconds...")
|
|
79
|
+
time.sleep(duration_seconds)
|
|
80
|
+
|
|
81
|
+
# Get statistics before stopping
|
|
82
|
+
stats = gateway.get_statistics()
|
|
83
|
+
|
|
84
|
+
# Stop streaming
|
|
85
|
+
gateway.stop_streaming()
|
|
86
|
+
|
|
87
|
+
elapsed = time.time() - start_time
|
|
88
|
+
|
|
89
|
+
# Extract key metrics
|
|
90
|
+
transmission_stats = stats.get('transmission_stats', {})
|
|
91
|
+
total_frames = transmission_stats.get('total_frames_sent', 0)
|
|
92
|
+
total_bytes = transmission_stats.get('total_bytes_sent', 0)
|
|
93
|
+
|
|
94
|
+
avg_fps = total_frames / elapsed if elapsed > 0 else 0
|
|
95
|
+
bandwidth_mbps = (total_bytes * 8) / (elapsed * 1_000_000) if elapsed > 0 else 0
|
|
96
|
+
|
|
97
|
+
result = {
|
|
98
|
+
'mode': mode_name,
|
|
99
|
+
'success': True,
|
|
100
|
+
'runtime_seconds': elapsed,
|
|
101
|
+
'total_frames': total_frames,
|
|
102
|
+
'total_bytes': total_bytes,
|
|
103
|
+
'avg_fps': avg_fps,
|
|
104
|
+
'bandwidth_mbps': bandwidth_mbps,
|
|
105
|
+
'cache_efficiency': stats.get('cache_efficiency', 0),
|
|
106
|
+
'stats': stats,
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
print(f"\nResults for {mode_name}:")
|
|
110
|
+
print(f" Runtime: {elapsed:.1f}s")
|
|
111
|
+
print(f" Total frames: {total_frames:,}")
|
|
112
|
+
print(f" Avg FPS: {avg_fps:.2f}")
|
|
113
|
+
print(f" Bandwidth: {bandwidth_mbps:.2f} Mbps")
|
|
114
|
+
|
|
115
|
+
if stats.get('cache_efficiency'):
|
|
116
|
+
print(f" Cache efficiency: {stats.get('cache_efficiency', 0):.1f}%")
|
|
117
|
+
|
|
118
|
+
return result
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
def run_mode1_benchmark(video_path: str, fps: int, duration: int) -> Optional[Dict]:
|
|
122
|
+
"""Benchmark Mode 1: CameraStreamer (single-threaded OpenCV)."""
|
|
123
|
+
try:
|
|
124
|
+
from matrice_streaming.streaming_gateway.debug.debug_streaming_gateway import DebugStreamingGateway
|
|
125
|
+
|
|
126
|
+
gateway = DebugStreamingGateway(
|
|
127
|
+
video_paths=[video_path],
|
|
128
|
+
fps=fps,
|
|
129
|
+
video_codec="h264",
|
|
130
|
+
loop_videos=True,
|
|
131
|
+
use_workers=False, # Single-threaded
|
|
132
|
+
log_messages=False,
|
|
133
|
+
)
|
|
134
|
+
return benchmark_mode("Mode 1 (CameraStreamer)", gateway, duration)
|
|
135
|
+
except Exception as e:
|
|
136
|
+
logger.error(f"Mode 1 failed: {e}")
|
|
137
|
+
return {'mode': 'Mode 1 (CameraStreamer)', 'success': False, 'error': str(e)}
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
def run_mode2_benchmark(video_path: str, fps: int, duration: int, num_workers: int = 2) -> Optional[Dict]:
|
|
141
|
+
"""Benchmark Mode 2: WorkerManager (multi-process OpenCV)."""
|
|
142
|
+
try:
|
|
143
|
+
from matrice_streaming.streaming_gateway.debug.debug_streaming_gateway import DebugStreamingGateway
|
|
144
|
+
|
|
145
|
+
gateway = DebugStreamingGateway(
|
|
146
|
+
video_paths=[video_path],
|
|
147
|
+
fps=fps,
|
|
148
|
+
video_codec="h264",
|
|
149
|
+
loop_videos=True,
|
|
150
|
+
use_workers=True, # Multi-process
|
|
151
|
+
num_workers=num_workers,
|
|
152
|
+
log_messages=False,
|
|
153
|
+
)
|
|
154
|
+
return benchmark_mode(f"Mode 2 (WorkerManager, {num_workers} workers)", gateway, duration)
|
|
155
|
+
except Exception as e:
|
|
156
|
+
logger.error(f"Mode 2 failed: {e}")
|
|
157
|
+
return {'mode': 'Mode 2 (WorkerManager)', 'success': False, 'error': str(e)}
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
def run_mode3_benchmark(video_path: str, fps: int, duration: int) -> Optional[Dict]:
|
|
161
|
+
"""Benchmark Mode 3: GStreamerCameraStreamer (single-threaded GStreamer)."""
|
|
162
|
+
try:
|
|
163
|
+
from matrice_streaming.streaming_gateway.debug.debug_gstreamer_gateway import DebugGStreamerGateway
|
|
164
|
+
|
|
165
|
+
gateway = DebugGStreamerGateway(
|
|
166
|
+
video_paths=[video_path],
|
|
167
|
+
fps=fps,
|
|
168
|
+
gstreamer_encoder="jpeg",
|
|
169
|
+
jpeg_quality=85,
|
|
170
|
+
loop_videos=True,
|
|
171
|
+
use_workers=False, # Single-threaded
|
|
172
|
+
enable_frame_optimizer=True,
|
|
173
|
+
log_messages=False,
|
|
174
|
+
)
|
|
175
|
+
return benchmark_mode("Mode 3 (GStreamer)", gateway, duration)
|
|
176
|
+
except Exception as e:
|
|
177
|
+
logger.error(f"Mode 3 failed: {e}")
|
|
178
|
+
return {'mode': 'Mode 3 (GStreamer)', 'success': False, 'error': str(e)}
|
|
179
|
+
|
|
180
|
+
|
|
181
|
+
def run_mode4_benchmark(video_path: str, fps: int, duration: int, num_workers: int = 2) -> Optional[Dict]:
|
|
182
|
+
"""Benchmark Mode 4: GStreamerWorkerManager (multi-process GStreamer)."""
|
|
183
|
+
try:
|
|
184
|
+
from matrice_streaming.streaming_gateway.debug.debug_gstreamer_gateway import DebugGStreamerGateway
|
|
185
|
+
|
|
186
|
+
gateway = DebugGStreamerGateway(
|
|
187
|
+
video_paths=[video_path],
|
|
188
|
+
fps=fps,
|
|
189
|
+
gstreamer_encoder="jpeg",
|
|
190
|
+
jpeg_quality=85,
|
|
191
|
+
loop_videos=True,
|
|
192
|
+
use_workers=True, # Multi-process
|
|
193
|
+
num_workers=num_workers,
|
|
194
|
+
enable_frame_optimizer=True,
|
|
195
|
+
log_messages=False,
|
|
196
|
+
)
|
|
197
|
+
return benchmark_mode(f"Mode 4 (GStreamer Workers, {num_workers} workers)", gateway, duration)
|
|
198
|
+
except Exception as e:
|
|
199
|
+
logger.error(f"Mode 4 failed: {e}")
|
|
200
|
+
return {'mode': 'Mode 4 (GStreamer Workers)', 'success': False, 'error': str(e)}
|
|
201
|
+
|
|
202
|
+
|
|
203
|
+
def print_summary(results: List[Dict]):
|
|
204
|
+
"""Print benchmark comparison summary."""
|
|
205
|
+
print("\n" + "="*70)
|
|
206
|
+
print("BENCHMARK SUMMARY")
|
|
207
|
+
print("="*70)
|
|
208
|
+
|
|
209
|
+
# Filter successful results
|
|
210
|
+
successful = [r for r in results if r.get('success', False)]
|
|
211
|
+
failed = [r for r in results if not r.get('success', False)]
|
|
212
|
+
|
|
213
|
+
if successful:
|
|
214
|
+
print(f"\n{'Mode':<45} {'FPS':>10} {'Bandwidth':>15}")
|
|
215
|
+
print("-"*70)
|
|
216
|
+
|
|
217
|
+
for result in successful:
|
|
218
|
+
print(f"{result['mode']:<45} {result['avg_fps']:>10.2f} {result['bandwidth_mbps']:>12.2f} Mbps")
|
|
219
|
+
|
|
220
|
+
# Find best performers
|
|
221
|
+
if len(successful) > 1:
|
|
222
|
+
best_fps = max(successful, key=lambda r: r['avg_fps'])
|
|
223
|
+
best_bandwidth = min(successful, key=lambda r: r['bandwidth_mbps'])
|
|
224
|
+
|
|
225
|
+
print(f"\nBest FPS: {best_fps['mode']} ({best_fps['avg_fps']:.2f} fps)")
|
|
226
|
+
print(f"Lowest Bandwidth: {best_bandwidth['mode']} ({best_bandwidth['bandwidth_mbps']:.2f} Mbps)")
|
|
227
|
+
|
|
228
|
+
if failed:
|
|
229
|
+
print("\nFailed modes:")
|
|
230
|
+
for result in failed:
|
|
231
|
+
print(f" - {result['mode']}: {result.get('error', 'Unknown error')}")
|
|
232
|
+
|
|
233
|
+
|
|
234
|
+
def main():
|
|
235
|
+
"""Benchmark all 4 streaming modes."""
|
|
236
|
+
parser = argparse.ArgumentParser(description="Benchmark all streaming modes")
|
|
237
|
+
parser.add_argument("--video", type=str, default="videoplayback.mp4",
|
|
238
|
+
help="Video file to use for benchmarking")
|
|
239
|
+
parser.add_argument("--duration", type=int, default=30,
|
|
240
|
+
help="Duration in seconds for each benchmark")
|
|
241
|
+
parser.add_argument("--fps", type=int, default=30,
|
|
242
|
+
help="Target FPS")
|
|
243
|
+
parser.add_argument("--workers", type=int, default=2,
|
|
244
|
+
help="Number of workers for multi-process modes")
|
|
245
|
+
parser.add_argument("--modes", type=str, default="all",
|
|
246
|
+
help="Modes to test: all, 1, 2, 3, 4, or comma-separated (e.g., '1,3')")
|
|
247
|
+
|
|
248
|
+
args = parser.parse_args()
|
|
249
|
+
|
|
250
|
+
video_path = args.video
|
|
251
|
+
|
|
252
|
+
if not Path(video_path).exists():
|
|
253
|
+
print(f"Error: {video_path} not found")
|
|
254
|
+
print(f"Current directory: {Path.cwd()}")
|
|
255
|
+
return
|
|
256
|
+
|
|
257
|
+
print("="*70)
|
|
258
|
+
print("STREAMING MODE BENCHMARK")
|
|
259
|
+
print("="*70)
|
|
260
|
+
print(f"\nVideo: {video_path}")
|
|
261
|
+
print(f"Duration: {args.duration}s per mode")
|
|
262
|
+
print(f"Target FPS: {args.fps}")
|
|
263
|
+
print(f"Workers: {args.workers}")
|
|
264
|
+
|
|
265
|
+
results = []
|
|
266
|
+
|
|
267
|
+
# Determine which modes to run
|
|
268
|
+
if args.modes == "all":
|
|
269
|
+
modes_to_run = [1, 2, 3, 4]
|
|
270
|
+
else:
|
|
271
|
+
modes_to_run = [int(m.strip()) for m in args.modes.split(',')]
|
|
272
|
+
|
|
273
|
+
# Run benchmarks with delay between modes for resource cleanup
|
|
274
|
+
if 1 in modes_to_run:
|
|
275
|
+
print("\n" + "="*70)
|
|
276
|
+
print("MODE 1: CameraStreamer (single-threaded OpenCV)")
|
|
277
|
+
print("="*70)
|
|
278
|
+
result = run_mode1_benchmark(video_path, args.fps, args.duration)
|
|
279
|
+
if result:
|
|
280
|
+
results.append(result)
|
|
281
|
+
time.sleep(2) # Allow cleanup
|
|
282
|
+
|
|
283
|
+
if 2 in modes_to_run:
|
|
284
|
+
print("\n" + "="*70)
|
|
285
|
+
print("MODE 2: WorkerManager (multi-process OpenCV)")
|
|
286
|
+
print("="*70)
|
|
287
|
+
result = run_mode2_benchmark(video_path, args.fps, args.duration, args.workers)
|
|
288
|
+
if result:
|
|
289
|
+
results.append(result)
|
|
290
|
+
time.sleep(2) # Allow cleanup
|
|
291
|
+
|
|
292
|
+
if 3 in modes_to_run:
|
|
293
|
+
print("\n" + "="*70)
|
|
294
|
+
print("MODE 3: GStreamerCameraStreamer (single-threaded GStreamer)")
|
|
295
|
+
print("="*70)
|
|
296
|
+
result = run_mode3_benchmark(video_path, args.fps, args.duration)
|
|
297
|
+
if result:
|
|
298
|
+
results.append(result)
|
|
299
|
+
time.sleep(2) # Allow GStreamer cleanup before Mode 4
|
|
300
|
+
|
|
301
|
+
if 4 in modes_to_run:
|
|
302
|
+
print("\n" + "="*70)
|
|
303
|
+
print("MODE 4: GStreamerWorkerManager (multi-process GStreamer)")
|
|
304
|
+
print("="*70)
|
|
305
|
+
result = run_mode4_benchmark(video_path, args.fps, args.duration, args.workers)
|
|
306
|
+
if result:
|
|
307
|
+
results.append(result)
|
|
308
|
+
|
|
309
|
+
# Print summary
|
|
310
|
+
print_summary(results)
|
|
311
|
+
|
|
312
|
+
print("\n" + "="*70)
|
|
313
|
+
print("Benchmark complete!")
|
|
314
|
+
print("="*70)
|
|
315
|
+
|
|
316
|
+
|
|
317
|
+
if __name__ == "__main__":
|
|
318
|
+
main()
|