AVFoundation captureOutput didOutputSampleBuffer Delay

Estoy usando AVFoundation captureOutput didOutputSampleBuffer para extraer una image y luego usarla para un filter.

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 } } 

Por encima de solo las actualizaciones self.cameraBufferImage cada vez que hay un nuevo buffer de muestra de salida.

Luego, cuando se presiona un button de filter, uso self.cameraBufferImage como sigue :

  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!) } } } } } 

Cuando se invoca el método anterior, toma la image de self.cameraBufferImage 'actual' y la usa para aplicar el filter. Esto funciona bien en times de duración de exposition normal (por debajo de 1/15 segundos más o less …)

Problema

Cuando la duración de la exposition es lenta, es decir, 1/3 segundos, se necesita un time (aproximadamente 1/3 segundos) para aplicar el filter. Este retraso solo está presente en la primera vez después del lanzamiento. Si se hace de nuevo, no hay demora en absoluto.


Pensamientos

Entiendo que si la duración de la exposition es 1/3 segundos, didOutputSampleBuffer solo se actualiza cada 1/3 segundos. Sin embargo, ¿por qué es ese retraso inicial? ¿No debería simplemente tomar lo que self.cameraBufferImage esté disponible en ese momento, en lugar de esperar?

  1. ¿Problema de queue?
  2. CMSampleBuffer retiene el problema? (Aunque en Swift 3, no hay CFRetain)

Actualizar

Documentación de Apple

Los delegates reciben este post cada vez que la salida captura y produce un nuevo marco de video, decodificándolo o recodificándolo como lo especifica su propiedad de videoSettings. Los delegates pueden usar el marco de video provisto junto con otras API para su posterior procesamiento.

Este método se invoca en la queue de despacho especificada por la propiedad sampleBufferCallbackQueue de la salida. Se llama periódicamente, por lo que debe ser eficiente para evitar problemas de performance de captura, incluidos los cuadros perdidos.

Si necesita hacer reference al object CMSampleBuffer fuera del scope de este método, debe CFRetain y luego CFRelease cuando haya terminado con él.

Para mantener un performance óptimo, algunos búferes de muestra hacen reference directamente a grupos de memory que pueden necesitar ser reutilizados por el sistema del dispositivo y otras inputs de captura. Este es frecuentemente el caso de la captura nativa de dispositivos sin comprimir donde los bloques de memory se copyn lo less posible. Si varios búferes de muestra hacen reference a dichos grupos de memory durante demasiado time, las inputs ya no podrán copyr nuevas muestras en la memory y esas muestras se eliminarán.

Si su aplicación hace que las muestras se eliminen al retener los objects CMSampleBuffer proporcionados durante demasiado time, pero necesita acceso a los datos de muestra durante un período de time prolongado, considere copyr los datos en un nuevo búfer y luego liberar el búfer de muestra (si se retuvo previamente) para que la memory a la que hace reference pueda reutilizarse.