如何实现摄像头从前置摄像头更改为后置摄像头
How do I implement camera changing from front to back camera
下面是摄像头部分的代码,我尝试添加一个布尔值来检测前置摄像头何时被激活,但我收到错误消息。
import UIKit
import AVFoundation
class MainCameraCollectionViewCell: UICollectionViewCell {
@IBOutlet weak var myView: UIView!
var captureSession = AVCaptureSession()
var backCamera: AVCaptureDevice?
var frontCamera: AVCaptureDevice?
var currentCamera: AVCaptureDevice?
var photoOutPut: AVCapturePhotoOutput?
var cameraPreviewLayer: AVCaptureVideoPreviewLayer?
var image: UIImage?
var usingFrontCamera = false
override func awakeFromNib() {
super.awakeFromNib()
setupCaptureSession()
setupDevice()
setupInput()
setupPreviewLayer()
startRunningCaptureSession()
}
func setupCaptureSession(){
captureSession.sessionPreset = AVCaptureSession.Preset.photo
}
func setupDevice(usingFrontCamera:Bool = false){
let deviceDiscoverySession = AVCaptureDevice.DiscoverySession(deviceTypes: [AVCaptureDevice.DeviceType.builtInWideAngleCamera], mediaType: AVMediaType.video, position: AVCaptureDevice.Position.unspecified)
let devices = deviceDiscoverySession.devices
for device in devices {
if device.position == AVCaptureDevice.Position.back {
backCamera = device
} else if device.position == AVCaptureDevice.Position.front {
frontCamera = device
}
}
if usingFrontCamera {
currentCamera = frontCamera
} else {
currentCamera = backCamera
}
}
func setupInput() {
do {
let captureDeviceInput = try AVCaptureDeviceInput(device: currentCamera!)
captureSession.addInput(captureDeviceInput)
photoOutPut = AVCapturePhotoOutput()
photoOutPut?.setPreparedPhotoSettingsArray([AVCapturePhotoSettings(format:[AVVideoCodecKey: AVVideoCodecType.jpeg])], completionHandler: nil)
captureSession.addOutput(photoOutPut!)
} catch {
print(error)
}
}
func setupPreviewLayer(){
cameraPreviewLayer = AVCaptureVideoPreviewLayer(session: captureSession)
cameraPreviewLayer?.videoGravity = AVLayerVideoGravity.resizeAspectFill
cameraPreviewLayer?.connection?.videoOrientation = AVCaptureVideoOrientation.portrait
cameraPreviewLayer?.frame = CGRect(x: 0, y: 0, width: UIScreen.main.bounds.width, height: UIScreen.main.bounds.height)
self.layer.insertSublayer(cameraPreviewLayer!, at: 0)
}
func startRunningCaptureSession(){
captureSession.startRunning()
}
@IBAction func cameraButton_TouchUpInside(_ sender: Any) {
let settings = AVCapturePhotoSettings()
photoOutPut?.capturePhoto(with: settings, delegate: self as! AVCapturePhotoCaptureDelegate)
}
//Flip to front and back camera
@IBAction func FlipThe_camera(_ sender: UIButton) {
print("Flip touched")
if let inputs = captureSession.inputs as? [AVCaptureDeviceInput] {
for input in inputs {
captureSession.removeInput(input)
}
}
usingFrontCamera = !usingFrontCamera
setupCaptureSession()
setupDevice(usingFrontCamera:usingFrontCamera)
setupInput()
setupPreviewLayer()
startRunningCaptureSession()
}
}
collectionViewAttemptOfPagingAttempt002[2908:834004] * Terminating
app due to uncaught exception 'NSInvalidArgumentException', reason:
'* -[AVCaptureSession addOutput:] Cannot add output
to capture session
->
-> because more than one output of the same type is
unsupported'
您的问题是在将输入 and/or 输出添加到捕获会话之前,您没有检查是否可以添加它们。顺便说一句,你不需要在切换相机时再次设置预览层,你只需要一个 captureDevice:
if captureSession.canAddInput(captureDeviceInput) {
captureSession.addInput(captureDeviceInput)
}
和
if captureSession.canAddOutput(photoOutPut) {
captureSession.addOutput(photoOutPut)
}
您的 CollectionViewCell 代码应如下所示:
class MainCameraCollectionViewCell: UICollectionViewCell, AVCapturePhotoCaptureDelegate {
private var captureSession = AVCaptureSession()
private var sessionQueue: DispatchQueue!
private var captureDevice: AVCaptureDevice!
private var photoOutPut: AVCapturePhotoOutput!
private var cameraPreviewLayer: AVCaptureVideoPreviewLayer!
var image: UIImage?
var usingFrontCamera = false
override func awakeFromNib() {
super.awakeFromNib()
setupCaptureSession()
setupDevice()
setupInput()
setupPreviewLayer()
startRunningCaptureSession()
}
func setupCaptureSession(){
captureSession.sessionPreset = .photo
sessionQueue = DispatchQueue(label: "session queue")
}
func setupDevice(usingFrontCamera: Bool = false){
sessionQueue.async {
let deviceDiscoverySession = AVCaptureDevice.DiscoverySession(deviceTypes: [.builtInWideAngleCamera], mediaType: .video, position: .unspecified)
let devices = deviceDiscoverySession.devices
for device in devices {
if usingFrontCamera && device.position == .front {
self.captureDevice = device
} else if device.position == .back {
self.captureDevice = device
}
}
}
}
func setupInput() {
sessionQueue.async {
do {
let captureDeviceInput = try AVCaptureDeviceInput(device: self.captureDevice)
if self.captureSession.canAddInput(captureDeviceInput) {
self.captureSession.addInput(captureDeviceInput)
}
self.photoOutPut = AVCapturePhotoOutput()
self.photoOutPut.setPreparedPhotoSettingsArray([AVCapturePhotoSettings(format:[AVVideoCodecKey: AVVideoCodecType.jpeg])], completionHandler: nil)
if self.captureSession.canAddOutput(self.photoOutPut) {
self.captureSession.addOutput(self.photoOutPut)
}
} catch {
print(error)
}
}
}
func setupPreviewLayer() {
cameraPreviewLayer = AVCaptureVideoPreviewLayer(session: captureSession)
cameraPreviewLayer.videoGravity = .resizeAspectFill
cameraPreviewLayer.connection?.videoOrientation = .portrait
cameraPreviewLayer.frame = UIScreen.main.bounds
layer.insertSublayer(cameraPreviewLayer, at: 0)
}
func startRunningCaptureSession() {
captureSession.startRunning()
}
@IBAction func cameraButton_TouchUpInside(_ sender: Any) {
let settings = AVCapturePhotoSettings()
photoOutPut.capturePhoto(with: settings, delegate: self)
}
//Flip to front and back camera
@IBAction func FlipThe_camera(_ sender: UIButton) {
captureSession.beginConfiguration()
if let inputs = captureSession.inputs as? [AVCaptureDeviceInput] {
for input in inputs {
captureSession.removeInput(input)
}
}
usingFrontCamera = !usingFrontCamera
setupCaptureSession()
setupDevice(usingFrontCamera: usingFrontCamera)
setupInput()
captureSession.commitConfiguration()
startRunningCaptureSession()
}
}
下面是摄像头部分的代码,我尝试添加一个布尔值来检测前置摄像头何时被激活,但我收到错误消息。
import UIKit
import AVFoundation
class MainCameraCollectionViewCell: UICollectionViewCell {
@IBOutlet weak var myView: UIView!
var captureSession = AVCaptureSession()
var backCamera: AVCaptureDevice?
var frontCamera: AVCaptureDevice?
var currentCamera: AVCaptureDevice?
var photoOutPut: AVCapturePhotoOutput?
var cameraPreviewLayer: AVCaptureVideoPreviewLayer?
var image: UIImage?
var usingFrontCamera = false
override func awakeFromNib() {
super.awakeFromNib()
setupCaptureSession()
setupDevice()
setupInput()
setupPreviewLayer()
startRunningCaptureSession()
}
func setupCaptureSession(){
captureSession.sessionPreset = AVCaptureSession.Preset.photo
}
func setupDevice(usingFrontCamera:Bool = false){
let deviceDiscoverySession = AVCaptureDevice.DiscoverySession(deviceTypes: [AVCaptureDevice.DeviceType.builtInWideAngleCamera], mediaType: AVMediaType.video, position: AVCaptureDevice.Position.unspecified)
let devices = deviceDiscoverySession.devices
for device in devices {
if device.position == AVCaptureDevice.Position.back {
backCamera = device
} else if device.position == AVCaptureDevice.Position.front {
frontCamera = device
}
}
if usingFrontCamera {
currentCamera = frontCamera
} else {
currentCamera = backCamera
}
}
func setupInput() {
do {
let captureDeviceInput = try AVCaptureDeviceInput(device: currentCamera!)
captureSession.addInput(captureDeviceInput)
photoOutPut = AVCapturePhotoOutput()
photoOutPut?.setPreparedPhotoSettingsArray([AVCapturePhotoSettings(format:[AVVideoCodecKey: AVVideoCodecType.jpeg])], completionHandler: nil)
captureSession.addOutput(photoOutPut!)
} catch {
print(error)
}
}
func setupPreviewLayer(){
cameraPreviewLayer = AVCaptureVideoPreviewLayer(session: captureSession)
cameraPreviewLayer?.videoGravity = AVLayerVideoGravity.resizeAspectFill
cameraPreviewLayer?.connection?.videoOrientation = AVCaptureVideoOrientation.portrait
cameraPreviewLayer?.frame = CGRect(x: 0, y: 0, width: UIScreen.main.bounds.width, height: UIScreen.main.bounds.height)
self.layer.insertSublayer(cameraPreviewLayer!, at: 0)
}
func startRunningCaptureSession(){
captureSession.startRunning()
}
@IBAction func cameraButton_TouchUpInside(_ sender: Any) {
let settings = AVCapturePhotoSettings()
photoOutPut?.capturePhoto(with: settings, delegate: self as! AVCapturePhotoCaptureDelegate)
}
//Flip to front and back camera
@IBAction func FlipThe_camera(_ sender: UIButton) {
print("Flip touched")
if let inputs = captureSession.inputs as? [AVCaptureDeviceInput] {
for input in inputs {
captureSession.removeInput(input)
}
}
usingFrontCamera = !usingFrontCamera
setupCaptureSession()
setupDevice(usingFrontCamera:usingFrontCamera)
setupInput()
setupPreviewLayer()
startRunningCaptureSession()
}
}
collectionViewAttemptOfPagingAttempt002[2908:834004] * Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '* -[AVCaptureSession addOutput:] Cannot add output to capture session -> -> because more than one output of the same type is unsupported'
您的问题是在将输入 and/or 输出添加到捕获会话之前,您没有检查是否可以添加它们。顺便说一句,你不需要在切换相机时再次设置预览层,你只需要一个 captureDevice:
if captureSession.canAddInput(captureDeviceInput) {
captureSession.addInput(captureDeviceInput)
}
和
if captureSession.canAddOutput(photoOutPut) {
captureSession.addOutput(photoOutPut)
}
您的 CollectionViewCell 代码应如下所示:
class MainCameraCollectionViewCell: UICollectionViewCell, AVCapturePhotoCaptureDelegate {
private var captureSession = AVCaptureSession()
private var sessionQueue: DispatchQueue!
private var captureDevice: AVCaptureDevice!
private var photoOutPut: AVCapturePhotoOutput!
private var cameraPreviewLayer: AVCaptureVideoPreviewLayer!
var image: UIImage?
var usingFrontCamera = false
override func awakeFromNib() {
super.awakeFromNib()
setupCaptureSession()
setupDevice()
setupInput()
setupPreviewLayer()
startRunningCaptureSession()
}
func setupCaptureSession(){
captureSession.sessionPreset = .photo
sessionQueue = DispatchQueue(label: "session queue")
}
func setupDevice(usingFrontCamera: Bool = false){
sessionQueue.async {
let deviceDiscoverySession = AVCaptureDevice.DiscoverySession(deviceTypes: [.builtInWideAngleCamera], mediaType: .video, position: .unspecified)
let devices = deviceDiscoverySession.devices
for device in devices {
if usingFrontCamera && device.position == .front {
self.captureDevice = device
} else if device.position == .back {
self.captureDevice = device
}
}
}
}
func setupInput() {
sessionQueue.async {
do {
let captureDeviceInput = try AVCaptureDeviceInput(device: self.captureDevice)
if self.captureSession.canAddInput(captureDeviceInput) {
self.captureSession.addInput(captureDeviceInput)
}
self.photoOutPut = AVCapturePhotoOutput()
self.photoOutPut.setPreparedPhotoSettingsArray([AVCapturePhotoSettings(format:[AVVideoCodecKey: AVVideoCodecType.jpeg])], completionHandler: nil)
if self.captureSession.canAddOutput(self.photoOutPut) {
self.captureSession.addOutput(self.photoOutPut)
}
} catch {
print(error)
}
}
}
func setupPreviewLayer() {
cameraPreviewLayer = AVCaptureVideoPreviewLayer(session: captureSession)
cameraPreviewLayer.videoGravity = .resizeAspectFill
cameraPreviewLayer.connection?.videoOrientation = .portrait
cameraPreviewLayer.frame = UIScreen.main.bounds
layer.insertSublayer(cameraPreviewLayer, at: 0)
}
func startRunningCaptureSession() {
captureSession.startRunning()
}
@IBAction func cameraButton_TouchUpInside(_ sender: Any) {
let settings = AVCapturePhotoSettings()
photoOutPut.capturePhoto(with: settings, delegate: self)
}
//Flip to front and back camera
@IBAction func FlipThe_camera(_ sender: UIButton) {
captureSession.beginConfiguration()
if let inputs = captureSession.inputs as? [AVCaptureDeviceInput] {
for input in inputs {
captureSession.removeInput(input)
}
}
usingFrontCamera = !usingFrontCamera
setupCaptureSession()
setupDevice(usingFrontCamera: usingFrontCamera)
setupInput()
captureSession.commitConfiguration()
startRunningCaptureSession()
}
}