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:
parent
bb3a42e6bc
commit
cad5240420
@ -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(() => ({
|
||||
|
@ -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())
|
||||
|
@ -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,
|
||||
|
@ -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)
|
||||
}
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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.
|
||||
*
|
||||
|
@ -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.
|
||||
*/
|
||||
|
Loading…
Reference in New Issue
Block a user