nedo-vision-worker 1.2.0__py3-none-any.whl → 1.2.1__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.
@@ -6,5 +6,5 @@ A library for running worker agents in the Nedo Vision platform.
6
6
 
7
7
  from .worker_service import WorkerService
8
8
 
9
- __version__ = "1.2.0"
9
+ __version__ = "1.2.1"
10
10
  __all__ = ["WorkerService"]
nedo_vision_worker/cli.py CHANGED
@@ -49,7 +49,7 @@ Examples:
49
49
  parser.add_argument(
50
50
  "--version",
51
51
  action="version",
52
- version="nedo-vision-worker 1.2.0"
52
+ version="nedo-vision-worker 1.2.1"
53
53
  )
54
54
 
55
55
  subparsers = parser.add_subparsers(
@@ -8,6 +8,7 @@ import fractions
8
8
  from urllib.parse import urlparse
9
9
  from .GrpcClientBase import GrpcClientBase
10
10
  from .SharedDirectDeviceClient import SharedDirectDeviceClient
11
+ from ..util.FFmpegUtil import get_rtsp_ffmpeg_options, get_rtsp_probe_options
11
12
  from ..protos.VisionWorkerService_pb2_grpc import VideoStreamServiceStub
12
13
  from ..protos.VisionWorkerService_pb2 import VideoFrame
13
14
 
@@ -47,8 +48,10 @@ class VideoStreamClient(GrpcClientBase):
47
48
  ]
48
49
 
49
50
  if stream_type == "rtsp":
50
- probe_cmd.insert(1, "-rtsp_transport")
51
- probe_cmd.insert(2, "tcp")
51
+ probe_options = get_rtsp_probe_options()
52
+ # Insert options at the beginning (after ffprobe)
53
+ for i, option in enumerate(probe_options):
54
+ probe_cmd.insert(1 + i, option)
52
55
 
53
56
  result = subprocess.run(probe_cmd, capture_output=True, text=True)
54
57
  probe_data = json.loads(result.stdout)
@@ -97,10 +100,8 @@ class VideoStreamClient(GrpcClientBase):
97
100
  logging.error(f"Failed to create ffmpeg input for direct device: {e}")
98
101
  return
99
102
  elif stream_type == "rtsp":
100
- ffmpeg_input = (
101
- ffmpeg
102
- .input(url, rtsp_transport="tcp", fflags="nobuffer", timeout="5000000")
103
- )
103
+ rtsp_options = get_rtsp_ffmpeg_options()
104
+ ffmpeg_input = ffmpeg.input(url, **rtsp_options)
104
105
  elif stream_type == "hls":
105
106
  ffmpeg_input = (
106
107
  ffmpeg
@@ -148,8 +149,13 @@ class VideoStreamClient(GrpcClientBase):
148
149
  if stream_type == "direct":
149
150
  self.shared_device_client.release_device_access(url)
150
151
 
151
- stderr_output = process.stderr.read().decode()
152
- logging.error(f"FFmpeg stderr: {stderr_output}")
152
+ try:
153
+ stderr_output = process.stderr.read().decode()
154
+ if stderr_output.strip(): # Only log if there's actual error content
155
+ logging.error(f"FFmpeg stderr for {stream_type} stream: {stderr_output}")
156
+ except Exception as e:
157
+ logging.warning(f"Could not read FFmpeg stderr: {e}")
158
+
153
159
  process.terminate()
154
160
  process.wait()
155
161
 
@@ -8,6 +8,7 @@ from pathlib import Path
8
8
  from ..database.DatabaseManager import _get_storage_paths
9
9
  from ..repositories.WorkerSourcePipelineDebugRepository import WorkerSourcePipelineDebugRepository
10
10
  from ..repositories.WorkerSourcePipelineDetectionRepository import WorkerSourcePipelineDetectionRepository
11
+ from ..util.FFmpegUtil import get_rtsp_ffmpeg_options, get_stream_timeout_duration
11
12
  from .GrpcClientBase import GrpcClientBase
12
13
  from .SharedDirectDeviceClient import SharedDirectDeviceClient
13
14
  from ..protos.WorkerSourcePipelineService_pb2_grpc import WorkerSourcePipelineServiceStub
@@ -194,10 +195,8 @@ class WorkerSourcePipelineClient(GrpcClientBase):
194
195
  logging.error(f"Error setting up direct device {device_index}: {e}")
195
196
  return None
196
197
  elif stream_type == "rtsp":
197
- ffmpeg_input = (
198
- ffmpeg
199
- .input(url, rtsp_transport="tcp", fflags="nobuffer", timeout="5000000")
200
- )
198
+ rtsp_options = get_rtsp_ffmpeg_options()
199
+ ffmpeg_input = ffmpeg.input(url, **rtsp_options)
201
200
  elif stream_type == "hls":
202
201
  ffmpeg_input = (
203
202
  ffmpeg
@@ -246,11 +245,13 @@ class WorkerSourcePipelineClient(GrpcClientBase):
246
245
  )
247
246
 
248
247
  try:
249
- stdout, stderr = process.communicate(timeout=15)
248
+ # Use appropriate timeout for different stream types
249
+ timeout_duration = get_stream_timeout_duration(stream_type)
250
+ stdout, stderr = process.communicate(timeout=timeout_duration)
250
251
 
251
252
  if process.returncode != 0:
252
253
  error_msg = stderr.decode('utf-8', errors='ignore')
253
- logging.error(f"FFmpeg error: {error_msg}")
254
+ logging.error(f"FFmpeg error for {stream_type} stream: {error_msg}")
254
255
  return None
255
256
 
256
257
  if not stdout:
@@ -0,0 +1,124 @@
1
+ """
2
+ FFmpeg utilities for Jetson compatibility and RTSP stream handling.
3
+
4
+ This module provides common FFmpeg configurations and utilities that work
5
+ reliably on Jetson devices with FFmpeg 4.4.1 and newer versions.
6
+ """
7
+
8
+ import logging
9
+ import subprocess
10
+ import re
11
+ from typing import Dict, Any, Tuple
12
+
13
+
14
+ def get_ffmpeg_version() -> Tuple[int, int, int]:
15
+ """
16
+ Get the FFmpeg version as a tuple of (major, minor, patch).
17
+
18
+ Returns:
19
+ Tuple[int, int, int]: Version tuple (major, minor, patch)
20
+ """
21
+ try:
22
+ result = subprocess.run(['ffmpeg', '-version'], capture_output=True, text=True, timeout=5)
23
+ if result.returncode == 0:
24
+ # Extract version from output like "ffmpeg version n7.1.1" or "ffmpeg version 4.4.1"
25
+ match = re.search(r'ffmpeg version n?(\d+)\.(\d+)\.(\d+)', result.stdout)
26
+ if match:
27
+ return (int(match.group(1)), int(match.group(2)), int(match.group(3)))
28
+ except Exception as e:
29
+ logging.warning(f"Could not determine FFmpeg version: {e}")
30
+
31
+ # Default to a reasonable version if detection fails
32
+ return (4, 4, 1)
33
+
34
+
35
+ def get_rtsp_ffmpeg_options() -> Dict[str, Any]:
36
+ """
37
+ Get FFmpeg options optimized for RTSP streams with version compatibility.
38
+
39
+ These options work across different FFmpeg versions:
40
+ - FFmpeg 4.4.x: Uses stimeout
41
+ - FFmpeg 5.x+: Uses timeout
42
+ - FFmpeg 7.x+: Uses timeout
43
+
44
+ Returns:
45
+ Dict[str, Any]: FFmpeg input options for RTSP streams
46
+ """
47
+ version = get_ffmpeg_version()
48
+ major, minor, patch = version
49
+
50
+ # Base options that work across all versions
51
+ options = {
52
+ "rtsp_transport": "tcp",
53
+ "fflags": "nobuffer+genpts",
54
+ "max_delay": "5000000", # Max buffering delay
55
+ "buffer_size": "1024000", # Input buffer size
56
+ "avoid_negative_ts": "make_zero" # Handle timestamp issues
57
+ }
58
+
59
+ # Add version-specific timeout option
60
+ if major == 4 and minor == 4:
61
+ # FFmpeg 4.4.x uses stimeout
62
+ options["stimeout"] = "5000000"
63
+ logging.debug("Using stimeout for FFmpeg 4.4.x")
64
+ else:
65
+ # FFmpeg 5.x+ uses timeout (microseconds)
66
+ options["timeout"] = "5000000"
67
+ logging.debug(f"Using timeout for FFmpeg {major}.{minor}.{patch}")
68
+
69
+ return options
70
+
71
+
72
+ def get_rtsp_probe_options() -> list:
73
+ """
74
+ Get ffprobe command line options for RTSP streams with version compatibility.
75
+
76
+ Returns:
77
+ list: Command line options to insert into ffprobe command
78
+ """
79
+ version = get_ffmpeg_version()
80
+ major, minor, patch = version
81
+
82
+ base_options = ["-rtsp_transport", "tcp"]
83
+
84
+ # Add version-specific timeout option
85
+ if major == 4 and minor == 4:
86
+ # FFmpeg 4.4.x uses stimeout
87
+ return base_options + ["-stimeout", "5000000"]
88
+ else:
89
+ # FFmpeg 5.x+ uses timeout
90
+ return base_options + ["-timeout", "5000000"]
91
+
92
+
93
+ def log_ffmpeg_version_info():
94
+ """Log information about FFmpeg compatibility."""
95
+ version = get_ffmpeg_version()
96
+ major, minor, patch = version
97
+
98
+ logging.info(f"Detected FFmpeg version: {major}.{minor}.{patch}")
99
+
100
+ if major == 4 and minor == 4:
101
+ logging.info("Using 'stimeout' parameter for FFmpeg 4.4.x compatibility")
102
+ else:
103
+ logging.info(f"Using 'timeout' parameter for FFmpeg {major}.{minor}.{patch}")
104
+
105
+ logging.info("RTSP configuration optimized for embedded devices")
106
+
107
+
108
+ def get_stream_timeout_duration(stream_type: str) -> int:
109
+ """
110
+ Get appropriate timeout duration for different stream types.
111
+
112
+ Args:
113
+ stream_type (str): Type of stream (rtsp, hls, direct, etc.)
114
+
115
+ Returns:
116
+ int: Timeout duration in seconds
117
+ """
118
+ timeouts = {
119
+ "rtsp": 30, # RTSP streams may take longer to connect
120
+ "hls": 20, # HLS streams need time for manifest download
121
+ "direct": 10, # Direct device access should be faster
122
+ "video_file": 5 # Local files should be very fast
123
+ }
124
+ return timeouts.get(stream_type, 15) # Default 15 seconds
@@ -8,6 +8,7 @@ import sys
8
8
  import platform
9
9
  from pathlib import Path
10
10
  from urllib.parse import urlparse
11
+ from .FFmpegUtil import get_rtsp_probe_options
11
12
 
12
13
 
13
14
  try:
@@ -289,8 +290,10 @@ class VideoProbeUtil:
289
290
  "-show_entries", "stream=width,height,avg_frame_rate", "-of", "json"]
290
291
 
291
292
  if stream_type == "rtsp":
292
- cmd.insert(1, "-rtsp_transport")
293
- cmd.insert(2, "tcp")
293
+ probe_options = get_rtsp_probe_options()
294
+ # Insert options at the beginning (after ffprobe)
295
+ for i, option in enumerate(probe_options):
296
+ cmd.insert(1 + i, option)
294
297
 
295
298
  cmd.append(video_url)
296
299
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: nedo-vision-worker
3
- Version: 1.2.0
3
+ Version: 1.2.1
4
4
  Summary: Nedo Vision Worker Service Library for AI Vision Processing
5
5
  Author-email: Willy Achmat Fauzi <willy.achmat@gmail.com>
6
6
  Maintainer-email: Willy Achmat Fauzi <willy.achmat@gmail.com>
@@ -1,5 +1,5 @@
1
- nedo_vision_worker/__init__.py,sha256=8AbQ3PK5CGdbnFRLBVzw8dcVQNHlNS_bBiqyygqIJ-Q,203
2
- nedo_vision_worker/cli.py,sha256=d7oDe3wJMfXd-ddStnyFASkLU0F3VemFsD9i0K7CYqU,7457
1
+ nedo_vision_worker/__init__.py,sha256=OuQTi_CjaQDpS1kVellEttgj1dkluSOCwxE0teArbyY,203
2
+ nedo_vision_worker/cli.py,sha256=ddWspJmSgVkcUYvRdkvTtMNuMTDvNCqLLuMVU9KE3Ik,7457
3
3
  nedo_vision_worker/doctor.py,sha256=uZ-NM_PfaTG5CG5OWFnl7cEsOTBWMGXNuKWuTV07deg,47228
4
4
  nedo_vision_worker/worker_service.py,sha256=rXUVmyxcJPGhQEZ4UQvjQS5UqlnLBYudHQZCj0dQDxo,10421
5
5
  nedo_vision_worker/config/ConfigurationManager.py,sha256=QrQaQ9Cdjpkcr2JE_miyrWJIZmMgZwJYBz-wE45Zzes,8011
@@ -63,18 +63,19 @@ nedo_vision_worker/services/SharedVideoStreamServer.py,sha256=WMKVxkzMoyfbgYiJ0f
63
63
  nedo_vision_worker/services/SystemUsageClient.py,sha256=PbRuwDWKnMarcnkGtOKfYB5nA-3DeKv7V5_hZr8EDEo,3200
64
64
  nedo_vision_worker/services/SystemWideDeviceCoordinator.py,sha256=9zBJMCbTMZS7gwN67rFpoUiTr82El2rpIO7DKFzeMjM,9417
65
65
  nedo_vision_worker/services/VideoSharingDaemon.py,sha256=hYMjUIKNUVT1qSxuUuHN-7Bd85MDkxfqslxDLe2PBYQ,29721
66
- nedo_vision_worker/services/VideoStreamClient.py,sha256=jSStEGjIHId4GseL-eE7FNGYU1CXgLaSjOm5CFVliPE,6828
66
+ nedo_vision_worker/services/VideoStreamClient.py,sha256=QSgUV3LijYrNdnBG1ylABOdUaSatQamfXaqJhAiol9M,7260
67
67
  nedo_vision_worker/services/WorkerSourceClient.py,sha256=vDZeCuHL5QQ2-knZ4TOSA59jzmbbThGIwFKKLEZ72Ws,9198
68
- nedo_vision_worker/services/WorkerSourcePipelineClient.py,sha256=rkKTPDWDgXhutMTqo_qvGvx1uVkhHcgi-3mJMywub8s,17705
68
+ nedo_vision_worker/services/WorkerSourcePipelineClient.py,sha256=amhZOua0lmlWl7ZkU-SSbT2E1Y5D-uKde9bDCVxOqM4,17924
69
69
  nedo_vision_worker/services/WorkerSourceUpdater.py,sha256=MsUsKL75sXj2odCcbupkFDW0KXg9LSu6-67iMWpYkHs,7679
70
70
  nedo_vision_worker/services/WorkerStatusClient.py,sha256=7kC5EZjEBwWtHOE6UQ29OPCpYnv_6HSuH7Tc0alK_2Q,2531
71
71
  nedo_vision_worker/services/__init__.py,sha256=Nqnn8clbgv-5l0PgxcTOldg8mkMKrFn4TvPL-rYUUGg,1
72
+ nedo_vision_worker/util/FFmpegUtil.py,sha256=_TRA_Q2CAKatrbhOMKG5Uhhk6FrMJ6sbwMnd0Qwq0co,4086
72
73
  nedo_vision_worker/util/HardwareID.py,sha256=rSW8-6stm7rjXEdkYGqXMUn56gyw62YiWnSwZQVCCLM,4315
73
74
  nedo_vision_worker/util/ImageUploader.py,sha256=2xipN3fwpKgFmbvoGIdElpGn5ARJyrgR4dXtbRf73hw,3764
74
75
  nedo_vision_worker/util/Networking.py,sha256=uOtL8HkKZXJp02ZZIHWYMAvAsaYb7BsAPTncfdvJx2c,3241
75
76
  nedo_vision_worker/util/PlatformDetector.py,sha256=-iLPrKs7hp_oltkCI3hESJQkC2uRyu1-8mAbZrvgWx0,1501
76
77
  nedo_vision_worker/util/SystemMonitor.py,sha256=2MWYaEXoL91UANT_-SuDWrFMq1ajPorh8co6Py9PV_c,11300
77
- nedo_vision_worker/util/VideoProbeUtil.py,sha256=whgvZvSeO5y7IG3E1mxn5KRKYqxyrGtLJowV3nHgwYA,13181
78
+ nedo_vision_worker/util/VideoProbeUtil.py,sha256=1ViUjt6NSMilquapHf6XC0h93OwhA40LwGSnYOtpMh0,13362
78
79
  nedo_vision_worker/util/__init__.py,sha256=Nqnn8clbgv-5l0PgxcTOldg8mkMKrFn4TvPL-rYUUGg,1
79
80
  nedo_vision_worker/worker/CoreActionWorker.py,sha256=lb7zPY3yui6I3F4rX4Ii7JwpWZahLEO72rh3iWOgFmg,5441
80
81
  nedo_vision_worker/worker/DataSenderWorker.py,sha256=o32MT28EqYwAPmd9NKhX3rfNlDKekNOI2n8mZ6s8CpU,7162
@@ -90,8 +91,8 @@ nedo_vision_worker/worker/SystemUsageManager.py,sha256=StutV4UyLUfduYfK20de4SbPd
90
91
  nedo_vision_worker/worker/VideoStreamWorker.py,sha256=5n6v1PNO7IB-jj_McALLkUP-cBjJoIEw4UiSAs3vTb0,7606
91
92
  nedo_vision_worker/worker/WorkerManager.py,sha256=T0vMfhOd7YesgQ9o2w6soeJ6n9chUAcuwcGe7p31xr0,5298
92
93
  nedo_vision_worker/worker/__init__.py,sha256=Nqnn8clbgv-5l0PgxcTOldg8mkMKrFn4TvPL-rYUUGg,1
93
- nedo_vision_worker-1.2.0.dist-info/METADATA,sha256=uj39xqzh3cXjTI02_xRZpZVPieB8PjqLUxIOvEbT12M,14591
94
- nedo_vision_worker-1.2.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
95
- nedo_vision_worker-1.2.0.dist-info/entry_points.txt,sha256=LrglS-8nCi8C_PL_pa6uxdgCe879hBETHDVXAckvs-8,60
96
- nedo_vision_worker-1.2.0.dist-info/top_level.txt,sha256=vgilhlkyD34YsEKkaBabmhIpcKSvF3XpzD2By68L-XI,19
97
- nedo_vision_worker-1.2.0.dist-info/RECORD,,
94
+ nedo_vision_worker-1.2.1.dist-info/METADATA,sha256=GUzjnngaGQ7i48oY3BMpdPB701o8_n2LxwlayNJb3uw,14591
95
+ nedo_vision_worker-1.2.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
96
+ nedo_vision_worker-1.2.1.dist-info/entry_points.txt,sha256=LrglS-8nCi8C_PL_pa6uxdgCe879hBETHDVXAckvs-8,60
97
+ nedo_vision_worker-1.2.1.dist-info/top_level.txt,sha256=vgilhlkyD34YsEKkaBabmhIpcKSvF3XpzD2By68L-XI,19
98
+ nedo_vision_worker-1.2.1.dist-info/RECORD,,