AVFoundation captureOutput didOutputSampleBuffer Delay

时间:2017-06-26 00:02:45

标签: ios swift avfoundation cmsamplebuffer avcaptureoutput

我正在使用 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 ,而不是等待?

  1. 队列问题?
  2. CMSampleBuffer保留问题? (虽然在Swift 3上,没有CFRetain)
  3. 更新

    Apple's Documentation

      

    只要输出捕获和,代理就会收到此消息   输出一个新的视频帧,按照规定解码或重新编码   它的videoSettings属性。代表可以使用提供的视频帧   与其他API一起进行进一步处理。

         

    在输出指定的调度队列上调用此方法   sampleBufferCallbackQueue属性。它被定期调用,所以它   必须有效地防止捕获性能问题,包括   丢帧。

         

    如果需要引用之外的CMSampleBuffer对象   这个方法的范围,你必须CFRetain它,然后CFRelease它   你完成了它。

         

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

         

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

0 个答案:

没有答案