Skip to content

Commit fe0e6a2

Browse files
committed
feat: Add manual iso/exposureDuration props
1 parent 45e9c81 commit fe0e6a2

File tree

6 files changed

+58
-8
lines changed

6 files changed

+58
-8
lines changed

package/ios/Core/CameraConfiguration.swift

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -46,12 +46,18 @@ final class CameraConfiguration {
4646

4747
// Exposure
4848
var exposure: Float?
49+
var exposureDuration: Double?
50+
var iso: Float?
4951

5052
// isActive (Start/Stop)
5153
var isActive = false
5254

5355
// Audio Session
5456
var audio: OutputConfiguration<Audio> = .disabled
57+
58+
var isManualExposure: Bool {
59+
return exposureDuration != nil || iso != nil
60+
}
5561

5662
init(copyOf other: CameraConfiguration?) {
5763
if let other {
@@ -83,7 +89,6 @@ final class CameraConfiguration {
8389
/**
8490
Throw this to abort calls to configure { ... } and apply no changes.
8591
*/
86-
@frozen
8792
enum AbortThrow: Error {
8893
case abort
8994
}
@@ -131,7 +136,7 @@ final class CameraConfiguration {
131136
// format (depends on cameraId)
132137
formatChanged = inputChanged || left?.format != right.format
133138
// side-props (depends on format)
134-
sidePropsChanged = formatChanged || left?.minFps != right.minFps || left?.maxFps != right.maxFps || left?.enableLowLightBoost != right.enableLowLightBoost
139+
sidePropsChanged = formatChanged || left?.minFps != right.minFps || left?.maxFps != right.maxFps || left?.enableLowLightBoost != right.enableLowLightBoost || left?.exposureDuration != right.exposureDuration || left?.iso != right.iso
135140
// torch (depends on isActive)
136141
let wasInactiveAndNeedsToEnableTorchAgain = left?.isActive == false && right.isActive == true && right.torch == .on
137142
torchChanged = inputChanged || wasInactiveAndNeedsToEnableTorchAgain || left?.torch != right.torch
@@ -148,7 +153,6 @@ final class CameraConfiguration {
148153
}
149154
}
150155

151-
@frozen
152156
enum OutputConfiguration<T: Equatable>: Equatable {
153157
case disabled
154158
case enabled(config: T)

package/ios/Core/CameraSession+Configuration.swift

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -273,19 +273,29 @@ extension CameraSession {
273273
}
274274
device.automaticallyEnablesLowLightBoostWhenAvailable = configuration.enableLowLightBoost
275275
}
276-
276+
277277
// Configure auto-focus
278278
if device.isFocusModeSupported(.continuousAutoFocus) {
279279
if device.isFocusPointOfInterestSupported {
280280
device.focusPointOfInterest = CGPoint(x: 0.5, y: 0.5)
281281
}
282282
device.focusMode = .continuousAutoFocus
283283
}
284-
if device.isExposureModeSupported(.continuousAutoExposure) {
285-
if device.isExposurePointOfInterestSupported {
286-
device.exposurePointOfInterest = CGPoint(x: 0.5, y: 0.5)
284+
285+
286+
if configuration.isManualExposure {
287+
// Lock exposure to manual
288+
let duration = CMTime(seconds: configuration.exposureDuration ?? AVCaptureDevice.currentExposureDuration.seconds, preferredTimescale: 1)
289+
let iso = configuration.iso ?? AVCaptureDevice.currentISO
290+
device.setExposureModeCustom(duration: duration, iso: iso)
291+
} else {
292+
// Configure auto-exposure
293+
if device.isExposureModeSupported(.continuousAutoExposure) {
294+
if device.isExposurePointOfInterestSupported {
295+
device.exposurePointOfInterest = CGPoint(x: 0.5, y: 0.5)
296+
}
297+
device.exposureMode = .continuousAutoExposure
287298
}
288-
device.exposureMode = .continuousAutoExposure
289299
}
290300
}
291301

package/ios/Core/Types/CameraDeviceFormat.swift

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,9 @@ struct CameraDeviceFormat: Equatable, CustomStringConvertible {
2424

2525
let minISO: Float
2626
let maxISO: Float
27+
28+
let minExposureDuration: Double
29+
let maxExposureDuration: Double
2730

2831
let fieldOfView: Float
2932

@@ -44,6 +47,8 @@ struct CameraDeviceFormat: Equatable, CustomStringConvertible {
4447
maxFps = format.maxFps
4548
minISO = format.minISO
4649
maxISO = format.maxISO
50+
minExposureDuration = format.minExposureDuration.seconds
51+
maxExposureDuration = format.maxExposureDuration.seconds
4752
fieldOfView = format.videoFieldOfView
4853
videoStabilizationModes = format.videoStabilizationModes.map { VideoStabilizationMode(from: $0) }
4954
autoFocusSystem = AutoFocusSystem(fromFocusSystem: format.autoFocusSystem)
@@ -62,6 +67,8 @@ struct CameraDeviceFormat: Equatable, CustomStringConvertible {
6267
maxFps = jsValue["maxFps"] as! Double
6368
minISO = jsValue["minISO"] as! Float
6469
maxISO = jsValue["maxISO"] as! Float
70+
minExposureDuration = jsValue["minExposureDuration"] as! Double
71+
maxExposureDuration = jsValue["minExposureDuration"] as! Double
6572
fieldOfView = jsValue["fieldOfView"] as! Float
6673
let jsVideoStabilizationModes = jsValue["videoStabilizationModes"] as! [String]
6774
videoStabilizationModes = try jsVideoStabilizationModes.map { try VideoStabilizationMode(jsValue: $0) }
@@ -88,6 +95,8 @@ struct CameraDeviceFormat: Equatable, CustomStringConvertible {
8895
"videoWidth": videoWidth,
8996
"minISO": minISO,
9097
"maxISO": maxISO,
98+
"minExposureDuration": minExposureDuration,
99+
"maxExposureDuration": maxExposureDuration,
91100
"fieldOfView": fieldOfView,
92101
"supportsVideoHdr": supportsVideoHdr,
93102
"supportsPhotoHdr": supportsPhotoHdr,

package/ios/React/CameraViewManager.m

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,8 @@ @interface RCT_EXTERN_REMAP_MODULE (CameraView, CameraViewManager, RCTViewManage
5353
RCT_EXPORT_VIEW_PROPERTY(torch, NSString);
5454
RCT_EXPORT_VIEW_PROPERTY(zoom, NSNumber);
5555
RCT_EXPORT_VIEW_PROPERTY(exposure, NSNumber);
56+
RCT_EXPORT_VIEW_PROPERTY(iso, NSNumber);
57+
RCT_EXPORT_VIEW_PROPERTY(exposureDuration, NSNumber);
5658
RCT_EXPORT_VIEW_PROPERTY(enableZoomGesture, BOOL);
5759
RCT_EXPORT_VIEW_PROPERTY(outputOrientation, NSString);
5860
RCT_EXPORT_VIEW_PROPERTY(resizeMode, NSString);

package/src/types/CameraDevice.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,14 @@ export interface CameraDeviceFormat {
7878
* Minimum supported ISO value
7979
*/
8080
minISO: number
81+
/**
82+
* Minimum supported exposure duration, in seconds
83+
*/
84+
minExposureDuration: number
85+
/**
86+
* Maximum supported exposure duration, in seconds
87+
*/
88+
maxExposureDuration: number
8189
/**
8290
* The video field of view in degrees
8391
*/

package/src/types/CameraProps.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,23 @@ export interface CameraProps extends ViewProps {
149149
* The value between min- and max supported exposure is considered the default, neutral value.
150150
*/
151151
exposure?: number
152+
153+
/**
154+
* Manually configures the ISO value of the Camera.
155+
*
156+
* If either {@linkcode iso} or {@linkcode exposureDuration} is set, the Camera will be locked to manual exposure.
157+
*
158+
* @default undefined
159+
*/
160+
iso?: number
161+
/**
162+
* Manually configures the exposure duration (in seconds) of the Camera.
163+
*
164+
* If either {@linkcode exposureDuration} or {@linkcode iso} is set, the Camera will be locked to manual exposure.
165+
*
166+
* @default undefined
167+
*/
168+
exposureDuration?: number
152169
//#endregion
153170

154171
//#region Format/Preset selection

0 commit comments

Comments
 (0)