framesource 0.3.0__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.
Files changed (37) hide show
  1. frame_processors/__init__.py +37 -0
  2. frame_source/__init__.py +50 -0
  3. framesource/__init__.py +93 -0
  4. framesource/_msmf_config.py +26 -0
  5. framesource/_version.py +24 -0
  6. framesource/discovery.py +109 -0
  7. framesource/errors.py +82 -0
  8. framesource/factory.py +290 -0
  9. framesource/processors/__init__.py +34 -0
  10. framesource/processors/equirectangular360_processor.py +577 -0
  11. framesource/processors/fisheye2equirectangular_processor.py +328 -0
  12. framesource/processors/frame_processor.py +30 -0
  13. framesource/processors/hyperspectral_processor.py +23 -0
  14. framesource/processors/realsense_depth_processor.py +90 -0
  15. framesource/py.typed +0 -0
  16. framesource/sources/__init__.py +40 -0
  17. framesource/sources/audiospectrogram_capture.py +1068 -0
  18. framesource/sources/basler_capture.py +477 -0
  19. framesource/sources/folder_capture.py +920 -0
  20. framesource/sources/genicam_capture.py +681 -0
  21. framesource/sources/huateng_capture.py +245 -0
  22. framesource/sources/ipcamera_capture.py +254 -0
  23. framesource/sources/mvsdk.py +2454 -0
  24. framesource/sources/realsense_capture.py +565 -0
  25. framesource/sources/screen_capture.py +800 -0
  26. framesource/sources/video_capture_base.py +560 -0
  27. framesource/sources/video_file_capture.py +259 -0
  28. framesource/sources/webcam_capture.py +511 -0
  29. framesource/sources/ximea_capture.py +299 -0
  30. framesource/threading_utils.py +790 -0
  31. framesource-0.3.0.dist-info/METADATA +787 -0
  32. framesource-0.3.0.dist-info/RECORD +37 -0
  33. framesource-0.3.0.dist-info/WHEEL +5 -0
  34. framesource-0.3.0.dist-info/licenses/LICENSE +21 -0
  35. framesource-0.3.0.dist-info/scm_file_list.json +276 -0
  36. framesource-0.3.0.dist-info/scm_version.json +8 -0
  37. framesource-0.3.0.dist-info/top_level.txt +3 -0
@@ -0,0 +1,259 @@
1
+ import logging
2
+ import time
3
+ import warnings
4
+ from typing import Any, Optional
5
+
6
+ import cv2
7
+ import numpy as np
8
+
9
+ from .video_capture_base import VideoCaptureBase
10
+
11
+ logger = logging.getLogger(__name__)
12
+
13
+
14
+ class VideoFileCapture(VideoCaptureBase):
15
+ has_discovery = False # Uses file paths, not discoverable devices
16
+ supports_exposure = False # Video files have no controllable exposure
17
+ supports_gain = False # Video files have no controllable gain
18
+
19
+ """Video file capture using OpenCV."""
20
+
21
+ def __init__(
22
+ self,
23
+ source: str,
24
+ *,
25
+ loop: bool = False,
26
+ real_time: bool = True,
27
+ width: Optional[int] = None,
28
+ height: Optional[int] = None,
29
+ fps: Optional[float] = None,
30
+ **kwargs,
31
+ ):
32
+ """Initialize the video file capture.
33
+
34
+ Args:
35
+ source: Path to the video file.
36
+ loop: Restart playback from the beginning when the end is reached.
37
+ real_time: Play at the file's native frame rate (disable for
38
+ fastest processing).
39
+ width: Optional target frame width (applied on :meth:`connect`).
40
+ height: Optional target frame height (applied on :meth:`connect`).
41
+ fps: Optional target frame rate (applied on :meth:`connect`).
42
+ **kwargs: Additional passthrough options stored on ``self.config``.
43
+ """
44
+ # Forward the promoted options back into ``self.config`` so behaviour
45
+ # that reads them (``connect()`` for width/height/fps) is preserved.
46
+ for _key, _val in (
47
+ ("loop", loop),
48
+ ("real_time", real_time),
49
+ ("width", width),
50
+ ("height", height),
51
+ ("fps", fps),
52
+ ):
53
+ if _val is not None:
54
+ kwargs[_key] = _val
55
+ super().__init__(source, **kwargs)
56
+ self.cap = None
57
+ self.loop = loop
58
+ self.real_time = real_time
59
+ self.time_of_last_frame = 0.0
60
+
61
+ def connect(self) -> bool:
62
+ """Connect to video file."""
63
+ try:
64
+ self.cap = cv2.VideoCapture(self.source)
65
+ if not self.cap.isOpened():
66
+ logger.error(f"Failed to open video file {self.source}")
67
+ return False
68
+
69
+ # Set additional parameters if provided
70
+ if "width" in self.config:
71
+ self.cap.set(cv2.CAP_PROP_FRAME_WIDTH, self.config["width"])
72
+ if "height" in self.config:
73
+ self.cap.set(cv2.CAP_PROP_FRAME_HEIGHT, self.config["height"])
74
+ if "fps" in self.config:
75
+ self.cap.set(cv2.CAP_PROP_FPS, self.config["fps"])
76
+
77
+ self.is_connected = True
78
+ logger.info(f"Connected to video file {self.source}")
79
+ return True
80
+ except Exception as e:
81
+ logger.error(f"Error connecting to video file: {e}")
82
+ return False
83
+
84
+ def disconnect(self) -> bool:
85
+ """Disconnect from video file."""
86
+ try:
87
+ if self.cap is not None:
88
+ self.cap.release()
89
+ self.cap = None
90
+ self.is_connected = False
91
+ logger.info("Disconnected from video file")
92
+ return True
93
+ except Exception as e:
94
+ logger.error(f"Error disconnecting from video file: {e}")
95
+ return False
96
+
97
+ def _read_implementation(self) -> tuple[bool, Optional[np.ndarray]]:
98
+ """
99
+ Read a single frame from the video file.
100
+ Returns:
101
+ Tuple[bool, Optional[np.ndarray]]: (success, frame)
102
+ """
103
+ if not self.is_connected or self.cap is None:
104
+ return False, None
105
+ # Add delay for real-time playback simulation
106
+ if self.real_time:
107
+ video_fps = self.cap.get(cv2.CAP_PROP_FPS)
108
+ if video_fps > 0:
109
+ frame_duration = 1.0 / video_fps
110
+ current_time = time.time()
111
+ elapsed = current_time - self.time_of_last_frame
112
+ if elapsed < frame_duration:
113
+ time.sleep(frame_duration - elapsed)
114
+ self.time_of_last_frame = time.time()
115
+ ret, frame = self.cap.read()
116
+ # If we've reached the end of the video and looping is enabled
117
+ if not ret and self.loop:
118
+ self.cap.set(cv2.CAP_PROP_POS_FRAMES, 0)
119
+ ret, frame = self.cap.read()
120
+ if self.real_time:
121
+ self.time_of_last_frame = time.time()
122
+ return ret, frame if ret else None
123
+
124
+ def set_exposure(self, value: float) -> bool:
125
+ """Set exposure (not applicable for video files)."""
126
+ logger.warning("Exposure control not applicable for video files")
127
+ return False
128
+
129
+ def get_exposure(self) -> Optional[float]:
130
+ """Get exposure (not applicable for video files)."""
131
+ return None
132
+
133
+ def set_gain(self, value: float) -> bool:
134
+ """Set gain (not applicable for video files)."""
135
+ logger.warning("Gain control not applicable for video files")
136
+ return False
137
+
138
+ def get_gain(self) -> Optional[float]:
139
+ """Get gain (not applicable for video files)."""
140
+ return None
141
+
142
+ def enable_auto_exposure(self, enable: bool = True) -> bool:
143
+ """
144
+ Enable or disable auto exposure (not applicable for video files).
145
+
146
+ Args:
147
+ enable: True to enable, False to disable
148
+
149
+ Returns:
150
+ bool: Always False for video files
151
+ """
152
+ logger.warning("Auto exposure control not applicable for video files")
153
+ return False
154
+
155
+ def set_frame_size(self, width: int, height: int) -> bool:
156
+ """Set frame size (not applicable for video files)."""
157
+ logger.warning("Setting resolution is not applicable for video files")
158
+ return False
159
+
160
+ @classmethod
161
+ def discover(cls) -> list:
162
+ """
163
+ Discover method for video file capture.
164
+
165
+ Returns:
166
+ list: Empty list, as discovery is not applicable for file-based sources.
167
+ Use this class directly with file paths as the source parameter.
168
+ """
169
+ # Video file capture doesn't discover devices - it works with file paths
170
+ logger.info("VideoFileCapture uses file paths as sources, not discoverable devices.")
171
+ return []
172
+
173
+ @classmethod
174
+ def get_config_schema(cls) -> dict[str, Any]:
175
+ """Get configuration schema for video file capture"""
176
+ warnings.warn(
177
+ "get_config_schema() is deprecated and will be removed in a future release; "
178
+ "UI form schemas belong in the consuming application.",
179
+ DeprecationWarning,
180
+ stacklevel=2,
181
+ )
182
+ return {
183
+ "title": "Video File Configuration",
184
+ "description": "Configure video file playback settings",
185
+ "fields": [
186
+ {
187
+ "name": "source",
188
+ "label": "Video File Path",
189
+ "type": "text",
190
+ "placeholder": "C:/path/to/video.mp4",
191
+ "description": (
192
+ "Full path to video file (supports .mp4, .avi, .mov, .mkv, "
193
+ ".wmv, .flv, .webm)"
194
+ ),
195
+ "required": True,
196
+ },
197
+ {
198
+ "name": "loop",
199
+ "label": "Loop Playback",
200
+ "type": "checkbox",
201
+ "description": "Restart video from beginning when it ends",
202
+ "required": False,
203
+ "default": False,
204
+ },
205
+ {
206
+ "name": "real_time",
207
+ "label": "Real-time Playback",
208
+ "type": "checkbox",
209
+ "description": (
210
+ "Play video at original frame rate (disable for fastest processing)"
211
+ ),
212
+ "required": False,
213
+ "default": True,
214
+ },
215
+ {
216
+ "name": "width",
217
+ "label": "Width",
218
+ "type": "number",
219
+ "min": 160,
220
+ "max": 4096,
221
+ "placeholder": "1920",
222
+ "description": "Resize frame width (optional)",
223
+ "required": False,
224
+ },
225
+ {
226
+ "name": "height",
227
+ "label": "Height",
228
+ "type": "number",
229
+ "min": 120,
230
+ "max": 2160,
231
+ "placeholder": "1080",
232
+ "description": "Resize frame height (optional)",
233
+ "required": False,
234
+ },
235
+ ],
236
+ }
237
+
238
+
239
+ if __name__ == "__main__":
240
+ # Example usage
241
+ video_file = "path/to/your/video.mp4" # Replace with your video file path
242
+ camera = VideoFileCapture(source=video_file, loop=True, real_time=True)
243
+
244
+ if camera.connect():
245
+ print("Webcam connected successfully.")
246
+ print(f"Exposure: {camera.get_exposure()}")
247
+ print(f"Gain: {camera.get_gain()}")
248
+ print(f"Frame size: {camera.get_frame_size()}")
249
+
250
+ # Read a few frames
251
+ while camera.is_connected:
252
+ ret, frame = camera.read()
253
+ if ret and frame is not None:
254
+ cv2.imshow("Webcam", frame)
255
+ if cv2.waitKey(1) & 0xFF == ord("q"):
256
+ break
257
+ camera.disconnect()
258
+ else:
259
+ print("Failed to connect to webcam.")