From 30ef50814fd28397e958e90d68165a434109d799 Mon Sep 17 00:00:00 2001 From: ykcheungab Date: Mon, 14 Sep 2026 13:40:04 +0800 Subject: [PATCH] =?UTF-8?q?=E6=8E=A2=E9=92=88=E5=A2=9E=E5=8A=A0=E5=B0=BA?= =?UTF-8?q?=E5=AF=B8=E6=89=AB=E6=8F=8F=EF=BC=9A=E5=8C=BA=E5=88=86=E9=93=BE?= =?UTF-8?q?=E8=B7=AF=E5=B8=A6=E5=AE=BD=E4=B8=8D=E5=A4=9F=E4=B8=8E=E6=91=84?= =?UTF-8?q?=E5=83=8F=E5=A4=B4=E6=9C=AC=E8=BA=AB=E5=B0=B1=E6=98=AF=2015=20f?= =?UTF-8?q?ps=20-=20What:=20tools/camera=5Fprobe.py=20=E6=96=B0=E5=A2=9E?= =?UTF-8?q?=20SWEEP=5FSIZES=20=E4=B8=8E=20size=5Fsweep()=EF=BC=8C=E5=9C=A8?= =?UTF-8?q?=E5=B8=A7=E7=8E=87=E6=89=AB=E6=8F=8F=E4=B9=8B=E5=90=8E=E5=AF=B9?= =?UTF-8?q?=20MJPG@30=20=E4=BE=9D=E6=AC=A1=E7=94=B3=E8=AF=B7=201920x1080/1?= =?UTF-8?q?280x720/960x540/848x480/640x480=20=E5=B9=B6=E6=89=93=E5=8D=B0?= =?UTF-8?q?=E5=AE=9E=E6=B5=8B=E9=80=9F=E7=8E=87=EF=BC=8C=E6=8F=90=E7=A4=BA?= =?UTF-8?q?=E8=AF=AD=E5=86=99=E6=98=8E=E5=88=A4=E6=96=AD=E6=96=B9=E5=BC=8F?= =?UTF-8?q?=EF=BC=9A=E5=B8=A7=E8=B6=8A=E5=B0=8F=E8=B6=8A=E5=BF=AB=20?= =?UTF-8?q?=E2=87=92=20=E9=93=BE=E8=B7=AF=E5=B8=A6=E5=AE=BD=E6=98=AF?= =?UTF-8?q?=E7=93=B6=E9=A2=88=EF=BC=9B=E6=AF=8F=E4=B8=AA=E5=B0=BA=E5=AF=B8?= =?UTF-8?q?=E9=83=BD=E4=B8=80=E6=A0=B7=20=E2=87=92=20=E6=98=AF=E6=91=84?= =?UTF-8?q?=E5=83=8F=E5=A4=B4=E6=9C=AC=E8=BA=AB=E7=9A=84=E9=80=9F=E7=8E=87?= =?UTF-8?q?=E4=B8=8A=E9=99=90=E3=80=82=20-=20Why:=20=E7=94=A8=E6=88=B7?= =?UTF-8?q?=E5=AE=9E=E6=B5=8B=20MJPG=20=E5=9C=A8=201080p=20=E4=B8=8E=20720?= =?UTF-8?q?p=20=E9=83=BD=E6=98=AF=2015=20fps=E3=80=81YUYV=20=E4=B8=A4?= =?UTF-8?q?=E6=A1=A3=E9=83=BD=E6=98=AF=201=20fps=EF=BC=8C=E4=B8=A4?= =?UTF-8?q?=E7=A7=8D=E8=A7=A3=E9=87=8A=E4=BB=8D=E7=84=B6=E9=83=BD=E6=88=90?= =?UTF-8?q?=E7=AB=8B=EF=BC=88=E9=93=BE=E8=B7=AF=E5=8F=AA=E8=83=BD=E6=89=9B?= =?UTF-8?q?=E7=BA=A6=203-4=20MB/s=EF=BC=8C=E6=88=96=E8=BF=99=E9=A2=97?= =?UTF-8?q?=E6=91=84=E5=83=8F=E5=A4=B4=E5=9C=A8=E8=BF=99=E4=BA=9B=E6=A0=BC?= =?UTF-8?q?=E5=BC=8F=E4=B8=8A=E5=B0=B1=E6=98=AF=2015=20fps=20=E8=AE=BE?= =?UTF-8?q?=E5=A4=87=EF=BC=89=EF=BC=8C=E8=80=8C=E5=A4=84=E7=BD=AE=E5=AE=8C?= =?UTF-8?q?=E5=85=A8=E4=B8=8D=E5=90=8C=EF=BC=9B=E5=B8=A7=E7=8E=87=E6=89=AB?= =?UTF-8?q?=E6=8F=8F=E5=8F=AA=E8=83=BD=E5=8C=BA=E5=88=86"=E7=94=B3?= =?UTF-8?q?=E8=AF=B7=E8=A2=AB=E7=A0=8D=E5=8D=8A"=E4=B8=8E"=E5=9B=BA?= =?UTF-8?q?=E5=AE=9A=E4=B8=8A=E9=99=90"=EF=BC=8C=E5=B0=BA=E5=AF=B8?= =?UTF-8?q?=E6=89=AB=E6=8F=8F=E6=89=8D=E8=83=BD=E5=8C=BA=E5=88=86"?= =?UTF-8?q?=E5=B8=A6=E5=AE=BD"=E4=B8=8E"=E8=AE=BE=E5=A4=87"=E3=80=82=20-?= =?UTF-8?q?=20Verification:=20compileall=20=E9=80=9A=E8=BF=87=EF=BC=9B?= =?UTF-8?q?=E6=97=A0=E6=91=84=E5=83=8F=E5=A4=B4=E6=97=B6=E4=BB=8D=E8=BF=94?= =?UTF-8?q?=E5=9B=9E=201=20=E5=B9=B6=E7=BB=99=E5=87=BA=E8=A7=A3=E9=87=8A?= =?UTF-8?q?=EF=BC=9Bstudio=20=E5=85=A8=E9=87=8F=2091=20passed=EF=BC=88?= =?UTF-8?q?=E6=8E=A2=E9=92=88=E7=9A=84=E6=97=A0=E6=91=84=E5=83=8F=E5=A4=B4?= =?UTF-8?q?=E7=94=A8=E4=BE=8B=E8=A6=86=E7=9B=96=20main()=20=E7=9A=84?= =?UTF-8?q?=E9=99=8D=E7=BA=A7=E8=B7=AF=E5=BE=84=EF=BC=89=E3=80=82=20-=20No?= =?UTF-8?q?t=20in=20this=20change:=20=E6=9C=AA=E6=94=B9=20SDK=20=E9=87=87?= =?UTF-8?q?=E9=9B=86=E5=8F=82=E6=95=B0=EF=BC=9B=E6=9C=AA=E5=81=9A=E8=87=AA?= =?UTF-8?q?=E5=8A=A8=E9=99=8D=E7=BA=A7=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/studio/tools/camera_probe.py | 45 +++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) 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