Ios AVFoundation captureOutput didOutputSampleBuffer延迟

Ios AVFoundation captureOutput didOutputSampleBuffer延迟,ios,swift,avfoundation,cmsamplebuffer,avcaptureoutput,Ios,Swift,Avfoundation,Cmsamplebuffer,Avcaptureoutput,我正在使用AVFoundation captureOutput didOutputSampleBuffer来提取图像,然后用于过滤器 self.bufferFrameQueue = DispatchQueue(label: "bufferFrame queue", qos: DispatchQoS.background, attributes: [], autoreleaseFrequency: .inherit) self.videoDataOutput = AVCaptureVi

我正在使用AVFoundation captureOutput didOutputSampleBuffer来提取图像,然后用于过滤器

  self.bufferFrameQueue = DispatchQueue(label: "bufferFrame queue", qos: DispatchQoS.background,  attributes: [], autoreleaseFrequency: .inherit)

  self.videoDataOutput = AVCaptureVideoDataOutput()
  if self.session.canAddOutput(self.videoDataOutput) {
       self.session.addOutput(videoDataOutput)
       self.videoDataOutput!.alwaysDiscardsLateVideoFrames = true
       self.videoDataOutput!.videoSettings = [kCVPixelBufferPixelFormatTypeKey as String: Int(kCVPixelFormatType_32BGRA)]
           self.videoDataOutput!.setSampleBufferDelegate(self, queue: self.bufferFrameQueue)
  }



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

        connection.videoOrientation = .portrait

        let pixelBuffer = CMSampleBufferGetImageBuffer(sampleBuffer)!
        let ciImage = CIImage(cvPixelBuffer: pixelBuffer)

        DispatchQueue.main.async {
            self.cameraBufferImage = ciImage
        }
}
只要有新的输出样本缓冲区,上面只更新self.cameraBufferImage

然后,当按下过滤器按钮时,我使用self.cameraBufferImage如下:

  func filterButtonPressed() {

    if var inputImage = self.cameraBufferImage {

      if let currentFilter = CIFilter(name: "CISepiaTone") {
        currentFilter.setValue(inputImage, forKey: "inputImage")
        currentFilter.setValue(1, forKey: "inputIntensity")
        if let output = currentFilter.outputImage {
          if let cgimg = self.context.createCGImage(output, from: inputImage.extent) {

            self.filterImageLayer = CALayer()
            self.filterImageLayer!.frame = self.imagePreviewView.bounds
            self.filterImageLayer!.contents = cgimg
            self.filterImageLayer!.contentsGravity = kCAGravityResizeAspectFill
            self.imagePreviewView.layer.addSublayer(self.filterImageLayer!)

          }
        }
      }
    }
  }
调用上述方法时,它将获取“当前”self.cameraBufferImage,并使用它应用过滤器。这在正常曝光持续时间内(低于1/15秒左右)效果良好

问题 当曝光持续时间较慢时,即1/3秒,需要一段时间(约1/3秒)来应用过滤器。此延迟仅在发射后第一次出现。如果再这样做,就不会有任何延误


思想

我知道如果曝光持续时间为1/3秒,didOutputSampleBuffer只会每1/3秒更新一次。然而,为什么会出现最初的延迟?它不应该只抓取在那个确切时间可用的self.cameraBufferImage,而不是等待吗

  • 排队问题
  • CMSampleBuffer保留问题?(尽管在Swift 3上没有CFRetain)

  • 更新

    每当输出捕获并显示时,学员都会收到此消息 输出一个新的视频帧,按照 它的videoSettings属性。学员可以使用提供的视频帧 结合其他API进行进一步处理

    此方法在输出的 sampleBufferCallbackQueue属性。它被周期性地调用,因此 必须能够有效防止捕获性能问题,包括 掉帧

    如果需要在外部引用CMSampleBuffer对象 此方法的作用域,您必须保留它,然后在 你完成了

    为了保持最佳性能,一些示例缓冲区直接 设备可能需要重用的内存引用池 系统和其他捕获输入。这种情况经常发生在 未压缩的设备本机捕获,其中内存块被复制为 尽量少。如果多个样本缓冲区引用了这些样本池 内存太长,输入将无法再复制新样本 这些样本将被丢弃到内存中

    如果您的应用程序通过保留 提供的CMSampleBuffer对象太长,但需要访问 样本数据在很长一段时间内,考虑复制数据 放入新的缓冲区,然后释放样本缓冲区(如果是 以前保留),以便可以重用它引用的内存


    嗨,你有什么解决办法吗?当我前后或前后更改设备类型时,一些帧会掉落并冻结3-4秒,这很容易察觉。