在 Swift 中正确移除 AVCaptureSession 和 PreviewLayer

Remove AVCaptureSession and PreviewLayer Properly in Swift

使用 iOS Swift 从 App 捕获视频源,并希望正确停止它。

现在,我创建了一个启动 AVCaptureSession 的按钮,并希望允许同一个按钮在用户喜欢时正确停止 AVCapture 会话。这将允许用户轻松开始和结束相机捕获。

我在使用时收到错误消息:

captureSession.stopRunning()  

代码如下:

import UIKit
import AVFoundation
import Vision

class ViewController: UIViewController, AVCaptureVideoDataOutputSampleBufferDelegate {

    // creates a new capture session
    let captureSession = AVCaptureSession()

    override func viewDidLoad() {
        super.viewDidLoad()

        setupLabel()
        createButton()

    }


    func setupCaptureSession() {

        // search for available capture devices
        let availableDevices = AVCaptureDevice.DiscoverySession(deviceTypes: [.builtInWideAngleCamera], mediaType: AVMediaType.video, position: .back).devices

        // get capture device, add device input to capture session
        do {
            if let captureDevice = availableDevices.first {
                captureSession.addInput(try AVCaptureDeviceInput(device: captureDevice))
            }
        } catch {
            print(error.localizedDescription)
        }

        // setup output for Model 1, add output to capture session
        let captureOutput = AVCaptureVideoDataOutput()
        captureSession.addOutput(captureOutput)

        captureOutput.setSampleBufferDelegate(self, queue: DispatchQueue(label: "videoQueue"))

        let previewLayer = AVCaptureVideoPreviewLayer(session: captureSession)
        previewLayer.frame = view.frame
        view.layer.addSublayer(previewLayer)

        captureSession.startRunning()

    }

    // called everytime a frame is captured
    func captureOutput(_ output: AVCaptureOutput, didOutput sampleBuffer: CMSampleBuffer, from connection: AVCaptureConnection) {

        guard let model_one = try? VNCoreMLModel(for: imagenet_ut().model) else { return }

        let request = VNCoreMLRequest(model: model_one) { (finishedRequest, error) in
            guard let results = finishedRequest.results as? [VNClassificationObservation] else { return }
            guard let Observation = results.first else { return }

            DispatchQueue.main.async(execute: {

                // use model here
            })
        }

        guard let pixelBuffer: CVPixelBuffer = CMSampleBufferGetImageBuffer(sampleBuffer) else { return }

        // executes request
        try? VNImageRequestHandler(cvPixelBuffer: pixelBuffer, options: [:]).perform([request])

        self.label.text = "label text"

    }

    func setupLabel() {
        let label: UILabel = {
            let label = UILabel()
            label.textColor = .white
            label.translatesAutoresizingMaskIntoConstraints = false
            label.text = "Label"
            label.font = label.font.withSize(30)
            return label
        }90

        view.addSubview(label)
        label.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
        label.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: -50).isActive = true
    }

    func createButton () {
        let button = UIButton();
        button.setTitle("Start Camera", for: .normal)
        button.setTitleColor(UIColor.white, for: .normal)
        button.frame = CGRect(x: 5, y: 710, width: 200, height: 100)

        button.addTarget(self, action: #selector(ViewController.buttonPressed(_:)), for: .touchUpInside)
        self.view.addSubview(button)

    }

    @objc func buttonPressed(_ sender: UIButton!) {
        setupCaptureSession()

        if let buttonTitle = sender.title(for: .normal) {
            print(buttonTitle)
            if buttonTitle == "Stop Camera" {
                print("was stopped")
            }
        }

        sender.setTitle("Stop Camera", for: .normal)
    }

    func stopCamera() {
        captureSession.stopRunning()  // error occurs here
    }
}

停止捕获会话:)

func stopSession() {
    if captureSession.isRunning {
        DispatchQueue.global().async {
            self.captureSession.stopRunning()
        }
    }
}