在Swift中正确移除AVCaptureSession和PreviewLayer

8

使用iOS Swift从应用中捕获视频流,并希望正确停止。

目前,我已经创建了一个按钮来启动AVCaptureSession,并希望允许同一个按钮在用户偏好时正确地停止AVCaptureSession。这将使用户轻松启动和结束相机捕获。

当我使用以下代码时,我收到错误:

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
    }
}
1个回答

9

停止捕获会话:)

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

那个代码是可以运行的,但是当我尝试重新启动时,会出现未捕获异常错误。我是否也应该停止AVCaptureVideoDataOutput或VNCoreMLRequest呢? - jKraut
1
viewDidLoadviewWillAppear 上调用此函数名 (startsession)。 func startSession() { if !captureSession.isRunning { DispatchQueue.global().async { self.captureSession.startRunning() } } } - SAXENA
我因为这个问题遇到了崩溃:“-[AVCaptureSession startRunning] 应该从后台线程调用。在主线程上调用它可能导致 UI 无响应”,有人之前遇到过吗? - alearner

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接