在不删除 previewLayer 的情况下开始新的 captureSession

Begin new captureSession without removing previewLayer

我正在为 CameraView 创建一个 customView,它工作正常,但我现在正在努力从后置摄像头更改为前置摄像头。我现在已经通过以下方式完成了。然而,这似乎会造成糟糕的用户体验,因为它会删除 previewLayer(屏幕变白),然后正确显示前置摄像头。有没有办法在显示新 session?

之前的 1 秒内不让所有内容变白来创造更好的用户体验?

switchCamera

func switchCamera() {
    if usingbackCamera == true {
        endSession()
        beginSession(frontCamera!)
        usingbackCamera = false
        self.cameraView.bringSubviewToFront(actionView)

    } else {
        endSession()
        beginSession(backCamera!)
        usingbackCamera = true
        self.cameraView.bringSubviewToFront(actionView)
    }
}

开始会议

func beginSession(device: AVCaptureDevice) {

    do {
        captureSession.addInput(try AVCaptureDeviceInput(device: device))
        self.previewLayer?.removeFromSuperlayer()
        previewLayer = AVCaptureVideoPreviewLayer(session: captureSession)

        self.cameraView.layer.addSublayer(previewLayer!)

        previewLayer?.frame = self.cameraView.bounds
        captureSession.startRunning()

        stillImageOutput.outputSettings = [AVVideoCodecKey:AVVideoCodecJPEG]
        if captureSession.canAddOutput(stillImageOutput) {
            captureSession.addOutput(stillImageOutput)
        }
        if captureSession.canAddOutput(videoOutput) {
            captureSession.addOutput(videoOutput)
        }



    } catch let err as NSError {
        print(err)
    }

}

结束会议

func endSession() {
    self.previewLayer?.removeFromSuperlayer()
    captureSession.stopRunning()
    captureSession = AVCaptureSession()

}

拍照

func takePicture() {


    if let videoConnection = stillImageOutput.connectionWithMediaType(AVMediaTypeVideo){
        videoConnection.videoOrientation = AVCaptureVideoOrientation.Portrait
        stillImageOutput.captureStillImageAsynchronouslyFromConnection(videoConnection, completionHandler: {
            (sampleBuffer, error) in


                let imageData = AVCaptureStillImageOutput.jpegStillImageNSDataRepresentation(sampleBuffer)
                let dataProvider  = CGDataProviderCreateWithCFData(imageData)
                let cgImageRef = CGImageCreateWithJPEGDataProvider(dataProvider, nil, true, CGColorRenderingIntent.RenderingIntentDefault)

                let image = UIImage(CGImage: cgImageRef!, scale: 1.0, orientation: UIImageOrientation.Right)

                self.previewImageView.image = image
                self.previewImageView.hidden = false
                self.cameraView.bringSubviewToFront(self.previewImageView)





        })
    }


}

我认为您在更改输入设备时不必删除预览层。 该层绑定到会话,您所要做的就是停止会话,删除原始输入并添加新输入,然后再次启动会话。

我通过自定义渲染制作捕获视图,但我认为过程是一样的。

捕获片段:

    for output in session.outputs {
        if let capture = output as? AVCaptureStillImageOutput{
            for connection in (capture.connections as! [AVCaptureConnection]){
                for port in (connection.inputPorts as! [AVCaptureInputPort]){
                    if port.mediaType == AVMediaTypeVideo{
                        capture.captureStillImageAsynchronouslyFromConnection(connection, completionHandler: {(buffer, err) -> Void in
                            if err != nil{
                                print(err)
                            }
                            let imageData = AVCaptureStillImageOutput.jpegStillImageNSDataRepresentation(buffer)
                            guard let image = CIImage(data: imageData) else{
                                completion(nil)
                                return
                            }
                            let rotatedImage = image.imageByApplyingTransform(CGAffineTransformMakeRotation(-CGFloat(M_PI_2)))
                        })
                    }
                }
            }
        }
    }

从后置摄像头切换到前置摄像头时,您无需停止 captureSession 并再次启动它。

您需要做的就是删除旧的捕获会话输入,在 begin/commit 会话配置块之间添加新的输入和所有输入。

这是一个粗略的例子:

  func switchCamera() {
    //begin configuration changes
    captureSession.beginConfiguration()

    //remove the previous inputs
    let inputs = captureSession.inputs as! [AVCaptureInput]
    for oldInput:AVCaptureInput in inputs {
        captureSession.removeInput(oldInput)
    }

    //add the new input
    if usingbackCamera == true {
        addInput(frontCamera!)
        usingbackCamera = false
        self.cameraView.bringSubviewToFront(actionView)

    }
    else {
        addInput(backCamera!)
        usingbackCamera = true
        self.cameraView.bringSubviewToFront(actionView)
    }

    //end the configuration
    captureSession.commitConfiguration()
}


func addInput(device: AVCaptureDevice) {

    do {
        captureSession.addInput(try AVCaptureDeviceInput(device: device))

    } catch let err as NSError {
        print(err)
    }

}