Bias the 0.5x lens, since its feed has no frame pipeline

The ultra-wide preview is a bare Camera2 surface: it never goes through
Skia, so the software EV gain that carries exposure on the 1x preview had
nothing to act on and quick EV / the LIGHT-EV slider did nothing at 0.5x.
The lens itself now takes the bias, as CONTROL_AE_EXPOSURE_COMPENSATION on
every preview request (session builder, metering rebuilds, and a setEv call
the viewfinder pushes whenever the value changes).

The still is left alone: capture() pins the compensation back to 0 and
waits on an AE precapture trigger, so the file stays unbiased and the export
applies its software gain exactly once, as it does for the 1x path. The
hardware range clamps the bias where the lens offers less than the app's
+/-3 EV.
This commit is contained in:
2026-09-16 07:41:38 +07:00
parent 39487ffd67
commit 78630d8a2d
3 changed files with 77 additions and 0 deletions
+8
View File
@@ -559,6 +559,14 @@ const Viewfinder = forwardRef<ViewfinderHandle, ViewfinderProps>(function Viewfi
const [ultraWideOn, setUltraWideOn] = useState(false);
const ultraWideOnRef = useRef(false);
ultraWideOnRef.current = ultraWideOn;
// The 0.5x feed is a bare Camera2 surface — the Skia matrix gain that carries
// EV on the 1x preview never touches it, so the lens gets the same EV as a
// hardware AE bias instead. The still is captured unbiased (see the module),
// so the export applies its software gain once and the file matches.
useEffect(() => {
if (!ultraWideOn) return;
UltraWide.setEvAsync(evApplied).catch(() => {});
}, [ultraWideOn, evApplied]);
useEffect(() => {
let alive = true;
UltraWide.availableAsync()