src.nth.io/

summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLuke Hoersten <[email protected]>2026-06-15 08:49:34 -0500
committerLuke Hoersten <[email protected]>2026-06-15 08:49:34 -0500
commitfd3faa934999ee3953d66d9db84f67b699e81548 (patch)
treef507d639dc54fa124c145159a47b41d01909b3d1
parent2429179eaf1a62af770fe6de3b25b276db3ce401 (diff)
scrypted: rotate-before-scale so portrait JPEGs report 800x480
The portrait filter chain was scale=480:800,transpose=1. Output frame dimensions came out 800x480 (correct) but the mjpeg encoder was occasionally writing the pre-transpose 480x800 into the JPEG SOF marker, so the firmware's dimension check rejected the frame: expected 800x480, got 480x800 Reordering to transpose=1,scale=800:480,setsar=1 makes the post-filter dims explicit and unambiguous — transpose first changes the frame to 800x480, scale re-asserts it, setsar clears any leftover non-1:1 aspect ratio metadata. The encoder now writes 800x480 into SOF every frame.
-rw-r--r--scrypted/scrypted-viewport.ts12
1 files changed, 10 insertions, 2 deletions
diff --git a/scrypted/scrypted-viewport.ts b/scrypted/scrypted-viewport.ts
index 7b69a75..22f233a 100644
--- a/scrypted/scrypted-viewport.ts
+++ b/scrypted/scrypted-viewport.ts
@@ -614,9 +614,17 @@ class ScryptedViewportProvider extends ScryptedDeviceBase
// panel is already in the right rotation. The firmware never
// touches pixels — the hardware JPEG decoder writes BGR888
// straight into a DMA buffer that gets handed to the DSI engine.
+ // Filter order matters here. Earlier we did
+ // scale=480:800,transpose=1
+ // which intermittently produced a JPEG with a SOF marker
+ // reporting 480x800 — the firmware then rejected it with
+ // "expected 800x480, got 480x800". Rotating *first* and then
+ // scaling to an EXPLICIT panelWxpanelH (with setsar to clear
+ // any leftover aspect-ratio metadata) makes the final encoded
+ // dimensions deterministic regardless of source resolution.
const vf = v.orientation === "portrait"
- ? `scale=${panelH}:${panelW}:flags=lanczos,transpose=1` // 90° CW → panelW x panelH
- : `scale=${panelW}:${panelH}:flags=lanczos`;
+ ? `transpose=1,scale=${panelW}:${panelH}:flags=lanczos,setsar=1`
+ : `scale=${panelW}:${panelH}:flags=lanczos,setsar=1`;
const fps = Math.max(1, Math.round(1000 / v.frameIntervalMs));
// Pull the camera's video stream, convert to ffmpeg input args, and