cd0b413706
Moves everything Camera related into `core/` / `Core/` so that it is better encapsulated from React Native. Benefits: 1. Code is much better organized. Should be easier for collaborators now, and cleaner codebase for me. 2. Locking is fully atomically as you can now only configure the session through a lock/Mutex which is batch-overridable * On iOS, this makes Camera startup time **MUCH** faster, I measured speedups from **1.5 seconds** to only **240 milliseconds** since we only lock/commit once! 🚀 * On Android, this fixes a few out-of-sync/concurrency issues like "Capture Request contains unconfigured Input/Output Surface!" since it is now a single lock-operation! 💪 3. It is easier to integrate VisionCamera outside of React Native (e.g. Native iOS Apps, NativeScript, Flutter, etc) With this PR, VisionCamera V3 is up to **7x** faster than V2
83 lines
2.4 KiB
Swift
83 lines
2.4 KiB
Swift
//
|
|
// CameraSession+Focus.swift
|
|
// VisionCamera
|
|
//
|
|
// Created by Marc Rousavy on 11.10.23.
|
|
// Copyright © 2023 mrousavy. All rights reserved.
|
|
//
|
|
|
|
import AVFoundation
|
|
import Foundation
|
|
|
|
extension CameraSession {
|
|
/**
|
|
Focuses the Camera to the specified point. The point must be in the Camera coordinate system, so {0...1} on both axis.
|
|
*/
|
|
func focus(point: CGPoint) throws {
|
|
guard let device = videoDeviceInput?.device else {
|
|
throw CameraError.session(SessionError.cameraNotReady)
|
|
}
|
|
if !device.isFocusPointOfInterestSupported {
|
|
throw CameraError.device(DeviceError.focusNotSupported)
|
|
}
|
|
|
|
do {
|
|
try device.lockForConfiguration()
|
|
defer {
|
|
device.unlockForConfiguration()
|
|
}
|
|
|
|
// Set Focus
|
|
if device.isFocusPointOfInterestSupported {
|
|
device.focusPointOfInterest = point
|
|
device.focusMode = .autoFocus
|
|
}
|
|
|
|
// Set Exposure
|
|
if device.isExposurePointOfInterestSupported {
|
|
device.exposurePointOfInterest = point
|
|
device.exposureMode = .autoExpose
|
|
}
|
|
|
|
// Remove any existing listeners
|
|
NotificationCenter.default.removeObserver(self,
|
|
name: NSNotification.Name.AVCaptureDeviceSubjectAreaDidChange,
|
|
object: nil)
|
|
|
|
// Listen for focus completion
|
|
device.isSubjectAreaChangeMonitoringEnabled = true
|
|
NotificationCenter.default.addObserver(self,
|
|
selector: #selector(subjectAreaDidChange),
|
|
name: NSNotification.Name.AVCaptureDeviceSubjectAreaDidChange,
|
|
object: nil)
|
|
} catch {
|
|
throw CameraError.device(DeviceError.configureError)
|
|
}
|
|
}
|
|
|
|
@objc
|
|
func subjectAreaDidChange(notification _: NSNotification) {
|
|
guard let device = videoDeviceInput?.device else {
|
|
return
|
|
}
|
|
|
|
try? device.lockForConfiguration()
|
|
defer {
|
|
device.unlockForConfiguration()
|
|
}
|
|
|
|
// Reset Focus to continuous/auto
|
|
if device.isFocusPointOfInterestSupported {
|
|
device.focusMode = .continuousAutoFocus
|
|
}
|
|
|
|
// Reset Exposure to continuous/auto
|
|
if device.isExposurePointOfInterestSupported {
|
|
device.exposureMode = .continuousAutoExposure
|
|
}
|
|
|
|
// Disable listeners
|
|
device.isSubjectAreaChangeMonitoringEnabled = false
|
|
}
|
|
}
|