Skip to content
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
78 changes: 51 additions & 27 deletions Sources/VideoIO/Camera.swift
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
//
// File.swift
//
//
//
// Created by Yu Ao on 2019/12/18.
//
Expand Down Expand Up @@ -47,13 +47,15 @@ public class Camera {

public let photoOutput: AVCapturePhotoOutput?

private let configurator: Configurator
private var 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()
Expand All @@ -68,6 +70,7 @@ public class Camera {
captureSession.commitConfiguration()
self.captureSession = captureSession
self.configurator = configurator
self.defaultCameraUniqueId = defaultCameraUniqueId
self.defaultCameraPosition = defaultCameraPosition
self.defaultCameraDeviceTypes = defaultCameraDeviceTypes
}
Expand Down Expand Up @@ -100,7 +103,10 @@ 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, preset: AVCaptureSession.Preset? = nil, lockConfiguration: Bool = false, configurator: Configurator? = nil) throws {
if let configurator = configurator {
self.configurator = configurator
}
let deviceTypes: [AVCaptureDevice.DeviceType]
if preferredDeviceTypes.count == 0 {
if defaultCameraDeviceTypes.count == 0 {
Expand All @@ -124,31 +130,49 @@ 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 preset != nil {
self.captureSession.sessionPreset = .low
}
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)
}
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? {
Expand All @@ -160,7 +184,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 {
Expand Down