fix: Move minExposure/maxExposure from format into device (#2211)

* fix: Move `minExposure`/`maxExposure` into `device`

* Update docs

* chore: Remove unneeded dependency

* chore: Update code
This commit is contained in:
Marc Rousavy 2023-11-24 18:20:56 +01:00 committed by GitHub
parent bb3a42e6bc
commit cad5240420
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 25 additions and 36 deletions

View File

@ -12,7 +12,7 @@ To adjust the exposure of the Camera, you can use the Camera's [`exposure`](/doc
<Camera {...props} exposure={-1} />
```
Values for the `exposure` prop range from [`format.minExposure`](/docs/api/interfaces/CameraDeviceFormat#maxExposure) to [`format.maxExposure`](/docs/api/interfaces/CameraDeviceFormat#minExposure), inclusively. By default (`undefined`), it is set to neutral auto exposure.
Values for the `exposure` prop range from [`device.minExposure`](/docs/api/interfaces/CameraDevice#minexposure) to [`device.maxExposure`](/docs/api/interfaces/CameraDevice#maxexposure), inclusively. By default (`undefined`), it is set to neutral auto exposure.
Instead of manually adjusting ISO and Exposure-Duration, this acts as an "exposure compensation bias", meaning the Camera will still continuously automatically adjust exposure as it goes, but premultiplies the given exposure value to it's ISO and Exposure Duration settings.
@ -44,12 +44,12 @@ Just like [`zoom`](zooming), this property can be animated using Reanimated.
// 2. map slider to [minExposure, 0, maxExposure]
const exposureValue = useDerivedValue(() => {
if (format == null) return 0
if (device == null) return 0
return interpolate(exposureSlider.value,
[-1, 0, 1],
[format.minExposure, 0, format.maxExposure])
}, [exposureSlider, format])
[device.minExposure, 0, device.maxExposure])
}, [exposureSlider, device])
// 3. pass it as an animated prop
const animatedProps = useAnimatedProps(() => ({

View File

@ -177,8 +177,6 @@ class CameraDeviceDetails(private val cameraManager: CameraManager, private val
map.putInt("videoWidth", videoSize.width)
map.putInt("minISO", isoRange.lower)
map.putInt("maxISO", isoRange.upper)
map.putDouble("minExposure", exposureRange.lower.toDouble() / exposureStep.toDouble())
map.putDouble("maxExposure", exposureRange.upper.toDouble() / exposureStep.toDouble())
map.putInt("minFps", fpsRange.lower)
map.putInt("maxFps", fpsRange.upper)
map.putDouble("maxZoom", maxZoom)
@ -209,6 +207,8 @@ class CameraDeviceDetails(private val cameraManager: CameraManager, private val
map.putDouble("minZoom", minZoom)
map.putDouble("maxZoom", maxZoom)
map.putDouble("neutralZoom", 1.0) // Zoom is always relative to 1.0 on Android
map.putDouble("minExposure", exposureRange.lower.toDouble() / exposureStep.toDouble())
map.putDouble("maxExposure", exposureRange.upper.toDouble() / exposureStep.toDouble())
map.putString("hardwareLevel", hardwareLevel.unionValue)
map.putString("sensorOrientation", Orientation.fromRotationDegrees(sensorOrientation).unionValue)
map.putArray("formats", getFormats())

View File

@ -13,8 +13,6 @@ data class CameraDeviceFormat(
val maxFps: Double,
val minISO: Double,
val maxISO: Double,
val minExposure: Double,
val maxExposure: Double,
val fieldOfView: Double,
val maxZoom: Double,
val videoStabilizationModes: List<VideoStabilizationMode>,
@ -48,8 +46,6 @@ data class CameraDeviceFormat(
value.getDouble("maxFps"),
value.getDouble("minISO"),
value.getDouble("maxISO"),
value.getDouble("minExposure"),
value.getDouble("maxExposure"),
value.getDouble("fieldOfView"),
value.getDouble("maxZoom"),
videoStabilizationModes,

View File

@ -187,14 +187,14 @@ extension CameraSession {
ReactLogger.log(level: .info, message: "Configuring Format (\(targetFormat))...")
let currentFormat = CameraDeviceFormat(fromFormat: device.activeFormat, forDevice: device)
let currentFormat = CameraDeviceFormat(fromFormat: device.activeFormat)
if currentFormat == targetFormat {
ReactLogger.log(level: .info, message: "Already selected active format, no need to configure.")
return
}
// Find matching format (JS Dictionary -> strongly typed Swift class)
let format = device.formats.first { targetFormat.isEqualTo(format: $0, device: device) }
let format = device.formats.first { targetFormat.isEqualTo(format: $0) }
guard let format else {
throw CameraError.format(.invalidFormat)
}
@ -295,7 +295,7 @@ extension CameraSession {
return
}
let clamped = max(min(exposure, device.maxExposureTargetBias), device.minExposureTargetBias)
let clamped = min(max(exposure, device.minExposureTargetBias), device.maxExposureTargetBias)
device.setExposureTargetBias(clamped)
}

View File

@ -10,7 +10,7 @@ import AVFoundation
extension AVCaptureDevice {
func toDictionary() -> [String: Any] {
let formats = formats.map { CameraDeviceFormat(fromFormat: $0, forDevice: self) }
let formats = formats.map { CameraDeviceFormat(fromFormat: $0) }
return [
"id": uniqueID,
@ -20,8 +20,10 @@ extension AVCaptureDevice {
"hasFlash": hasFlash,
"hasTorch": hasTorch,
"minZoom": minAvailableVideoZoomFactor,
"neutralZoom": neutralZoomFactor,
"maxZoom": maxAvailableVideoZoomFactor,
"neutralZoom": neutralZoomFactor,
"minExposure": minExposureTargetBias,
"maxExposure": maxExposureTargetBias,
"isMultiCam": isMultiCam,
"supportsRawCapture": false, // TODO: supportsRawCapture
"supportsLowLightBoost": isLowLightBoostSupported,

View File

@ -22,9 +22,6 @@ struct CameraDeviceFormat: Equatable, CustomStringConvertible {
let minFps: Double
let maxFps: Double
let minExposure: Float
let maxExposure: Float
let minISO: Float
let maxISO: Float
@ -41,15 +38,13 @@ struct CameraDeviceFormat: Equatable, CustomStringConvertible {
let supportsDepthCapture: Bool
init(fromFormat format: AVCaptureDevice.Format, forDevice device: AVCaptureDevice) {
init(fromFormat format: AVCaptureDevice.Format) {
videoWidth = Int(format.videoDimensions.width)
videoHeight = Int(format.videoDimensions.height)
photoWidth = Int(format.photoDimensions.width)
photoHeight = Int(format.photoDimensions.height)
minFps = format.minFps
maxFps = format.maxFps
minExposure = device.minExposureTargetBias
maxExposure = device.maxExposureTargetBias
minISO = format.minISO
maxISO = format.maxISO
fieldOfView = format.videoFieldOfView
@ -72,8 +67,6 @@ struct CameraDeviceFormat: Equatable, CustomStringConvertible {
maxFps = jsValue["maxFps"] as! Double
minISO = jsValue["minISO"] as! Float
maxISO = jsValue["maxISO"] as! Float
minExposure = jsValue["minExposure"] as! Float
maxExposure = jsValue["maxExposure"] as! Float
fieldOfView = jsValue["fieldOfView"] as! Float
maxZoom = jsValue["maxZoom"] as! Double
let jsVideoStabilizationModes = jsValue["videoStabilizationModes"] as! [String]
@ -88,8 +81,8 @@ struct CameraDeviceFormat: Equatable, CustomStringConvertible {
// swiftlint:enable force_cast
}
func isEqualTo(format other: AVCaptureDevice.Format, device otherDevice: AVCaptureDevice) -> Bool {
let other = CameraDeviceFormat(fromFormat: other, forDevice: otherDevice)
func isEqualTo(format other: AVCaptureDevice.Format) -> Bool {
let other = CameraDeviceFormat(fromFormat: other)
return self == other
}
@ -103,8 +96,6 @@ struct CameraDeviceFormat: Equatable, CustomStringConvertible {
"videoWidth": videoWidth,
"minISO": minISO,
"maxISO": maxISO,
"minExposure": minExposure,
"maxExposure": maxExposure,
"fieldOfView": fieldOfView,
"maxZoom": maxZoom,
"supportsVideoHdr": supportsVideoHdr,

View File

@ -80,14 +80,6 @@ export interface CameraDeviceFormat {
* Minimum supported ISO value
*/
minISO: number
/**
* The minimum Exposure-Bias value this format supports. When setting the `exposure` to this value, the image is almost completely dark (under-exposed).
*/
minExposure: number
/**
* The maximum Exposure-Bias value this format supports. When setting the `exposure` to this value, the image is almost completely bright (over-exposed).
*/
maxExposure: number
/**
* The video field of view in degrees
*/
@ -204,6 +196,14 @@ export interface CameraDevice {
* }))
*/
neutralZoom: number
/**
* The minimum Exposure-Bias value this format supports. When setting the `exposure` to this value, the image is almost completely dark (under-exposed).
*/
minExposure: number
/**
* The maximum Exposure-Bias value this format supports. When setting the `exposure` to this value, the image is almost completely bright (over-exposed).
*/
maxExposure: number
/**
* All available formats for this camera device. Use this to find the best format for your use case and set it to the Camera's {@linkcode CameraProps.format | Camera's .format} property.
*

View File

@ -116,7 +116,7 @@ export interface CameraProps extends ViewProps {
*
* The Camera will still continue to auto-adjust exposure and focus, but will premultiply the exposure setting with the provided value here.
*
* This values ranges from {@linkcode CameraDeviceFormat.minExposure format.minExposure} to {@linkcode CameraDeviceFormat.maxExposure format.maxExposure}.
* This values ranges from {@linkcode CameraDevice.minExposure device.minExposure} to {@linkcode CameraDevice.maxExposure device.maxExposure}.
*
* The value between min- and max supported exposure is considered the default, neutral value.
*/