我正在创建一个类似于相机的应用程序来在屏幕上双击交换相机。代码编译没有错误,但是当我双击屏幕到达前置摄像头时,我收到错误。这是错误:
2018-03-30 18:44:46.717257 + 0530相机[369:36651] *终止应用 由于未捕获的异常'NSInvalidArgumentException',原因:'* - [AVCaptureSession addOutput:]无法将输出添加到捕获会话 - > 因为不止一个输出 相同的类型不受支持' ***首先抛出调用堆栈:(0x18564ed8c 0x1848085ec 0x18b13ca74 0x104b3c140 0x104b3b75c 0x104b3b794 0x18f3fe750 0x18f96b2a4 0x18f560e6c 0x18f3fd7a8 0x18f95cac4 0x18f3f7540 0x18f3f7078 0x18f3f68dc 0x18f3f5238 0x18fbd6c0c 0x18fbd91b8 0x18fbd2258 0x1855f7404 0x1855f6c2c 0x1855f479c 0x185514da8 0x1874f7020 0x18f4f578c 0x104b40ca8 0x184fa5fc0)libc ++ abi.dylib:终止于 NSException类型的未捕获异常
这是我的ViewController文件:
import UIKit
import AVFoundation
class ViewController: UIViewController, AVCapturePhotoCaptureDelegate {
@IBOutlet weak var previewView: UIView!
override var prefersStatusBarHidden: Bool { return true }
var session = AVCaptureSession()
var device = AVCaptureDevice.default(.builtInWideAngleCamera, for: .video, position: .back)
var frontCameraMode = false
var photoOutput : AVCapturePhotoOutput?
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
loadCamera()
let tap = UITapGestureRecognizer(target: self, action: #selector(swapCamera))
tap.numberOfTapsRequired = 2
previewView.addGestureRecognizer(tap)
}
@objc func swapCamera() {
if(frontCameraMode == true){
frontCameraMode = false
}
else if(frontCameraMode == false){
frontCameraMode = true
}
loadCamera()
}
func loadCamera() {
if(frontCameraMode == false){
var device = AVCaptureDevice.default(.builtInWideAngleCamera, for: .video, position: .back)
}
else if (frontCameraMode == true){
var device = AVCaptureDevice.default(.builtInWideAngleCamera, for: .video, position: .front)
}
do{
var deviceInput = try AVCaptureDeviceInput(device: device!)
print(deviceInput)
session.sessionPreset = AVCaptureSession.Preset.high
/*if let inputs = session.inputs as? [AVCaptureDeviceInput] {
for input in inputs {
session.removeInput(input)
}
}*/
if session.inputs.isEmpty {
session.addInput(deviceInput)
}
var previewLayer = AVCaptureVideoPreviewLayer(session: session)
previewLayer.videoGravity = AVLayerVideoGravity.resizeAspectFill
previewLayer.frame = view.layer.bounds
previewView.layer.addSublayer(previewLayer)
session.startRunning()
photoOutput = AVCapturePhotoOutput()
session.addOutput(photoOutput!)
}
catch{
print(error)
}
}
@IBAction func onShootButtonTap(_ sender: Any) {
// Make sure capturePhotoOutput is valid
guard let photoOutput = self.photoOutput else { return }
// Get an instance of AVCapturePhotoSettings class
let photoSettings = AVCapturePhotoSettings()
// Set photo settings for our need
photoSettings.isAutoStillImageStabilizationEnabled = true
//photoSettings.isHighResolutionPhotoEnabled = true
photoSettings.flashMode = .auto
// Call capturePhoto method by passing our photo settings and a
// delegate implementing AVCapturePhotoCaptureDelegate
photoOutput.capturePhoto(with: photoSettings, delegate: self)
}
@available(iOS 11.0, *)
func photoOutput(_ output: AVCapturePhotoOutput, didFinishProcessingPhoto photo: AVCapturePhoto, error: Error?) {
let imageData = photo.fileDataRepresentation()
let capturedImage = UIImage.init(data: imageData! , scale: 1.0)
if let image = capturedImage {
// Save our captured image to photos album
UIImageWriteToSavedPhotosAlbum(image, nil, nil, nil)
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
答案 0 :(得分:1)
在添加输入和输出之前,您需要检查会话的canAddInput和canAddOutput
session.beginConfiguration()
session.sessionPreset = AVCaptureSession.Preset.photo
let cameraPosition: AVCaptureDevice.Position = self.configuration.usesFrontCamera ? .front : .back
let aDevice = deviceForPosition(cameraPosition)
if let d = aDevice {
videoInput = try? AVCaptureDeviceInput(device: d)
}
if let videoInput = videoInput {
if session.canAddInput(videoInput) {
session.addInput(videoInput)
}
if session.canAddOutput(imageOutput) {
session.addOutput(imageOutput)
}
}
session.commitConfiguration()
//A helper function for device position
func deviceForPosition(_ p: AVCaptureDevice.Position) -> AVCaptureDevice? {
for device in AVCaptureDevice.devices(for: AVMediaType.video) where device.position == p {
return device
}
return nil
}
我建议你不要重新发明轮子并使用这个资源 - https://github.com/Yummypets/YPImagePicker
答案 1 :(得分:0)
请确保在请求相机访问时为Privacy - Camera Usage Description
文件中的Info.plist
键设置值。
答案 2 :(得分:0)
每次按下交换按钮,您都会使用已经使用过的相机会话创建新的相机预览图层,这会导致崩溃。修复:
为当前设备输入声明新变量
var deviceInput: AVCaptureDeviceInput?
更改swapCamera函数以更改设备输入前/后并将输入保存在上面声明的变量中,以在第二次交换中删除。
@objc func swapCamera() {
frontCameraMode = !frontCameraMode
let newDeviceInput = try! AVCaptureDeviceInput(device: device!)
session.beginConfiguration()
if(frontCameraMode == false){
device = AVCaptureDevice.default(.builtInWideAngleCamera, for: .video, position: .back)
session.removeInput(deviceInput!)
session.addInput(newDeviceInput)
}
else if (frontCameraMode == true){
device = AVCaptureDevice.default(.builtInWideAngleCamera, for: .video, position: .front)
session.removeInput(deviceInput!)
session.addInput(newDeviceInput)
}
session.commitConfiguration();
deviceInput = newDeviceInput
}
在loadCamera函数中删除local let变量
更改
let deviceInput = try AVCaptureDeviceInput(device: device!)
到
deviceInput = try AVCaptureDeviceInput(device: device!)