|
18 | 18 | """ |
19 | 19 |
|
20 | 20 | import math |
| 21 | +import os |
21 | 22 | import os.path |
22 | 23 | import typing as ty |
23 | 24 | import warnings |
|
34 | 35 | TimecodeLike, |
35 | 36 | framerate_to_fraction, |
36 | 37 | ) |
37 | | -from scenedetect.platform import get_file_name |
| 38 | +from scenedetect.platform import StrPath, get_file_name |
38 | 39 | from scenedetect.video_stream import ( |
39 | 40 | FrameRateUnavailable, |
40 | 41 | SeekError, |
@@ -71,10 +72,10 @@ class VideoStreamCv2(VideoStream): |
71 | 72 |
|
72 | 73 | def __init__( |
73 | 74 | self, |
74 | | - path: ty.AnyStr | None = None, |
| 75 | + path: StrPath | None = None, |
75 | 76 | framerate: float | None = None, |
76 | 77 | max_decode_attempts: int = 5, |
77 | | - path_or_device: bytes | str | int | None = None, |
| 78 | + path_or_device: StrPath | int | None = None, |
78 | 79 | ): |
79 | 80 | """Open a video file, image sequence, or network stream. |
80 | 81 |
|
@@ -103,15 +104,19 @@ def __init__( |
103 | 104 | DeprecationWarning, |
104 | 105 | stacklevel=2, |
105 | 106 | ) |
106 | | - path = path_or_device |
107 | | - if path is None: |
| 107 | + resolved: str | int = ( |
| 108 | + path_or_device if isinstance(path_or_device, int) else os.fspath(path_or_device) |
| 109 | + ) |
| 110 | + elif path is None: |
108 | 111 | raise ValueError("Path must be specified!") |
| 112 | + else: |
| 113 | + resolved = os.fspath(path) |
109 | 114 | if framerate is not None and framerate < MAX_FPS_DELTA: |
110 | 115 | raise ValueError(f"Specified framerate ({framerate:f}) is invalid!") |
111 | 116 | if max_decode_attempts < 0: |
112 | 117 | raise ValueError("Maximum decode attempts must be >= 0!") |
113 | 118 |
|
114 | | - self._path_or_device = path |
| 119 | + self._path_or_device: str | int = resolved |
115 | 120 | self._is_device = isinstance(self._path_or_device, int) |
116 | 121 |
|
117 | 122 | # Initialized in _open_capture: |
@@ -156,11 +161,11 @@ def frame_rate(self) -> Fraction: |
156 | 161 | return self._frame_rate |
157 | 162 |
|
158 | 163 | @property |
159 | | - def path(self) -> bytes | str: |
| 164 | + def path(self) -> str: |
160 | 165 | if self._is_device: |
161 | | - assert isinstance(self._path_or_device, (int)) |
| 166 | + assert isinstance(self._path_or_device, int) |
162 | 167 | return f"Device {self._path_or_device}" |
163 | | - assert isinstance(self._path_or_device, (bytes, str)) |
| 168 | + assert isinstance(self._path_or_device, str) |
164 | 169 | return self._path_or_device |
165 | 170 |
|
166 | 171 | @property |
@@ -316,15 +321,21 @@ def read(self, decode: bool = True) -> np.ndarray | bool: |
316 | 321 |
|
317 | 322 | def _open_capture(self, framerate: float | None = None): |
318 | 323 | """Opens capture referenced by this object and resets internal state.""" |
319 | | - if self._is_device and self._path_or_device < 0: |
320 | | - raise ValueError("Invalid/negative device ID specified.") |
321 | | - input_is_video_file = not self._is_device and not any( |
322 | | - identifier in self._path_or_device for identifier in NON_VIDEO_FILE_INPUT_IDENTIFIERS |
323 | | - ) |
324 | | - # We don't have a way of querying why opening a video fails (errors are logged at least), |
325 | | - # so provide a better error message if we try to open a file that doesn't exist. |
326 | | - if input_is_video_file and not os.path.exists(self._path_or_device): |
327 | | - raise OSError("Video file not found.") |
| 324 | + if self._is_device: |
| 325 | + assert isinstance(self._path_or_device, int) |
| 326 | + if self._path_or_device < 0: |
| 327 | + raise ValueError("Invalid/negative device ID specified.") |
| 328 | + input_is_video_file = False |
| 329 | + else: |
| 330 | + assert isinstance(self._path_or_device, str) |
| 331 | + input_is_video_file = not any( |
| 332 | + identifier in self._path_or_device |
| 333 | + for identifier in NON_VIDEO_FILE_INPUT_IDENTIFIERS |
| 334 | + ) |
| 335 | + # We don't have a way of querying why opening a video fails (errors are logged at |
| 336 | + # least), so provide a better error message if we try to open a missing file. |
| 337 | + if input_is_video_file and not os.path.exists(self._path_or_device): |
| 338 | + raise OSError("Video file not found.") |
328 | 339 |
|
329 | 340 | cap = cv2.VideoCapture(self._path_or_device) |
330 | 341 | if not cap.isOpened(): |
|
0 commit comments