在没有预览窗口的情况下使用AVCaptureVideoDataOutputSampleBufferDelegate

7
我正在开发一款基于Swift的macOS应用程序,需要捕获视频输入,但不在屏幕上显示它...我希望发送缓冲数据以便在别处进行处理,并最终在SceneKit场景中显示它而不是显示视频。
我有一个CameraInput类,其中包含一个prepareCamera方法:
    fileprivate func prepareCamera() {
        self.videoSession = AVCaptureSession()
        self.videoSession.sessionPreset = AVCaptureSession.Preset.photo

        if let devices = AVCaptureDevice.devices() as? [AVCaptureDevice] {
            for device in devices {
                if device.hasMediaType(AVMediaType.video) {
                    cameraDevice = device

                    if cameraDevice != nil  {
                        do {
                            let input = try AVCaptureDeviceInput(device: cameraDevice)


                            if videoSession.canAddInput(input) {
                                videoSession.addInput(input)
                            }


                           } catch {
                            print(error.localizedDescription)
                        }
                    }
                }
            }

            let videoOutput = AVCaptureVideoDataOutput()
            videoOutput.setSampleBufferDelegate(self as AVCaptureVideoDataOutputSampleBufferDelegate, queue: DispatchQueue(label: "sample buffer delegate", attributes: []))
            if videoSession.canAddOutput(videoOutput) {
                videoSession.addOutput(videoOutput)
            }
        }
    }

还有一个startSession方法,用于启动AVCaptureSession会话:

fileprivate func startSession() {
    if let videoSession = videoSession {
        if !videoSession.isRunning {
            self.videoInputRunning = true
            videoSession.startRunning()
        }
    }
}

我还实现了AVCaptureVideoDataOutputSampleBufferDelegate,我打算捕获CMSampleBuffer以便以后使用:

extension CameraInput: AVCaptureVideoDataOutputSampleBufferDelegate {

    internal func captureOutput(_ captureOutput: AVCaptureOutput!, didOutputSampleBuffer sampleBuffer: CMSampleBuffer!, from connection: AVCaptureConnection!) {
        print(Date())
    }
}

然而,代理从未被调用。这是一个需要我必须展示视频输出才能调用的情况吗?


你是在哪个类中编写这些代码?你的输入设备是什么? - El Tomato
@ElTomato 输入设备只是我的Mac的iSight相机。该类是一个名为CameraInput的自定义类,继承自NSObject。 - narner
你没有使用previewLayer。它有什么作用?据我所知,你确实需要它。 - El Tomato
@ElTomato 啊,是的;那是因为我不小心留下来的——我已经更新了上面的代码。 - narner
1个回答

9

您所遇到的问题都与是否显示捕获视频预览无关。

如果您使用的是Swift 4(看起来是这样),那么您要实现的委托方法签名不是captureOutput(_:didOutputSampleBuffer:from:),而是这个

optional func captureOutput(_ output: AVCaptureOutput, 
              didOutput sampleBuffer: CMSampleBuffer, 
                     from connection: AVCaptureConnection)

无关提示:

  • Namespaced constants mean you can be more brief if you like; e.g. videoSession.sessionPreset = .photo

  • AVCaptureDevice.devices() is deprecated. Instead of calling that and looping through devices yourself, just ask AVCaptureDevice for exactly the kind of device you want:

    let captureDevice = AVCaptureDevice.default(.builtInWideAngleCamera, 
                                           for: .video, position: .back)
    
  • You don't need the as cast in videoOutput.setSampleBufferDelegate(self as AVCaptureVideoDataOutputSampleBufferDelegate if your class already declares conformance to the AVCaptureVideoDataOutputSampleBufferDelegate protocol.


最后,如果你只是想将摄像头实时视频映射到SceneKit场景的某个部分,请注意,在iOS 11中,你可以直接将AVCaptureDevice分配给SCNMaterialPropertycontents属性,无需自己获取、处理和移动像素缓冲区。


很棒的答案,这些提示非常有用!谢谢。 - Richard
哇,我真希望SpriteKit也有相同的“contents”功能。我正在尝试在SKNode中显示网络摄像头,看起来我必须将每个帧复制到纹理中。 - bugloaf

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