【问题标题】:How to switch camera using AVFoundation如何使用 AVFoundation 切换相机
【发布时间】:2019-01-01 11:32:18
【问题描述】:

我已经使用 AVFoundation 实现了预览相机,它工作正常。但是我很难前后切换相机。我在底部栏添加了一个切换按钮。默认情况下,它的后置摄像头,我想将其切换到前置。我该怎么做?

class FifteenSecsViewController: UIViewController, AVCaptureFileOutputRecordingDelegate {

    @IBOutlet weak var camPreview: UIView!
    let captureSession = AVCaptureSession()
    let movieOutput = AVCaptureMovieFileOutput()
    var previewLayer: AVCaptureVideoPreviewLayer!
    var activeInput: AVCaptureDeviceInput!
    var outputURL: URL!

    override func viewDidLoad() {
    super.viewDidLoad()

        if setupSession() {
            setupPreview()
            startSession()
        }
        self.switchCameraButton.addTarget(self, action: #selector(switchButtonTapped), for: .touchUpInside)
    }

    func setupSession() -> Bool {

    captureSession.sessionPreset = AVCaptureSession.Preset.high

    // Setup Camera
    let camera: AVCaptureDevice?

    camera = AVCaptureDevice.default(for: .video)
    do {
        let input = try AVCaptureDeviceInput(device: camera!)
        if captureSession.canAddInput(input) {
            captureSession.addInput(input)
            activeInput = input
        }
    } catch {
        print("Error setting device video input: \(error)")
        return false
    }

    // Setup Microphone
    let microphone = AVCaptureDevice.default(for: .audio)

    do {
        let micInput = try AVCaptureDeviceInput(device: microphone!)
        if captureSession.canAddInput(micInput) {
            captureSession.addInput(micInput)
        }
    } catch {
        print("Error setting device audio input: \(error)")
        return false
    }


    // Movie output
    let seconds : Int64 = 3
    let maxDuration = CMTime(seconds: Double(seconds), 
    preferredTimescale: 1)
    movieOutput.maxRecordedDuration = maxDuration
    if captureSession.canAddOutput(movieOutput) {
        captureSession.addOutput(movieOutput)
    }

    return true
    }

    func setupPreview() {
    // Configure previewLayer
        previewLayer = AVCaptureVideoPreviewLayer(session: 
        captureSession)
        previewLayer.frame = camPreview.bounds
        previewLayer.videoGravity = AVLayerVideoGravity.resizeAspectFill
        camPreview.layer.addSublayer(previewLayer)
    }

        //MARK:- Camera Session
    func startSession() {      
        if !captureSession.isRunning {
            videoQueue().async {
                self.captureSession.startRunning()
            }
        }
    }

    @objc func switchButtonTapped(){
    // what to write here??
    }

}

函数switchButtonTappedUIButton 的actionTarget。如果我在此按钮中添加此代码:

@objc func switchButtonTapped(){

    if setupSession() {
        setupPreview()
        startSession()
    }
}

Camerapreview 屏幕显示白屏并卡住。

【问题讨论】:

  • 查看此链接可能对您有帮助 stackoverflow.com/questions/20864372/…
  • 不鼓励仅提供链接作为答案。如果页面移动,链接可能会中断。请考虑解释您提供的答案的基础知识,因为我们不是在这里进行 OP 可以自己进行的基本搜索。

标签: ios swift avfoundation


【解决方案1】:

试试这个代码:

func switchCamera() {
    session?.beginConfiguration()
    let currentInput = session?.inputs.first as? AVCaptureDeviceInput
    session?.removeInput(currentInput!)
    let newCameraDevice = currentInput?.device.position == .back ? getCamera(with: .front) : getCamera(with: .back)
    let newVideoInput = try? AVCaptureDeviceInput(device: newCameraDevice!)
    session?.addInput(newVideoInput!)
    session?.commitConfiguration()
}

func getCamera(with position: AVCaptureDevice.Position) -> AVCaptureDevice? {
    guard let devices = AVCaptureDevice.devices(for: AVMediaType.video) as? [AVCaptureDevice] else {
        return nil
    }
    
    return devices.filter {
        $0.position == position
        }.first
}

【讨论】:

  • getCamera(with: ) 方法返回什么?它是如何工作的?
【解决方案2】:

开始为前置摄像头创建设备输入:

let frontDevice: AVCaptureDevice? = {
  for device in AVCaptureDevice.devices(for: AVMediaType.video) {
    if device.position == .front {
      return device
    }
  }

  return nil
}()

lazy var frontDeviceInput: AVCaptureDeviceInput? = {
  if let _frontDevice = self.frontDevice {
    return try? AVCaptureDeviceInput(device: _frontDevice)
  }

  return nil
}()

然后在你的switchButtonTapped,如果有前置摄像头你可以做前置和前置的切换:

func switchButtonTapped() {
  if let _frontDeviceInput = frontDeviceInput {
    captureSession.beginConfiguration()

    if let _currentInput = captureSession.inputs.first as? AVCaptureDeviceInput {
      captureSession.removeInput(_currentInput)

      let newDeviceInput = (_currentInput.device.position == .front) ? activeInput : _frontDeviceInput
      captureSession.addInput(newDeviceInput!)
    }

    captureSession.commitConfiguration()
  }
}

如果您需要更多详细信息,请不要犹豫。

【讨论】:

  • 嗨,非常感谢它的工作。但是当我再次点击开关按钮时,应用程序崩溃并出现错误;“一个 AVCaptureInput 实例可能不会被添加到多个会话中”
  • 您确定没有在别处添加activeInput 吗?您可以检查activeInput 是否已经存在于captureSession.inputs 中并相应地添加/删除它。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多