From 54ff90604d8b623078823b86f1de0378d87b7f16 Mon Sep 17 00:00:00 2001 From: Daniel Murfin Date: Sun, 6 Mar 2022 10:49:36 +0000 Subject: [PATCH 1/2] Added method to request a specific camera unique identifier. --- Sources/VideoIO/Camera.swift | 59 +++++++++++++++++++++--------------- 1 file changed, 34 insertions(+), 25 deletions(-) diff --git a/Sources/VideoIO/Camera.swift b/Sources/VideoIO/Camera.swift index f33e1fa..22006b7 100644 --- a/Sources/VideoIO/Camera.swift +++ b/Sources/VideoIO/Camera.swift @@ -49,11 +49,13 @@ public class Camera { private let configurator: Configurator + private let defaultCameraUniqueId: String? + private let defaultCameraPosition: AVCaptureDevice.Position private let defaultCameraDeviceTypes: [AVCaptureDevice.DeviceType] - public init(captureSessionPreset: AVCaptureSession.Preset, defaultCameraPosition: AVCaptureDevice.Position = .back, defaultCameraDeviceTypes: [AVCaptureDevice.DeviceType] = [], configurator: Configurator = Configurator()) { + public init(captureSessionPreset: AVCaptureSession.Preset, defaultCameraUniqueId: String? = nil, defaultCameraPosition: AVCaptureDevice.Position = .back, defaultCameraDeviceTypes: [AVCaptureDevice.DeviceType] = [], configurator: Configurator = Configurator()) { let captureSession = AVCaptureSession() assert(captureSession.canSetSessionPreset(captureSessionPreset)) captureSession.beginConfiguration() @@ -68,6 +70,7 @@ public class Camera { captureSession.commitConfiguration() self.captureSession = captureSession self.configurator = configurator + self.defaultCameraUniqueId = defaultCameraUniqueId self.defaultCameraPosition = defaultCameraPosition self.defaultCameraDeviceTypes = defaultCameraDeviceTypes } @@ -100,7 +103,7 @@ public class Camera { return self.audioDeviceInput?.device } - public func switchToVideoCaptureDevice(with position: AVCaptureDevice.Position, preferredDeviceTypes: [AVCaptureDevice.DeviceType] = []) throws { + public func switchToVideoCaptureDevice(with position: AVCaptureDevice.Position, preferredDeviceTypes: [AVCaptureDevice.DeviceType] = [], preferredCameraUniqueId: String? = nil) throws { let deviceTypes: [AVCaptureDevice.DeviceType] if preferredDeviceTypes.count == 0 { if defaultCameraDeviceTypes.count == 0 { @@ -124,31 +127,37 @@ public class Camera { deviceTypes = preferredDeviceTypes } let discoverySession = AVCaptureDevice.DiscoverySession(deviceTypes: deviceTypes, mediaType: .video, position: position) - if let device = discoverySession.devices.first { - let newVideoDeviceInput = try AVCaptureDeviceInput(device: device) - self.captureSession.beginConfiguration() - if let currentVideoDeviceInput = self.videoDeviceInput { - self.captureSession.removeInput(currentVideoDeviceInput) - } - if self.captureSession.canAddInput(newVideoDeviceInput) { - self.captureSession.addInput(newVideoDeviceInput) - self.videoDeviceInput = newVideoDeviceInput - } else { - self.captureSession.commitConfiguration() - throw Error.cannotAddInput - } - - if let connection = self.videoCaptureConnection { - self.configurator.videoConnectionConfigurator(self, connection) - } - self.captureSession.commitConfiguration() - - try device.lockForConfiguration() - self.configurator.videoDeviceConfigurator(self, device) - device.unlockForConfiguration() + + let device: AVCaptureDevice + if let preferredCamera = discoverySession.devices.first(where: { $0.uniqueID == preferredCameraUniqueId }) { + device = preferredCamera + } else if let discoveredDevice = discoverySession.devices.first { + device = discoveredDevice } else { throw Error.noDeviceFound } + + let newVideoDeviceInput = try AVCaptureDeviceInput(device: device) + self.captureSession.beginConfiguration() + if let currentVideoDeviceInput = self.videoDeviceInput { + self.captureSession.removeInput(currentVideoDeviceInput) + } + if self.captureSession.canAddInput(newVideoDeviceInput) { + self.captureSession.addInput(newVideoDeviceInput) + self.videoDeviceInput = newVideoDeviceInput + } else { + self.captureSession.commitConfiguration() + throw Error.cannotAddInput + } + + if let connection = self.videoCaptureConnection { + self.configurator.videoConnectionConfigurator(self, connection) + } + self.captureSession.commitConfiguration() + + try device.lockForConfiguration() + self.configurator.videoDeviceConfigurator(self, device) + device.unlockForConfiguration() } public var videoCaptureConnection: AVCaptureConnection? { @@ -160,7 +169,7 @@ public class Camera { public func enableVideoDataOutput(on queue: DispatchQueue = .main, delegate: AVCaptureVideoDataOutputSampleBufferDelegate) throws { assert(self.videoDataOutput == nil) if self.videoDevice == nil { - try self.switchToVideoCaptureDevice(with: self.defaultCameraPosition) + try self.switchToVideoCaptureDevice(with: self.defaultCameraPosition, preferredCameraUniqueId: self.defaultCameraUniqueId) } self.captureSession.beginConfiguration() defer { From 6a0837616e8df0fecc30e18f0cc81d6abc0aafb2 Mon Sep 17 00:00:00 2001 From: Daniel Murfin Date: Sun, 6 Mar 2022 15:25:54 +0000 Subject: [PATCH 2/2] Adds a method to set the session preset, and maintain a lock on device config (macOS) --- Sources/VideoIO/Camera.swift | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/Sources/VideoIO/Camera.swift b/Sources/VideoIO/Camera.swift index 22006b7..76346a0 100644 --- a/Sources/VideoIO/Camera.swift +++ b/Sources/VideoIO/Camera.swift @@ -1,6 +1,6 @@ // // File.swift -// +// // // Created by Yu Ao on 2019/12/18. // @@ -103,7 +103,7 @@ public class Camera { return self.audioDeviceInput?.device } - public func switchToVideoCaptureDevice(with position: AVCaptureDevice.Position, preferredDeviceTypes: [AVCaptureDevice.DeviceType] = [], preferredCameraUniqueId: String? = nil) throws { + public func switchToVideoCaptureDevice(with position: AVCaptureDevice.Position, preferredDeviceTypes: [AVCaptureDevice.DeviceType] = [], preferredCameraUniqueId: String? = nil, preset: AVCaptureSession.Preset? = nil, lockConfiguration: Bool = false) throws { let deviceTypes: [AVCaptureDevice.DeviceType] if preferredDeviceTypes.count == 0 { if defaultCameraDeviceTypes.count == 0 { @@ -139,6 +139,9 @@ public class Camera { let newVideoDeviceInput = try AVCaptureDeviceInput(device: device) self.captureSession.beginConfiguration() + if preset != nil { + self.captureSession.sessionPreset = .low + } if let currentVideoDeviceInput = self.videoDeviceInput { self.captureSession.removeInput(currentVideoDeviceInput) } @@ -153,11 +156,20 @@ public class Camera { if let connection = self.videoCaptureConnection { self.configurator.videoConnectionConfigurator(self, connection) } + if let preset = preset, self.captureSession.canSetSessionPreset(preset) { + self.captureSession.sessionPreset = preset + } self.captureSession.commitConfiguration() try device.lockForConfiguration() self.configurator.videoDeviceConfigurator(self, device) + #if os(iOS) device.unlockForConfiguration() + #else + if !lockConfiguration { + device.unlockForConfiguration() + } + #endif } public var videoCaptureConnection: AVCaptureConnection? {