双击或使用按钮将相机从后向前切换(Xcode 8,Swift 3)

时间:2016-09-26 00:33:16

标签: ios swift3

所以,最近我一直在尝试在Swift 3中实现从后台到前置摄像头切换摄像机视图的功能。但是,没有运气。

目前,我的默认视图来自后置摄像头 - 我可以用它拍照然后重拍。但任何人都可以帮助我,并展示如何双击屏幕切换摄像头或只是使用指定的按钮切换它们?谢谢!

import UIKit
import AVFoundation
import FirebaseDatabase

class CameraView: UIViewController, UIImagePickerControllerDelegate, UINavigationControllerDelegate {

override var prefersStatusBarHidden: Bool {
    return true
}

var captureSession : AVCaptureSession!
var stillImageOutput : AVCaptureStillImageOutput!
var previewLayer : AVCaptureVideoPreviewLayer!

@IBOutlet var cameraView: UIView!
override func viewDidLoad() {
    super.viewDidLoad()

    // Do any additional setup after loading the view.
}

override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
    // Dispose of any resources that can be recreated.
}

override func viewDidAppear(_ animated: Bool) {
    super.viewDidAppear(animated)
    previewLayer?.frame = cameraView.bounds
}

override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)

    captureSession = AVCaptureSession()
    captureSession?.sessionPreset = AVCaptureSessionPreset1920x1080

    var backCamera = AVCaptureDevice.defaultDevice(withMediaType: AVMediaTypeVideo)
    var error : NSError?

    do {
        var input = try! AVCaptureDeviceInput(device: backCamera)
        if (error == nil && captureSession?.canAddInput(input) != nil) {

            captureSession?.addInput(input)

            stillImageOutput = AVCaptureStillImageOutput()
            stillImageOutput.outputSettings = [AVVideoCodecKey: AVVideoCodecJPEG]

            if (captureSession?.canAddOutput(stillImageOutput) != nil) {

                captureSession?.addOutput(stillImageOutput)

                previewLayer = AVCaptureVideoPreviewLayer (session: captureSession)
                previewLayer.videoGravity = AVLayerVideoGravityResizeAspectFill
                previewLayer.connection.videoOrientation = AVCaptureVideoOrientation.portrait
                cameraView.layer.addSublayer(previewLayer)
                captureSession?.startRunning() }
        }

    } catch {

    }
}

@IBOutlet var tempImageView: UIImageView!
@IBAction func didPressTakePhoto(_ sender: UIButton) {

    if let videoConnection = stillImageOutput.connection(withMediaType: AVMediaTypeVideo) {

        videoConnection.videoOrientation = AVCaptureVideoOrientation.portrait
        stillImageOutput.captureStillImageAsynchronously(from: videoConnection, completionHandler: {

            (sampleBuffer, error) in
            if sampleBuffer != nil {

                var imageData = AVCaptureStillImageOutput.jpegStillImageNSDataRepresentation(sampleBuffer)
                var dataProvider = CGDataProvider.init(data: imageData as! CFData)
                var cgImageRef = CGImage.init(jpegDataProviderSource: dataProvider!, decode: nil, shouldInterpolate: true, intent: .defaultIntent)

                var image = UIImage (cgImage: cgImageRef!, scale: 1.0, orientation: UIImageOrientation.right)

                self.tempImageView.image = image
                self.tempImageView.isHidden = false

            }

        })

    }
}

var didTakePhoto = Bool()

@IBAction func didPressTakeAnother(_ sender: UIButton) {

    if didTakePhoto == true {

        tempImageView.isHidden = true
        didTakePhoto = false

    } else {

        captureSession?.startRunning()
        didTakePhoto = true

    }
}
}

3 个答案:

答案 0 :(得分:14)

这里没有看到任何问题 - 这是工作解决方案:

import Foundation
import UIKit
import AVFoundation

class MainViewController: UIViewController {

    var tempImage: UIImageView?

    var captureSession: AVCaptureSession?
    var stillImageOutput: AVCaptureStillImageOutput?
    var videoPreviewLayer: AVCaptureVideoPreviewLayer?
    var currentCaptureDevice: AVCaptureDevice?

    var usingFrontCamera = false


    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
        loadCamera()
    }

    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
        videoPreviewLayer!.frame = self.cameraPreviewSurface.bounds
    }

    @IBAction func switchButtonAction(_ sender: Any) {
        usingFrontCamera = !usingFrontCamera
        loadCamera()
    }


    func getFrontCamera() -> AVCaptureDevice?{
        let videoDevices = AVCaptureDevice.devices(withMediaType: AVMediaTypeVideo)


        for device in videoDevices!{
            let device = device as! AVCaptureDevice
            if device.position == AVCaptureDevicePosition.front {
                return device
            }
        }
        return nil
    }

    func getBackCamera() -> AVCaptureDevice{
        return AVCaptureDevice.defaultDevice(withMediaType: AVMediaTypeVideo)
    }



    func loadCamera() {
        if(captureSession == nil){
            captureSession = AVCaptureSession()
            captureSession!.sessionPreset = AVCaptureSessionPresetPhoto
        }
        var error: NSError?
        var input: AVCaptureDeviceInput!

        currentCaptureDevice = (usingFrontCamera ? getFrontCamera() : getBackCamera())

        do {
            input = try AVCaptureDeviceInput(device: currentCaptureDevice)
        } catch let error1 as NSError {
            error = error1
            input = nil
            print(error!.localizedDescription)
        }

        for i : AVCaptureDeviceInput in (self.captureSession?.inputs as! [AVCaptureDeviceInput]){
            self.captureSession?.removeInput(i)
        }
        if error == nil && captureSession!.canAddInput(input) {
            captureSession!.addInput(input)
            stillImageOutput = AVCaptureStillImageOutput()
            stillImageOutput?.outputSettings = [AVVideoCodecKey: AVVideoCodecJPEG]
            if captureSession!.canAddOutput(stillImageOutput) {
                captureSession!.addOutput(stillImageOutput)
                videoPreviewLayer = AVCaptureVideoPreviewLayer(session: captureSession)
                videoPreviewLayer!.videoGravity = AVLayerVideoGravityResizeAspectFill
                videoPreviewLayer!.connection?.videoOrientation = AVCaptureVideoOrientation.portrait
                //self.cameraPreviewSurface.layer.sublayers?.forEach { $0.removeFromSuperlayer() }
                self.cameraPreviewSurface.layer.addSublayer(videoPreviewLayer!)
                DispatchQueue.main.async {
                    self.captureSession!.startRunning()
                }


            }
        }



    }
}

一些注意事项:

cameraPreviewSurface - 这是你的UIView,相机会显示

不要重新分配会话,不要只是添加输入,而是在添加新内容之前 - 删除现有内容,

P.S。用swift 3.0.1 / xcode 8.1完成的代码

干杯)

答案 1 :(得分:0)

除了Stepan Maksymov的帖子,我还想添加这个功能

func stopCaptureSession () {
    self.captureSession.stopRunning()

    if let inputs = captureSession.inputs as? [AVCaptureDeviceInput] {
        for input in inputs {
            self.captureSession.removeInput(input)
        }
    }

}

并称之为而不是他的帖子:

for i : AVCaptureDeviceInput in (self.captureSession?.inputs as! [AVCaptureDeviceInput]){
    self.captureSession?.removeInput(i)
}

这样相机会更快地改变。

答案 2 :(得分:0)

Xcode版本:版本10.1(10B61)
Swift版本: Swift 4.2
更改AVCaptureSession捕获源

引用 Stepan Maksymov 解决方案
我们可以通过替换captureSession.inputs 来简化

首先创建一个IBAction出口并连接ViewController以更改摄影机视图

@IBAction private func changeCamera(_ cameraButton: UIButton) {
    usingFrontCamera = !usingFrontCamera
    do{
        captureSession.removeInput(captureSession.inputs.first!)

        if(usingFrontCamera){
            captureDevice = getFrontCamera()
        }else{
            captureDevice = getBackCamera()
        }
        let captureDeviceInput1 = try AVCaptureDeviceInput(device: captureDevice)
        captureSession.addInput(captureDeviceInput1)
    }catch{
        print(error.localizedDescription)
    }
}

第二步复制简化的AVCaptureDevice设置||请参阅 Stepan Maksymov

func getFrontCamera() -> AVCaptureDevice?{
    return AVCaptureDevice.DiscoverySession(deviceTypes: [.builtInWideAngleCamera], mediaType: AVMediaType.video, position: .front).devices.first
    return nil
}

func getBackCamera() -> AVCaptureDevice?{
    return AVCaptureDevice.DiscoverySession(deviceTypes: [.builtInWideAngleCamera], mediaType: AVMediaType.video, position: .back).devices.first
    return nil
}

您可以使用类似的功能替换@IBAction。

func changeCamera(){
    usingFrontCamera = !usingFrontCamera
    do{
        captureSession.removeInput(captureSession.inputs.first!)

        if(usingFrontCamera){
            captureDevice = getFrontCamera()
        }else{
            captureDevice = getBackCamera()
        }
        let captureDeviceInput1 = try AVCaptureDeviceInput(device: captureDevice)
        captureSession.addInput(captureDeviceInput1)
    }catch{
        print(error.localizedDescription)
    }
}