@capgo/camera-preview 8.8.0 → 8.8.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -105,6 +105,10 @@ class CameraController: NSObject {
|
|
|
105
105
|
|
|
106
106
|
var captureSession: AVCaptureSession?
|
|
107
107
|
var disableFocusIndicator: Bool = false
|
|
108
|
+
private var focusExposureRestoreGeneration: UInt = 0
|
|
109
|
+
private var focusExposureRestoreTimeoutWorkItem: DispatchWorkItem?
|
|
110
|
+
private let focusExposureRestoreTimeout: TimeInterval = 3.0
|
|
111
|
+
private let focusExposureRestorePollInterval: TimeInterval = 0.05
|
|
108
112
|
|
|
109
113
|
var currentCameraPosition: CameraPosition?
|
|
110
114
|
|
|
@@ -1195,6 +1199,7 @@ extension CameraController {
|
|
|
1195
1199
|
}
|
|
1196
1200
|
|
|
1197
1201
|
func switchCameras() throws {
|
|
1202
|
+
self.cancelPendingFocusExposureRestore()
|
|
1198
1203
|
configuredVideoFrameRate = nil
|
|
1199
1204
|
guard let currentCameraPosition = currentCameraPosition,
|
|
1200
1205
|
let captureSession = self.captureSession else {
|
|
@@ -2179,46 +2184,116 @@ extension CameraController {
|
|
|
2179
2184
|
}
|
|
2180
2185
|
}
|
|
2181
2186
|
|
|
2182
|
-
|
|
2183
|
-
|
|
2184
|
-
|
|
2185
|
-
|
|
2186
|
-
|
|
2187
|
-
|
|
2188
|
-
|
|
2189
|
-
|
|
2187
|
+
|
|
2188
|
+
private func cancelPendingFocusExposureRestore() {
|
|
2189
|
+
self.focusExposureRestoreGeneration &+= 1
|
|
2190
|
+
self.focusExposureRestoreTimeoutWorkItem?.cancel()
|
|
2191
|
+
self.focusExposureRestoreTimeoutWorkItem = nil
|
|
2192
|
+
}
|
|
2193
|
+
|
|
2194
|
+
private func applyOneShotFocusAndExposure(at point: CGPoint, on device: AVCaptureDevice, adjustExposure: Bool) throws {
|
|
2195
|
+
try device.lockForConfiguration()
|
|
2196
|
+
defer { device.unlockForConfiguration() }
|
|
2197
|
+
|
|
2198
|
+
if device.isFocusModeSupported(.autoFocus) {
|
|
2199
|
+
device.focusMode = .autoFocus
|
|
2200
|
+
} else if device.isFocusModeSupported(.continuousAutoFocus) {
|
|
2201
|
+
device.focusMode = .continuousAutoFocus
|
|
2190
2202
|
}
|
|
2191
2203
|
|
|
2192
|
-
|
|
2204
|
+
if device.isFocusPointOfInterestSupported {
|
|
2205
|
+
device.focusPointOfInterest = point
|
|
2206
|
+
}
|
|
2207
|
+
|
|
2208
|
+
if adjustExposure, device.exposureMode != .locked {
|
|
2209
|
+
if device.isExposurePointOfInterestSupported, device.isExposureModeSupported(.autoExpose) {
|
|
2210
|
+
device.exposureMode = .autoExpose
|
|
2211
|
+
device.setExposureTargetBias(0.0) { _ in }
|
|
2212
|
+
device.exposurePointOfInterest = point
|
|
2213
|
+
}
|
|
2214
|
+
}
|
|
2215
|
+
|
|
2216
|
+
device.isSubjectAreaChangeMonitoringEnabled = true
|
|
2217
|
+
}
|
|
2218
|
+
|
|
2219
|
+
private func scheduleFocusExposureRestore(for device: AVCaptureDevice) {
|
|
2220
|
+
self.focusExposureRestoreGeneration &+= 1
|
|
2221
|
+
let generation = self.focusExposureRestoreGeneration
|
|
2222
|
+
|
|
2223
|
+
self.focusExposureRestoreTimeoutWorkItem?.cancel()
|
|
2224
|
+
|
|
2225
|
+
let timeoutWork = DispatchWorkItem { [weak self] in
|
|
2226
|
+
self?.restoreContinuousFocusAndExposureIfCurrent(on: device, generation: generation)
|
|
2227
|
+
}
|
|
2228
|
+
self.focusExposureRestoreTimeoutWorkItem = timeoutWork
|
|
2229
|
+
|
|
2230
|
+
self.pollFocusExposureAdjustmentCompletion(on: device, generation: generation)
|
|
2231
|
+
DispatchQueue.main.asyncAfter(deadline: .now() + self.focusExposureRestoreTimeout, execute: timeoutWork)
|
|
2232
|
+
}
|
|
2233
|
+
|
|
2234
|
+
private func pollFocusExposureAdjustmentCompletion(on device: AVCaptureDevice, generation: UInt) {
|
|
2235
|
+
guard generation == self.focusExposureRestoreGeneration else { return }
|
|
2236
|
+
|
|
2237
|
+
if device.isAdjustingFocus || device.isAdjustingExposure {
|
|
2238
|
+
DispatchQueue.main.asyncAfter(deadline: .now() + self.focusExposureRestorePollInterval) { [weak self] in
|
|
2239
|
+
self?.pollFocusExposureAdjustmentCompletion(on: device, generation: generation)
|
|
2240
|
+
}
|
|
2193
2241
|
return
|
|
2194
2242
|
}
|
|
2195
2243
|
|
|
2196
|
-
|
|
2197
|
-
|
|
2244
|
+
self.restoreContinuousFocusAndExposureIfCurrent(on: device, generation: generation)
|
|
2245
|
+
}
|
|
2246
|
+
|
|
2247
|
+
private func restoreContinuousFocusAndExposureIfCurrent(on device: AVCaptureDevice, generation: UInt) {
|
|
2248
|
+
guard generation == self.focusExposureRestoreGeneration else { return }
|
|
2249
|
+
|
|
2250
|
+
self.focusExposureRestoreTimeoutWorkItem?.cancel()
|
|
2251
|
+
self.focusExposureRestoreTimeoutWorkItem = nil
|
|
2198
2252
|
|
|
2199
2253
|
do {
|
|
2200
2254
|
try device.lockForConfiguration()
|
|
2255
|
+
defer { device.unlockForConfiguration() }
|
|
2201
2256
|
|
|
2202
|
-
|
|
2203
|
-
|
|
2204
|
-
|
|
2205
|
-
if device.isFocusPointOfInterestSupported {
|
|
2206
|
-
device.focusPointOfInterest = centerPoint
|
|
2207
|
-
}
|
|
2208
|
-
} else if device.isFocusModeSupported(.continuousAutoFocus) {
|
|
2257
|
+
let centerPoint = CGPoint(x: 0.5, y: 0.5)
|
|
2258
|
+
|
|
2259
|
+
if device.isFocusModeSupported(.continuousAutoFocus) {
|
|
2209
2260
|
device.focusMode = .continuousAutoFocus
|
|
2210
2261
|
if device.isFocusPointOfInterestSupported {
|
|
2211
2262
|
device.focusPointOfInterest = centerPoint
|
|
2212
2263
|
}
|
|
2213
2264
|
}
|
|
2214
2265
|
|
|
2215
|
-
if device.
|
|
2216
|
-
|
|
2217
|
-
|
|
2218
|
-
device.
|
|
2266
|
+
if device.exposureMode != .locked {
|
|
2267
|
+
if device.isExposureModeSupported(.continuousAutoExposure) {
|
|
2268
|
+
device.exposureMode = .continuousAutoExposure
|
|
2269
|
+
if device.isExposurePointOfInterestSupported {
|
|
2270
|
+
device.exposurePointOfInterest = centerPoint
|
|
2271
|
+
}
|
|
2272
|
+
device.setExposureTargetBias(0.0) { _ in }
|
|
2219
2273
|
}
|
|
2220
2274
|
}
|
|
2221
|
-
|
|
2275
|
+
|
|
2276
|
+
device.isSubjectAreaChangeMonitoringEnabled = false
|
|
2277
|
+
} catch {
|
|
2278
|
+
print("[CameraPreview] Failed to restore continuous focus/exposure: \(error)")
|
|
2279
|
+
}
|
|
2280
|
+
}
|
|
2281
|
+
|
|
2282
|
+
private func triggerAutoFocus() {
|
|
2283
|
+
guard let device = self.activeVideoDevice() else { return }
|
|
2284
|
+
|
|
2285
|
+
let centerPoint = CGPoint(x: 0.5, y: 0.5)
|
|
2286
|
+
let adjustExposure: Bool
|
|
2287
|
+
do {
|
|
2288
|
+
let exposureMode = try self.getExposureMode()
|
|
2289
|
+
adjustExposure = exposureMode == "AUTO" || exposureMode == "CONTINUOUS"
|
|
2290
|
+
} catch {
|
|
2291
|
+
adjustExposure = true
|
|
2292
|
+
}
|
|
2293
|
+
|
|
2294
|
+
do {
|
|
2295
|
+
try self.applyOneShotFocusAndExposure(at: centerPoint, on: device, adjustExposure: adjustExposure)
|
|
2296
|
+
self.scheduleFocusExposureRestore(for: device)
|
|
2222
2297
|
} catch {
|
|
2223
2298
|
// Silently ignore errors during autofocus
|
|
2224
2299
|
}
|
|
@@ -2257,33 +2332,8 @@ extension CameraController {
|
|
|
2257
2332
|
}
|
|
2258
2333
|
|
|
2259
2334
|
do {
|
|
2260
|
-
try
|
|
2261
|
-
|
|
2262
|
-
// Set focus mode to auto if supported
|
|
2263
|
-
if device.isFocusModeSupported(.autoFocus) {
|
|
2264
|
-
device.focusMode = .autoFocus
|
|
2265
|
-
} else if device.isFocusModeSupported(.continuousAutoFocus) {
|
|
2266
|
-
device.focusMode = .continuousAutoFocus
|
|
2267
|
-
}
|
|
2268
|
-
|
|
2269
|
-
// Set the focus point
|
|
2270
|
-
device.focusPointOfInterest = point
|
|
2271
|
-
|
|
2272
|
-
// Skip exposure point if exposure locked
|
|
2273
|
-
if device.exposureMode != .locked {
|
|
2274
|
-
|
|
2275
|
-
// Also set exposure point if supported
|
|
2276
|
-
if device.isExposurePointOfInterestSupported && device.isExposureModeSupported(.autoExpose) {
|
|
2277
|
-
device.exposureMode = .autoExpose
|
|
2278
|
-
device.setExposureTargetBias(0.0) { _ in }
|
|
2279
|
-
device.exposurePointOfInterest = point
|
|
2280
|
-
}
|
|
2281
|
-
}
|
|
2282
|
-
|
|
2283
|
-
// Turn on subject area monitor for switch to continuous focus if needed
|
|
2284
|
-
device.isSubjectAreaChangeMonitoringEnabled = true
|
|
2285
|
-
|
|
2286
|
-
device.unlockForConfiguration()
|
|
2335
|
+
try self.applyOneShotFocusAndExposure(at: point, on: device, adjustExposure: true)
|
|
2336
|
+
self.scheduleFocusExposureRestore(for: device)
|
|
2287
2337
|
} catch {
|
|
2288
2338
|
throw CameraControllerError.unknown
|
|
2289
2339
|
}
|
|
@@ -2372,6 +2422,7 @@ extension CameraController {
|
|
|
2372
2422
|
}
|
|
2373
2423
|
|
|
2374
2424
|
func swapToDevice(deviceId: String) throws {
|
|
2425
|
+
self.cancelPendingFocusExposureRestore()
|
|
2375
2426
|
guard let captureSession = self.captureSession else {
|
|
2376
2427
|
throw CameraControllerError.captureSessionIsMissing
|
|
2377
2428
|
}
|
|
@@ -2460,6 +2511,7 @@ extension CameraController {
|
|
|
2460
2511
|
}
|
|
2461
2512
|
|
|
2462
2513
|
func cleanup() {
|
|
2514
|
+
self.cancelPendingFocusExposureRestore()
|
|
2463
2515
|
configuredVideoFrameRate = nil
|
|
2464
2516
|
stopBarcodeScanner()
|
|
2465
2517
|
if let captureSession = self.captureSession {
|
|
@@ -2914,38 +2966,16 @@ extension CameraController: UIGestureRecognizerDelegate {
|
|
|
2914
2966
|
|
|
2915
2967
|
@objc
|
|
2916
2968
|
func handleTap(_ tap: UITapGestureRecognizer) {
|
|
2917
|
-
guard let
|
|
2918
|
-
|
|
2919
|
-
let point = tap.location(in: tap.view)
|
|
2920
|
-
let devicePoint = self.previewLayer?.captureDevicePointConverted(fromLayerPoint: point)
|
|
2921
|
-
|
|
2922
|
-
// Show focus indicator at the tap point if not disabled
|
|
2923
|
-
if !self.disableFocusIndicator, let view = tap.view {
|
|
2924
|
-
showFocusIndicator(at: point, in: view)
|
|
2969
|
+
guard let devicePoint = self.previewLayer?.captureDevicePointConverted(fromLayerPoint: tap.location(in: tap.view)) else {
|
|
2970
|
+
return
|
|
2925
2971
|
}
|
|
2926
2972
|
|
|
2927
2973
|
do {
|
|
2928
|
-
try
|
|
2929
|
-
|
|
2930
|
-
|
|
2931
|
-
|
|
2932
|
-
|
|
2933
|
-
device.focusPointOfInterest = CGPoint(x: CGFloat(devicePoint?.x ?? 0), y: CGFloat(devicePoint?.y ?? 0))
|
|
2934
|
-
device.focusMode = focusMode
|
|
2935
|
-
}
|
|
2936
|
-
// Skip exposure point if locked
|
|
2937
|
-
if device.exposureMode != .locked {
|
|
2938
|
-
let exposureMode = AVCaptureDevice.ExposureMode.autoExpose
|
|
2939
|
-
if device.isExposurePointOfInterestSupported && device.isExposureModeSupported(exposureMode) {
|
|
2940
|
-
device.exposurePointOfInterest = CGPoint(x: CGFloat(devicePoint?.x ?? 0), y: CGFloat(devicePoint?.y ?? 0))
|
|
2941
|
-
device.exposureMode = exposureMode
|
|
2942
|
-
device.setExposureTargetBias(0.0) { _ in }
|
|
2943
|
-
}
|
|
2944
|
-
}
|
|
2945
|
-
|
|
2946
|
-
// Turn on subject area monitor for switch to continuous focus if needed
|
|
2947
|
-
device.isSubjectAreaChangeMonitoringEnabled = true
|
|
2948
|
-
|
|
2974
|
+
try self.setFocus(
|
|
2975
|
+
at: devicePoint,
|
|
2976
|
+
showIndicator: !self.disableFocusIndicator,
|
|
2977
|
+
in: tap.view
|
|
2978
|
+
)
|
|
2949
2979
|
} catch {
|
|
2950
2980
|
debugPrint(error)
|
|
2951
2981
|
}
|
|
@@ -35,7 +35,7 @@ extension UIWindow {
|
|
|
35
35
|
*/
|
|
36
36
|
@objc(CameraPreview)
|
|
37
37
|
public class CameraPreview: CAPPlugin, CAPBridgedPlugin, CLLocationManagerDelegate {
|
|
38
|
-
private let pluginVersion: String = "8.8.
|
|
38
|
+
private let pluginVersion: String = "8.8.1"
|
|
39
39
|
public let identifier = "CameraPreviewPlugin"
|
|
40
40
|
public let jsName = "CameraPreview"
|
|
41
41
|
public let pluginMethods: [CAPPluginMethod] = [
|