framelock 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 (43) hide show
  1. framelock/__init__.py +115 -0
  2. framelock/__main__.py +6 -0
  3. framelock/_compat.py +49 -0
  4. framelock/assets/chirps/00_reference_linear_ramp_chirp.wav +0 -0
  5. framelock/assets/chirps/01_hidden_chirp_water_ringtone.wav +0 -0
  6. framelock/assets/chirps/02_glass_plink_hidden_probe.wav +0 -0
  7. framelock/assets/chirps/03_bubble_code_microchirps.wav +0 -0
  8. framelock/assets/chirps/04_tiny_sparkle_notification_good_sync.wav +0 -0
  9. framelock/assets/chirps/05_natural_water_wood_phrase_no_obvious_ramp.wav +0 -0
  10. framelock/audioalign.py +1068 -0
  11. framelock/chirps.py +679 -0
  12. framelock/cli.py +349 -0
  13. framelock/clock.py +53 -0
  14. framelock/controls.py +247 -0
  15. framelock/correspondence.py +765 -0
  16. framelock/diagnostics.py +643 -0
  17. framelock/odometry.py +374 -0
  18. framelock/preview.py +591 -0
  19. framelock/registration/__init__.py +183 -0
  20. framelock/registration/_se3.py +81 -0
  21. framelock/registration/acoustic.py +517 -0
  22. framelock/registration/board.py +571 -0
  23. framelock/registration/cli.py +268 -0
  24. framelock/registration/store.py +252 -0
  25. framelock/registration/tagcli.py +127 -0
  26. framelock/registration/tags.py +793 -0
  27. framelock/registration/visual.py +171 -0
  28. framelock/registration/wave.py +1242 -0
  29. framelock/session.py +1781 -0
  30. framelock/soundspeed.py +370 -0
  31. framelock/sources/__init__.py +6 -0
  32. framelock/sources/base.py +177 -0
  33. framelock/sources/mic.py +356 -0
  34. framelock/sources/oak.py +1520 -0
  35. framelock/sources/phonedata.py +559 -0
  36. framelock/sources/rtsp.py +778 -0
  37. framelock/sync.py +242 -0
  38. framelock/viz.py +931 -0
  39. framelock-0.3.0.dist-info/METADATA +283 -0
  40. framelock-0.3.0.dist-info/RECORD +43 -0
  41. framelock-0.3.0.dist-info/WHEEL +4 -0
  42. framelock-0.3.0.dist-info/entry_points.txt +9 -0
  43. framelock-0.3.0.dist-info/licenses/LICENSE +21 -0
framelock/__init__.py ADDED
@@ -0,0 +1,115 @@
1
+ """Synchronized multi-camera recording.
2
+
3
+ Compose a recording session from heterogeneous sources — OAK-D devices
4
+ (all three cameras, hardware-synced where possible), RTSP streams (e.g. an
5
+ iPhone camera app), and anything else that can produce timestamped frames —
6
+ and record them all into one session folder with per-device subfolders,
7
+ per-frame timestamps, and cross-device sync groups.
8
+
9
+ from framelock import Session, OakD, RtspCamera, Ramp
10
+
11
+ oak = OakD(shutter_sync=True, shutter=1/125, iso=800)
12
+ phone = RtspCamera("rtsp://192.168.1.23:8554/live", name="iphone")
13
+
14
+ with Session("recordings", name="take1", warmup="auto") as session:
15
+ session.record(oak, phone)
16
+ """
17
+
18
+ from typing import TYPE_CHECKING
19
+
20
+ if TYPE_CHECKING:
21
+ from framelock.audioalign import AirConditions, AlignmentResult, align_session
22
+ from framelock.soundspeed import SoundModel
23
+ from framelock.clock import ClockMap
24
+ from framelock.correspondence import Correspondence, write_correspondence
25
+ from framelock.controls import (
26
+ Automation, Control, ShutterFunc, ShutterRamp, ShutterStep,
27
+ FocusFunc, FocusRamp, FocusStep, Func, Interpolation, IsoFunc, IsoRamp,
28
+ IsoStep, Ramp, Step, ZoomFunc, ZoomRamp, ZoomStep,
29
+ )
30
+ from framelock.session import Session, Warmup
31
+ from framelock.sources.base import Source, SyncSample
32
+ from framelock.sources.mic import Microphone
33
+ from framelock.sources.oak import (
34
+ ExternalSync, OakD, Resolution, VideoFormat,
35
+ )
36
+ from framelock.sources.rtsp import RtspCamera, Transport
37
+ from framelock.sync import SyncGroup, Synchronizer
38
+ from framelock.chirps import (
39
+ BubbleCodeMicro,
40
+ GlassPlinkHidden,
41
+ HiddenChirpWater,
42
+ MLS,
43
+ NaturalWaterWood,
44
+ ReferenceLinearRamp,
45
+ Sweep,
46
+ Chirp,
47
+ TinySparkle,
48
+ ChirpKind,
49
+ Velvet,
50
+ )
51
+
52
+ # Lazy imports (PEP 562): importing framelock stays instant and does not
53
+ # pull in depthai/av until the corresponding source is actually used.
54
+ _EXPORTS = {
55
+ "ClockMap": "framelock.clock",
56
+ "Correspondence": "framelock.correspondence",
57
+ "write_correspondence": "framelock.correspondence",
58
+ "Automation": "framelock.controls",
59
+ "Control": "framelock.controls",
60
+ "Interpolation": "framelock.controls",
61
+ "Func": "framelock.controls",
62
+ "Ramp": "framelock.controls",
63
+ "Step": "framelock.controls",
64
+ "ZoomRamp": "framelock.controls",
65
+ "ZoomFunc": "framelock.controls",
66
+ "ZoomStep": "framelock.controls",
67
+ "FocusRamp": "framelock.controls",
68
+ "FocusFunc": "framelock.controls",
69
+ "FocusStep": "framelock.controls",
70
+ "ShutterRamp": "framelock.controls",
71
+ "ShutterFunc": "framelock.controls",
72
+ "ShutterStep": "framelock.controls",
73
+ "IsoRamp": "framelock.controls",
74
+ "IsoFunc": "framelock.controls",
75
+ "IsoStep": "framelock.controls",
76
+ "Session": "framelock.session",
77
+ "Warmup": "framelock.session",
78
+ "Source": "framelock.sources.base",
79
+ "SyncSample": "framelock.sources.base",
80
+ "Microphone": "framelock.sources.mic",
81
+ "OakD": "framelock.sources.oak",
82
+ "Resolution": "framelock.sources.oak",
83
+ "VideoFormat": "framelock.sources.oak",
84
+ "ExternalSync": "framelock.sources.oak",
85
+ "RtspCamera": "framelock.sources.rtsp",
86
+ "Transport": "framelock.sources.rtsp",
87
+ "SyncGroup": "framelock.sync",
88
+ "Synchronizer": "framelock.sync",
89
+ "Chirp": "framelock.chirps",
90
+ "MLS": "framelock.chirps",
91
+ "Velvet": "framelock.chirps",
92
+ "Sweep": "framelock.chirps",
93
+ "ReferenceLinearRamp": "framelock.chirps",
94
+ "HiddenChirpWater": "framelock.chirps",
95
+ "GlassPlinkHidden": "framelock.chirps",
96
+ "BubbleCodeMicro": "framelock.chirps",
97
+ "TinySparkle": "framelock.chirps",
98
+ "NaturalWaterWood": "framelock.chirps",
99
+ "ChirpKind": "framelock.chirps",
100
+ "AirConditions": "framelock.audioalign",
101
+ "SoundModel": "framelock.soundspeed",
102
+ "align_session": "framelock.audioalign",
103
+ "AlignmentResult": "framelock.audioalign",
104
+ }
105
+
106
+ __all__ = sorted(_EXPORTS)
107
+
108
+
109
+ def __getattr__(name: str):
110
+ module = _EXPORTS.get(name)
111
+ if module is None:
112
+ raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
113
+ import importlib
114
+
115
+ return getattr(importlib.import_module(module), name)
framelock/__main__.py ADDED
@@ -0,0 +1,6 @@
1
+ """python -m framelock"""
2
+
3
+ from framelock.cli import main
4
+
5
+ if __name__ == "__main__":
6
+ raise SystemExit(main())
framelock/_compat.py ADDED
@@ -0,0 +1,49 @@
1
+ """Environment quirks, contained.
2
+
3
+ macOS + opencv-python + PyAV: each wheel bundles its OWN copy of FFmpeg,
4
+ and when the second library loads, the Objective-C runtime prints
5
+ duplicate-class warnings for FFmpeg's AVFoundation capture classes
6
+ (AVFFrameReceiver / AVFAudioReceiver):
7
+
8
+ objc[…]: Class AVFFrameReceiver is implemented in both … libavdevice …
9
+
10
+ Scary wording, benign here: those classes belong to libavdevice's camera
11
+ capture, which framelock never uses through either library (we read and
12
+ write files; live capture goes through DepthAI and RTSP). The wheels
13
+ double-bundling is upstream's to fix; the noise is ours to silence — by
14
+ importing both libraries together, early, with stderr muted at the file
15
+ descriptor level (the objc runtime writes straight to fd 2, so Python's
16
+ sys.stderr redirection cannot catch it).
17
+ """
18
+
19
+ from __future__ import annotations
20
+
21
+ import contextlib
22
+ import os
23
+ import sys
24
+
25
+
26
+ @contextlib.contextmanager
27
+ def _fd_stderr_silenced():
28
+ saved = os.dup(2)
29
+ devnull = os.open(os.devnull, os.O_WRONLY)
30
+ try:
31
+ os.dup2(devnull, 2)
32
+ yield
33
+ finally:
34
+ os.dup2(saved, 2)
35
+ os.close(saved)
36
+ os.close(devnull)
37
+
38
+
39
+ def preload_media_libs() -> None:
40
+ """Import av and cv2 up front, muting the macOS duplicate-FFmpeg
41
+ warnings their combined load triggers. Call at CLI entry points; a
42
+ real ImportError still propagates (raised, not printed)."""
43
+ if sys.platform != "darwin":
44
+ return
45
+ with _fd_stderr_silenced():
46
+ with contextlib.suppress(ImportError):
47
+ import av # noqa: F401
48
+ with contextlib.suppress(ImportError):
49
+ import cv2 # noqa: F401