diff options
| author | Luke Hoersten <[email protected]> | 2026-06-20 10:06:58 -0500 |
|---|---|---|
| committer | Luke Hoersten <[email protected]> | 2026-06-20 10:06:58 -0500 |
| commit | f982b88d447f265f9847a48946a9903d1faebf49 (patch) | |
| tree | 10179e542eadd78959b0c7bf7551eabb00ca2aa4 | |
| parent | aa1ce70d546355997c58488fc409767d1dc8088f (diff) | |
scrypted: drop substream picker, hardcode best-resolution + skip low-res
Reverts the per-viewport "Camera substream" UI added in 6d74d02 —
having a knob the user has to find and tune is the wrong shape. The
goal is "best quality, highest fps that's actually achievable" and
that's a deterministic walk, not a user choice.
New walk: medium-resolution → local → remote → camera-default.
Explicitly NOT in the list:
- low-resolution: the camera's preview substream, capped at the
~5-8 fps that's been bottlenecking us.
- remote-recorder: has the camera's ~10s prebuffer baked in (we'd
display the past rather than the present).
Wire cost is unchanged: every input resolution is re-encoded to
panel-native 800x480 mjpeg q:v 1 before going to the device. The
only tradeoff for picking the main stream is Scrypted-side ffmpeg
CPU, which is plentiful. Throughput to the firmware is the same;
upstream camera fps is what changes (5fps → 15-30fps typical).
| -rw-r--r-- | scrypted/scrypted-viewport.ts | 43 |
1 files changed, 19 insertions, 24 deletions
diff --git a/scrypted/scrypted-viewport.ts b/scrypted/scrypted-viewport.ts index bf67a6d..63cab8d 100644 --- a/scrypted/scrypted-viewport.ts +++ b/scrypted/scrypted-viewport.ts @@ -6,7 +6,7 @@ // short git hash of the commit that added this constant — if the // hash in the log doesn't match the HEAD this file came from, the // Scrypted Script editor is still on stale code. -const SCRIPT_VERSION = "6d74d02"; +const SCRIPT_VERSION = "pending"; // // Architecture // ------------ @@ -123,16 +123,6 @@ class Viewport extends ScryptedDeviceBase implements Settings { const v = this.storage.getItem("brightness"); return v ? Math.max(0, Math.min(100, parseInt(v, 10) || 0)) : DEFAULT_BRIGHTNESS; } - // Preferred camera substream. "auto" walks a low-latency-first - // priority list and takes the first that resolves; the other - // options pin a specific substream so the user can pick a higher- - // fps source when "auto" lands on a slow 5-fps preview stream. - get streamDestination(): string { - const v = this.storage.getItem("stream_destination"); - const allowed = new Set(["auto", "low-resolution", "medium-resolution", - "local", "remote", "remote-recorder"]); - return allowed.has(v as any) ? (v as string) : "auto"; - } // ffmpeg mjpeg encoder -q:v. Valid range 1..31, lower = higher // quality + bigger JPEG (1 ≈ visually lossless, 31 ≈ very lossy). // Default 1 — with HTTP keep-alive + NODELAY we have plenty of @@ -207,14 +197,6 @@ class Viewport extends ScryptedDeviceBase implements Settings { } as any, { group: "Display", - key: "stream_destination", - title: "Camera substream", - description: "Which camera-side stream to pull. 'auto' walks low-latency-first and picks the first that resolves (typically a low-fps preview substream — ~5-8 fps). Pin to medium-resolution or remote-recorder to force a higher-fps stream at the cost of larger frames + latency.", - choices: ["auto", "low-resolution", "medium-resolution", "local", "remote", "remote-recorder"], - value: this.streamDestination, - } as any, - { - group: "Display", key: "jpeg_quality", title: "JPEG quality (1–31, lower = better)", description: "ffmpeg mjpeg encoder -q:v. 1 ≈ visually lossless (~140KB at panel-native), 5 ≈ good (~70KB), 10+ noticeably lossy. Default 1.", @@ -794,13 +776,26 @@ class ScryptedViewportProvider extends ScryptedDeviceBase // prebuffer baked in — we'd watch the past, not the present. // Walk substreams from lowest-latency → highest-latency and // take the first one that resolves. + // Source substream selection. We always want the highest-fps + // highest-quality option that still has acceptable latency. + // The wire cost is unaffected — we re-encode to panel-native + // 800x480 mjpeg q:v 1 regardless of input resolution — so the + // only tradeoff is Scrypted-side ffmpeg CPU (irrelevant here). + // + // Order of preference: + // medium-resolution — usually the camera's main 1080p + // stream at 15-30 fps, low latency + // local — main stream for local clients + // remote — main stream for remote clients + // (camera default) — last-ditch fallback + // + // Explicitly NOT trying: + // low-resolution — preview substream, capped 5-8 fps + // remote-recorder — has ~10s prebuffer baked in (we'd watch + // the past, not the present) let stream: any; let pickedDest = "(default)"; - const userPref = v.streamDestination; - const destOrder = userPref === "auto" - ? ["low-resolution", "medium-resolution", "local", "remote", "remote-recorder"] - : [userPref]; - for (const destination of destOrder) { + for (const destination of ["medium-resolution", "local", "remote"]) { try { stream = await cam.getVideoStream({ destination }); pickedDest = destination; break; } catch { /* try next */ } } |
