nedo-vision-worker 1.3.11__tar.gz → 1.3.13__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.
Files changed (110) hide show
  1. {nedo_vision_worker-1.3.11 → nedo_vision_worker-1.3.13}/PKG-INFO +1 -1
  2. {nedo_vision_worker-1.3.11 → nedo_vision_worker-1.3.13}/nedo_vision_worker/__init__.py +1 -1
  3. {nedo_vision_worker-1.3.11 → nedo_vision_worker-1.3.13}/nedo_vision_worker/bootstrap.py +9 -0
  4. {nedo_vision_worker-1.3.11 → nedo_vision_worker-1.3.13}/nedo_vision_worker/cli.py +7 -0
  5. {nedo_vision_worker-1.3.11 → nedo_vision_worker-1.3.13}/nedo_vision_worker/config/ConfigurationManager.py +10 -1
  6. {nedo_vision_worker-1.3.11 → nedo_vision_worker-1.3.13}/nedo_vision_worker/config/DummyConfigurationManager.py +3 -0
  7. {nedo_vision_worker-1.3.11 → nedo_vision_worker-1.3.13}/nedo_vision_worker/services/ConnectionInfoClient.py +1 -1
  8. {nedo_vision_worker-1.3.11 → nedo_vision_worker-1.3.13}/nedo_vision_worker/services/DirectDeviceToRTMPStreamer.py +3 -3
  9. {nedo_vision_worker-1.3.11 → nedo_vision_worker-1.3.13}/nedo_vision_worker/services/FileToRTMPServer.py +3 -2
  10. {nedo_vision_worker-1.3.11 → nedo_vision_worker-1.3.13}/nedo_vision_worker/services/RTSPtoRTMPStreamer.py +60 -12
  11. nedo_vision_worker-1.3.13/nedo_vision_worker/util/RTMPUrl.py +24 -0
  12. {nedo_vision_worker-1.3.11 → nedo_vision_worker-1.3.13}/nedo_vision_worker/worker/VideoStreamWorker.py +3 -3
  13. {nedo_vision_worker-1.3.11 → nedo_vision_worker-1.3.13}/nedo_vision_worker.egg-info/PKG-INFO +1 -1
  14. {nedo_vision_worker-1.3.11 → nedo_vision_worker-1.3.13}/nedo_vision_worker.egg-info/SOURCES.txt +1 -0
  15. {nedo_vision_worker-1.3.11 → nedo_vision_worker-1.3.13}/README.md +0 -0
  16. {nedo_vision_worker-1.3.11 → nedo_vision_worker-1.3.13}/nedo_vision_worker/config/ConfigurationManagerInterface.py +0 -0
  17. {nedo_vision_worker-1.3.11 → nedo_vision_worker-1.3.13}/nedo_vision_worker/config/__init__.py +0 -0
  18. {nedo_vision_worker-1.3.11 → nedo_vision_worker-1.3.13}/nedo_vision_worker/database/DatabaseManager.py +0 -0
  19. {nedo_vision_worker-1.3.11 → nedo_vision_worker-1.3.13}/nedo_vision_worker/database/__init__.py +0 -0
  20. {nedo_vision_worker-1.3.11 → nedo_vision_worker-1.3.13}/nedo_vision_worker/doctor.py +0 -0
  21. {nedo_vision_worker-1.3.11 → nedo_vision_worker-1.3.13}/nedo_vision_worker/models/__init__.py +0 -0
  22. {nedo_vision_worker-1.3.11 → nedo_vision_worker-1.3.13}/nedo_vision_worker/models/ai_model.py +0 -0
  23. {nedo_vision_worker-1.3.11 → nedo_vision_worker-1.3.13}/nedo_vision_worker/models/auth.py +0 -0
  24. {nedo_vision_worker-1.3.11 → nedo_vision_worker-1.3.13}/nedo_vision_worker/models/config.py +0 -0
  25. {nedo_vision_worker-1.3.11 → nedo_vision_worker-1.3.13}/nedo_vision_worker/models/dataset_source.py +0 -0
  26. {nedo_vision_worker-1.3.11 → nedo_vision_worker-1.3.13}/nedo_vision_worker/models/logs.py +0 -0
  27. {nedo_vision_worker-1.3.11 → nedo_vision_worker-1.3.13}/nedo_vision_worker/models/ppe_detection.py +0 -0
  28. {nedo_vision_worker-1.3.11 → nedo_vision_worker-1.3.13}/nedo_vision_worker/models/ppe_detection_label.py +0 -0
  29. {nedo_vision_worker-1.3.11 → nedo_vision_worker-1.3.13}/nedo_vision_worker/models/restricted_area_violation.py +0 -0
  30. {nedo_vision_worker-1.3.11 → nedo_vision_worker-1.3.13}/nedo_vision_worker/models/user.py +0 -0
  31. {nedo_vision_worker-1.3.11 → nedo_vision_worker-1.3.13}/nedo_vision_worker/models/worker_source.py +0 -0
  32. {nedo_vision_worker-1.3.11 → nedo_vision_worker-1.3.13}/nedo_vision_worker/models/worker_source_pipeline.py +0 -0
  33. {nedo_vision_worker-1.3.11 → nedo_vision_worker-1.3.13}/nedo_vision_worker/models/worker_source_pipeline_config.py +0 -0
  34. {nedo_vision_worker-1.3.11 → nedo_vision_worker-1.3.13}/nedo_vision_worker/models/worker_source_pipeline_debug.py +0 -0
  35. {nedo_vision_worker-1.3.11 → nedo_vision_worker-1.3.13}/nedo_vision_worker/models/worker_source_pipeline_detection.py +0 -0
  36. {nedo_vision_worker-1.3.11 → nedo_vision_worker-1.3.13}/nedo_vision_worker/protos/AIModelService_pb2.py +0 -0
  37. {nedo_vision_worker-1.3.11 → nedo_vision_worker-1.3.13}/nedo_vision_worker/protos/AIModelService_pb2_grpc.py +0 -0
  38. {nedo_vision_worker-1.3.11 → nedo_vision_worker-1.3.13}/nedo_vision_worker/protos/DatasetSourceService_pb2.py +0 -0
  39. {nedo_vision_worker-1.3.11 → nedo_vision_worker-1.3.13}/nedo_vision_worker/protos/DatasetSourceService_pb2_grpc.py +0 -0
  40. {nedo_vision_worker-1.3.11 → nedo_vision_worker-1.3.13}/nedo_vision_worker/protos/HumanDetectionService_pb2.py +0 -0
  41. {nedo_vision_worker-1.3.11 → nedo_vision_worker-1.3.13}/nedo_vision_worker/protos/HumanDetectionService_pb2_grpc.py +0 -0
  42. {nedo_vision_worker-1.3.11 → nedo_vision_worker-1.3.13}/nedo_vision_worker/protos/PPEDetectionService_pb2.py +0 -0
  43. {nedo_vision_worker-1.3.11 → nedo_vision_worker-1.3.13}/nedo_vision_worker/protos/PPEDetectionService_pb2_grpc.py +0 -0
  44. {nedo_vision_worker-1.3.11 → nedo_vision_worker-1.3.13}/nedo_vision_worker/protos/VisionWorkerService_pb2.py +0 -0
  45. {nedo_vision_worker-1.3.11 → nedo_vision_worker-1.3.13}/nedo_vision_worker/protos/VisionWorkerService_pb2_grpc.py +0 -0
  46. {nedo_vision_worker-1.3.11 → nedo_vision_worker-1.3.13}/nedo_vision_worker/protos/WorkerSourcePipelineService_pb2.py +0 -0
  47. {nedo_vision_worker-1.3.11 → nedo_vision_worker-1.3.13}/nedo_vision_worker/protos/WorkerSourcePipelineService_pb2_grpc.py +0 -0
  48. {nedo_vision_worker-1.3.11 → nedo_vision_worker-1.3.13}/nedo_vision_worker/protos/WorkerSourceService_pb2.py +0 -0
  49. {nedo_vision_worker-1.3.11 → nedo_vision_worker-1.3.13}/nedo_vision_worker/protos/WorkerSourceService_pb2_grpc.py +0 -0
  50. {nedo_vision_worker-1.3.11 → nedo_vision_worker-1.3.13}/nedo_vision_worker/protos/__init__.py +0 -0
  51. {nedo_vision_worker-1.3.11 → nedo_vision_worker-1.3.13}/nedo_vision_worker/repositories/AIModelRepository.py +0 -0
  52. {nedo_vision_worker-1.3.11 → nedo_vision_worker-1.3.13}/nedo_vision_worker/repositories/DatasetSourceRepository.py +0 -0
  53. {nedo_vision_worker-1.3.11 → nedo_vision_worker-1.3.13}/nedo_vision_worker/repositories/PPEDetectionRepository.py +0 -0
  54. {nedo_vision_worker-1.3.11 → nedo_vision_worker-1.3.13}/nedo_vision_worker/repositories/RestrictedAreaRepository.py +0 -0
  55. {nedo_vision_worker-1.3.11 → nedo_vision_worker-1.3.13}/nedo_vision_worker/repositories/WorkerSourcePipelineDebugRepository.py +0 -0
  56. {nedo_vision_worker-1.3.11 → nedo_vision_worker-1.3.13}/nedo_vision_worker/repositories/WorkerSourcePipelineDetectionRepository.py +0 -0
  57. {nedo_vision_worker-1.3.11 → nedo_vision_worker-1.3.13}/nedo_vision_worker/repositories/WorkerSourcePipelineRepository.py +0 -0
  58. {nedo_vision_worker-1.3.11 → nedo_vision_worker-1.3.13}/nedo_vision_worker/repositories/WorkerSourceRepository.py +0 -0
  59. {nedo_vision_worker-1.3.11 → nedo_vision_worker-1.3.13}/nedo_vision_worker/repositories/__init__.py +0 -0
  60. {nedo_vision_worker-1.3.11 → nedo_vision_worker-1.3.13}/nedo_vision_worker/services/AIModelClient.py +0 -0
  61. {nedo_vision_worker-1.3.11 → nedo_vision_worker-1.3.13}/nedo_vision_worker/services/DatasetSourceClient.py +0 -0
  62. {nedo_vision_worker-1.3.11 → nedo_vision_worker-1.3.13}/nedo_vision_worker/services/GrpcClientBase.py +0 -0
  63. {nedo_vision_worker-1.3.11 → nedo_vision_worker-1.3.13}/nedo_vision_worker/services/GrpcClientManager.py +0 -0
  64. {nedo_vision_worker-1.3.11 → nedo_vision_worker-1.3.13}/nedo_vision_worker/services/GrpcConnection.py +0 -0
  65. {nedo_vision_worker-1.3.11 → nedo_vision_worker-1.3.13}/nedo_vision_worker/services/ImageUploadClient.py +0 -0
  66. {nedo_vision_worker-1.3.11 → nedo_vision_worker-1.3.13}/nedo_vision_worker/services/PPEDetectionClient.py +0 -0
  67. {nedo_vision_worker-1.3.11 → nedo_vision_worker-1.3.13}/nedo_vision_worker/services/RestrictedAreaClient.py +0 -0
  68. {nedo_vision_worker-1.3.11 → nedo_vision_worker-1.3.13}/nedo_vision_worker/services/SharedDirectDeviceClient.py +0 -0
  69. {nedo_vision_worker-1.3.11 → nedo_vision_worker-1.3.13}/nedo_vision_worker/services/SharedVideoStreamServer.py +0 -0
  70. {nedo_vision_worker-1.3.11 → nedo_vision_worker-1.3.13}/nedo_vision_worker/services/SystemUsageClient.py +0 -0
  71. {nedo_vision_worker-1.3.11 → nedo_vision_worker-1.3.13}/nedo_vision_worker/services/SystemWideDeviceCoordinator.py +0 -0
  72. {nedo_vision_worker-1.3.11 → nedo_vision_worker-1.3.13}/nedo_vision_worker/services/VideoSharingDaemon.py +0 -0
  73. {nedo_vision_worker-1.3.11 → nedo_vision_worker-1.3.13}/nedo_vision_worker/services/VideoStreamClient.py +0 -0
  74. {nedo_vision_worker-1.3.11 → nedo_vision_worker-1.3.13}/nedo_vision_worker/services/WorkerSourceClient.py +0 -0
  75. {nedo_vision_worker-1.3.11 → nedo_vision_worker-1.3.13}/nedo_vision_worker/services/WorkerSourcePipelineClient.py +0 -0
  76. {nedo_vision_worker-1.3.11 → nedo_vision_worker-1.3.13}/nedo_vision_worker/services/WorkerSourceUpdater.py +0 -0
  77. {nedo_vision_worker-1.3.11 → nedo_vision_worker-1.3.13}/nedo_vision_worker/services/WorkerStatusClient.py +0 -0
  78. {nedo_vision_worker-1.3.11 → nedo_vision_worker-1.3.13}/nedo_vision_worker/services/__init__.py +0 -0
  79. {nedo_vision_worker-1.3.11 → nedo_vision_worker-1.3.13}/nedo_vision_worker/util/CorruptedImageValidator.py +0 -0
  80. {nedo_vision_worker-1.3.11 → nedo_vision_worker-1.3.13}/nedo_vision_worker/util/EncoderSelector.py +0 -0
  81. {nedo_vision_worker-1.3.11 → nedo_vision_worker-1.3.13}/nedo_vision_worker/util/FFmpegUtil.py +0 -0
  82. {nedo_vision_worker-1.3.11 → nedo_vision_worker-1.3.13}/nedo_vision_worker/util/HardwareID.py +0 -0
  83. {nedo_vision_worker-1.3.11 → nedo_vision_worker-1.3.13}/nedo_vision_worker/util/ImageUploader.py +0 -0
  84. {nedo_vision_worker-1.3.11 → nedo_vision_worker-1.3.13}/nedo_vision_worker/util/Networking.py +0 -0
  85. {nedo_vision_worker-1.3.11 → nedo_vision_worker-1.3.13}/nedo_vision_worker/util/PlatformDetector.py +0 -0
  86. {nedo_vision_worker-1.3.11 → nedo_vision_worker-1.3.13}/nedo_vision_worker/util/SystemMonitor.py +0 -0
  87. {nedo_vision_worker-1.3.11 → nedo_vision_worker-1.3.13}/nedo_vision_worker/util/VideoProbeUtil.py +0 -0
  88. {nedo_vision_worker-1.3.11 → nedo_vision_worker-1.3.13}/nedo_vision_worker/util/__init__.py +0 -0
  89. {nedo_vision_worker-1.3.11 → nedo_vision_worker-1.3.13}/nedo_vision_worker/worker/CoreActionWorker.py +0 -0
  90. {nedo_vision_worker-1.3.11 → nedo_vision_worker-1.3.13}/nedo_vision_worker/worker/DataSenderWorker.py +0 -0
  91. {nedo_vision_worker-1.3.11 → nedo_vision_worker-1.3.13}/nedo_vision_worker/worker/DataSyncWorker.py +0 -0
  92. {nedo_vision_worker-1.3.11 → nedo_vision_worker-1.3.13}/nedo_vision_worker/worker/DatasetFrameSender.py +0 -0
  93. {nedo_vision_worker-1.3.11 → nedo_vision_worker-1.3.13}/nedo_vision_worker/worker/DatasetFrameWorker.py +0 -0
  94. {nedo_vision_worker-1.3.11 → nedo_vision_worker-1.3.13}/nedo_vision_worker/worker/PPEDetectionManager.py +0 -0
  95. {nedo_vision_worker-1.3.11 → nedo_vision_worker-1.3.13}/nedo_vision_worker/worker/PipelineActionWorker.py +0 -0
  96. {nedo_vision_worker-1.3.11 → nedo_vision_worker-1.3.13}/nedo_vision_worker/worker/PipelineImageWorker.py +0 -0
  97. {nedo_vision_worker-1.3.11 → nedo_vision_worker-1.3.13}/nedo_vision_worker/worker/PipelinePreviewWorker.py +0 -0
  98. {nedo_vision_worker-1.3.11 → nedo_vision_worker-1.3.13}/nedo_vision_worker/worker/RabbitMQListener.py +0 -0
  99. {nedo_vision_worker-1.3.11 → nedo_vision_worker-1.3.13}/nedo_vision_worker/worker/RestrictedAreaManager.py +0 -0
  100. {nedo_vision_worker-1.3.11 → nedo_vision_worker-1.3.13}/nedo_vision_worker/worker/SystemUsageManager.py +0 -0
  101. {nedo_vision_worker-1.3.11 → nedo_vision_worker-1.3.13}/nedo_vision_worker/worker/WorkerManager.py +0 -0
  102. {nedo_vision_worker-1.3.11 → nedo_vision_worker-1.3.13}/nedo_vision_worker/worker/__init__.py +0 -0
  103. {nedo_vision_worker-1.3.11 → nedo_vision_worker-1.3.13}/nedo_vision_worker/worker_service.py +0 -0
  104. {nedo_vision_worker-1.3.11 → nedo_vision_worker-1.3.13}/nedo_vision_worker.egg-info/dependency_links.txt +0 -0
  105. {nedo_vision_worker-1.3.11 → nedo_vision_worker-1.3.13}/nedo_vision_worker.egg-info/entry_points.txt +0 -0
  106. {nedo_vision_worker-1.3.11 → nedo_vision_worker-1.3.13}/nedo_vision_worker.egg-info/requires.txt +0 -0
  107. {nedo_vision_worker-1.3.11 → nedo_vision_worker-1.3.13}/nedo_vision_worker.egg-info/top_level.txt +0 -0
  108. {nedo_vision_worker-1.3.11 → nedo_vision_worker-1.3.13}/pyproject.toml +0 -0
  109. {nedo_vision_worker-1.3.11 → nedo_vision_worker-1.3.13}/setup.cfg +0 -0
  110. {nedo_vision_worker-1.3.11 → nedo_vision_worker-1.3.13}/setup.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: nedo-vision-worker
3
- Version: 1.3.11
3
+ Version: 1.3.13
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>
@@ -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.11"
9
+ __version__ = "1.3.13"
10
10
  __all__ = ["WorkerService"]
@@ -2,6 +2,7 @@ import logging
2
2
  from nedo_vision_worker.config.ConfigurationManager import ConfigurationManager
3
3
  from nedo_vision_worker.database.DatabaseManager import set_storage_path, DatabaseManager
4
4
  from nedo_vision_worker.worker_service import WorkerService
5
+ from nedo_vision_worker.util.RTMPUrl import RTMPUrl
5
6
 
6
7
 
7
8
  def start_worker(
@@ -13,6 +14,7 @@ def start_worker(
13
14
  rtmp_server: str,
14
15
  storage_path: str,
15
16
  log_level: str = "INFO",
17
+ rtmp_publish_query_strings: str = ""
16
18
  ) -> WorkerService:
17
19
  # Logging (only once, force allowed)
18
20
  logging.basicConfig(
@@ -36,6 +38,13 @@ def start_worker(
36
38
  logger=logging.getLogger("configuration_manager"),
37
39
  )
38
40
 
41
+ RTMPUrl.configure(
42
+ rtmp_server_url=rtmp_server,
43
+ rtmp_publish_query_strings=rtmp_publish_query_strings
44
+ )
45
+
46
+ print(f"Got URL {RTMPUrl.get_publish_url("testtt")}")
47
+
39
48
  service = WorkerService(
40
49
  configuration_manager=configuration_manager,
41
50
  server_host=server_host,
@@ -7,6 +7,11 @@ from typing import NoReturn
7
7
  from nedo_vision_worker.bootstrap import start_worker
8
8
  from nedo_vision_worker import __version__
9
9
 
10
+ import faulthandler
11
+
12
+ # Enable fault handler to get a traceback
13
+ faulthandler.enable()
14
+
10
15
  class NedoWorkerCLI:
11
16
  def __init__(self):
12
17
  self.logger = logging.getLogger(__name__)
@@ -38,6 +43,7 @@ class NedoWorkerCLI:
38
43
  run.add_argument("--server-host", default="be.vision.sindika.co.id")
39
44
  run.add_argument("--server-port", type=int, default=50051)
40
45
  run.add_argument("--rtmp-server", default="rtmp://live.vision.sindika.co.id:1935/live")
46
+ run.add_argument("--rtmp-publish-query-strings", default="")
41
47
  run.add_argument("--storage-path", default="data")
42
48
  run.add_argument("--system-usage-interval", type=int, default=30)
43
49
  run.add_argument("--log-level", default="INFO")
@@ -61,6 +67,7 @@ class NedoWorkerCLI:
61
67
  rtmp_server=args.rtmp_server,
62
68
  storage_path=args.storage_path,
63
69
  log_level=args.log_level,
70
+ rtmp_publish_query_strings=args.rtmp_publish_query_strings
64
71
  )
65
72
  signal.pause() # wait for signal
66
73
 
@@ -13,13 +13,22 @@ class ConfigurationManager(ConfigurationManagerInterface):
13
13
  A class to manage local and remote configuration stored in the 'config' database.
14
14
  """
15
15
 
16
- def __init__(self, worker_token: str, server_host: str, server_port: int, rtmp_server_url: str, logger: logging.Logger):
16
+ def __init__(
17
+ self,
18
+ worker_token: str,
19
+ server_host: str,
20
+ server_port: int,
21
+ rtmp_server_url: str,
22
+ logger: logging.Logger,
23
+ rtmp_publish_query_strings: str = "",
24
+ ):
17
25
  try:
18
26
  self._logger = logger
19
27
  self._worker_token = worker_token
20
28
  self._server_host = server_host
21
29
  self._server_port = server_port
22
30
  self._rtmp_server_url = rtmp_server_url
31
+ self._rtmp_publish_query_strings = rtmp_publish_query_strings
23
32
 
24
33
  self._initialize_remote_configuration()
25
34
 
@@ -15,6 +15,7 @@ class DummyConfigurationManager(ConfigurationManagerInterface):
15
15
  server_host: str,
16
16
  server_port: str,
17
17
  rtmp_server_url: str,
18
+ rtmp_publish_query_strings: str,
18
19
  rabbitmq_host: str,
19
20
  rabbitmq_port: str,
20
21
  rabbitmq_username: str,
@@ -27,6 +28,7 @@ class DummyConfigurationManager(ConfigurationManagerInterface):
27
28
  self._server_host = server_host
28
29
  self._server_port = server_port
29
30
  self._rtmp_server_url = rtmp_server_url
31
+ self._rtmp_publish_query_strings = rtmp_publish_query_strings
30
32
  self._rabbitmq_host = rabbitmq_host
31
33
  self._rabbitmq_port = rabbitmq_port
32
34
  self._rabbitmq_username = rabbitmq_username
@@ -38,6 +40,7 @@ class DummyConfigurationManager(ConfigurationManagerInterface):
38
40
  "server_host": self._server_host,
39
41
  "server_port": str(self._server_port),
40
42
  "rtmp_server": self._rtmp_server_url,
43
+ "rtmp_publish_query_strings": self._rtmp_publish_query_strings,
41
44
  "rabbitmq_host": self._rabbitmq_host,
42
45
  "rabbitmq_port": self._rabbitmq_port,
43
46
  "rabbitmq_username": self._rabbitmq_username,
@@ -31,7 +31,7 @@ class ConnectionInfoClient(GrpcClientBase):
31
31
  try:
32
32
  if not self.stub:
33
33
  raise Exception("Not connected to manager")
34
-
34
+
35
35
  # Prepare the request
36
36
  request = GetWorkerConnectionInfoRequest(token=self.token)
37
37
 
@@ -9,10 +9,11 @@ import os
9
9
  from .VideoSharingDaemon import VideoSharingClient
10
10
  from ..database.DatabaseManager import get_storage_path
11
11
  from ..util.EncoderSelector import EncoderSelector
12
+ from ..util.RTMPUrl import RTMPUrl
12
13
 
13
14
 
14
15
  class DirectDeviceToRTMPStreamer:
15
- def __init__(self, device_url: str, rtmp_server: str, stream_key: str, stream_duration: int):
16
+ def __init__(self, device_url: str, stream_key: str, stream_duration: int):
16
17
  """
17
18
  Initialize the DirectDeviceToRTMPStreamer.
18
19
 
@@ -23,7 +24,6 @@ class DirectDeviceToRTMPStreamer:
23
24
  stream_duration: Duration in seconds
24
25
  """
25
26
  self.device_url = device_url
26
- self.rtmp_server = rtmp_server
27
27
  self.stream_key = stream_key
28
28
  self.duration = stream_duration
29
29
 
@@ -32,7 +32,7 @@ class DirectDeviceToRTMPStreamer:
32
32
  raise ValueError(f"Invalid device URL: {device_url}")
33
33
 
34
34
  self.device_index = device_index
35
- self.rtmp_url = f"{rtmp_server}/{stream_key}"
35
+ self.rtmp_url = RTMPUrl.get_publish_url(stream_key)
36
36
 
37
37
  self.ffmpeg_process = None
38
38
  self.active = False
@@ -2,9 +2,10 @@ import subprocess
2
2
  import logging
3
3
  import os
4
4
  from ..util.EncoderSelector import EncoderSelector
5
+ from ..util.RTMPUrl import RTMPUrl
5
6
 
6
7
  class FileToRTMPStreamer:
7
- def __init__(self, video_path, rtmp_url, stream_key, fps=30, resolution="1280x720", loop=False):
8
+ def __init__(self, video_path, stream_key, fps=30, resolution="1280x720", loop=False):
8
9
  """
9
10
  Initialize the file streamer.
10
11
 
@@ -17,7 +18,7 @@ class FileToRTMPStreamer:
17
18
  loop (bool): Loop the video until manually stopped.
18
19
  """
19
20
  self.video_path = video_path
20
- self.rtmp_url = f"{rtmp_url}/{stream_key}"
21
+ self.rtmp_url = RTMPUrl.get_publish_url(stream_key)
21
22
  self.fps = fps
22
23
  self.resolution = resolution
23
24
  self.loop = loop
@@ -2,11 +2,15 @@ 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
8
+ from ..util.RTMPUrl import RTMPUrl
9
+
10
+ logger = logging.getLogger(__name__)
7
11
 
8
12
  class RTSPtoRTMPStreamer:
9
- def __init__(self, rtsp_url, rtmp_url, stream_key, fps=30, resolution="1280x720", duration=120):
13
+ def __init__(self, rtsp_url, stream_key, fps=30, resolution="1280x720", duration=120):
10
14
  """
11
15
  Initialize the streamer.
12
16
 
@@ -19,7 +23,7 @@ class RTSPtoRTMPStreamer:
19
23
  duration (int): Duration in seconds to stream.
20
24
  """
21
25
  self.rtsp_url = rtsp_url
22
- self.rtmp_url = f"{rtmp_url}/{stream_key}"
26
+ self.rtmp_url = RTMPUrl.get_publish_url(stream_key)
23
27
  self.fps = fps
24
28
  self.resolution = resolution
25
29
  self.duration = duration
@@ -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"
@@ -0,0 +1,24 @@
1
+ class RTMPUrl:
2
+ """
3
+ Call `configure()` static method first.
4
+ """
5
+ _rtmp_server_url = ""
6
+ _rtmp_publish_query_strings = ""
7
+
8
+ @staticmethod
9
+ def configure(rtmp_server_url: str, rtmp_publish_query_strings: str = ""):
10
+ """
11
+ Example:
12
+ - `rtmp_server_url` = rtmp://live.sindika.co.id:8554/live
13
+ - `rtmp_publish_query_strings` = username=my-username&pass=mantap-jiwa
14
+ """
15
+ RTMPUrl._rtmp_server_url = rtmp_server_url
16
+ RTMPUrl._rtmp_publish_query_strings = rtmp_publish_query_strings
17
+
18
+ @staticmethod
19
+ def get_publish_url(stream_key: str) -> str:
20
+ url = f"{RTMPUrl._rtmp_server_url}/{stream_key}"
21
+ if RTMPUrl._rtmp_publish_query_strings:
22
+ url = f"{RTMPUrl._rtmp_server_url}/{stream_key}?{RTMPUrl._rtmp_publish_query_strings}"
23
+
24
+ return url
@@ -157,12 +157,12 @@ class VideoStreamWorker:
157
157
  logger.info(f"🎥 [APP] Starting RTMP stream (Worker: {worker_id})")
158
158
 
159
159
  if url.startswith("worker-source/"):
160
- streamer = FileToRTMPStreamer(self.source_file_path / os.path.basename(url), rtmp_server, stream_key, stream_duration)
160
+ streamer = FileToRTMPStreamer(self.source_file_path / os.path.basename(url), stream_key, stream_duration)
161
161
  elif self._is_direct_device(url):
162
- streamer = DirectDeviceToRTMPStreamer(url, rtmp_server, stream_key, stream_duration)
162
+ streamer = DirectDeviceToRTMPStreamer(url, stream_key, stream_duration)
163
163
  else:
164
164
  # Assume RTSP or other supported protocols
165
- streamer = RTSPtoRTMPStreamer(url, rtmp_server, stream_key, stream_duration)
165
+ streamer = RTSPtoRTMPStreamer(url, stream_key, stream_duration)
166
166
 
167
167
  streamer.start_stream()
168
168
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: nedo-vision-worker
3
- Version: 1.3.11
3
+ Version: 1.3.13
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>
@@ -87,6 +87,7 @@ nedo_vision_worker/util/HardwareID.py
87
87
  nedo_vision_worker/util/ImageUploader.py
88
88
  nedo_vision_worker/util/Networking.py
89
89
  nedo_vision_worker/util/PlatformDetector.py
90
+ nedo_vision_worker/util/RTMPUrl.py
90
91
  nedo_vision_worker/util/SystemMonitor.py
91
92
  nedo_vision_worker/util/VideoProbeUtil.py
92
93
  nedo_vision_worker/util/__init__.py