Add camera mode probe notes
This commit is contained in:
parent
058b421354
commit
f340082fa3
4 changed files with 142 additions and 6 deletions
|
|
@ -27,6 +27,12 @@ Capture camera snapshots:
|
|||
.\.venv\Scripts\python.exe .\scripts\calibration_probe.py snapshot --max-index 10
|
||||
```
|
||||
|
||||
Probe camera mode behavior:
|
||||
|
||||
```powershell
|
||||
.\.venv\Scripts\python.exe .\scripts\calibration_probe.py mode-probe --api msmf --index 0 --profile 320x240x120
|
||||
```
|
||||
|
||||
Smoke-test input devices:
|
||||
|
||||
```powershell
|
||||
|
|
@ -68,6 +74,12 @@ Observed video access:
|
|||
- `dshow:2`: second Razer Kiyo-class RGB camera, likely Kiyo Pro.
|
||||
- PS3 Eye video interfaces are attached but not usable yet. Both `USB\VID_1415&PID_2000&MI_00` devices report Windows problem code `28`, meaning the video-side driver is missing. Their audio interfaces are working through generic USB audio.
|
||||
|
||||
Mode probe notes:
|
||||
|
||||
- `msmf:0` LeapUVC accepts a `320x240x120` request and reports about 115 fps, with rough OpenCV measured capture around 52 fps in the first short probe. Treat that as "tracking mode is plausible," not calibrated throughput.
|
||||
- Kiyo RGB devices produce snapshots, but initial isolated mode probes against Kiyo indices timed out. Do not trust FPS configuration for Kiyos until a backend-specific capture path is chosen.
|
||||
- PS3 Eye tracking modes cannot be tested until the open driver is installed for `MI_00`.
|
||||
|
||||
Observed audio access over WASAPI at 48 kHz:
|
||||
|
||||
- Scarlett Solo USB microphone
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ import argparse
|
|||
import json
|
||||
import subprocess
|
||||
import sys
|
||||
import multiprocessing as mp
|
||||
from datetime import datetime, timezone
|
||||
from pathlib import Path
|
||||
|
||||
|
|
@ -75,11 +76,7 @@ def camera_probe(max_index: int, apis: list[str], read_frames: int = 1):
|
|||
except Exception as exc:
|
||||
return [{"error": f"cv2 unavailable: {exc!r}"}]
|
||||
|
||||
api_map = {
|
||||
"any": 0,
|
||||
"dshow": cv2.CAP_DSHOW,
|
||||
"msmf": cv2.CAP_MSMF,
|
||||
}
|
||||
api_map = cv2_api_map()
|
||||
results = []
|
||||
for api_name in apis:
|
||||
api = api_map[api_name]
|
||||
|
|
@ -108,6 +105,20 @@ def camera_probe(max_index: int, apis: list[str], read_frames: int = 1):
|
|||
return results
|
||||
|
||||
|
||||
def cv2_api_map():
|
||||
import cv2
|
||||
|
||||
return {
|
||||
"any": 0,
|
||||
"dshow": cv2.CAP_DSHOW,
|
||||
"msmf": cv2.CAP_MSMF,
|
||||
}
|
||||
|
||||
|
||||
def api_value(name: str):
|
||||
return cv2_api_map()[name]
|
||||
|
||||
|
||||
def discover(args):
|
||||
out = run_dir("discover")
|
||||
manifest = {
|
||||
|
|
@ -150,6 +161,103 @@ def snapshot(args):
|
|||
print(f"{item['api']}:{item['index']} -> {item['snapshot']}")
|
||||
|
||||
|
||||
def mode_probe(args):
|
||||
out = run_dir(f"mode-probe-{args.api}{args.index}")
|
||||
result = {
|
||||
"created_utc": datetime.now(timezone.utc).isoformat(),
|
||||
"camera": {"api": args.api, "index": args.index},
|
||||
"profiles": [],
|
||||
}
|
||||
|
||||
profiles = []
|
||||
requested_profiles = args.profile or [
|
||||
"640x480x30",
|
||||
"640x480x60",
|
||||
"320x240x60",
|
||||
"320x240x120",
|
||||
]
|
||||
for item in requested_profiles:
|
||||
parts = item.lower().split("x")
|
||||
if len(parts) != 3:
|
||||
raise SystemExit(f"Profile must be WIDTHxHEIGHTxFPS, got {item}")
|
||||
profiles.append(tuple(int(part) for part in parts))
|
||||
|
||||
for width, height, fps in profiles:
|
||||
entry = run_profile_probe(args.api, args.index, width, height, fps, args.duration, args.profile_timeout)
|
||||
result["profiles"].append(entry)
|
||||
|
||||
write_json(out / "manifest.json", result)
|
||||
print(out)
|
||||
print(json.dumps(result["profiles"], indent=2))
|
||||
|
||||
|
||||
def _profile_probe_worker(queue, api, index, width, height, fps, duration):
|
||||
import cv2
|
||||
import time
|
||||
|
||||
cap = cv2.VideoCapture(index, api_value(api))
|
||||
if not cap.isOpened():
|
||||
queue.put(
|
||||
{
|
||||
"requested": {"width": width, "height": height, "fps": fps},
|
||||
"opened": False,
|
||||
}
|
||||
)
|
||||
return
|
||||
cap.set(cv2.CAP_PROP_FRAME_WIDTH, width)
|
||||
cap.set(cv2.CAP_PROP_FRAME_HEIGHT, height)
|
||||
cap.set(cv2.CAP_PROP_FPS, fps)
|
||||
cap.set(cv2.CAP_PROP_BUFFERSIZE, 1)
|
||||
start = time.perf_counter()
|
||||
count = 0
|
||||
shape = None
|
||||
first_ok = False
|
||||
while (time.perf_counter() - start) < duration:
|
||||
ok, frame = cap.read()
|
||||
if ok and frame is not None:
|
||||
count += 1
|
||||
first_ok = True
|
||||
shape = list(frame.shape)
|
||||
elapsed = time.perf_counter() - start
|
||||
entry = {
|
||||
"requested": {"width": width, "height": height, "fps": fps},
|
||||
"opened": True,
|
||||
"read_ok": first_ok,
|
||||
"frames": count,
|
||||
"measured_fps": count / elapsed if elapsed else 0.0,
|
||||
"reported_width": cap.get(cv2.CAP_PROP_FRAME_WIDTH),
|
||||
"reported_height": cap.get(cv2.CAP_PROP_FRAME_HEIGHT),
|
||||
"reported_fps": cap.get(cv2.CAP_PROP_FPS),
|
||||
"fourcc": int(cap.get(cv2.CAP_PROP_FOURCC)),
|
||||
"shape": shape,
|
||||
"backend": cap.getBackendName(),
|
||||
}
|
||||
cap.release()
|
||||
queue.put(entry)
|
||||
|
||||
|
||||
def run_profile_probe(api, index, width, height, fps, duration, timeout):
|
||||
queue = mp.Queue()
|
||||
proc = mp.Process(target=_profile_probe_worker, args=(queue, api, index, width, height, fps, duration))
|
||||
proc.start()
|
||||
proc.join(timeout)
|
||||
if proc.is_alive():
|
||||
proc.terminate()
|
||||
proc.join(2)
|
||||
return {
|
||||
"requested": {"width": width, "height": height, "fps": fps},
|
||||
"opened": None,
|
||||
"timeout": True,
|
||||
}
|
||||
if not queue.empty():
|
||||
return queue.get()
|
||||
return {
|
||||
"requested": {"width": width, "height": height, "fps": fps},
|
||||
"opened": None,
|
||||
"error": f"worker exited with code {proc.exitcode}",
|
||||
}
|
||||
|
||||
|
||||
def audio_smoke(args):
|
||||
import numpy as np
|
||||
import sounddevice as sd
|
||||
|
|
@ -221,6 +329,19 @@ def main():
|
|||
p.add_argument("--api", action="append", choices=["any", "dshow", "msmf"], default=["dshow", "msmf"])
|
||||
p.set_defaults(func=snapshot)
|
||||
|
||||
p = sub.add_parser("mode-probe")
|
||||
p.add_argument("--api", choices=["any", "dshow", "msmf"], default="dshow")
|
||||
p.add_argument("--index", type=int, required=True)
|
||||
p.add_argument("--duration", type=float, default=1.0)
|
||||
p.add_argument("--profile-timeout", type=float, default=6.0)
|
||||
p.add_argument(
|
||||
"--profile",
|
||||
action="append",
|
||||
default=None,
|
||||
help="WIDTHxHEIGHTxFPS, repeatable. Example: --profile 320x240x120",
|
||||
)
|
||||
p.set_defaults(func=mode_probe)
|
||||
|
||||
p = sub.add_parser("audio-smoke")
|
||||
p.add_argument("--duration", type=float, default=1.0)
|
||||
p.add_argument("--samplerate", type=int)
|
||||
|
|
|
|||
|
|
@ -18,3 +18,4 @@
|
|||
{"ts": "2026-05-18T12:32:40+00:00", "type": "decision", "status": "ok", "note": "GPU fusion/splatting pass: use pinned host frame rings, async CUDA uploads, GPU feature/marker/stereo extraction, GPU-shaped observation and brush packet buffers, and CUDA/Vulkan/D3D splat rendering with minimal readback; CPU owns orchestration and semantics."}
|
||||
{"ts": "2026-05-18T12:46:08+00:00", "type": "verification", "status": "partial", "note": "Calibration harness enumerated the local rig: LeapUVC raw IR video, two Razer Kiyo-class RGB cameras, Scarlett/Kiyo/PS3 Eye microphones, and Scarlett speakers are accessible; both PS3 Eye video interfaces are attached but report Windows problem code 28 (missing video-side driver)."}
|
||||
{"ts": "2026-05-18T13:14:03+00:00", "type": "decision", "status": "ok", "note": "PS3 Eye video driver path should prefer the opentrack open driver via Zadig/libusb on interface MI_00; CL Eye remains historical reference only, not a repo dependency or redistribution target."}
|
||||
{"ts": "2026-05-18T13:24:02+00:00", "type": "verification", "status": "partial", "note": "Footage status: LeapUVC and two Kiyo-class cameras produce snapshots; PS3 Eye video still needs opentrack/Zadig driver. LeapUVC MSMF accepted 320x240x120 and reported about 115 fps, but rough OpenCV measured throughput was about 52 fps in a short probe; Kiyo FPS mode probes timed out."}
|
||||
|
|
|
|||
|
|
@ -116,7 +116,9 @@ current_status:
|
|||
has first physical-device access: LeapUVC raw IR video, two Razer Kiyo-class
|
||||
RGB cameras, all expected microphones, and Scarlett speaker output are
|
||||
accessible; both PS3 Eye video interfaces are attached but missing their
|
||||
video-side driver.
|
||||
video-side driver. LeapUVC MSMF mode probing accepts a 320x240x120 request
|
||||
and reports about 115 fps, though measured OpenCV throughput is lower in the
|
||||
first rough probe.
|
||||
next_action: >
|
||||
Fix PS3 Eye video driver access, then capture ChArUco intrinsics frames for
|
||||
LeapUVC and both Kiyo cameras before moving to multi-camera extrinsics.
|
||||
|
|
|
|||
Loading…
Reference in a new issue