探针增加尺寸扫描:区分链路带宽不够与摄像头本身就是 15 fps - What: tools/camera_probe.py 新增 SWEEP_SIZES 与 size_sweep(),在帧率扫描之后对 MJPG@30 依次申请 1920x1080/1280x720/960x540/848x480/640x480 并打印实测速率,提示语写明判断方式:帧越小越快 ⇒ 链路带宽是瓶颈;每个尺寸都一样 ⇒ 是摄像头本身的速率上限。 - Why: 用户实测 MJPG 在 1080p 与 720p 都是 15 fps、YUYV 两档都是 1 fps,两种解释仍然都成立(链路只能扛约 3-4 MB/s,或这颗摄像头在这些格式上就是 15 fps 设备),而处置完全不同;帧率扫描只能区分"申请被砍半"与"固定上限",尺寸扫描才能区分"带宽"与"设备"。 - Verification: compileall 通过;无摄像头时仍返回 1 并给出解释;studio 全量 91 passed(探针的无摄像头用例覆盖 main() 的降级路径)。 - Not in this change: 未改 SDK 采集参数;未做自动降级。
This commit is contained in:
@@ -49,6 +49,18 @@ BACKENDS: tuple[tuple[str, int], ...] = (
|
||||
#: follows the request or ignores it.
|
||||
SWEEP_RATES: tuple[float, ...] = (60.0, 30.0, 20.0, 15.0, 10.0)
|
||||
|
||||
#: Sizes asked for at one fixed rate. This is what separates the two remaining
|
||||
#: explanations for a low rate: "the link cannot carry the pixels" (smaller
|
||||
#: frames go faster) from "this camera is a 15 fps device" (the rate does not
|
||||
#: move at all).
|
||||
SWEEP_SIZES: tuple[tuple[int, int], ...] = (
|
||||
(1920, 1080),
|
||||
(1280, 720),
|
||||
(960, 540),
|
||||
(848, 480),
|
||||
(640, 480),
|
||||
)
|
||||
|
||||
SAMPLES = 60
|
||||
#: A request is "missed" when the measured rate is below this fraction of it.
|
||||
TOLERANCE = 0.9
|
||||
@@ -145,6 +157,24 @@ def sweep(index: int, backend_name: str, backend: int, size: tuple[int, int],
|
||||
return rows
|
||||
|
||||
|
||||
def size_sweep(index: int, backend_name: str, backend: int, fps: float = 30.0,
|
||||
*, samples: int = SAMPLES) -> list[dict]:
|
||||
"""Ask for one rate at shrinking sizes: bandwidth, or a fixed ceiling?
|
||||
|
||||
A link that cannot carry the pixels gets faster as the frames get smaller. A
|
||||
camera whose own rate is 15 fps delivers 15 whatever it is asked for.
|
||||
"""
|
||||
rows = []
|
||||
for width, height in SWEEP_SIZES:
|
||||
result = probe(
|
||||
index, backend_name, backend, ("MJPG", width, height, fps),
|
||||
samples=samples,
|
||||
)
|
||||
if result is not None:
|
||||
rows.append(result)
|
||||
return rows
|
||||
|
||||
|
||||
def main(argv: list[str] | None = None) -> int:
|
||||
parser = argparse.ArgumentParser(description=__doc__.splitlines()[0])
|
||||
parser.add_argument("--index", type=int, default=None, help="camera index to probe")
|
||||
@@ -198,6 +228,21 @@ def main(argv: list[str] | None = None) -> int:
|
||||
f"(a ceiling that does not move with the request is the "
|
||||
f"hardware's, not the request's)"
|
||||
)
|
||||
print(
|
||||
f"\n sizes at MJPG@{30:g} fps [{first_backend[0]}] -- bandwidth, "
|
||||
f"or a fixed ceiling?"
|
||||
)
|
||||
for result in size_sweep(
|
||||
index, first_backend[0], first_backend[1], samples=args.samples
|
||||
):
|
||||
width, height = result["asked"][1], result["asked"][2]
|
||||
print(
|
||||
f" {width}x{height:<5} -> measured {result['measured_fps']:5.1f} fps"
|
||||
)
|
||||
print(
|
||||
" smaller frames going faster means the link is the limit; the "
|
||||
"same number at every size means the camera is"
|
||||
)
|
||||
if header:
|
||||
found += 1
|
||||
|
||||
|
||||
Reference in New Issue
Block a user