margelo / margelo/react-native-vision-camera

OS: Auto-exposure restarts pinned at max ISO on every session start (regression from v4)

Open
#4,016 2 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

🐛 bug
Dominant language
TypeScript
Stars
9.6k
Forks
1.4k
Avg merge
1d 28m
Merged PRs (30d)
4

Description

Prerequisites
Reproduction

https://github.com/mrousavy/react-native-vision-camera/pull/4015/changes

Steps to reproduce

Reproduction: PR #4015 adds two failing harness tests to visioncamera.controller.harness.ts:

  • keeps an exposure lock applied between configure() and start() — scene-independent: start() resets an explicit setExposureLocked(...) back to continuous auto-exposure at the format's max ISO.
  • resumes auto-exposure near previously converged values on a fresh session — a fresh session restarts AE at max ISO instead of resuming near the previously converged exposure.
What did you expect to happen?

The preview should appear at (or very near) the correct exposure, with no visible exposure ramp — matching both VisionCamera v4 (same app, same device — no visible adjustment on camera open, including cold starts) and the native iOS Camera app.

Auto-exposure should start from a neutral mid-range default — or, when the AVCaptureDevice still holds exposure values from a previous session (which it demonstrably does right up until start() is called, see logs), from those retained values — rather than from the format's maximum ISO.

What actually happened?

On every CameraSession.configure() + start(), auto-exposure begins pinned at the format's maximum ISO (5184 on this format) and converges down to the correct value over ~1–1.5s. The preview is severely overexposed for that entire period. No crash.

Two additional data points:

  • When a previous session had run, polling controller.iso before start() returns that session's correct converged value (e.g. ISO 258). The first sample after start() jumps to ISO 5184 (max). So the start sequence itself resets exposure to max, discarding valid AE state.
  • Applying controller.setExposureLocked(duration, iso) with known-good values inside onConfigured (after configure, before start) does not help: the session start still resets exposure to max ISO, overriding the lock.
Affected platforms

iOS (device)

Device(s) affected

iPhone 17 Pro

VisionCamera version

5.0.11

React Native version

0.83.6

React Native architecture

New Architecture (Fabric / bridgeless)

Features being used
  • Preview
  • Photo capture
  • Video capture
  • Frame Processors (worklets)
  • Skia Frame Processors
  • Code/Barcode Scanner
  • Location metadata
  • Multi-cam
  • Depth data
  • HDR / custom dynamic range
  • Custom format / FPS / resolution
Relevant logs / stack trace
AE telemetry polled from the CameraController every ~100ms (iso, exposureDuration, exposureBias, exposureMode, zoom; timestamps relative to isActive=true; "session configured" / "session started" logged from onConfigured / onStarted):

[AE] session configured
[AE] +127ms  iso: 0    shutter: 1/NaN bias: 0.00 mode: continuous-auto-exposure zoom: 2.00
[AE] +234ms  iso: 0    shutter: 1/NaN bias: 0.00 mode: continuous-auto-exposure zoom: 2.00
[AE] session started
[AE] +381ms  iso: 5184 shutter: 1/30  bias: 0.00 mode: continuous-auto-exposure zoom: 2.00   <-- starts at max ISO
[AE] +484ms  iso: 3027 shutter: 1/30  bias: 0.00 mode: continuous-auto-exposure zoom: 2.00
[AE] +601ms  iso: 1768 shutter: 1/30  bias: 0.00 mode: continuous-auto-exposure zoom: 2.00
[AE] +718ms  iso: 1768 shutter: 1/30  bias: 0.00 mode: continuous-auto-exposure zoom: 2.00
[AE] +834ms  iso: 798  shutter: 1/36  bias: 0.00 mode: continuous-auto-exposure zoom: 2.00
[AE] +951ms  iso: 319  shutter: 1/36  bias: 0.00 mode: continuous-auto-exposure zoom: 2.00
[AE] +1051ms iso: 156  shutter: 1/36  bias: 0.00 mode: continuous-auto-exposure zoom: 2.00
[AE] +1151ms iso: 108  shutter: 1/38  bias: 0.00 mode: continuous-auto-exposure zoom: 2.00   <-- converged
[AE] +1268ms iso: 108  shutter: 1/50  bias: 0.00 mode: continuous-auto-exposure zoom: 2.00
A separate run showing the device still holding a previous session's correct exposure until start() resets it:

[AE] session configured
[AE] +113ms  iso: 258  shutter: 1/38  bias: 0.00 mode: continuous-auto-exposure zoom: 2.00   <-- retained from previous session (correct)
[AE] +300ms  iso: 0    shutter: 1/NaN bias: 0.00 mode: continuous-auto-exposure zoom: 2.00
[AE] session started
[AE] +411ms  iso: 5184 shutter: 1/30  bias: 0.00 mode: continuous-auto-exposure zoom: 2.00   <-- reset to max ISO
The negotiated session config (from onSessionConfigSelected):

CameraSessionConfig(format: <AVCaptureDeviceFormat: 'vide'/'420f' 3264x2448, { 1- 30 fps},
photo dims:{3264x2448,4032x3024}, fov:103.625, gdc fov:106.201, max zoom:189.00 (upscales @1.24),
secondaries:{4.00,16.00}, system zoom range:1.0-24.0, AF System:2, ISO:54.0-5184.0,
SS:0.000014-1.000000, system exposure bias range:-2.0-2.0, supports HDR, supports wide color>,
selectedFPS: Optional(30.0), selectedVideoStabilizationMode: nil,
selectedPreviewStabilizationMode: nil, selectedVideoDynamicRange: Optional(...sdr...),
isPhotoHDREnabled: false)
Additional context
  • exposureBias is 0.00 throughout (the exposure prop is not involved), and zoom is correct (2.00) from the first sample (no lens-switch involved).

  • No effect on the behavior:

    • Adding/removing constraints: { fps: 30 }, { videoDynamicRange: CommonDynamicRanges.ANY_SDR }, { resolutionBias: videoOutput }
    • Adding/removing a video output alongside the photo output
    • Removing the zoom / exposure props entirely
    • setExposureLocked(...) in onConfigured as described above
Submission
  • The reproduction I linked is either (preferred) a PR against this repo that adds a failing harness test following the harness-tests README, or (fallback) a public repo that reproduces the bug on a fresh clone. I understand the issue will be closed without one.
  • I pasted logs as text (not screenshots).
  • I wrote this report in my own words. I did not paste AI-generated descriptions of the bug.

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with the two failing harness tests added in PR #4015 to visioncamera.controller.harness.ts, following the harness-tests README in apps/simple-camera/tests. Run those tests first and trace the configure() to start() sequence they exercise. Done means the exposure lock remains applied and a fresh session resumes near the prior converged exposure instead of starting at maximum ISO.

Written by the indexing model from the issue text.

Assessment

Tech stack
ios, react-native, typescript
Domain
mobile-dev, testing-qa
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
55/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.