diff --git a/apps/studio/tools/camera_probe.py b/apps/studio/tools/camera_probe.py index ba6f816..3959d85 100644 --- a/apps/studio/tools/camera_probe.py +++ b/apps/studio/tools/camera_probe.py @@ -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