pyobs-aravis 2.0.0.dev7__tar.gz → 2.0.0.dev9__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.
- {pyobs_aravis-2.0.0.dev7 → pyobs_aravis-2.0.0.dev9}/PKG-INFO +1 -1
- {pyobs_aravis-2.0.0.dev7 → pyobs_aravis-2.0.0.dev9}/pyobs_aravis/araviscamera.py +53 -5
- {pyobs_aravis-2.0.0.dev7 → pyobs_aravis-2.0.0.dev9}/pyproject.toml +1 -1
- {pyobs_aravis-2.0.0.dev7 → pyobs_aravis-2.0.0.dev9}/uv.lock +1 -1
- {pyobs_aravis-2.0.0.dev7 → pyobs_aravis-2.0.0.dev9}/.github/workflows/pypi.yml +0 -0
- {pyobs_aravis-2.0.0.dev7 → pyobs_aravis-2.0.0.dev9}/.github/workflows/ruff.yml +0 -0
- {pyobs_aravis-2.0.0.dev7 → pyobs_aravis-2.0.0.dev9}/.pre-commit-config.yaml +0 -0
- {pyobs_aravis-2.0.0.dev7 → pyobs_aravis-2.0.0.dev9}/.readthedocs.yml +0 -0
- {pyobs_aravis-2.0.0.dev7 → pyobs_aravis-2.0.0.dev9}/CHANGELOG.rst +0 -0
- {pyobs_aravis-2.0.0.dev7 → pyobs_aravis-2.0.0.dev9}/LICENSE +0 -0
- {pyobs_aravis-2.0.0.dev7 → pyobs_aravis-2.0.0.dev9}/README.md +0 -0
- {pyobs_aravis-2.0.0.dev7 → pyobs_aravis-2.0.0.dev9}/docs/Makefile +0 -0
- {pyobs_aravis-2.0.0.dev7 → pyobs_aravis-2.0.0.dev9}/docs/make.bat +0 -0
- {pyobs_aravis-2.0.0.dev7 → pyobs_aravis-2.0.0.dev9}/docs/requirements.txt +0 -0
- {pyobs_aravis-2.0.0.dev7 → pyobs_aravis-2.0.0.dev9}/docs/source/_static/pyobs.gif +0 -0
- {pyobs_aravis-2.0.0.dev7 → pyobs_aravis-2.0.0.dev9}/docs/source/conf.py +0 -0
- {pyobs_aravis-2.0.0.dev7 → pyobs_aravis-2.0.0.dev9}/docs/source/index.rst +0 -0
- {pyobs_aravis-2.0.0.dev7 → pyobs_aravis-2.0.0.dev9}/pyobs_aravis/__init__.py +0 -0
- {pyobs_aravis-2.0.0.dev7 → pyobs_aravis-2.0.0.dev9}/pyobs_aravis/aravis.py +0 -0
- {pyobs_aravis-2.0.0.dev7 → pyobs_aravis-2.0.0.dev9}/pyobs_aravis/gui.py +0 -0
|
@@ -16,6 +16,11 @@ log = logging.getLogger(__name__)
|
|
|
16
16
|
# rather than let a single dead camera freeze the whole module.
|
|
17
17
|
_SDK_CALL_TIMEOUT = 5.0
|
|
18
18
|
|
|
19
|
+
# pop_frame() is polled from _capture() and is expected to legitimately take a while (up to the
|
|
20
|
+
# camera's own frame interval/exposure time), unlike the other SDK calls above -- a much more
|
|
21
|
+
# generous timeout than _SDK_CALL_TIMEOUT, so normal operation never trips it.
|
|
22
|
+
_FRAME_WAIT_TIMEOUT = 30.0
|
|
23
|
+
|
|
19
24
|
|
|
20
25
|
class AravisCamera(BaseVideo, IExposureTime):
|
|
21
26
|
"""A pyobs module for Aravis cameras."""
|
|
@@ -57,7 +62,18 @@ class AravisCamera(BaseVideo, IExposureTime):
|
|
|
57
62
|
|
|
58
63
|
await BaseVideo.open(self)
|
|
59
64
|
|
|
60
|
-
|
|
65
|
+
# device discovery is a blocking, network-based scan (GigE Vision/USB3 Vision devices
|
|
66
|
+
# reply to a broadcast query) that can take multiple seconds -- run it like the other
|
|
67
|
+
# aravis/GLib calls (see _run_blocking) instead of freezing the whole module's event
|
|
68
|
+
# loop, and with it, the ability to respond to any other module, for that long
|
|
69
|
+
ids: list[str] = []
|
|
70
|
+
|
|
71
|
+
def _list_device_ids() -> None:
|
|
72
|
+
ids.extend(aravis.get_device_ids()) # type: ignore[arg-type]
|
|
73
|
+
|
|
74
|
+
if not await self._run_blocking(_list_device_ids):
|
|
75
|
+
raise TimeoutError(f"Timed out listing available cameras after {_SDK_CALL_TIMEOUT}s.")
|
|
76
|
+
|
|
61
77
|
if self._camera_device_name not in ids:
|
|
62
78
|
raise ValueError("Could not find given device name in list of available cameras.")
|
|
63
79
|
|
|
@@ -142,10 +158,10 @@ class AravisCamera(BaseVideo, IExposureTime):
|
|
|
142
158
|
await asyncio.sleep(0.1)
|
|
143
159
|
continue
|
|
144
160
|
|
|
145
|
-
frame
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
161
|
+
frame = await self._wait_for_frame()
|
|
162
|
+
if frame is None:
|
|
163
|
+
# camera went away, or the wait timed out -- back off and retry
|
|
164
|
+
continue
|
|
149
165
|
|
|
150
166
|
if time.time() - last < self._interval:
|
|
151
167
|
await asyncio.sleep(0.01)
|
|
@@ -157,6 +173,38 @@ class AravisCamera(BaseVideo, IExposureTime):
|
|
|
157
173
|
except Exception:
|
|
158
174
|
await asyncio.sleep(1)
|
|
159
175
|
|
|
176
|
+
async def _wait_for_frame(self, timeout: float = _FRAME_WAIT_TIMEOUT) -> npt.NDArray[Any] | None:
|
|
177
|
+
"""Waits for the next frame without blocking the event loop.
|
|
178
|
+
|
|
179
|
+
Polls pop_frame() from a background thread (see _run_blocking) rather than polling it
|
|
180
|
+
directly from the async loop with a sleep in between each attempt -- pop_frame() is
|
|
181
|
+
assumed non-blocking in the common case, but if the underlying aravis/GLib call ever
|
|
182
|
+
doesn't honor that (camera hiccup, network stall for GigE Vision), polling it directly
|
|
183
|
+
would freeze the whole module for as long as that lasts, repeatedly, for the module's
|
|
184
|
+
entire runtime. Runs the whole "poll until ready" loop as a single blocking call instead,
|
|
185
|
+
so only one thread gets spawned per delivered frame rather than one per 10ms poll.
|
|
186
|
+
|
|
187
|
+
Returns:
|
|
188
|
+
The next frame, or None if the camera disappeared mid-wait or the wait timed out.
|
|
189
|
+
"""
|
|
190
|
+
result: list[npt.NDArray[Any]] = []
|
|
191
|
+
|
|
192
|
+
def _poll() -> None:
|
|
193
|
+
camera = self._camera
|
|
194
|
+
while camera is not None:
|
|
195
|
+
frame = camera.pop_frame() # type: ignore[union-attr]
|
|
196
|
+
# pop_frame() can return a non-None array that's empty along axis 0 instead of
|
|
197
|
+
# None -- treat that the same as "not ready yet" rather than a real frame
|
|
198
|
+
if frame is not None and frame.size != 0: # type: ignore[union-attr]
|
|
199
|
+
result.append(frame) # type: ignore[arg-type]
|
|
200
|
+
return
|
|
201
|
+
time.sleep(0.01)
|
|
202
|
+
|
|
203
|
+
if not await self._run_blocking(_poll, timeout=timeout):
|
|
204
|
+
log.error("Timed out waiting for a frame after %.1fs.", timeout)
|
|
205
|
+
return None
|
|
206
|
+
return result[0] if result else None
|
|
207
|
+
|
|
160
208
|
async def set_exposure_time(self, exposure_time: float, **kwargs: Any) -> None:
|
|
161
209
|
"""Set the exposure time in seconds.
|
|
162
210
|
|
|
@@ -1770,7 +1770,7 @@ wheels = [
|
|
|
1770
1770
|
|
|
1771
1771
|
[[package]]
|
|
1772
1772
|
name = "pyobs-aravis"
|
|
1773
|
-
version = "2.0.0.
|
|
1773
|
+
version = "2.0.0.dev9"
|
|
1774
1774
|
source = { editable = "." }
|
|
1775
1775
|
dependencies = [
|
|
1776
1776
|
{ name = "numpy", version = "2.4.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.12'" },
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|