像 Snapchat 或 Houseparty 一样自动将前置摄像头用于 AVCaptureDevice 预览层 (Swift 3)

J.G*_*ork 0 avfoundation avcapturesession swift swift3 xcode8

基本上我想要完成的是让 AVCaptureDevice 的前置摄像头成为 AVCaptureSession 期间应用程序上的第一个也是唯一的选项。

我环顾了 StackOverflow,提供的所有方法和答案都已从 iOS 10、Swift 3 和 Xcode 8 开始弃用。

我知道您应该使用 AVCaptureDeviceDiscoverySession 枚举设备并查看它们以区分正面和背面,但我不确定如何这样做。

有人可以帮忙吗?如果是这样就太棒了!

这是我的代码:

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

    previewLayer.frame = singleViewCameraSlot.bounds
    self.singleViewCameraSlot.layer.addSublayer(previewLayer)
    captureSession.startRunning()

}



lazy var captureSession: AVCaptureSession = {
    let capture = AVCaptureSession()
    capture.sessionPreset = AVCaptureSessionPreset1920x1080
    return capture
}()

lazy var previewLayer: AVCaptureVideoPreviewLayer = {
    let preview =  AVCaptureVideoPreviewLayer(session: self.captureSession)

    preview?.videoGravity = AVLayerVideoGravityResizeAspect
    preview?.connection.videoOrientation = AVCaptureVideoOrientation.portrait
    preview?.bounds = CGRect(x: 0, y: 0, width: self.view.bounds.width, height: self.view.bounds.height)
    preview?.position = CGPoint(x: self.view.bounds.midX, y: self.view.bounds.midY)

    return preview!
}()


func setupCameraSession() {


    let frontCamera = AVCaptureDevice.defaultDevice(withMediaType: AVMediaTypeVideo) as AVCaptureDevice

    do {
        let deviceInput = try AVCaptureDeviceInput(device: frontCamera)

        captureSession.beginConfiguration()

        if (captureSession.canAddInput(deviceInput) == true) {
            captureSession.addInput(deviceInput)
        }

        let dataOutput = AVCaptureVideoDataOutput()

        dataOutput.videoSettings = [(kCVPixelBufferPixelFormatTypeKey as NSString) : NSNumber(value: kCVPixelFormatType_420YpCbCr8BiPlanarFullRange as UInt32)]
        dataOutput.alwaysDiscardsLateVideoFrames = true

        if (captureSession.canAddOutput(dataOutput) == true) {
            captureSession.addOutput(dataOutput)
        }

        captureSession.commitConfiguration()

        let queue = DispatchQueue(label: "io.goodnight.videoQueue")
        dataOutput.setSampleBufferDelegate(self, queue: queue)

    }
    catch let error as NSError {
        NSLog("\(error), \(error.localizedDescription)")
    }

}
Run Code Online (Sandbox Code Playgroud)

ric*_*ter 6

如果您只需要根据简单的特性(例如可以拍摄视频的前置摄像头)查找单个设备,只需使用AVCaptureDevice. default(_:for:position:). 例如:

guard let device = AVCaptureDevice.default(.builtInWideAngleCamera,
    for: .video,
    position: .front)
    else { fatalError("no front camera. but don't all iOS 10 devices have them?")

// then use the device: captureSession.addInput(device) or whatever
Run Code Online (Sandbox Code Playgroud)

实际上,这就是大多数用例的全部内容。


AVCaptureDeviceDiscoverySession可以替代旧的遍历devices数组的方法。但是,您通常在devices数组中迭代的大部分内容都可以使用新default(_:for:position:)方法找到,因此您不妨使用它并编写更少的代码。

AVCaptureDeviceDiscoverySession值得使用的情况是不太常见、更复杂的情况:比如你想找到所有支持特定帧率的设备,或者使用键值观察来查看可用设备集何时发生变化。


顺便一提...

我环顾了 StackOverflow,提供的所有方法和答案都已从 iOS 10、Swift 3 和 Xcode 8 开始弃用。

如果您阅读 Apple 的关于这些方法的文档(至少是这个这个这个),您将看到这些弃用警告以及一些关于使用什么的建议。还有一个iOS 10 / Swift 3 照片捕获系统指南和一些示例代码,它们都显示了这些 API 的当前最佳实践。