nedo-vision-worker 1.3.12__py3-none-any.whl → 1.3.14__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.3.12"
9
+ __version__ = "1.3.14"
10
10
  __all__ = ["WorkerService"]
@@ -43,6 +43,8 @@ def start_worker(
43
43
  rtmp_publish_query_strings=rtmp_publish_query_strings
44
44
  )
45
45
 
46
+ print(f"Got URL {RTMPUrl.get_publish_url("testtt")}")
47
+
46
48
  service = WorkerService(
47
49
  configuration_manager=configuration_manager,
48
50
  server_host=server_host,
@@ -1,6 +1,7 @@
1
1
  import subprocess
2
2
  import logging
3
3
  import os
4
+ import threading
4
5
  from ..util.EncoderSelector import EncoderSelector
5
6
  from ..util.RTMPUrl import RTMPUrl
6
7
 
@@ -53,6 +54,7 @@ class FileToRTMPStreamer:
53
54
  "-g", str(self.fps),
54
55
  "-vf", f"scale={self.resolution}",
55
56
 
57
+ "-loglevel", "error",
56
58
  "-an", # Disable audio
57
59
 
58
60
  "-f", "flv",
@@ -63,11 +65,17 @@ class FileToRTMPStreamer:
63
65
  with open(os.devnull, "w") as devnull:
64
66
  self.process = subprocess.Popen(
65
67
  ffmpeg_command,
66
- stdout=devnull,
67
- stderr=devnull,
68
- text=True
68
+ stdout=subprocess.DEVNULL,
69
+ stderr=subprocess.PIPE,
70
+ text=True,
71
+ bufsize=1
69
72
  )
70
73
 
74
+ threading.Thread(
75
+ target=self._monitor_ffmpeg_errors,
76
+ daemon=True
77
+ ).start()
78
+
71
79
  logging.info("✅ [APP] FFmpeg file stream process started successfully.")
72
80
  self.process.wait() # Block until process is terminated
73
81
 
@@ -81,3 +89,43 @@ class FileToRTMPStreamer:
81
89
  self.process.terminate()
82
90
  self.process.wait()
83
91
  logging.info("🛑 [APP] FFmpeg file stream process terminated.")
92
+
93
+ def _classify_ffmpeg_error(self, msg: str):
94
+ if "No such file or directory" in msg:
95
+ return "FILE_NOT_FOUND"
96
+
97
+ if "Invalid data found" in msg:
98
+ return "INVALID_MEDIA"
99
+
100
+ if "encoder" in msg.lower() or "nvenc" in msg.lower():
101
+ return "ENCODER_ERROR"
102
+
103
+ if "server returned" in msg.lower() or "rtmp" in msg.lower():
104
+ return "RTMP_ERROR"
105
+
106
+ if "broken pipe" in msg.lower():
107
+ return "PIPE_BROKEN"
108
+
109
+ return "UNKNOWN_ERROR"
110
+
111
+ def _monitor_ffmpeg_errors(self):
112
+ """Read FFmpeg stderr and log meaningful errors."""
113
+ try:
114
+ for line in iter(self.process.stderr.readline, ''):
115
+ if not line:
116
+ break
117
+
118
+ msg = line.strip()
119
+ if not msg:
120
+ continue
121
+
122
+ error_type = self._classify_ffmpeg_error(msg)
123
+ logging.error(f"🔥 [FFMPEG][{error_type}] {msg}")
124
+
125
+ # Stop on critical errors
126
+ if error_type != "UNKNOWN_ERROR":
127
+ logging.error("🛑 [APP] Critical FFmpeg error detected. Stopping stream.")
128
+ self.stop_stream()
129
+ break
130
+ except Exception as e:
131
+ logging.error(f"🚨 [APP] Error while reading FFmpeg stderr: {e}")
@@ -2,9 +2,13 @@ import subprocess
2
2
  import logging
3
3
  import time
4
4
  import os
5
+ import threading
5
6
  from urllib.parse import urlparse
6
7
  from ..util.EncoderSelector import EncoderSelector
7
8
  from ..util.RTMPUrl import RTMPUrl
9
+
10
+ logger = logging.getLogger(__name__)
11
+
8
12
  class RTSPtoRTMPStreamer:
9
13
  def __init__(self, rtsp_url, stream_key, fps=30, resolution="1280x720", duration=120):
10
14
  """
@@ -34,14 +38,14 @@ class RTSPtoRTMPStreamer:
34
38
  def start_stream(self):
35
39
  """Start streaming RTSP to RTMP using FFmpeg without logs."""
36
40
  if self._detect_stream_type(self.rtsp_url) == "unknown":
37
- logging.error(f"❌ [APP] Invalid RTSP URL: {self.rtsp_url}")
41
+ logger.error(f"❌ [APP] Invalid RTSP URL: {self.rtsp_url}")
38
42
  return
39
43
 
40
- logging.info(f"📡 [APP] Starting RTSP to RTMP stream: {self.rtsp_url} → {self.rtmp_url} for {self.duration} seconds")
44
+ logger.info(f"📡 [APP] Starting RTSP to RTMP stream: {self.rtsp_url} → {self.rtmp_url} for {self.duration} seconds")
41
45
 
42
46
  # Get optimal encoder for hardware
43
47
  encoder_args, encoder_name = EncoderSelector.get_encoder_args()
44
- logging.info(f"🎬 [APP] Using encoder: {encoder_name}")
48
+ logger.info(f"🎬 [APP] Using encoder: {encoder_name}")
45
49
 
46
50
  # FFmpeg command
47
51
  ffmpeg_command = [
@@ -61,6 +65,8 @@ class RTSPtoRTMPStreamer:
61
65
  "-g", "25", # ✅ Reduce GOP size for faster keyframes
62
66
  "-vf", "scale='min(1024,iw)':-2", # ✅ Resize width to max 1024px
63
67
 
68
+ "-loglevel", "error",
69
+
64
70
  # ❌ Disable Audio (Avoid unnecessary encoding overhead)
65
71
  "-an",
66
72
 
@@ -73,23 +79,30 @@ class RTSPtoRTMPStreamer:
73
79
  with open(os.devnull, "w") as devnull:
74
80
  self.process = subprocess.Popen(
75
81
  ffmpeg_command,
76
- stdout=devnull, # Redirect stdout to null
77
- stderr=devnull, # Redirect stderr to null
78
- text=True
82
+ stdout=subprocess.DEVNULL,
83
+ stderr=subprocess.PIPE,
84
+ text=True,
85
+ bufsize=1
79
86
  )
80
87
 
81
- logging.info("✅ [APP] FFmpeg process started successfully.")
88
+ threading.Thread(
89
+ target=self._monitor_ffmpeg_errors,
90
+ daemon=True
91
+ ).start()
92
+
93
+
94
+ logger.info("✅ [APP] FFmpeg process started successfully.")
82
95
 
83
96
  start_time = time.time()
84
97
  while self.process.poll() is None:
85
98
  if time.time() - start_time > self.duration:
86
- logging.info(f"⏳ [APP] Streaming duration {self.duration}s reached. Stopping stream...")
99
+ logger.info(f"⏳ [APP] Streaming duration {self.duration}s reached. Stopping stream...")
87
100
  self.stop_stream()
88
101
  break
89
102
  time.sleep(1)
90
103
 
91
104
  except Exception as e:
92
- logging.error(f"🚨 [APP] Failed to start FFmpeg: {e}")
105
+ logger.error(f"🚨 [APP] Failed to start FFmpeg: {e}")
93
106
  self.stop_stream()
94
107
 
95
108
  def stop_stream(self):
@@ -97,4 +110,39 @@ class RTSPtoRTMPStreamer:
97
110
  if self.process:
98
111
  self.process.terminate()
99
112
  self.process.wait()
100
- logging.info("FFmpeg process terminated.")
113
+ logger.info("FFmpeg process terminated.")
114
+
115
+
116
+ def _monitor_ffmpeg_errors(self):
117
+ for line in iter(self.process.stderr.readline, ''):
118
+ if not line:
119
+ break
120
+
121
+ msg = line.strip()
122
+ if not msg:
123
+ continue
124
+
125
+ error_type = self._classify_ffmpeg_error(msg)
126
+
127
+ logger.error(f"🔥 [FFMPEG][{error_type}] {msg}")
128
+
129
+ if error_type != "UNKNOWN_ERROR":
130
+ logger.error("🛑 [APP] Critical streaming error, stopping FFmpeg.")
131
+ self.stop_stream()
132
+ break
133
+
134
+
135
+ def _classify_ffmpeg_error(self, msg: str):
136
+ if "rtsp" in msg.lower() and "connection" in msg.lower():
137
+ return "RTSP_CONNECTION_ERROR"
138
+
139
+ if "server returned" in msg.lower():
140
+ return "RTMP_SERVER_ERROR"
141
+
142
+ if "encoder" in msg.lower() or "nvenc" in msg.lower():
143
+ return "ENCODER_ERROR"
144
+
145
+ if "broken pipe" in msg.lower():
146
+ return "PIPE_BROKEN"
147
+
148
+ return "UNKNOWN_ERROR"
@@ -109,25 +109,6 @@ class VideoStreamWorker:
109
109
 
110
110
  def _process_video_preview_message(self, message):
111
111
  """Process messages related to video preview streaming."""
112
-
113
- print("masuk broooo anjayyy")
114
-
115
- # # Try segmentation fault
116
- # import ctypes
117
-
118
- # print("Attempting to access a NULL pointer...")
119
-
120
- # # Method 1: Dereference a null pointer
121
- # ctypes.string_at(0)
122
-
123
- # # Method 2: Write to a protected memory address
124
- # ctypes.memset(0, 0, 1)
125
-
126
- # # Method 3: Access invalid pointer
127
- # invalid_ptr = ctypes.cast(0, ctypes.POINTER(ctypes.c_int))
128
- # print(invalid_ptr.contents)
129
-
130
-
131
112
  try:
132
113
  data = json.loads(message)
133
114
  worker_id = data.get("workerId")
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: nedo-vision-worker
3
- Version: 1.3.12
3
+ Version: 1.3.14
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=RoVtZhuxCdarwYu83xdXmrvTl26wSon6_uw47nooOHQ,204
2
- nedo_vision_worker/bootstrap.py,sha256=pZ_2sLTQw0PO6hyDTgYoZgdpGJ7W6F7rwHWqnNAuUEs,1652
1
+ nedo_vision_worker/__init__.py,sha256=YIYYzNgmWVZKH7nI0wZ4bsn5ApvbaM7xF0hpBGOC6V8,204
2
+ nedo_vision_worker/bootstrap.py,sha256=5zqrR8rJL7SbYcpoDOT_fisXU7XcvXzRaBnBvOrJzSQ,1711
3
3
  nedo_vision_worker/cli.py,sha256=Yov2_YqZzOEPn6Ce-zZu5exCRCxg93l7xPgISL79Jf8,2769
4
4
  nedo_vision_worker/doctor.py,sha256=wNkpe8gLVd76Y_ViyK2h1ZFdqeSl37MnzZN5frWKu30,48410
5
5
  nedo_vision_worker/worker_service.py,sha256=4SoWqjuz7lQKByU48-yBLV0CeTmX9LIJ5uIc-vmn6ck,7318
@@ -52,13 +52,13 @@ nedo_vision_worker/services/AIModelClient.py,sha256=lxRNax6FR-pV0G1NpJnlaqjbQeu3
52
52
  nedo_vision_worker/services/ConnectionInfoClient.py,sha256=toC9zuY2Hrx1Cwq8Gycy_iFlaG1DvFT4qewlLlitpEQ,2214
53
53
  nedo_vision_worker/services/DatasetSourceClient.py,sha256=O5a7onxFl0z47zXaMXWxHAMPuuc-i_vzkd2w5fwrukc,3319
54
54
  nedo_vision_worker/services/DirectDeviceToRTMPStreamer.py,sha256=YO_z1DPQgVoR2hakmd5vP07D8_DYkWYaWT68mOT4rUk,24731
55
- nedo_vision_worker/services/FileToRTMPServer.py,sha256=ZxcV1sjvvTqfeIuRuwa8uxKbKATYnxP7xwxX5cWdlTc,2904
55
+ nedo_vision_worker/services/FileToRTMPServer.py,sha256=YSMB0rYqQo5T1lmglqo3PYXOMOJx5cSXjO7lbGbnkmg,4492
56
56
  nedo_vision_worker/services/GrpcClientBase.py,sha256=RkJDGRsXu5HalMDR8cOsIaoFf5tA_cLTkh5euBPyo2M,6852
57
57
  nedo_vision_worker/services/GrpcClientManager.py,sha256=DLXekmxlQogLo8V9-TNDXtyHT_UG-BaggqwsIups55k,5568
58
58
  nedo_vision_worker/services/GrpcConnection.py,sha256=UNjaUC4ZcXuteHQx8AAAL5ymYkT1OpoIvyCYPUc3tCI,4915
59
59
  nedo_vision_worker/services/ImageUploadClient.py,sha256=T353YsRfm74G7Mh-eWr5nvdQHXTfpKwHJFmNW8HyjT8,3019
60
60
  nedo_vision_worker/services/PPEDetectionClient.py,sha256=3oE_Y0Avw_kcWKgTA7qmChq32woW7JerWefrCxllUYU,5172
61
- nedo_vision_worker/services/RTSPtoRTMPStreamer.py,sha256=UoSMRlp9r7QCQRNkPjrVO9OmDeGIgJRxD1la6YFOPyk,3837
61
+ nedo_vision_worker/services/RTSPtoRTMPStreamer.py,sha256=xmmEg3Wi_1PoE-x2OOzL-vYQoz9MVEhRcvqDC8xT_MM,5058
62
62
  nedo_vision_worker/services/RestrictedAreaClient.py,sha256=TD2Y5UJ0NjXgNFNgwS5ze4P-5jWwgrP0j0Nlyyd7-6Q,4844
63
63
  nedo_vision_worker/services/SharedDirectDeviceClient.py,sha256=dylMhqpMsfK_UKLWIVL-ApJRP4g-NCP_55xvlGYBiwo,10760
64
64
  nedo_vision_worker/services/SharedVideoStreamServer.py,sha256=WMKVxkzMoyfbgYiJ0fQOT-Ujz9btz6FLlaDP738yfoY,11601
@@ -94,11 +94,11 @@ nedo_vision_worker/worker/PipelinePreviewWorker.py,sha256=owFiBbktcOZkdImQeykZSe
94
94
  nedo_vision_worker/worker/RabbitMQListener.py,sha256=Gwn7VpRg0fMZ0fva98eOnTzZ4HPFf2i_ZCUgwfTdyYQ,6768
95
95
  nedo_vision_worker/worker/RestrictedAreaManager.py,sha256=Pz2M9KPSMa1QPXZeYhyN9ih4eX6wmkNS_ZPu5KrvNxY,5927
96
96
  nedo_vision_worker/worker/SystemUsageManager.py,sha256=mkh4sT-HkIEY1CJHMEG6LP9ATu39YXvLRLyf995OkoQ,5315
97
- nedo_vision_worker/worker/VideoStreamWorker.py,sha256=e6J_9en03JHkWLBqHR5QDRQHWdhcD3Nz3pN8GgkPTgk,8052
97
+ nedo_vision_worker/worker/VideoStreamWorker.py,sha256=0g36xplrJSA2h_dDzlxFD4Yi1p5OyCjY1ZQ_drqRcTA,7567
98
98
  nedo_vision_worker/worker/WorkerManager.py,sha256=2bxXi19fp3p1qjYBStYRdVVgko8dnevXx1_M_sqH5og,5521
99
99
  nedo_vision_worker/worker/__init__.py,sha256=Nqnn8clbgv-5l0PgxcTOldg8mkMKrFn4TvPL-rYUUGg,1
100
- nedo_vision_worker-1.3.12.dist-info/METADATA,sha256=9ZtnikwQ8W5CZk726SpCC1eQi5TUY_6qvaQ2lucqexM,14654
101
- nedo_vision_worker-1.3.12.dist-info/WHEEL,sha256=qELbo2s1Yzl39ZmrAibXA2jjPLUYfnVhUNTlyF1rq0Y,92
102
- nedo_vision_worker-1.3.12.dist-info/entry_points.txt,sha256=LrglS-8nCi8C_PL_pa6uxdgCe879hBETHDVXAckvs-8,60
103
- nedo_vision_worker-1.3.12.dist-info/top_level.txt,sha256=vgilhlkyD34YsEKkaBabmhIpcKSvF3XpzD2By68L-XI,19
104
- nedo_vision_worker-1.3.12.dist-info/RECORD,,
100
+ nedo_vision_worker-1.3.14.dist-info/METADATA,sha256=9UhVy5tES0eLkOQz9vHjD19YxZ9TdEIX7YWkUz_PnkU,14654
101
+ nedo_vision_worker-1.3.14.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
102
+ nedo_vision_worker-1.3.14.dist-info/entry_points.txt,sha256=LrglS-8nCi8C_PL_pa6uxdgCe879hBETHDVXAckvs-8,60
103
+ nedo_vision_worker-1.3.14.dist-info/top_level.txt,sha256=vgilhlkyD34YsEKkaBabmhIpcKSvF3XpzD2By68L-XI,19
104
+ nedo_vision_worker-1.3.14.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (80.10.1)
2
+ Generator: setuptools (80.10.2)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5