【问题标题】:captureOutput function isn't called using setSampleBufferDelegate未使用 setSampleBufferDelegate 调用 captureOutput 函数
【发布时间】:2017-08-11 06:22:34
【问题描述】:

我开始开发 iOS 应用,这是我的第一篇 SO 帖子。我正在尝试实现一个 UI 视图,它可以显示后置摄像头的预览视频并处理捕获的帧。我的预览层完美运行,我可以在我的 UI 视图中看到图片显示。但是,从不调用 captureOutput 函数。

我在网上搜索了一段时间的类似问题和解决方案,并尝试调整不同的东西,包括输出、连接和调度队列设置,但都没有奏效。任何人都可以帮助我或分享一些见解和方向吗?提前非常感谢!

这是我的代码,我使用 Xcode 11 betaiOS 10 作为构建目标。

class ThreeDScanningViewController: UIViewController, 
AVCaptureVideoDataOutputSampleBufferDelegate {

    @IBOutlet weak var imageView: UIImageView!

    var session : AVCaptureSession!
    var device : AVCaptureDevice!
    var output : AVCaptureVideoDataOutput!
    var previewLayer : AVCaptureVideoPreviewLayer!

    override func viewDidLoad() {
        super.viewDidLoad()
                //NotificationCenter.default.addObserver(self, selector: #selector(self.startedNotif), name: NSNotification.name.CaptureSessionDidStartRunningNotification, object: nil)

    func initCamera() -> Bool {
        session = AVCaptureSession()
        session.sessionPreset = AVCaptureSession.Preset.medium

        let devices = AVCaptureDevice.devices()

        for d in devices { 
            if ((d as AnyObject).position == AVCaptureDevice.Position.back) {
                device = d as! AVCaptureDevice
            }
        }
        if device == nil {
            return false
        }

        do {
            // Set up the input

            let input : AVCaptureDeviceInput!
            try input = AVCaptureDeviceInput(device: device)

            if session.canAddInput(input) {
                session.addInput(input)
            } else {
                return false
            }

            // Set up the device

            try device.lockForConfiguration()
            device.activeVideoMinFrameDuration = CMTimeMake(1, 15)
            device.unlockForConfiguration()

            // Set up the preview layer

            previewLayer = AVCaptureVideoPreviewLayer(session: session)
            previewLayer.frame = imageView.bounds
            imageView.layer.addSublayer(previewLayer)

            // Set up the output

            output = AVCaptureVideoDataOutput()
            output.videoSettings = [(kCVPixelBufferPixelFormatTypeKey as NSString) as String: kCVPixelFormatType_32BGRA]

            let queue = DispatchQueue(label: "myqueue")
            output!.setSampleBufferDelegate(self, queue: queue)

            output.alwaysDiscardsLateVideoFrames = true

            if session.canAddOutput(output) {
                session.addOutput(output)
            } else {
                return false
            }

            for connection in output.connections {
                if let conn = connection as? AVCaptureConnection {
                    if conn.isVideoOrientationSupported {
                        conn.videoOrientation = AVCaptureVideoOrientation.portrait
                    }
                }
            }

            session.startRunning()

        } catch let error as NSError {
            print(error)
            return false
        }

        return true
    }

    func captureOutput (captureOutput: AVCaptureOutput!, didOutputSampleBuffer sampleBuffer: CMSampleBuffer!, from connection: AVCaptureConnection!) {
        print("captureOutput!\n");
        DispatchQueue.main.async(execute: {
            // Do stuff
        })
    }
}

以下是我查看的一些链接,没有一个与解决我的问题相关:

【问题讨论】:

    标签: swift


    【解决方案1】:

    我终于找到了问题的原因。您需要确保为 Swift 3 语法的 captureOutput 函数使用正确的函数签名。

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

    不是

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

    我使用的是旧版本的 Swift 语法,编译器没有警告我这个问题!更正函数签名后, captureOutput 函数被漂亮地调用:-)

    【讨论】:

    • 感谢您为此发布解决方案,即使您自己找到了。这样其他人也可以找到他们需要的答案!干得好!
    • 谢谢 Canis,你真好! :-)
    • 这应该被标记为正确答案。谢谢@CMao。我仍然对 Apple 没有将方法标记为 deprecated 感到震惊,我花了很长时间才找到问题。
    • 哦,我的话,这很糟糕!我花了几个小时漫无目的地研究 AV 框架(考虑到它对一般货物的崇拜),然后这个答案救了我。谢谢!
    • 这也为我解决了!我已经复制了一些示例代码,这次编译器似乎并不介意。我猜是因为它是一种可选方法。
    【解决方案2】:

    从 Swift 4:

    func captureOutput(_ captureOutput: AVCaptureOutput!, 
    didOutputMetadataObjects metadataObjects: [Any]!, from connection: 
    AVCaptureConnection!)  
    

    不会被调用,因为它不再存在。

    已经改成如下:

    func metadataOutput(_ output: AVCaptureMetadataOutput, didOutput metadataObjects: [AVMetadataObject], from connection: AVCaptureConnection) 
    

    【讨论】:

      【解决方案3】:

      我遇到了类似的问题,但是我的问题是由于我创建 AVCaptureSession 的方式造成的。

      我选择在函数中创建 AVCaptureSession 并将其返回给调用者,这部分很好,但是,我忽略了在导致 AVCaptureSession 超出范围的类变量中保存对会话的引用并在委托被调用之前由 ARC 收集。

      一旦我设置了类变量,以便在调用函数退出时不释放 AVCaptureSession,一切都开始工作了。

      想分享一下,以防其他人遇到同样的问题。

      【讨论】:

        【解决方案4】:

        如果以前的答案无法解决您的 swift 4 及更高版本的问题,通过添加 public 更正函数名称可以解决问题。

        public func captureOutput(_ output: AVCaptureOutput, didOutput sampleBuffer: CMSampleBuffer, from connection: AVCaptureConnection) {}
        

        【讨论】:

          【解决方案5】:

          根据this 教程,您需要在开始运行会话之前提交配置。

          我还看到,在会话开始运行之前,您有多个返回 false 的点。您是否检查过您是否在这些位置之一过早退出?只需控制台输出或返回语句上的断点即可为您提供一些信息。

          【讨论】:

          • 您好 Canis,感谢您的回复!我已经测试并且可以确认该函数在会话开始运行之前不会返回 false。在开始运行会话之前,我将研究提交配置,看看它是如何工作的。再次感谢!
          • 我尝试使用 startConfiguration 和 commitConfiguration 功能,但没有解决问题...
          • @CMao 如果按照该教程不起作用,那么我也很茫然。我的开发环境目前也不允许我自己测试您的代码...您可以尝试在单独的视图控制器中逐步按照教程进行操作吗?哦,另外一个,你是在真实设备上而不是在模拟器上测试?
          【解决方案6】:

          当我将 dualCamera 更改为 AVCaptureDeviceType.builtInWideAngleCamera swift 4 时,问题得到了解决。 希望对有需要的人有所帮助。

          【讨论】:

            猜你喜欢
            • 2017-12-13
            • 1970-01-01
            • 2018-12-10
            • 2016-10-19
            • 2021-12-14
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2022-01-14
            相关资源
            最近更新 更多